Launcher應(yīng)用的進程啟動流程
緊接上篇從開機到SystemServer系統(tǒng)服務(wù)啟動,這篇分析Launcher應(yīng)用進程是怎么啟動的贺氓。
注意事項寫在前頭:
- 本篇的閱讀順序為啟動關(guān)鍵類介紹--關(guān)鍵類的概述---啟動流程圖----圍繞啟動流程圖的源碼分析。
- 本篇的源碼分析部分(包括已作省略的偽代碼)都務(wù)必配合注釋食用,才能便于理解。
- 完整分析可以從下面開始看起(順序由上至下):
Launcher啟動相關(guān)類
啟動流程關(guān)鍵類的概述(重點)
- ActivityManagerService:Activity生命周期管理類,在SystemServer.java開啟了所有服務(wù)之后會調(diào)用其systemReady方法調(diào)起Launcher應(yīng)用
- ActivityTaskManagerService:原先在ActivityManagerService中管理Activity的工作轉(zhuǎn)移到了ActivityTaskManagerService中(Android10.0重構(gòu)加入)羔飞。
- RootActivityContainer:調(diào)用PackageManagerService查詢已安裝在設(shè)備中的應(yīng)用中符合Launcher的標準骨望,并構(gòu)造Intent對象。
- ActivityStarter:獲取RootActivityContainer中構(gòu)造的Intent對象來進一步啟動Launcher的Activity垂寥,在其中會做啟動前的檢查,比如Activity是否在清單文件注冊,Activity的class文件是否存在勾哩,是否有權(quán)限啟動等等。
- ActivityRecord:是在Server端對Activity的映射(因為Server端無法獲取Activity實例)扼睬,記錄和存儲了Activity的所有信息粪躬。
- TaskRecord:常說的任務(wù)棧,其中記錄了一個或多個ActivityRecord實例對象础淤。
- ActivityStack:直接翻譯像是任務(wù)棧,但實際上是任務(wù)棧(TaskRecord)的管理者角色茅坛,一個應(yīng)用運行時有可能有多個任務(wù)棧,這些任務(wù)棧交由ActivityStack管理。
- ActivityStackSupervisor:設(shè)備運行時會產(chǎn)生一個或多個應(yīng)用他膳,此時會產(chǎn)生一個或多個ActivityStack對象缚甩。ActivityStackSupervisor正是用來管理Launcher和非Launcher應(yīng)用的ActivityStack實例厉熟。
- ProcessList:作用是原先在ActivityManagerService中的啟動進程的工作轉(zhuǎn)移到了ProcessList(Android10.0加入)岛琼。
- ZygoteProcess:建立起與Zygote進程的socket鏈接猬错,將創(chuàng)建進程的所需的信息發(fā)送到Zygote中院尔,由Zygote創(chuàng)建Launcher進程。
講講所謂任務(wù)棧
這里就先來簡單講講ActivityStackSupervisor曹仗,ActivityStack榨汤,TaskRecord,ActivityRecord這幾個類整葡。
ActivityRecord件余、TaskRecord、ActivityStack三個類之間有共同點:都是繼承自ConfigurationContainer,字面意思是配置容器啼器,包括了這些配置(僅舉例旬渠,詳情可自行查資料了解):
- 字體縮放比例;
- 移動國家碼(MCC)端壳、移動網(wǎng)絡(luò)碼(MNC)告丢;
- 區(qū)域(語言);
- 顏色模式(飽和度损谦、HDR)岖免;
- 屏幕布局(尺寸(小中大超大)、是否寬屏或長屏幕照捡、布局方向(從左到右颅湘、從右到左)、是否圓角屏幕)栗精;
- Window邊界范圍(l, t, r, b)闯参、Window方向;
- Window顯示模式(全屏悲立、畫中畫鹿寨、分屏模式-主屏幕、分屏模式-副屏幕薪夕、自由拖動)脚草;
- Activity類型(普通、啟動器/桌面原献、最近任務(wù)/任務(wù)管理器馏慨、語音助手);
- 觸屏類型(無觸屏嚼贡、手寫筆熏纯、手指);
- 鍵盤類型(無鍵盤粤策、QWERTY鍵盤、12鍵)误窖、鍵盤是否可用/彈出叮盘;
- 非觸摸導航設(shè)備(無、方向鍵(上下左右確定返回)霹俺、軌跡球柔吼、方向盤)
- UI類型(普通(常規(guī)手機)、桌面(電腦版)丙唧、車載愈魏、智能電視、嵌入式終端機、智能手表培漏、VR設(shè)備)溪厘、UI模式(日間、夜間)牌柄;
- 屏幕密度畸悬、可用屏幕寬度、可用屏幕高度珊佣;
首先看到ConfigurationContainer是一個抽象類蹋宦,總共有三個抽象方法
//------------------------------ConfigurationContainer.java------------------------------
/**
* Contains common logic for classes that have override configurations and are organized in a
* hierarchy.
*/
// 官方注釋:包含具有覆蓋配置并按層次結(jié)構(gòu)組織的類的通用邏輯。
public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
...
abstract protected int getChildCount();
abstract protected E getChildAt(int index);
abstract protected ConfigurationContainer getParent();
}
而在ActivityRecord中對其的的實現(xiàn):
//------------------------------ActivityRecord.java------------------------------
final class ActivityRecord extends ConfigurationContainer {
private TaskRecord task; // the task this is in.
@Override
protected int getChildCount() {
// {@link ActivityRecord} is a leaf node and has no children.
return 0;
}
@Override
protected ConfigurationContainer getChildAt(int index) {
return null;
}
@Override
protected ConfigurationContainer getParent() {
return getTaskRecord();
}
TaskRecord getTaskRecord() {
return task;
}
}
ActivityRecord的getChildCount
返回0,getChildAt
返回null,而getParent
返回的是它持有的一個TaskRecord實例咒锻。
接下來看看TaskRecord:
//------------------------------TaskRecord.java------------------------------
class TaskRecord extends ConfigurationContainer {
/** List of all activities in the task arranged in history order */
final ArrayList<ActivityRecord> mActivities;
/** Current stack. Setter must always be used to update the value. */
private ActivityStack mStack;
@Override
protected int getChildCount() {
return mActivities.size();
}
@Override
protected ActivityRecord getChildAt(int index) {
return mActivities.get(index);
}
@Override
protected ConfigurationContainer getParent() {
return mStack;
}
}
TaskRecord的getChildCount
返回ActivityRecord集合的容量,getChildAt
返回在mActivities集合取對應(yīng)ActivityRecord實例,而getParent
返回的是它持有的一個ActivityStack實例冷冗。
最后來看看ActivityTask:
//------------------------------ActivityStack.java------------------------------
class ActivityStack extends ConfigurationContainer {
private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
protected final RootActivityContainer mRootActivityContainer;
@Override
protected int getChildCount() {
return mTaskHistory.size();
}
@Override
protected TaskRecord getChildAt(int index) {
return mTaskHistory.get(index);
}
@Override
protected ActivityDisplay getParent() {
return getDisplay();
}
ActivityDisplay getDisplay() {
return mRootActivityContainer.getActivityDisplay(mDisplayId);
}
}
ActivityStack的getChildCount
返回TaskRecord集合的容量,getChildAt
返回在TaskRecord集合取對應(yīng)TaskRecord實例,而getParent
返回的是它持有的一個ActivityDisplay實例.
ActivityDisplay不是我們重點分析的對象,但我們還是來看下它的源碼
//------------------------------ActivityDisplay.java------------------------------
class ActivityDisplay extends ConfigurationContainer<ActivityStack>
implements WindowContainerListener {
private RootActivityContainer mRootActivityContainer;
/**
* All of the stacks on this display. Order matters, topmost stack is in front of all other
* stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls
* changing the list should also call {@link #onStackOrderChanged()}.
*/
private final ArrayList<ActivityStack> mStacks = new ArrayList<>();
@Override
protected int getChildCount() {
return mStacks.size();
}
@Override
protected ActivityStack getChildAt(int index) {
return mStacks.get(index);
}
@Override
protected ConfigurationContainer getParent() {
return mRootActivityContainer;
}
}
ActivityDisplay的的getChildCount
返回ActivityStack集合的容量,getChildAt
返回在ActivityStack集合取對應(yīng)TaskRecord實例,而getParent
返回的是它持有的一個RootActivityContainer實例.
既然追蹤到這就追蹤完吧
RootActivityContainer
//------------------------------RootActivityContainer.java------------------------------
/**
* Root node for activity containers.
* TODO: This class is mostly temporary to separate things out of ActivityStackSupervisor.java. The
* intention is to have this merged with RootWindowContainer.java as part of unifying the hierarchy.
*/
// 官方注釋:表示Activity Containers的根節(jié)點,只是暫時從ActivityStackSupervisor.java分離出來的功能,將來可以統(tǒng)一到RootWindowContainer.java中
class RootActivityContainer extends ConfigurationContainer
implements DisplayManager.DisplayListener {
/**
* List of displays which contain activities, sorted by z-order.
* The last entry in the list is the topmost.
*/
private final ArrayList<ActivityDisplay> mActivityDisplays = new ArrayList<>();
@Override
protected int getChildCount() {
return mActivityDisplays.size();
}
@Override
protected ActivityDisplay getChildAt(int index) {
return mActivityDisplays.get(index);
}
@Override
protected ConfigurationContainer getParent() {
return null;
}
}
在RootActivityContainer這個類中,getChildCount
返回ActivityDisplay集合的容量,getChildAt
返回在ActivityDisplay集合取對應(yīng)TaskRecord實例,而getParent
返回的為null了.
從上面的分析之后可以得到這樣一個圖:
正如上面的ActivityRecord惑艇,TaskRecord贾惦,ActivityStack的概括:
ActivityRecord對應(yīng)著一個Activity實例,TaskRecord對應(yīng)著一個任務(wù)棧敦捧,所以它們都以ArrayList集合的形式存在须板,而ActivityStack也以ArrayList集合的形式存在則是因為Activity啟動時,系統(tǒng)會根據(jù)該Activity的類型和Window顯示模式來決定它所對應(yīng)的TaskRecord應(yīng)該放在哪個Stack(如果沒有合適的就創(chuàng)建)
比如:
- HOME_STACK(啟動器/桌面專屬Stack)兢卵;
- RECENTS_STACK( 最近任務(wù)/任務(wù)管理器專屬)习瑰;
- ASSISTANT_STACK(語音助手專屬);
- FULLSCREEN_WORKSPACE_STACK(全屏應(yīng)用專屬)秽荤;
- PINNED_STACK(畫中畫專屬)甜奄;
- FREEFORM_WORKSPACE_STACK(自由拖動窗口專屬);
簡單分析完任務(wù)棧相關(guān)內(nèi)容窃款,繼續(xù)對Launcher的啟動流程的分析课兄,上篇從開機到SystemServer系統(tǒng)服務(wù)啟動的分析中,在最后SystemSever#startOtherServices方法在開啟了必須的系統(tǒng)服務(wù)后會調(diào)用ActivityManagerService的systemReady方法去調(diào)起Launcher應(yīng)用晨继。
先看看Launcher啟動流程圖:
先看下流程圖烟阐,熟悉關(guān)鍵流程,再進行源碼分析紊扬。
關(guān)鍵處的源碼分析
RootActivityContainer.java
//------------------------------RootActivityContainer.java------------------------------
boolean startHomeOnAllDisplays(int userId, String reason) {
boolean homeStarted = false;
// 遍歷設(shè)備連接的所有屏幕獲取其DisplayId,依次調(diào)用startHomeOnDisplay
// 即依次啟動桌面應(yīng)用
for (int i = mActivityDisplays.size() - 1; i >= 0; i--) {
final int displayId = mActivityDisplays.get(i).mDisplayId;
homeStarted |= startHomeOnDisplay(userId, reason, displayId);
}
return homeStarted;
}
繼續(xù)跟進會到
//------------------------------RootActivityContainer.java------------------------------
// 重點在中文注釋的兩處
boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting,
boolean fromHomeKey) {
// Fallback to top focused display if the displayId is invalid.
if (displayId == INVALID_DISPLAY) {
displayId = getTopDisplayFocusedStack().mDisplayId;
}
Intent homeIntent = null;
ActivityInfo aInfo = null;
if (displayId == DEFAULT_DISPLAY) {
// 這里的mService為ActivityTaskManagerService
// 調(diào)用ActivityTaskManagerService#getHomeIntent()方法返回符合Home類型的Intent
// mark住該處蜒茄,可先追蹤下面的ActivityTaskManagerService#getHomeIntent()分析,再回到此處繼續(xù)分析
homeIntent = mService.getHomeIntent();
// 這里調(diào)用的PackageManagerService的檢索Intent方法
// mark住該處餐屎,可先追蹤下面的resolveHomeActivity分析檀葛,再回到此處繼續(xù)分析
aInfo = resolveHomeActivity(userId, homeIntent);
} else if (shouldPlaceSecondaryHomeOnDisplay(displayId)) {
Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, displayId);
aInfo = info.first;
homeIntent = info.second;
}
if (aInfo == null || homeIntent == null) {
return false;
}
if (!canStartHomeOnDisplay(aInfo, displayId, allowInstrumenting)) {
return false;
}
// Updates the home component of the intent.
homeIntent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
homeIntent.setFlags(homeIntent.getFlags() | FLAG_ACTIVITY_NEW_TASK);
// Updates the extra information of the intent.
if (fromHomeKey) {
homeIntent.putExtra(WindowManagerPolicy.EXTRA_FROM_HOME_KEY, true);
}
// Update the reason for ANR debugging to verify if the user activity is the one that
// actually launched.
final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId(
aInfo.applicationInfo.uid) + ":" + displayId;
// 此處會跳轉(zhuǎn)到ActivityStartController的startHomeActivity中
mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason,
displayId);
return true;
}
//------------------------------ActivityTaskManagerService.java------------------------------
// ActivityTaskManagerService#getHomeIntent()
Intent getHomeIntent() {
Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
intent.setComponent(mTopComponent);
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
// 重點在這里,返回一個Category為Intent.CATEGORY_HOME的Intent
intent.addCategory(Intent.CATEGORY_HOME);
}
return intent;
}
//------------------------------RootActivityContainer.java------------------------------
// RootActivityContainer#resolveHomeActivity(),通過PackageManagerService檢索出符合的Activity
ActivityInfo resolveHomeActivity(int userId, Intent homeIntent) {
final int flags = ActivityManagerService.STOCK_PM_FLAGS;
final ComponentName comp = homeIntent.getComponent();
ActivityInfo aInfo = null;
try {
if (comp != null) {
// Factory test.
aInfo = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
} else {
final String resolvedType =
homeIntent.resolveTypeIfNeeded(mService.mContext.getContentResolver());
final ResolveInfo info = AppGlobals.getPackageManager()
.resolveIntent(homeIntent, resolvedType, flags, userId);
if (info != null) {
aInfo = info.activityInfo;
}
}
} catch (RemoteException e) {
// ignore
}
if (aInfo == null) {
Slog.wtf(TAG, "No home screen found for " + homeIntent, new Throwable());
return null;
}
aInfo = new ActivityInfo(aInfo);
aInfo.applicationInfo = mService.getAppInfoForUser(aInfo.applicationInfo, userId);
return aInfo;
}
至此流程從ActivityTaskManagerService到RootActivityContainer中腹缩,
小結(jié):
- RootActivityContainer通過PackageManagerService檢索出符合啟動的Launcher Activity屿聋,返回其對應(yīng)的ActivityInfo實例(該實例包含了清單文件對Activity的配置信息等)
- 跳轉(zhuǎn)到ActivityStartController的startHomeActivity中空扎,ActivityStartController類的作用是配置Activity啟動前的信息并且傳遞個ActivityStarter。
ActivityStarter.java
追蹤上文中ActivityStartController的startHomeActivity會一路追蹤到ActivityStarter#execute方法(省略了一些非關(guān)鍵處).
//------------------------------ActivityStartController.java------------------------------
void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, int displayId) {
...
// obtainStarter()方法返回ActivityStarter實例
// set系列方法向ActivityStarter實例傳遞參數(shù),最終調(diào)用execute方法
mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
.setOutActivity(tmpOutRecord)
.setCallingUid(0)
.setActivityInfo(aInfo)
.setActivityOptions(options.toBundle())
.execute();
...
}
繼續(xù)分析下execute方法
//------------------------------ActivityStarter.java------------------------------
/**
* Starts an activity based on the request parameters provided earlier.
* @return The starter result.
*/
// 官方注釋:會根據(jù)request參數(shù)啟動Activity
int execute() {
try {
// TODO(b/64750076): Look into passing request directly to these methods to allow
// for transactional diffs and preprocessing.
// 由于啟動流程中沒有配置過mayWait參數(shù)润讥,所以其為默認值false转锈,進入else分支
if (mRequest.mayWait) {
return startActivityMayWait(mRequest.caller, mRequest.callingUid,
mRequest.callingPackage, mRequest.realCallingPid, mRequest.realCallingUid,
mRequest.intent, mRequest.resolvedType,
mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
mRequest.activityOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
mRequest.inTask, mRequest.reason,
mRequest.allowPendingRemoteAnimationRegistryLookup,
mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);
} else {
// 跳轉(zhuǎn)自身的startActivity(...)方法
return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
mRequest.resultWho, mRequest.requestCode, mRequest.callingPid,
mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid,
mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,
mRequest.ignoreTargetSecurity, mRequest.componentSpecified,
mRequest.outActivity, mRequest.inTask, mRequest.reason,
mRequest.allowPendingRemoteAnimationRegistryLookup,
mRequest.originatingPendingIntent, mRequest.allowBackgroundActivityStart);
}
} finally {
onExecutionComplete();
}
}
繼續(xù)跟進會startActivity方法,會在它某個的重載方法中看到一些清單文件檢驗,權(quán)限檢查等操作,我們來看下其中比較重要的幾處代碼.
//------------------------------ActivityStarter.java------------------------------
private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
SafeActivityOptions options,
boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup,
PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
...
// 創(chuàng)建err變量,默認為ActivityManager.START_SUCCESS
// 該int值就是本次啟動Activity的反饋值,所以可以通過追蹤它的賦值來查看該方法執(zhí)行的Activity校驗流程
int err = ActivityManager.START_SUCCESS;
...
// caller是IApplicationThread類型,該參數(shù)是作為傳參傳遞進來的
// 只有當進程創(chuàng)建完成之后,caller才不為null。由于追蹤分析的流程仍未創(chuàng)建進程象对,所以不會進入if分支
if (caller != null) {
callerApp = mService.getProcessController(caller);
if (callerApp != null) {
callingPid = callerApp.getPid();
callingUid = callerApp.mInfo.uid;
} else {
Slog.w(TAG, "Unable to find app for caller " + caller
+ " (pid=" + callingPid + ") when starting: "
+ intent.toString());
err = ActivityManager.START_PERMISSION_DENIED;
}
}
...
// 這個if分支是判斷Activity是否在清單文件中注冊,如果沒有注冊的話,Intent的getComponent會返回null
if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
// We couldn't find a class that can handle the given Intent.
// That's the end of that!
// 表示Activity沒在清單文件注冊
err = ActivityManager.START_INTENT_NOT_RESOLVED;
}
// 這個if分支是判斷Activity的Java文件是否存在,如果Activity的Java文件不存在的話,aInfo為null
if (err == ActivityManager.START_SUCCESS && aInfo == null) {
// We couldn't find the specific class specified in the Intent.
// Also the end of the line.
// 表示沒找到Activity的Java文件,為Activity啟動之前的安全校驗
err = ActivityManager.START_CLASS_NOT_FOUND;
}
...
// 還有會對Activity的后臺啟動做判斷
// Android9.0以后就不允許Activity后臺啟動打動用戶的操作
...
// 還會對Activity的啟動權(quán)限做校驗
// 如果在AndroidManifest.xml中配置了android:permission=""權(quán)限
// 如果想要啟動這個Activity,則要申請這個權(quán)限
...
// 還會對Activity是否可見做校驗
// 如果在AndroidManifest.xml中配置了android:exported="false"
// 別的app就無法啟動該Activity
...
// 最后這個方法又調(diào)用了startActivity的重載方法,繼續(xù)跟進
final int res = startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
true /* doResume */, checkedOptions, inTask, outActivity, restrictedBgActivity);
mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res, outActivity[0]);
return res;
}
// 此處可以看到Framework層對Activity的啟動會做很多判斷,而熱修復中的動態(tài)加載Activity技術(shù),部分Activity是根本沒在清單文件進行注冊的黑忱。
// 在一般情況下動態(tài)加載(未在清單文件中注冊)的Activity根本無法啟動(因為在ActivityStarter會進行多種校驗),而熱修復團隊就是了解了Activity啟動流程勒魔,從而想到了解決辦法甫煞。
跟進下一個startActivity的重載方法發(fā)現(xiàn)它沒做什么重要操作(跳過分析),然后就調(diào)用了startActivityUnchecked方法。該方法需要重點關(guān)注冠绢,因為它會記錄這個Activity要以何種方法啟動以及入棧的方式(啟動時要不要創(chuàng)建新的任務(wù)棧,要不要復用棧中已存在的Activity實例并回調(diào)它的newIntent,還是創(chuàng)建新的Activity對象然后再加入任務(wù)棧)
//------------------------------ActivityStarter.java------------------------------
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity, boolean restrictedBgActivity) {
...
// 根據(jù)Activity的LaunchMode和Intent.flag計算出Activity的入棧方式
computeLaunchingTaskFlags();
// 計算出該Activity的任務(wù)棧,也就是從哪個任務(wù)棧啟動Activity
computeSourceStack();
mIntent.setFlags(mLaunchFlags);
// getReusableIntentActivity從當前的任務(wù)棧中取出是否有可復用的ActivityRecord對象,可為null
ActivityRecord reusedActivity = getReusableIntentActivity();
...
// 表示當前任務(wù)棧中存在可以復用的Activity
if (reusedActivity != null) {
...
// 執(zhí)行其newIntent流程,onNewIntent
deliverNewIntent(top);
...
}
...
// 該方法的出口會調(diào)用RootActivityContainer#resumeFocusedStacksTopActivities方法
mRootActivityContainer.resumeFocusedStacksTopActivities(
mTargetStack, mStartActivity, mOptions);
}
經(jīng)過上述startActivityUnchecked方法的大量計算,在Server進程中要啟動的Activity對應(yīng)的ActivityRecord對象就會入棧了,但是此時Activity實例還未創(chuàng)建,更別說顯示抚吠。在方法出口處會調(diào)用RootActivityContainer#resumeFocusedStacksTopActivities方法.
//------------------------------RootActivityContainer.java------------------------------
// 經(jīng)過上個方法的計算已經(jīng)確定要啟動Activity的所處的ActivityStack任務(wù)棧,以何種方式入棧
// 所以該方法就是去啟動棧頂?shù)腁ctivity
boolean resumeFocusedStacksTopActivities(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
...
// 經(jīng)過該循環(huán)判斷Activity是否已經(jīng)處在Resume狀態(tài),很明顯新入棧待啟動的Activity還未創(chuàng)建成功,更別說resume,顯示,所以resumedOnDisplay為false
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
boolean resumedOnDisplay = false;
...
// resumedOnDisplay為false進入分支,最終調(diào)用ActivityStack的resumeTopActivityUncheckedLocked方法
if (!resumedOnDisplay) {
// In cases when there are no valid activities (e.g. device just booted or launcher
// crashed) it's possible that nothing was resumed on a display. Requesting resume
// of top activity in focused stack explicitly will make sure that at least home
// activity is started and resumed, and no recursion occurs.
final ActivityStack focusedStack = display.getFocusedStack();
if (focusedStack != null) {
focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}
}
}
}
至此流程會從ActivityStarter走到ActivityStack類中,
小結(jié):
- ActivityStarter中對待啟動Activity的清單文件配置,啟動權(quán)限校驗,Java文件是否存在等進行判斷
- 并且根據(jù)啟動模式/Intent.flag等計算出所屬的任務(wù)棧,并將其在Server進程對應(yīng)的ActivityRecord進棧,但此時Activity真正實例仍未創(chuàng)建,更別說顯示
ActivityStack.java
resumeTopActivityUncheckedLocked什么都沒做,緊接著調(diào)用resumeTopActivityInnerLocked,所以我們分析resumeTopActivityInnerLocked
//------------------------------ActivityStack.java------------------------------
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
...
// Find the next top-most activity to resume in this stack that is not finishing and is
// focusable. If it is not focusable, we will fall into the case below to resume the
// top activity in the next focusable task.
// 官方注釋很清晰:獲取棧頂?shù)腁ctivityRecord對象
ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
...
// 判斷待啟動Activity的進程是否已經(jīng)創(chuàng)建,仍未創(chuàng)建所以走else分支
if (next.attachedToProcess()) {
...
} else {
...
// 跳轉(zhuǎn)ActivityStackSupervisor中
mStackSupervisor.startSpecificActivityLocked(next, true, true);
}
}
至此流程從ActivityStack走到ActivityStackSupervisor類中,
小結(jié):
- 判斷待啟動Activity的進程是否已經(jīng)創(chuàng)建
ActivityStackSupervisor.java
這里我們直接進行startSpecificActivityLocked的源碼分析,配合注釋來理解流程弟胀。
//------------------------------ActivityStackSupervisor.java------------------------------
void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
// 再次判斷進程是否已經(jīng)被創(chuàng)建
final WindowProcessController wpc =
mService.getProcessController(r.processName, r.info.applicationInfo.uid);
boolean knownToBeDead = false;
if (wpc != null && wpc.hasThread()) {
try {
// 如果wpc不為null,則會真正去啟動Activity
// 但此時我們追蹤的Launcher進程還沒被創(chuàng)建,所以不會進入這個分支
realStartActivityLocked(r, wpc, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
knownToBeDead = true;
}
// Suppress transition until the new activity becomes ready, otherwise the keyguard can
// appear for a short amount of time before the new process with the new activity had the
// ability to set its showWhenLocked flags.
if (getKeyguardController().isKeyguardLocked()) {
r.notifyUnknownVisibilityLaunched();
}
try {
if (Trace.isTagEnabled(TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "dispatchingStartProcess:"
+ r.processName);
}
// Post message to start process to avoid possible deadlock of calling into AMS with the
// ATMS lock held.
// 所以Launcher啟動流程會執(zhí)行到這里
// ActivityManagerInternal::startProcess的寫法是用于適配Java8之前的方法傳參,實際是調(diào)用ActivityManagerService#LocalService的startProcess方法
final Message msg = PooledLambda.obtainMessage(
ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName,
r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent());
mService.mH.sendMessage(msg);
} finally {
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
...
}
至此流程從ActivityStackSupervisor類結(jié)束,之后會跳轉(zhuǎn)到ActivityManagerService#LocalService的startProcess方法中
小結(jié):
- ActivityStackSupervisor#startSpecificActivityLocked會再次判斷待啟動Activity進程是否已存在,若存在則真正啟動Activity,調(diào)用其realStartActivityLocked方法
- 若不存在,則調(diào)用ActivityManagerService#LocalService的startProcess方法創(chuàng)建進程
ProcessList.java
流程從ActivityStackSupervisor類又回到了ActivityManagerService類中,確實在舊的版本中創(chuàng)建進程的工作是由ActivityManagerService完成的,但是Google團隊覺得ActivityManagerService已經(jīng)十分臃腫,所以在Android10.0之后增加了ProcessList類將之前在AMS的工作轉(zhuǎn)移到其中.
startProcess方法跳轉(zhuǎn)到startProcessLocked方法之后,會發(fā)現(xiàn)直接進入ProcessList的流程中(省略部分非關(guān)鍵處),所以我們直接追蹤ProcessList#startProcessLocked方法
//------------------------------ProcessList.java------------------------------
/**
* Activity manager code dealing with processes.
*
* Method naming convention:
* <ul>
* <li> Methods suffixed with "LS" should be called within the {@link #sLmkdSocketLock} lock.
* </ul>
*/
// 官方注釋: 管理Activity的進程的工作
public final class ProcessList {
...
// 該方法以及在本類跳轉(zhuǎn)的系列方法主要作用都是在進程創(chuàng)建之前配置其必要的參數(shù),比如abi類型,版本號
// 其中有一個很重要的參數(shù),需要了解,就是final String entryPoint = "android.app.ActivityThread";(該參數(shù)會在系列跳轉(zhuǎn)方法中使用楷力,這里我們直接指出來)
// ActivityThread這就是應(yīng)用進程的入口類,并不是我們熟知的Application
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
boolean knownToBeDead, int intentFlags, HostingRecord hostingRecord,
boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
...
...
}
...
}
至此從ProcessList所在流程追蹤到這,進程的配置完成之后會跳轉(zhuǎn)到ZygoteProcess.java類
小結(jié):
- ProcessList的流程主要是在進程創(chuàng)建之前配置其必要的參數(shù),比如abi類型,版本號,其中其中有一個很重要的參數(shù)需要了解,就是final String entryPoint = "android.app.ActivityThread";
- 表明了應(yīng)用進程的入口類,并不是我們熟知的Application,而是ActivityThread。
ZygoteProcess.java
此時仍處于SystemServer進程中,這個類的目的是創(chuàng)建本地Socket連接對象,并且連接遠在Zygote進程的Socket服務(wù)
//------------------------------ZygoteProcess.java------------------------------
/**
* Tries to open a session socket to a Zygote process with a compatible ABI if one is not
* already open. If a compatible session socket is already open that session socket is returned.
* This function may block and may have to try connecting to multiple Zygotes to find the
* appropriate one. Requires that mLock be held.
*/
// 創(chuàng)建本地Socket連接對象,并且連接遠在Zygote進程的Socket服務(wù)孵户,這里我們就不重點分析了萧朝,感興趣的童鞋可以追蹤下源碼
@GuardedBy("mLock")
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
try {
attemptConnectionToPrimaryZygote();
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}
if (mZygoteSecondarySocketAddress != null) {
// The primary zygote didn't match. Try the secondary.
attemptConnectionToSecondaryZygote();
if (secondaryZygoteState.matches(abi)) {
return secondaryZygoteState;
}
}
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to zygote", ioe);
}
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}
至此流程從ZygoteProcess走到Zygote進程中,小結(jié):
- 在ZygoteProcess會創(chuàng)建本地Socket連接對象,并且連接遠在Zygote進程的Socket服務(wù)
- 然后通過字符輸入流將進程創(chuàng)建所需參數(shù)發(fā)送到Zygote進程中
Zygote進程
最后Zygote進程會創(chuàng)建出新的進程,在進程創(chuàng)建完畢之后,會根據(jù)進程傳遞的入口類(ActivityThread)由ZygoteInit進行反射執(zhí)行,這樣調(diào)用到了App應(yīng)用進程的入口類ActivityThread夏哭。Launcher應(yīng)用的進程啟動流程分析也就到一段落了检柬。
最后,來講下Framework源碼分析套路
在Framework層中有許多面向接口的設(shè)計模式竖配,這種設(shè)計模式可以保證在接口不變的情況下改變其真正的實現(xiàn)何址,但對于源碼分析追蹤并不友好,下面是一個被總結(jié)出來的源碼分析套路:當遇到分析跳轉(zhuǎn)的是xxxManagerInternal抽象類時进胯,可以嘗試尋找xxxManagerService$LocalService是否存在并繼承于xxxManagerInternal抽象類用爪。如果是,這一般就是其真正的實現(xiàn)類胁镐。