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机制创建子进程,这里不分析这部分内容。