11.2.3 启动应用程序进程

启动应用程序Activity的第三阶段是启动应用程序进程,该阶段的主要工作是创建目标Activity所运行的进程。这个阶段由5个主要步骤组成,接下来详细分析各个步骤。

1.第二次进入resumeTopActivityLocked(ActivityRecord prev)

启动应用程序进程的第一步由ActivityStack.resumeTopActivityLocked(ActivityRecord prev)方法完成,这是第二次进入该方法。代码如下:


final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options){

//取出第一个非finishing的Activity,此时的next变成了Settings.

ActivityRecord next=topRunningActivityLocked(null);

final boolean userLeaving=mUserLeaving;//false

mUserLeaving=false;

if(next==null){//不满足

……

}

next.delayedResume=false;

//mResumedActivity为null, next.state为INITIALIZING

if(mResumedActivity==next&&next.state==ActivityState.RESUMED){

……

}

……

if(mPausingActivity!=null){//mPausingActivity已经重置为null

return false;

}

if(mResumedActivity!=null){//此时为null

startPausingLocked(userLeaving, false);

return true;

}

……//上面的代码都是第一次进入resumeTopActivityLocked时执行的,此时跳过执行

if(prev!=null&&prev!=next){//prev是Launcher, next是Settings

if(!prev.waitingVisible&&next!=null&&!next.nowVisible){

prev.waitingVisible=true;

mWaitingVisibleActivities.add(prev);

}else{

/*prev处于finish状态时,需要立刻使其不可见,从而

*使新Activity立刻可见。prev处于非finish状态时

需要根据新Activity是否占满全屏决定prev是否可见/

if(prev.finishing){//前一个Activity为Launcher,不满足该分支

mService.mWindowManager.setAppVisibility(prev.appToken, false);

}else{//满足此分支

……//打印log

}

}

}

//确定应用程序非stop状态

try{

AppGlobals.getPackageManager().setPackageStoppedState(

next.packageName, false, next.userId);

}

……

boolean noAnim=false;

if(prev!=null){

if(prev.finishing){

……

}else{//满足该分支

if(mNoAnimActivities.contains(next)){

……

}else{

//准备切换动画

mService.mWindowManager.prepareAppTransition(

prev.task==next.task

?WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN

:WindowManagerPolicy.TRANSIT_TASK_OPEN, false);

}

}

}else if(mHistory.size()>1){

……

}

if(!noAnim){

next.applyOptionsLocked();

}else{

next.clearOptionsLocked();//Options存储切换动画信息,不需要动画便清空

}

//next.app为ProcessRecord,此时还未创建应用程序进程,因此为null

if(next.app!=null&&next.app.thread!=null){

……//

}else{//满足

if(!next.hasBeenLaunched){//该Activity是否已经启动过?,此时为false

next.hasBeenLaunched=true;

}else{//如果Activity已启动,则直接执行restart

if(SHOW_APP_STARTING_PREVIEW){

//显示Activity窗口之前,先显示一个过渡窗口(Starting Window)

mService.mWindowManager.setAppStartingWindow(

next.appToken, next.packageName, next.theme,

mService.compatibilityInfoForPackageLocked(

next.info.applicationInfo),

next.nonLocalizedLabel,

next.labelRes, next.icon, next.windowFlags,

null, true);

}

}

startSpecificActivityLocked(next, true, true);//执行到这里

}

return true;

}


与第一次进入resumeTopActivityLocked方法最大的不同之处是:此时mResumedActivity为null,即此前处于resume状态的Launcher已经进入暂停状态。因此,首先从mHistory中取出第一个非finishing状态的ActivityRecord,此时next变成了Settings,然后调用startSpecificActivityLocked方法进入启动应用程序进程阶段的第二步。

2.ActivityStack.startSpecificActivityLocked

启动应用程序进程阶段的第二步由ActivityStack.startSpecificActivityLocked方法完成,代码如下:


private final void startSpecificActivityLocked(ActivityRecord r,

boolean andResume, boolean checkConfig){

//第一次启动Activity,此时其应用程序进程还没有创建,因此app为null

//ProcessRecord将记录Settings的进程信息,包括UID、进程名、UI主线程等

ProcessRecord app=mService.getProcessRecordLocked(r.processName,

r.info.applicationInfo.uid);

……

if(app!=null&&app.thread!=null){//第一次启动的时候不满足

try{

//应用进程已经存在,则直接启动Activity

app.addPackage(r.info.packageName);

realStartActivityLocked(r, app, andResume, checkConfig);

return;

}catch(RemoteException e){

Slog.w(TAG,"Exception when starting activity"

+r.intent.getComponent().flattenToShortString(),e);

}

}

//否则,启动应用程序进程,最终还是要执行realStartActivityLocked

mService.startProcessLocked(r.processName, r.info.applicationInfo,

true,0,"activity",r.intent.getComponent(),false, false);

}


startSpecificActivityLocked方法首先查询ActivityManagerService.mProcessNames成员变量中是否已经存在指定的进程信息,如果存在便复用该进程信息,直接启动Activity;否则调用ActivityManagerService的startProcessLocked方法创建进程信息。

3.startProcessLocked(String processName,……)

启动应用程序进程的第三步是startProcessLocked(String processName,……)方法,代码如下:


final ProcessRecord startProcessLocked(String processName,

ApplicationInfo info, boolean knownToBeDead, int intentFlags,

String hostingType, ComponentName hostingName,……){

ProcessRecord app;

if(!isolated){

//对于非isolated的app,需要从mProcessNames中查询是否已经存在其进程信息

app=getProcessRecordLocked(processName, info.uid);

}else{

app=null;//对于isolated的app,不能复用已经存在的进程

}

/*在本例中,processName=com.android.settings

app=null knownToBeDead=true thread=null pid=-1/

if(app!=null&&app.pid>0){//复用已有的进程

if(!knownToBeDead||app.thread==null){

app.addPackage(info.packageName);

return app;

}else{

handleAppDiedLocked(app, true, true);

}

}

//hostingName表示运行于该进程的组件类型,本例中为Activity

String hostingNameStr=hostingName!=null

?hostingName.flattenToShortString():null;

if(!isolated){

//FLAG_FROM_BACKGROUND用于表明该Intent由后台程序发出(即非用户交互界面)

if((intentFlags&Intent.FLAG_FROM_BACKGROUND)!=0){

/*如果此时要启动的app是bad process,那么需要直接返回。不希望

*后台程序启动一个bad process导致出现莫名其妙的错误信息影响用户体验。

*所谓bad process,指那些在最小时间段内连续出现两次crash的程序,最

小时间段由ProcessList.MIN_CRASH_INTERVAL指定,默认为1分钟/

if(mBadProcesses.get(info.processName, info.uid)!=null){

return null;

}

}else{

/*如果是用户在交互界面显式启动一个app,将首先从mProcessCrashTimes中

删除这个bad process的最后一次crash的时间信息/

mProcessCrashTimes.remove(info.processName, info.uid);

/*此时即便是bad process,用户也能得到一些错误提示

信息,因此需要从mBadProcesses列表中删除/

if(mBadProcesses.get(info.processName, info.uid)!=null){

mBadProcesses.remove(info.processName, info.uid);

if(app!=null){

app.bad=false;

}

}

}

}

if(app==null){

//创建一个新的ProcessRecord

app=newProcessRecordLocked(null, info, processName, isolated);

if(app==null){

return null;

}

//将新建的ProcessRecord存入mProcessNames,该变量中将保存当前运行的app

mProcessNames.put(processName, app.uid, app);

if(isolated){

mIsolatedProcesses.put(app.uid, app);

}

}else{

app.addPackage(info.packageName);

}

/*mProcessesReady是在ActivityManagerService的systemReady执行完程序

*升级后,赋值为true的。该值表明此时系统进入可以真正启动应用程序的阶段。如果

还没有进入此状态,需要先将启动的应用进程加入mProcessesOnHold列表中等待/

if(!mProcessesReady

&&!isAllowedWhileBooting(info)

&&!allowWhileBooting){

if(!mProcessesOnHold.contains(app)){

mProcessesOnHold.add(app);

}

return app;

}

//调用重载方法startProcessLocked(ProcessRecord app,……)

startProcessLocked(app, hostingType, hostingNameStr);

return(app.pid!=0)?app:null;

}


startProcessLocked(String processName,……)方法首先根据processName查找ActivityManagerService的成员变量mProcessNames中是否已经存在该进程名对应的进程ProcessRecord信息,如果找到对应的ProcessRecord信息,则直接复用该信息。本例是第一次启动Settings应用程序,不可能存在其进程信息,因此调用newProcessRecordLocked方法创建Settings对应的ProcessRecord进程信息,并将其存入mProcessNames中。最后调用startProcessLocked,以进程信息为参数创建进程。

4.startProcessLocked(ProcessRecord app,……)

启动应用程序进程的第四步由startProcessLocked(ProcessRecord app,……)方法完成,代码如下:


private final void startProcessLocked(ProcessRecord app,

String hostingType, String hostingNameStr){

/*如果已经指定了PID且非当前进程的PID,需要从已有记录中删除,

本例app.pid未分配,值为0;MY_PID是system_server的进程ID/

if(app.pid>0&&app.pid!=MY_PID){

synchronized(mPidsSelfLocked){

mPidsSelfLocked.remove(app.pid);

mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);

}

app.pid=0;

}

//从mProcessesOnHold列表中删除等待的ProcessRecord

mProcessesOnHold.remove(app);

……

try{

int uid=app.uid;

int[]gids=null;

if(!app.isolated){

try{//通过PackageManagerService获取应用程序组ID

gids=mContext.getPackageManager().getPackageGids(

app.info.packageName);

}catch(PackageManager.NameNotFoundException e){

Slog.w(TAG,"Unable to retrieve gids",e);

}

}

……//Factory Test

int debugFlags=0;

……//设置Zygote调试标记,会读取属性配置

/*通过zygote启动一个新的进程。其本质仍然是fork出一个子进程,然后

在子进程中执行android.app.ActivityThread类的main方法/

Process.ProcessStartResult startResult=Process.start(

"android.app.ActivityThread",

app.processName, uid, uid, gids, debugFlags,

app.info.targetSdkVersion, null);

BatteryStatsImpl bs=app.batteryStats.getBatteryStats();

synchronized(bs){

if(bs.isOnBattery()){

app.batteryStats.incStartsLocked();//记录进程启动次数

}

}

/*对于persistent类型的应用程序,需要通知Watchdog

*processStarted方法内部,仅仅判断新进程是否为com.android.phone,

如果是,将该PID记录到mPhonePid/

if(app.persistent){

Watchdog.getInstance().processStarted(app.processName,

startResult.pid);

}

/*第一次启动应用程序时在logcat中打印的Start proc信息便来自于此。

*在本例中其信息如下:

*Start proc com.android.settings for activity

*com.android.settings/.Settings:pid=725 uid=1000

gids={1015,3002,3001,3003,1028}/

……//打印Start proc的详细信息

app.pid=startResult.pid;//获得PID

app.usingWrapper=startResult.usingWrapper;

app.removed=false;

synchronized(mPidsSelfLocked){

/*将应用进程信息存入mPidsSelfLocked中,该变量以PID为键

存储当前正在运行的应用程序进程信息/

this.mPidsSelfLocked.put(startResult.pid, app);

/*发送一个超时处理的消息,如果新创建的应用进程在指定时间内

*没有attach到ActivityManagerService,则认为该进程启动超时,将触发

*相应的处理函数。在通常情况下,指定超时时间为10s;如果应用程序运行在

一个监测环境下,比如使用valgrind监测内存使用,此时指定时间为30s/

Message msg=mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);

msg.obj=app;

mHandler.sendMessageDelayed(msg, startResult.usingWrapper

?PROC_START_TIMEOUT_WITH_WRAPPER:PROC_START_TIMEOUT);

}

}catch(RuntimeException e){//启动进程失败

app.pid=0;

}

}


startProcessLocked(ProcessRecord app,……)方法的主要工作是通过PackageManagerService获取当前应用程序的组ID,然后调用Process.start创建应用程序进程,该进程的入口是android.app.ActivityThread的main方法。进程创建完毕后,便拥有了自己的PID。此外,在创建进程的过程中,ActivityManagerService会发送一个超时消息PROC_START_TIMEOUT_MSG到自身的消息队列中,并指定PROC_START_TIMEOUT(10s)或者PROC_START_TIMEOUT_WITH_WRAPPER(30s)后处理该消息。如果Process.start不能在指定时间内完成启动工作并通知ActivityManagerService,会触发超时处理。Process.start方法启动应用程序的本质是使用Linux的fork机制创建子进程,这里不分析这部分内容。