startActivityLocked是startActivityMayWait第二阶段的工作重点,该函数有点长,请读者耐心看代码。
**ActivityStack.java::startActivityLocked**
~~~
final int startActivityLocked(IApplicationThreadcaller,
Intent intent, String resolvedType,
Uri[] grantedUriPermissions,
int grantedMode, ActivityInfo aInfo, IBinder resultTo,
String resultWho, int requestCode,
int callingPid, int callingUid, boolean onlyIfNeeded,
boolean componentSpecified, ActivityRecord[]outActivity) {
int err = START_SUCCESS;
ProcessRecord callerApp = null;
//如果caller不为空,则需要从AMS中找到它的ProcessRecord。本例的caller为null
if(caller != null) {
callerApp = mService.getRecordForAppLocked(caller);
//其实就是想得到调用进程的pid和uid
if(callerApp != null) {
callingPid = callerApp.pid;//一定要保证调用进程的pid和uid正确
callingUid = callerApp.info.uid;
}else {//如调用进程没有在AMS中注册,则认为其是非法的
err = START_PERMISSION_DENIED;
}
}// if (caller != null)判断结束
//下面两个变量意义很重要。sourceRecord用于描述启动目标Activity的那个Activity,
//resultRecord用于描述接收启动结果的Activity,即该Activity的onActivityResult
//将被调用以通知启动结果,读者可先阅读SDK中startActivityForResult函数的说明
ActivityRecordsourceRecord = null;
ActivityRecord resultRecord = null;
if(resultTo != null) {
//本例resultTo为null,
}
//获取Intent设置的启动标志,它们是和Launch Mode相类似的“小把戏”,
//所以,读者务必理解“关于Launch Mode的介绍”一节的知识点
intlaunchFlags = intent.getFlags();
if((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
&& sourceRecord != null) {
......
/*
前面介绍的Launch Mode和Activity的启动有关,实际上还有一部分标志用于控制
Activity启动结果的通知。有关FLAG_ACTIVITY_FORWARD_RESULT的作用,读者可
参考SDK中的说明。使用这个标签有个前提,即A必须先存在,正如if中sourceRecord
不为null的判断所示。另外,读者自己可尝试编写例子,以测试FLAG_ACTIVITY_FORWARD_
RESULT标志的作用
*/
}
//检查err值及Intent的情况
if (err== START_SUCCESS && intent.getComponent() == null)
err = START_INTENT_NOT_RESOLVED;
......
//如果err不为0,则调用sendActivityResultLocked返回错误
if (err!= START_SUCCESS) {
if(resultRecord != null) {// resultRecord接收启动结果
sendActivityResultLocked(-1,esultRecord, resultWho, requestCode,
Activity.RESULT_CANCELED, null);
}
.......
returnerr;
}
//检查权限
finalint perm = mService.checkComponentPermission(aInfo.permission,
callingPid,callingUid,aInfo.applicationInfo.uid, aInfo.exported);
......//权限检查失败的处理,不必理会
if (mMainStack) {
//可为AMS设置一个IActivityController类型的监听者,AMS有任何动静都会回调该
//监听者。不过谁又有如此本领去监听AMS呢?在进行Monkey测试的时候,Monkey会
//设置该回调对象。这样,Monkey就能根据AMS放映的情况进行相应处理了
if(mService.mController != null) {
boolean abort = false;
try {
Intent watchIntent = intent.cloneFilter();
//交给回调对象处理,由它判断是否能继续后面的行程
abort = !mService.mController.activityStarting(watchIntent,
aInfo.applicationInfo.packageName);
}......
//回调对象决定不启动该Activity。在进行Monkey测试时,可设置黑名单,位于
//黑名单中的Activity将不能启动
if (abort) {
.......//通知resultRecord
return START_SUCCESS;
}
}
}// if(mMainStack)判断结束
//创建一个ActivityRecord对象
ActivityRecordr = new ActivityRecord(mService, this, callerApp, callingUid,
intent, resolvedType, aInfo, mService.mConfiguration,
resultRecord, resultWho, requestCode, componentSpecified);
if(outActivity != null)
outActivity[0] = r;//保存到输入参数outActivity数组中
if(mMainStack) {
//mResumedActivity代表当前界面显示的Activity
if(mResumedActivity == null
|| mResumedActivity.info.applicationInfo.uid!= callingUid) {
//检查调用进程是否有权限切换Application,相关知识见下文的解释
if(!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
"Activity start")) {
PendingActivityLaunch pal = new PendingActivityLaunch();
//如果调用进程没有权限切换Activity,则只能把这次Activity启动请求保存起来,
//后续有机会时再启动它
pal.r = r;
pal.sourceRecord = sourceRecord;
......
//所有Pending的请求均保存到AMS mPendingActivityLaunches变量中
mService.mPendingActivityLaunches.add(pal);
mDismissKeyguardOnNextActivity = false;
return START_SWITCHES_CANCELED;
}
}//if(mResumedActivity == null...)判断结束
if (mService.mDidAppSwitch) {//用于控制app switch,见下文解释
mService.mAppSwitchesAllowedTime = 0;
} else{
mService.mDidAppSwitch = true;
}
//启动处于Pending状态的Activity
mService.doPendingActivityLaunchesLocked(false);
}// if(mMainStack)判断结束
//调用startActivityUncheckedLocked函数
err =startActivityUncheckedLocked(r, sourceRecord,
grantedUriPermissions, grantedMode, onlyIfNeeded, true);
......
return err;
}
~~~
startActivityLocked函数的主要工作包括:
- 处理sourceRecord及resultRecord。其中,sourceRecord表示发起本次请求的Activity,resultRecord表示接收处理结果的Activity(启动一个Activity肯定需要它完成某项事情,当目标Activity将事情成后,就需要告知请求者该事情的处理结果)。在一般情况下,sourceRecord和resultRecord应指向同一个Activity。
- 处理app Switch。如果AMS当前禁止app switch,则只能把本次启动请求保存起来,以待允许app switch时再处理。从代码中可知,AMS在处理本次请求前,会先调用doPendingActivityLaunchesLocked函数,在该函数内部将启动之前因系统禁止app switch而保存的Pending请求。
- 调用startActivityUncheckedLocked处理本次Activity启动请求。
先来看app Switch,它虽然是一个小变量,但是意义重大。
1. 关于resume/stopAppSwitches的介绍
AMS提供了两个函数,用于暂时(注意,是暂时)禁止App切换。为什么会有这种需求呢?因为当某些重要(例如设置账号等)Activity处于前台(即用户当前所见的Activity)时,不希望系统因用户操作之外的原因而切换Activity(例如恰好此时收到来电信号而弹出来电界面)。
先来看stopAppSwitches,代码如下:
**ActivityManagerService.java::stopAppSwitches**
~~~
public void stopAppSwitches() {
......//检查调用进程是否有STOP_APP_SWITCHES权限
synchronized(this) {
//设置一个超时时间,过了该时间,AMS可以重新切换App(switch app)了
mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
+ APP_SWITCH_DELAY_TIME;
mDidAppSwitch = false;//设置mDidAppSwitch为false
mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
Message msg =//防止应用进程调用了stop却没调用resume,5秒后处理该消息
mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
}
}
~~~
在以上代码中有两点需要注意:
- 此处控制机制名叫app switch,而不是activity switch。为什么呢?因为如果从受保护的activity中启动另一个activity,那么这个新activity的目的应该是针对同一任务,这次启动就不应该受app switch的制约,反而应该对其大开绿灯。目前,在执行Settings中设置设备策略(DevicePolicy)时就会stopAppSwitch。
- 执行stopAppSwitch后,应用程序应该调resumeAppSwitches以允许app switch,但是为了防止应用程序有意或无意忘记resume app switch,系统设置了一个超时(5秒)消息,过了此超时时间,系统将处理相应的消息,其内部会resume app switch。
再来看resumeAppSwitches函数,代码如下:
**ActivityManagerService::resumeAppSwitches**
~~~
public voidresumeAppSwitches() {
......//检查调用进程是否有STOP_APP_SWITCHES权限
synchronized(this) {
mAppSwitchesAllowedTime = 0;
}
//注意,系统并不在此函数内启动那些被阻止的Activity
}
~~~
在resumeAppSwitches中只设置mAppSwitchesAllowedTime的值为0,它并不处理在stop和resume这段时间内积攒起的Pending请求,那么这些请求是在何时被处理的呢?
- 从前面代码可知,如果在执行resume app switch后,又有新的请求需要处理,则先处理那些pending的请求(调用doPendingActivityLaunchesLocked)。
- 在resumeAppSwitches中并未撤销stopAppSwitches函数中设置的超时消息,所以在处理那条超时消息的过程中,也会处理pending的请求。
在本例中,由于不考虑app switch的情况,那么接下来的工作就是调用startActivityUncheckedLocked函数来处理本次activity的启动请求。此时,我们已经创建了一个ActivityRecord用于保存目标Activity的相关信息。
2. startActivityUncheckedLocked函数分析
startActivityUncheckedLocked函数很长,但是目的比较简单,即为新创建的ActivityRecord找到一个合适的Task。虽然本例最终的结果是创建一个新的Task,但是该函数的处理逻辑却比较复杂。先看第一段分析。
(1) startActivityUncheckedLocked分析之一
**ActivityStack.java::startActivityUncheckedLocked**
~~~
final intstartActivityUncheckedLocked(ActivityRecord r,
ActivityRecord sourceRecord, Uri[] grantedUriPermissions,
intgrantedMode, boolean onlyIfNeeded, boolean doResume) {
//在本例中,sourceRecord为null,onlyIfNeeded为false,doResume为true
finalIntent intent = r.intent;
final intcallingUid = r.launchedFromUid;
intlaunchFlags = intent.getFlags();
//判断是否需要调用因本次Activity启动而被系统移到后台的当前Activity的
//onUserLeaveHint函数。可阅读SDK文档中关于Activity onUserLeaveHint函数的说明
mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) ==0;
//设置ActivityRecord的delayedResume为true,本例中的doResume为true
if (!doResume) r.delayedResume = true;
//在本例中,notTop为null
ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
!= 0 ? r : null;
if(onlyIfNeeded) {....//在本例中,该变量为false,故略去相关代码
}
//根据sourceRecord的情况进行对应处理,能理解下面这段if/else的判断语句吗
if(sourceRecord == null) {
//如果请求的发起者为空,则当然需要新建一个Task
if((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0)
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}else if (sourceRecord.launchMode ==ActivityInfo.LAUNCH_SINGLE_INSTANCE){
//如果sourceRecord单独占一个Instance,则新的Activity必然处于另一个Task中
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
} else if(r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
//如果启动模式设置了singleTask或singleInstance,则也要创建新Task
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}//if(sourceRecord== null)判断结束
//如果新Activity和接收结果的Activity不在一个Task中,则不能启动新的Activity
if(r.resultTo!= null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
sendActivityResultLocked(-1,r.resultTo, r.resultWho, r.requestCode,
Activity.RESULT_CANCELED, null);
r.resultTo = null;
}
~~~
startActivityUncheckedLocked第一阶段的工作还算简单,主要确定是否需要为新的Activity创建一个Task,即是否设置FLAG_ACTIVITY_NEW_TASK标志。
接下来看下一阶段的工作。
(2) startActivityUncheckedLocked分析之二
**ActivityStack.java::startActivityUncheckedLocked**
~~~
booleanaddingToTask = false;
TaskRecord reuseTask = null;
if(((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK)== 0)
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
if(r.resultTo == null) {
//搜索mHistory,得到一个ActivityRecord
ActivityRecord taskTop = r.launchMode !=
ActivityInfo.LAUNCH_SINGLE_INSTANCE
?findTaskLocked(intent, r.info)
: findActivityLocked(intent,r.info);
if (taskTop != null ){
......//一堆复杂的逻辑处理,无非就是找到一个合适的Task,然后对应做一些
//处理。此处不讨论这段代码,读者可根据工作中的具体情况进行研究
}
}//if(r.resultTo == null)判断结束
}
~~~
在本例中,目标Activity首次登场,所以前面的逻辑处理都没有起作用,建议读者根据具体情况分析该段代码。
下面来看startActivityUncheckLocked第三阶段的工作。
(3) startActivityUncheckLocked分析之三
**ActivityStack.java::startActivityUncheckLocked**
~~~
if(r.packageName != null) {
//判断目标Activity是否已经在栈顶,如果是,需要判断是创建一个新的Activity
//还是调用onNewIntent(singleTop模式的处理)
ActivityRecord top = topRunningNonDelayedActivityLocked(notTop);
if (top != null && r.resultTo == null){
......//不讨论此段代码
}//if(top != null...)结束
} else {
......//通知错误
returnSTART_CLASS_NOT_FOUND;
}
//在本例中,肯定需要创建一个Task
booleannewTask = false;
booleankeepCurTransition = false;
if(r.resultTo == null && !addingToTask
&& (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
if(reuseTask == null) {
mService.mCurTask++;//AMS中保存了当前Task的数量
if (mService.mCurTask <= 0) mService.mCurTask = 1;
//为该AactivityRecord设置一个新的TaskRecord
r.setTask(new TaskRecord(mService.mCurTask, r.info, intent),
null,true);
}else r.setTask(reuseTask, reuseTask,true);
newTask = true;
//下面这个函数为Android 4.0新增的,用于处理FLAG_ACTIVITY_TASK_ON_HOME的情况,
//请阅读SDK文档对Intent的相关说明
moveHomeToFrontFromLaunchLocked(launchFlags);
}elseif......//其他处理情况
//授权控制。在SDK中启动Activity的函数没有授权设置方面的参数。在实际工作中,笔者曾碰
//到过一个有趣的情况:在开发的一款定制系统中,用浏览器下载了受DRM保护的图片,
//此时要启动Gallery3D来查看该图片,但是由于为DRM目录设置了读写权限,而Gallery3D
//并未声明相关权限,结果抛出异常,导致不能浏览该图片。由于startActivity等函数不能设置
//授权,最终只能修改Gallery3D并为其添加use-permissions项了
if(grantedUriPermissions != null && callingUid > 0) {
for(int i=0; i<grantedUriPermissions.length; i++) {
mService.grantUriPermissionLocked(callingUid, r.packageName,
grantedUriPermissions[i],grantedMode,
r.getUriPermissionsLocked());
}
mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
intent, r.getUriPermissionsLocked());
//调用startActivityLocked,此时ActivityRecord和TaskRecord均创建完毕
startActivityLocked(r, newTask, doResume, keepCurTransition);
return START_SUCCESS;
}//startActivityUncheckLocked函数结束
~~~
startActivityUncheckLocked的第三阶段工作也比较复杂,不过针对本例,它将创建一个新的TaskRecord,并调用startActivityLocked函数进行处理。
下面我们转战startActivityLocked函数。
(4) startActivityLocked函数分析
**ActivityStack.java::startActivityLocked**
~~~
private final voidstartActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume, boolean keepCurTransition) {
final intNH = mHistory.size();
intaddPos = -1;
if(!newTask){//如果不是新Task,则从mHistory中找到对应的ActivityRecord的位置
......
}
if(addPos < 0) addPos = NH;
//否则加到mHistory数组的最后
mHistory.add(addPos,r);
//设置ActivityRecord的inHistory变量为true,表示已经加到mHistory数组中了
r.putInHistory();
r.frontOfTask = newTask;
if (NH> 0) {
//判断是否显示Activity切换动画之类的事情,需要与WindowManagerService交互
}
//最终调用resumeTopActivityLocked
if (doResume) resumeTopActivityLocked(null);//重点分析这个函数
}
~~~
在以上列出的startActivityLocked函数中,略去了一部分逻辑处理,这部分内容和Activity之间的切换动画有关(通过这些动画,使切换过程看起来更加平滑和美观,需和WMS交互)。
* * * * *
**提示**:笔者认为,此处将Activity切换和动画处理这两个逻辑揉到一起并不合适,但是似乎也没有更合适的地方来进行该工作了。读者不妨自行研读一下该段代码以加深体会。
* * * * *
(5) startActivityUncheckedLocked总结
说实话,startActivityUncheckedLocked函数的复杂度超乎笔者的想象,光这些函数名就够让人头疼的。但是针对本例而言,相关逻辑的难度还算适中,毕竟这是Activity启动流程中最简单的情况。可用一句话总结本例中startActivityUncheckedLocked函数的功能:创建ActivityRecord和TaskRecord并将ActivityRecord添加到mHistory末尾,然后调用resumeTopActivityLocked启动它。
下面用一节来分析resumeTopActivityLocked函数。
3. resumeTopActivityLocked函数分析
**ActivityStack.java::resumeTopActivityLocked**
~~~
finalboolean resumeTopActivityLocked(ActivityRecord prev) {
//从mHistory中找到第一个需要启动的ActivityRecord
ActivityRecord next = topRunningActivityLocked(null);
finalboolean userLeaving = mUserLeaving;
mUserLeaving = false;
if (next== null) {
//如果mHistory中没有要启动的Activity,则启动Home
if(mMainStack) returnmService.startHomeActivityLocked();
}
//在本例中,next将是目标Activity
next.delayedResume= false;
......//和WMS交互,略去
//将该ActivityRecord从下面几个队列中移除
mStoppingActivities.remove(next);
mGoingToSleepActivities.remove(next);
next.sleeping = false;
mWaitingVisibleActivities.remove(next);
//如果当前正在中断一个Activity,需先等待那个Activity pause完毕,然后系统会重新
//调用resumeTopActivityLocked函数以找到下一个要启动的Activity
if(mPausingActivity != null) return false;
/************************请读者注意***************************/
//①mResumedActivity指向上一次启动的Activity,也就是当前界面显示的这个Activity
//在本例中,当前Activity就是Home界面
if(mResumedActivity != null) {
//先中断 Home。这种情况放到最后进行分析
startPausingLocked(userLeaving,false);
return true;
}
//②如果mResumedActivity为空,则一定是系统第一个启动的Activity,读者应能猜测到它就
//是Home
......//如果prev不为空,则需要通知WMS进行与Activity切换相关的工作
try {
//通知PKMS修改该Package stop状态,详细信息参考第4章“readLPw的‘佐料’”
//一节的说明
AppGlobals.getPackageManager().setPackageStoppedState(
next.packageName, false);
}......
if(prev!= null){
......//还是和WMS有关,通知它停止绘画
}
if(next.app != null && next.app.thread != null) {
//如果该ActivityRecord已有对应的进程存在,则只需要重启Activity。就本例而言,
//此进程还不存在,所以要先创建一个应用进程
} else {
//第一次启动
if (!next.hasBeenLaunched) {
next.hasBeenLaunched = true;
} else {
......//通知WMS显示启动界面
}
//调用另外一个startSpecificActivityLocked函数
startSpecificActivityLocked(next, true, true);
}
returntrue;
}
~~~
resumeTopActivityLocked函数中有两个非常重要的关键点:
- 如果mResumedActivity不为空,则需要先暂停(pause)这个Activity。由代码中的注释可知,mResumedActivity代表上一次启动的(即当前正显示的)Activity。现在要启动一个新的Activity,须先停止当前Activity,这部分工作由startPausingLocked函数完成。
- 那么,mResumedActivity什么时候为空呢?当然是在启动全系统第一个Activity时,即启动Home界面的时候。除此之外,该值都不会为空。
先分析第二个关键点,即mResumedActivity为null的情况选择分析此种情况的原因是:如果先分析startPausingLocked,则后续分析会牵扯三个进程,即当前Activity所在进程、AMS所在进程及目标进程,分析的难度相当大。
好了,继续我们的分析。resumeTopActivityLocked最后将调用另外一个startSpecificActivityLocked,该函数将真正创建一个应用进程。
(1) startSpecificActivityLocked分析
**ActivityStack.java::startSpecificActivityLocked**
~~~
private final voidstartSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
//从AMS中查询是否已经存在满足要求的进程(根据processName和uid来查找)
//在本例中,查询结果应该为null
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid);
//设置启动时间等信息
if(r.launchTime == 0) {
r.launchTime = SystemClock.uptimeMillis();
if(mInitialStartTime == 0) mInitialStartTime = r.launchTime;
} else if(mInitialStartTime == 0) {
mInitialStartTime = SystemClock.uptimeMillis();
}
//如果该进程存在并已经向AMS注册(例如之前在该进程中启动了其他Activity)
if (app!= null && app.thread != null) {
try {
app.addPackage(r.info.packageName);
//通知该进程中的启动目标Activity
realStartActivityLocked(r, app, andResume, checkConfig);
return;
}......
}
//如果该进程不存在,则需要调用AMS的startProcessLocked创建一个应用进程
mService.startProcessLocked(r.processName, r.info.applicationInfo,
true, 0,"activity",r.intent.getComponent(), false);
}
~~~
来看AMS的startProcessLocked函数,它将创建一个新的应用进程。
(2) startProcessLocked分析
**ActivityManagerService.java::startProcessLocked**
~~~
final ProcessRecord startProcessLocked(StringprocessName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName,
boolean allowWhileBooting) {
//根据processName和uid寻找是否已经存在ProcessRecord
ProcessRecordapp = getProcessRecordLocked(processName, info.uid);
if (app!= null && app.pid > 0) {
......//处理相关情况
}
StringhostingNameStr = hostingName != null
? hostingName.flattenToShortString() : null;
//①处理FLAG_FROM_BACKGROUND标志,见下文解释
if((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
if(mBadProcesses.get(info.processName, info.uid) != null)
return null;
} else {
mProcessCrashTimes.remove(info.processName,info.uid);
if(mBadProcesses.get(info.processName, info.uid) != null) {
mBadProcesses.remove(info.processName, info.uid);
if (app != null) app.bad =false;
}
}
if (app== null) {
//创建一个ProcessRecord,并保存到mProcessNames中。注意,此时还没有创建实际进程
app= newProcessRecordLocked(null, info, processName);
mProcessNames.put(processName, info.uid, app);
}else app.addPackage(info.packageName);
......
//②调用另外一个startProcessLocked函数
startProcessLocked(app, hostingType, hostingNameStr);
return(app.pid != 0) ? app : null;
}
~~~
在以上代码中列出两个关键点,其中第一点和FLAG_FROM_BACKGROUND有关,相关知识点如下:
- FLAG_FROM_BACKGROUND标识发起这次启动的Task属于后台任务。很显然,手机中没有界面供用户操作位于后台Task中的Activity。如果没有设置该标志,那么这次启动请求就是由前台Task因某种原因而触发的(例如用户单击某个按钮)。
- 如果一个应用进程在1分钟内连续崩溃超过2次,则AMS会将其ProcessRecord加入所谓的mBadProcesses中。一个应用崩溃后,系统会弹出一个警告框以提醒用户。但是,如果一个后台Task启动了一个“BadProcess”,然后该Process崩溃,结果弹出一个警告框,那么用户就会觉得很奇怪:“为什么突然弹出一个框?”因此,此处将禁止后台Task启动“Bad Process”。如果用户主动选择启动(例如单击一个按钮),则不能禁止该操作,并且要把应用进程从mBadProcesses中移除,以给它们“重新做人”的机会。当然,要是该应用每次启动时都会崩溃,而且用户不停地去启动,那该用户可能是位测试工作者。
* * * * *
**提示**:这其实是一种安全机制,防止不健全的程序不断启动可能会崩溃的组件,但是这种机制并不限制用户的行为。
* * * * *
下面来看第二个关键点,即另一个startProcessLocked函数,其代码如下:
**ActivityManagerService.java::startProcessLocked**
~~~
private final voidstartProcessLocked(ProcessRecord app,
String hostingType, StringhostingNameStr) {
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);
updateCpuStats();
System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
mProcDeaths[0] = 0;
try {
intuid = app.info.uid;
int[] gids = null;
try {//从PKMS中查询该进程所属的gid
gids = mContext.getPackageManager().getPackageGids(
app.info.packageName);
}......
......//工厂测试
intdebugFlags = 0;
if((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
debugFlags |=Zygote.DEBUG_ENABLE_DEBUGGER;
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}......//设置其他一些debugFlags
//发送消息给Zygote,它将派生一个子进程,该子进程执行ActivityThread的main函数
//注意,我们传递给Zygote的参数并没有包含任何与Activity相关的信息。现在仅仅启动
//一个应用进程
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();
}
//如果该进程为persisitent,则需要通知Watchdog,实际上processStarted内部只
//关心刚才创建的进程是不是com.android.phone
if(app.persistent) {
Watchdog.getInstance().processStarted(app.processName,
startResult.pid);
}
app.pid= startResult.pid;
app.usingWrapper = startResult.usingWrapper;
app.removed = false;
synchronized (mPidsSelfLocked) {
//以pid为key,将代表该进程的ProcessRecord对象加入到mPidsSelfLocked中保管
this.mPidsSelfLocked.put(startResult.pid, app);
//发送一个超时消息,如果这个新创建的应用进程10秒内没有和AMS交互,则可断定
//该应用进程启动失败
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
msg.obj = app;
//正常的超时时间为10秒。不过如果该应用进程通过valgrind加载,则延长到300秒
//valgrind是Linux平台上一款检查内存泄露的程序,被加载的应用将在它的环境中工作,
//这项工作需耗费较长时间。读者可查询valgrind的用法
mHandler.sendMessageDelayed(msg,startResult.usingWrapper
?PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}......
}
~~~
startProcessLocked通过发送消息给Zygote以派生一个应用进程[^①],读者仔细研究所发消息的内容,大概会发现此处并未设置和Activity相关的信息,也就是说,该进程启动后,将完全不知道自己要干什么,怎么办?下面就此进行分析。
4. startActivity分析之半程总结
很抱歉,我们现在还处于startActivity分析之旅的中间点,即使越过了很多险滩恶途,一路走来还是发觉有点艰难。此处用图6-14来记录半程中的各个关键点。
:-: ![](http://img.blog.csdn.net/20150803123218950?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图6-14 startActivity半程总结
图6-14列出了针对本例的调用顺序,其中对每个函数的大体功能也做了简单描述。
* * * * *
**注意**:图6-14中的调用顺序及功能说明只是针对本例而言的。读者以后可结合具体情况再深入研究其中的内容。
* * * * *
5. 应用进程的创建及初始化
如前所述,应用进程的入口是ActivityThread的main函数,它是在主线程中执行的,其代码如下:
**ActivityThread.java::main**
~~~
public static void main(String[] args) {
SamplingProfilerIntegration.start();
//和调试及strictMode有关
CloseGuard.setEnabled(false);
//设置进程名为"<pre-initialized>"
Process.setArgV0("<pre-initialized>");
//准备主线程消息循环
Looper.prepareMainLooper();
if(sMainThreadHandler == null)
sMainThreadHandler = new Handler();
//创建一个ActivityThread对象
ActivityThread thread = new ActivityThread();
//①调用attach函数,注意其参数值为false
thread.attach(false);
Looper.loop(); //进入主线程消息循环
throw newRuntimeException("Main thread loop unexpectedly exited");
}
~~~
在main函数内部将创建一个消息循环Loop,接着调用ActivityThread的attach函数,最终将主线程加入消息循环。
我们在分析AMS的setSystemProcess时曾分析过ActivityThread的attach函数,那时传入的参数值为true。现在来看设置其为false的情况:
**ActivityThread.java::attach**
~~~
private void attach(boolean system) {
sThreadLocal.set(this);
mSystemThread = system;
if(!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
public void run() {
ensureJitEnabled();
}
});
//设置在DDMS中看到的本进程的名字为"<pre-initialized>"
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>");
//设置RuntimeInit的mApplicationObject参数,后续会介绍RuntimeInit类
RuntimeInit.setApplicationObject(mAppThread.asBinder());
//获取和AMS交互的Binder客户端
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
//①调用AMS的attachApplication,mAppThread为ApplicationThread类型,
//它是应用进程和AMS交互的接口
mgr.attachApplication(mAppThread);
}......
} else......// system process的处理
ViewRootImpl.addConfigCallback(newComponentCallbacks2()
{.......//添加回调函数});
}
~~~
我们知道,AMS创建一个应用进程后,会设置一个超时时间(一般是10秒)。如果超过这个时间,应用进程还没有和AMS交互,则断定该进程创建失败。所以,应用进程启动后,需要尽快和AMS交互,即调用AMS的attachApplication函数。在该函数内部将调用attachApplicationLocked,所以此处直接分析attachApplicationLocked,先看其第一阶段的工作。
(1) attachApplicationLocked分析之一
**ActivityManagerService.java::attachApplicationLocked**
~~~
private final booleanattachApplicationLocked(IApplicationThread thread,
int pid) {//此pid代表调用进程的pid
ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);//根据pid查找对应的ProcessRecord对象
}
}else app = null;
/*
如果该应用进程由AMS启动,则它一定在AMS中有对应的ProcessRecord,读者可回顾前面创建
应用进程的代码:AMS先创建了一个ProcessRecord对象,然后才发命令给Zygote。
如果此处app为null,表示AMS没有该进程的记录,故需要“杀死”它
*/
if (app== null) {
if(pid > 0 && pid != MY_PID) //如果pid大于零,且不是SystemServer进程,则
//Quietly(即不打印任何输出)”杀死”process
Process.killProcessQuiet(pid);
else{
//调用ApplicationThread的scheduleExit函数。应用进程完成处理工作后
//将退出运行
//为何不像上面一样直接杀死它呢?可查阅linux pid相关的知识并自行解答
thread.scheduleExit();
}
returnfalse;
}
/*
判断app的thread是否为空,如果不为空,则表示该ProcessRecord对象还未和一个
应用进程绑定。注意,app是根据pid查找到的,如果旧进程没有被杀死,系统则不会重用
该pid。为什么此处会出现ProcessRecord thread不为空的情况呢?见下面代码的注释说明
*/
if(app.thread != null) handleAppDiedLocked(app, true, true);
StringprocessName = app.processName;
try {
/*
创建一个应用进程讣告接收对象。当应用进程退出时,该对象的binderDied将被调
用。这样,AMS就能做相应处理。binderDied函数将在另外一个线程中执行,其内部也会
调用handleAppDiedLocked。假如用户在binderDied被调用之前又启动一个进程,
那么就会出现以上代码中app.thread不为null的情况。这是多线程环境中常出现的
情况,不熟悉多线程编程的读者要仔细体会。
*/
AppDeathRecipient adr = new AppDeathRecipient(pp, pid, thread);
thread.asBinder().linkToDeath(adr, 0);
app.deathRecipient = adr;
}......
//设置该进程的调度优先级和oom_adj等成员
app.thread= thread;
app.curAdj = app.setAdj = -100;
app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
app.forcingToForeground = null;
app.foregroundServices = false;
app.hasShownUi = false;
app.debugging = false;
//启动成功,从消息队列中撤销PROC_START_TIMEOUT_MSG消息
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
~~~
attachApplicationLocked第一阶段的工作比较简单:
- 设置代表该应用进程的ProcessRecrod对象的一些成员变量,例如用于和应用进程交互的thread对象、进程调度优先级及oom_adj的值等。
- 从消息队列中撤销PROC_START_TIMEOUT_MSG。
至此,该进程启动成功,但是这一阶段的工作仅针对进程本身(如设置调度优先级,oom_adj等),还没有涉及和Activity启动相关的内容,这部分工作将在第二阶段完成。
(2) attachApplicationLocked分析之二
**ActivityManagerService.java::attachApplicationLocked**
~~~
......
//SystemServer早就启动完毕,所以normalMode为true
booleannormalMode = mProcessesReady || isAllowedWhileBooting(app.info);
/*
我们在6.2.3的标题1中分析过generateApplicationProvidersLocked函数,
在该函数内部将查询(根据进程名,uid确定)PKMS以获取需运行在该进程中的ContentProvider
*/
Listproviders = normalMode ? generateApplicationProvidersLocked(app) : null;
try {
int testMode = IApplicationThread.DEBUG_OFF;
if(mDebugApp != null && mDebugApp.equals(processName)) {
......//处理debug选项
}
......//处理Profile
boolean isRestrictedBackupMode = false;
......//
//dex化对应的apk包
ensurePackageDexOpt(app.instrumentationInfo!= null ?
app.instrumentationInfo.packageName : app.info.packageName);
//如果设置了Instrumentation类,该类所在的Package也需要dex化
if(app.instrumentationClass != null)
ensurePackageDexOpt(app.instrumentationClass.getPackageName());
ApplicationInfo appInfo =app.instrumentationInfo != null
? app.instrumentationInfo :app.info;
//查询该Application使用的CompatibiliyInfo
app.compat =compatibilityInfoForPackageLocked(appInfo);
if (profileFd != null) //用于记录性能文件
profileFd = profileFd.dup();
//①通过ApplicationThread和应用进程交互,调用其bindApplication函数
thread.bindApplication(processName,appInfo, providers,
app.instrumentationClass, profileFile, profileFd,
profileAutoStop,app.instrumentationArguments,
app.instrumentationWatcher,testMode,
isRestrictedBackupMode || !normalMode, app.persistent,
mConfiguration, app.compat, getCommonServicesLocked(),
mCoreSettingsObserver.getCoreSettingsLocked());
//updateLruProcessLocked函数以后再作分析
updateLruProcessLocked(app,false, true);
//记录两个时间
app.lastRequestedGc= app.lastLowMemory = SystemClock.uptimeMillis();
}......//try结束
..//从mProcessesOnHold和mPersistentStartingProcesses中删除相关信息
mPersistentStartingProcesses.remove(app);
mProcessesOnHold.remove(app);
~~~
由以上代码可知,第二阶段的工作主要是为调用ApplicationThread的bindApplication做准备,将在后面的章节中分析该函数的具体内容。此处先来看它的原型。
~~~
/*
正如我们在前面分析时提到的,刚创建的这个进程并不知道自己的历史使命是什么,甚至连自己的
进程名都不知道,只能设为"<pre-initialized>"。其实,Android应用进程的历史使命是
AMS在其启动后才赋予它的,这一点和我们理解的一般意义上的进程不太一样。根据之前的介绍, Android的组件应该运行在Android运行环境中。从OS角度来说,该运行环境需要和一个进程绑定。
所以,创建应用进程这一步只是创建了一个能运行Android运行环境的容器,而我们的工作实际上
还远未结束。
bindApplication的功能就是创建并初始化位于该进程中的Android运行环境
*/
public final void bindApplication(
StringprocessName,//进程名,一般是package名
ApplicationInfo appInfo,//该进程对应的ApplicationInfo
List<ProviderInfo> providers,//在该APackage中声明的Provider信息
ComponentName instrumentationName,//和instrumentation有关
//下面3个参数和性能统计有关
StringprofileFile,
ParcelFileDescriptor profileFd, boolean autoStopProfiler,
//这两个和Instrumentation有关,在本例中,这几个参数暂时都没有作用
Bundle instrumentationArgs,
IInstrumentationWatcherinstrumentationWatcher,
intdebugMode,//调试模式
boolean isRestrictedBackupMode,
boolean persistent,//该进程是否是persist
Configuration config,//当前的配置信息,如屏幕大小和语言等
CompatibilityInfocompatInfo,//兼容信息
//AMS将常用的Service信息传递给应用进程,目前传递的Service信息只有PKMS、
//WMS及AlarmManagerService。读者可参看AMS getCommonServicesLocked函数
Map<String,IBinder> services,
BundlecoreSettings)//核心配置参数,目前仅有“long_press”值
~~~
对bindApplication的原型分析就到此为止,再来看attachApplicationLocked最后一阶段的工作。
(3) attachApplicationLocked分析之三
**ActivityManagerService.java::attachApplicationLocked**
~~~
booleanbadApp = false;
booleandidSomething = false;
/*
至此,应用进程已经准备好了Android运行环境,下面这句调用代码将返回ActivityStack中
第一个需要运行的ActivityRecord。由于多线程的原因,难道能保证得到的hr就是我们的目标
Activity吗?
*/
ActivityRecord hr = mMainStack.topRunningActivityLocked(null);
if (hr !=null && normalMode) {
//需要根据processName和uid等确定该Activity是否运行与目标进程有关
if(hr.app == null && app.info.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
//调用AS的realStartActivityLocked启动该Activity,最后两个参数为true
if (mMainStack.realStartActivityLocked(hr, app, true, true)) {
didSomething = true;
}
} catch (Exception e) {
badApp = true; //设置badApp为true
}
} else{
//如果hr和目标进程无关,则调用ensureActivitiesVisibleLocked函数处理它
mMainStack.ensureActivitiesVisibleLocked(hr, null, processName, 0);
}
}// if (hr!= null && normalMode)判断结束
//mPendingServices存储那些因目标进程还未启动而处于等待状态的ServiceRecord
if(!badApp && mPendingServices.size() > 0) {
ServiceRecord sr = null;
try{
for (int i=0; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);
//和Activity不一样的是,如果Service不属于目标进程,则暂不处理
if (app.info.uid != sr.appInfo.uid
||!processName.equals(sr.processName)) continue;//继续循环
//该Service将运行在目标进程中,所以从mPendingService中移除它
mPendingServices.remove(i);
i--;
//处理此service的启动,以后再作分析
realStartServiceLocked(sr, app);
didSomething = true;//设置该值为true
}
}
}......
......//启动等待的BroadcastReceiver
......//启动等待的BackupAgent,相关代码类似Service的启动
if(badApp) {
//如果以上几个组件启动有错误,则设置badApp为true。此处将调用handleAppDiedLocked
//进行处理。该函数我们以后再作分析
handleAppDiedLocked(app, false, true);
returnfalse;
}
/*
调整进程的oom_adj值。didSomething表示在以上流程中是否启动了Acivity或其他组件。
如果启动了任一组件,则didSomething为true。读者以后会知道,这里的启动只是向
应用进程发出对应的指令,客户端进程是否成功处理还是未知数。基于这种考虑,所以此处不宜
马上调节进程的oom_adj。
读者可简单地把oom_adj看做一种优先级。如果一个应用进程没有运行任何组件,那么当内存
出现不足时,该进程是最先被系统杀死的。反之,如果一个进程运行的组件越多,那么它就越不易被
系统杀死以回收内存。updateOomAdjLocked就是根据该进程中组件的情况对应调节进程的
oom_adj值的。
*/
if(!didSomething) updateOomAdjLocked();
returntrue;
}
~~~
attachApplicationLocked第三阶段的工作就是通知应用进程启动Activity和Service等组件,其中用于启动Activity的函数是ActivityStack realStartActivityLocked。
此处先来分析应用进程的bindApplication,该函数将为应用进程绑定一个Application。
* * * * *
**提示**:还记得AMS中System Context执行的两次init吗?第二次init的功能就是将Context和对应的Application绑定在一起。
* * * * *
(4) ApplicationThread的bindApplication分析
bindApplication在ApplicationThread中的实现,其代码如下:
**ActivityThread.java::bindApplication**
~~~
public final void bindApplication(......) {
if(services != null)//保存AMS传递过来的系统Service信息
ServiceManager.initServiceCache(services);
//向主线程消息队列添加SET_CORE_SETTINGS消息
setCoreSettings(coreSettings);
//创建一个AppBindData对象,其实就是用来存储一些参数
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
data.instrumentationName = instrumentationName;
......//将AMS传过来的参数保存到AppBindData中
//向主线程发送H.BIND_APPLICATION消息
queueOrSendMessage(H.BIND_APPLICATION, data);
}
~~~
由以上代码可知,ApplicationThread接收到来自AMS的指令后,均会将指令中的参数封装到一个数据结构中,然后通过发送消息的方式转交给主线程去处理。BIND_APPLICATION最终将由handleBindApplication函数处理。该函数并不复杂,但是其中有些点是值得关注的,这些点主要是初始化应用进程的一些参数。handleBindApplication函数的代码如下:
**ActivityThread.java::handleBindApplication**
~~~
private void handleBindApplication(AppBindDatadata) {
mBoundApplication = data;
mConfiguration = new Configuration(data.config);
mCompatConfiguration = new Configuration(data.config);
//初始化性能统计对象
mProfiler = new Profiler();
mProfiler.profileFile = data.initProfileFile;
mProfiler.profileFd = data.initProfileFd;
mProfiler.autoStopProfiler = data.initAutoStopProfiler;
//设置进程名。从此,之前那个默默无名的进程终于有了自己的名字
Process.setArgV0(data.processName);
android.ddm.DdmHandleAppName.setAppName(data.processName);
if(data.persistent) {
//对于persistent的进程,在低内存设备上,不允许其使用硬件加速显示
Display display =
WindowManagerImpl.getDefault().getDefaultDisplay();
//当内存大于512MB,或者屏幕尺寸大于1024*600,可以使用硬件加速
if(!ActivityManager.isHighEndGfx(display))
HardwareRenderer.disable(false);
}
//启动性能统计
if(mProfiler.profileFd != null) mProfiler.startProfiling();
//如果目标SDK版本小于12,则设置AsyncTask使用pool executor,否则使用
//serializedexecutor。这些executor涉及Java Concurrent类,对此不熟悉的读者
//请自行学习和研究。
if(data.appInfo.targetSdkVersion <= 12)
AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
//设置timezone
TimeZone.setDefault(null);
//设置语言
Locale.setDefault(data.config.locale);
//设置资源及兼容模式
applyConfigurationToResourcesLocked(data.config, data.compatInfo);
applyCompatConfiguration();
//根据传递过来的ApplicationInfo创建一个对应的LoadApk对象
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
//对于系统APK,如果当前系统为userdebug/eng版,则需要记录log信息到dropbox的日志记录
if((data.appInfo.flags &
(ApplicationInfo.FLAG_SYSTEM |
ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
StrictMode.conditionallyEnableDebugLogging();
}
/*
如目标SDK版本大于9,则不允许在主线程使用网络操作(如Socketconnect等),否则抛出
NetworkOnMainThreadException,这么做的目的是防止应用程序在主线程中因网络操作执行
时间过长而造成用户体验下降。说实话,没有必要进行这种限制,在主线程中是否网络操作
是应用的事情。再说,Socket也可作为进程间通信的手段,在这种情况下,网络操作耗时很短。
作为系统,不应该设置这种限制。另外,Goolge可以提供一些开发指南或规范来指导开发者,
而不应如此蛮横地强加限制。
*/
if (data.appInfo.targetSdkVersion> 9)
StrictMode.enableDeathOnNetwork();
//如果没有设置屏幕密度,则为Bitmap设置默认的屏幕密度
if((data.appInfo.flags
&ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) == 0)
Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
if(data.debugMode != IApplicationThread.DEBUG_OFF){
......//调试模式相关处理
}
IBinder b= ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
IConnectivityManager service =
IConnectivityManager.Stub.asInterface(b);
try {
//设置Http代理信息
ProxyPropertiesproxyProperties = service.getProxy();
Proxy.setHttpProxySystemProperty(proxyProperties);
} catch(RemoteException e) {}
if(data.instrumentationName != null){
//在正常情况下,此条件不满足
} else {
//创建Instrumentation对象,在正常情况都再这个条件下执行
mInstrumentation = new Instrumentation();
}
//如果Package中声明了FLAG_LARGE_HEAP,则可跳过虚拟机的内存限制,放心使用内存
if((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0)
dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
//创建一个Application,data.info为LoadedApk类型,在其内部会通过Java反射机制
//创建一个在该APK AndroidManifest.xml中声明的Application对象
Applicationapp = data.info.makeApplication(
data.restrictedBackupMode, null);
//mInitialApplication保存该进程中第一个创建的Application
mInitialApplication = app;
//安装本Package中携带的ContentProvider
if(!data.restrictedBackupMode){
List<ProviderInfo> providers = data.providers;
if(providers != null) {
//installContentProviders我们已经分析过了
installContentProviders(app, providers);
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
//调用Application的onCreate函数,做一些初始工作
mInstrumentation.callApplicationOnCreate(app);
}
~~~
由以上代码可知,bindApplication函数将设置一些初始化参数,其中最重要的有:
- 创建一个Application对象,该对象是本进程中运行的第一个Application。
- 如果该Application有ContentProvider,则应安装它们。
* * * * *
**提示**:从以上代码可知,ContentProvider的创建就在bindApplication函数中,其时机早于其他组件的创建。
* * * * *
(5) 应用进程的创建及初始化总结
本节从应用进程的入口函数main开始,分析了应用进程和AMS之间的两次重要交互,它们分别是:
- 在应用进程启动后,需要尽快调用AMS的attachApplication函数,该函数是这个刚呱呱坠地的应用进程第一次和AMS交互。此时的它还默默“无名”,连一个确定的进程名都没有。不过没关系,attachApplication函数将根据创建该应用进程之前所保存的ProcessRecord为其准备一切“手续”。
- attachApplication准备好一切后,将调用应用进程的bindApplication函数,在该函数内部将发消息给主线程,最终该消息由handleBindApplication处理。handleBindApplication将为该进程设置进程名,初始化一些策略和参数信息等。另外,它还创建一个Application对象。同时,如果该Application声明了ContentProvider,还需要为该进程安装ContentProvider。
* * * * *
**提示**:这个流程有点类似生孩子,一般生之前需要到医院去登记,生完后又需去注册户口,如此这般,这个孩子才会在社会有合法的身份。
* * * * *
6. ActivityStack realStartActivityLocked分析
如前所述,AMS调用完bindApplication后,将通过realStartActivityLocked启动Activity。在此之前,要创建完应用进程并初始化Android运行环境(除此之外,连ContentProvider都安装好了)。
**ActivityStack.java::realStartActivityLocked**
~~~
//注意,在本例中该函数的最后两个参数的值都为true
final booleanrealStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
r.startFreezingScreenLocked(app, 0);
mService.mWindowManager.setAppVisibility(r,true);
if(checkConfig) {
......//处理Config发生变化的情况
mService.updateConfigurationLocked(config, r, false);
}
r.app =app;
app.waitingToKill = null;
//将ActivityRecord加到ProcessRecord的activities中保存
int idx= app.activities.indexOf(r);
if (idx< 0) app.activities.add(r);
//更新进程的调度优先级等,以后再分析该函数
mService.updateLruProcessLocked(app, true, true);
try {
List<ResultInfo> results = null;
List<Intent> newIntents = null;
if(andResume) {
results = r.results;
newIntents = r.newIntents;
}
if(r.isHomeActivity) mService.mHomeProcess = app;
//看看是否有dex对应Package的需要
mService.ensurePackageDexOpt(
r.intent.getComponent().getPackageName());
r.sleeping = false;
r.forceNewConfig = false;
......
//①通知应用进程启动Activity
app.thread. scheduleLaunchActivity (new Intent(r.intent), r,
System.identityHashCode(r), r.info, mService.mConfiguration,
r.compat, r.icicle, results, newIntents, !andResume,
mService.isNextTransitionForward(), profileFile, profileFd,
profileAutoStop);
if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
......//处理heavy-weight的情况
}
}
} ......//try结束
r.launchFailed = false;
......
if(andResume) {
r.state = ActivityState.RESUMED;
r.stopped = false;
mResumedActivity = r;//设置mResumedActivity为目标Activity
r.task.touchActiveTime();
//添加该任务到近期任务列表中
if(mMainStack) mService.addRecentTaskLocked(r.task);
//②关键函数,见下文分析
completeResumeLocked(r);
//如果在这些过程中,用户按了Power键,怎么办?
checkReadyForSleepLocked();
r.icicle = null;
r.haveState = false;
}......
//启动系统设置向导Activity,当系统更新或初次使用时需要进行配置
if(mMainStack) mService.startSetupActivityLocked();
returntrue;
}
~~~
在以上代码中有两个关键函数,分别是:scheduleLaunchActivity和completeResumeLocked。其中,scheduleLaunchActivity用于和应用进程交互,通知它启动目标Activity。而completeResumeLocked将继续AMS的处理流程。先来看第一个关键函数。
(1) scheduleLaunchActivity函数分析
**ActivityThread.java::scheduleLaunchActivity**
~~~
public final void scheduleLaunchActivity(Intentintent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig,CompatibilityInfo compatInfo,
Bundlestate, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, booleanisForward,
StringprofileName, ParcelFileDescriptor profileFd,
booleanautoStopProfiler) {
ActivityClientRecord r = new ActivityClientRecord();
......//保存AMS发送过来的参数信息
//向主线程发送消息,该消息的处理在handleLaunchActivity中进行
queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
}
~~~
**ActivityThread.java::handleMessage**
~~~
public void handleMessage(Message msg) {
switch(msg.what) {
case LAUNCH_ACTIVITY: {
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
//根据ApplicationInfo得到对应的PackageInfo
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
//调用handleLaunchActivity处理
handleLaunchActivity(r, null);
}break;
......
}
~~~
**ActivityThread.java::handleLaunchActivity**
~~~
private voidhandleLaunchActivity(ActivityClientRecord r,
Intent customIntent){
unscheduleGcIdler();
if (r.profileFd != null) {......//略去}
handleConfigurationChanged(null, null);
/*
①创建Activity,通过Java反射机制创建目标Activity,将在内部完成Activity生命周期
的前两步,即调用其onCreate和onStart函数。至此,我们的目标com.dfp.test.TestActivity
创建完毕
*/
Activitya = performLaunchActivity(r, customIntent);
if (a !=null) {
r.createdConfig = new Configuration(mConfiguration);
BundleoldState = r.state;
//②调用handleResumeActivity,其内部有个关键点,见下文分析
handleResumeActivity(r.token, false, r.isForward);
if(!r.activity.mFinished && r.startsNotResumed) {
.......//
. r.paused = true;
}else {
//如果启动错误,通知AMS
ActivityManagerNative.getDefault()
.finishActivity(r.token,Activity.RESULT_CANCELED, null);
}
}
~~~
handleLaunchActivity的工作包括:
- 首先调用performLaunchActivity,该在函数内部通过Java反射机制创建目标Activity,然后调用它的onCreate及onStart函数。
- 调用handleResumeActivity,会在其内部调用目标Activity的onResume函数。除此之外,handleResumeActivity还完成了一件很重要的事情,见下面的代码:
**ActivityThread.java::handleResumeActivity**
~~~
final void handleResumeActivity(IBinder token,boolean clearHide,
booleanisForward) {
unscheduleGcIdler();
//内部调用目标Activity的onResume函数
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r !=null) {
finalActivity a = r.activity;
final int forwardBit = isForward ?
WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;
......
if(!r.onlyLocalRequest) {
//将上面完成onResume的Activity保存到mNewActivities中
r.nextIdle = mNewActivities;
mNewActivities = r;
//①向消息队列中添加一个Idler对象
Looper.myQueue().addIdleHandler(new Idler());
}
r.onlyLocalRequest = false;
......
}
~~~
根据第2章对MessageQueue的分析,当消息队列中没有其他要处理的消息时,将处理以上代码中通过addIdleHandler添加的Idler对象,也就是说,Idler对象的优先级最低,这是不是说它的工作不重要呢?非也。至少在handleResumeActivity函数中添加的这个Idler并不不简单,其代码如下:
**ActivityThread.java::Idler**
~~~
private class Idler implements MessageQueue.IdleHandler{
publicfinal boolean queueIdle() {
ActivityClientRecord a = mNewActivities;
booleanstopProfiling = false;
......
if (a !=null) {
mNewActivities = null;
IActivityManager am = ActivityManagerNative.getDefault();
ActivityClientRecord prev;
do {
if(a.activity != null && !a.activity.mFinished) {
//调用AMS的activityIdle
am.activityIdle(a.token, a.createdConfig, stopProfiling);
a.createdConfig = null;
}
prev =a;
a =a.nextIdle;
prev.nextIdle = null;
} while(a != null); //do循环结束
}//if(a!=null)判断结束
......
ensureJitEnabled();
returnfalse;
}// queueIdle函数结束
}
~~~
由以上代码可知,Idler将为那些已经完成onResume的Activity调用AMS的activityIdle函数。该函数是Activity成功创建并启动的流程中与AMS交互的最后一步。虽然对应用进程来说,Idler处理的优先级最低,但AMS似乎不这么认为,因为它还设置了超时等待,以处理应用进程没有及时调用activityIdle的情况。这个超时等待即由realStartActivityLocked中最后一个关键点completeResumeLocked函数设置。
(2) completeResumeLocked函数分析
**ActivityStack.java::completeResumeLocked**
~~~
private final voidcompleteResumeLocked(ActivityRecord next) {
next.idle = false;
next.results = null;
next.newIntents = null;
//发送一个超时处理消息,默认为10秒。IDLE_TIMEOUT_MSG就是针对acitivityIdle函数的
Messagemsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
msg.obj= next;
mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
//通知AMS
if(mMainStack) mService.reportResumedActivityLocked(next);
......//略去其他逻辑的代码
}
~~~
由以上代码可知,AMS给了应用进程10秒的时间,希望它在10秒内调用activityIdle函数。这个时间不算长,和前面AMS等待应用进程启动的超时时间一样。所以,笔者有些困惑,为什么要把这么重要的操作放到idler中去做。
下面来看activityIdle函数,在其内部将调用ActivityStack activityIdleInternal。
(3) activityIdleInternal函数分析
**ActivityStack.java::activityIdleInternal**
~~~
final ActivityRecord activityIdleInternal(IBindertoken, boolean fromTimeout,
Configuration config) {
/*
如果应用进程在超时时间内调用了activityIdleInternal函数,则fromTimeout为false
否则,一旦超时,在IDLE_TIMEOUT_MSG的消息处理中也会调用该函数,并设置fromTimeout
为true
*/
ActivityRecord res = null;
ArrayList<ActivityRecord> stops = null;
ArrayList<ActivityRecord> finishes = null;
ArrayList<ActivityRecord> thumbnails = null;
int NS =0;
int NF =0;
int NT =0;
IApplicationThread sendThumbnail = null;
booleanbooting = false;
booleanenableScreen = false;
synchronized (mService) {
//从消息队列中撤销IDLE_TIMEOUT_MSG
if(token != null) mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
int index= indexOfTokenLocked(token);
if(index >= 0) {
ActivityRecord r = mHistory.get(index);
res =r;
//注意,只有fromTimeout为true,才会走执行下面的条件语句
if(fromTimeout) reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
if(config != null) r.configuration =config;
/*
mLaunchingActivity是一个WakeLock,它能防止在操作Activity过程中掉电,同时
这个WakeLock又不能长时间使用,否则有可能耗费过多电量。所以,系统设置了一个超时
处理消息LAUNCH_TIMEOUT_MSG,超时时间为10秒。一旦目标Activity启动成功,
就需要需要释放 WakeLock
*/
if(mResumedActivity == r && mLaunchingActivity.isHeld()) {
mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
mLaunchingActivity.release();
}
r.idle = true;
mService.scheduleAppGcsLocked();
......
ensureActivitiesVisibleLocked(null, 0);
if(mMainStack) {
if(!mService.mBooted) {
mService.mBooted = true;
enableScreen = true;
}
}//if (mMainStack)判断结束
} else if(fromTimeout) {//注意,只有fromTimeout为true,才会走下面的case
reportActivityLaunchedLocked(fromTimeout, null, -1, -1);
}
/*
①processStoppingActivitiesLocked函数返回那些因本次Activity启动而
被暂停(paused)的Activity
*/
stops =processStoppingActivitiesLocked(true);
......
for (i=0;i<NS; i++) {
ActivityRecord r = (ActivityRecord)stops.get(i);
synchronized (mService) {
//如果这些Acitivity 处于finishing状态,则通知它们执行Destroy操作,最终它们
//的onDestroy函数会被调用
if(r.finishing) finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
else //否则将通知它们执行stop操作,最终Activity的onStop被调用
stopActivityLocked(r);
}//synchronized结束
}//for循环结束
......//处理等待结束的Activities
//发送ACTION_BOOT_COMPLETED广播
if(booting) mService.finishBooting();
......
returnres;
}
~~~
在activityIdleInternal中有一个非常重要的关键点,即处理那些因为本次Activity启动而被暂停的Activity。有两种情况需考虑:
- 如果被暂停的Activity处于finishing状态(例如Activity在其onStop中调用了finish函数),则调用finishCurrentActivityLocked。
- 否则,要调用stopActivityLocked处理暂停的Activity。
此处涉及除AMS和目标进程外的第三个进程,即被切换到后台的那个进程。不过至此,我们的目标Activity终于正式登上了历史舞台。
* * * * *
**提示**:本例的分析结束了吗?没有。因为am设置了-W选项,所以其实我们还在startActivityAndWait函数中等待结果。ActivityStack中有两个函数能够触发AMS notifyAll,一个是reportActivityLaunchedLocked,另一个是reportActivityVisibleLocked。前面介绍的activityInternal函数只在fromTimeout为true时才会调用reportActivityLaunchedLocked,而本例中fromTimeout为false,如何是好?该问题的解答非常复杂,姑且先一语带过:当Activity显示出来时,其在AMS中对应ActivityRecord对象的windowVisible函数将被调用,其内部会触发reportActivityLaunchedLocked函数,这样我们的startActivityAndWait才能被唤醒。
* * * * *
7. startActivity分析之后半程总结
总结startActivity后半部分的流程,主要涉及目标进程和AMS的交互,如图6-15所示。
:-: ![](http://img.blog.csdn.net/20150803123243623?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图6-15 startActivity后半程总结
图6-15中涉及16个重要函数调用,而且这仅是startActivity后半部分的调用流程,可见整个流程有多么复杂!
8. startPausingLocked函数分析
现在我们分析图6-14中的startPausingLocked分支。根据前面的介绍,当启动一个新Activity时,系统将先行处理当前的Activity,即调用startPausingLocked函数来暂停当前Activity。
(1) startPausingLocked分析
**ActivityStack.java::startPausingLocked**
~~~
private final void startPausingLocked(booleanuserLeaving, boolean uiSleeping) {
//mResumedActivity保存当前正显示的Activity,
ActivityRecord prev = mResumedActivity;
mResumedActivity = null;
//设置mPausingActivity为当前Activity
mPausingActivity = prev;
mLastPausedActivity = prev;
prev.state = ActivityState.PAUSING;//设置状态为PAUSING
prev.task.touchActiveTime();
......
if(prev.app != null && prev.app.thread != null) {
try {
//①调用当前Activity所在进程的schedulePauseActivity函数
prev.app.thread.schedulePauseActivity(prev,prev.finishing,
userLeaving,prev.configChangeFlags);
if(mMainStack) mService.updateUsageStats(prev, false);
} ......//catch分支
}......//else分支
if(!mService.mSleeping && !mService.mShuttingDown) {
//获取WakeLock,以防止在Activity切换过程中掉电
mLaunchingActivity.acquire();
if(!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
}
}
if(mPausingActivity != null) {
//暂停输入事件派发
if(!uiSleeping) prev.pauseKeyDispatchingLocked();
//设置PAUSE超时,时间为500毫秒,这个时间相对较短
Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
msg.obj = prev;
mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
}......//else分支
}
~~~
startPausingLocked将调用应用进程的schedulePauseActivity函数,并设置500毫秒的超时时间,所以应用进程需尽快完成相关处理。和scheduleLaunchActivity一样,schedulePauseActivity将向ActivityThread主线程发送PAUSE_ACTIVITY消息,最终该消息由handlePauseActivity来处理。
(2) handlePauseActivity分析
**ActivityThread.java::handlePauseActivity**
~~~
private void handlePauseActivity(IBinder token,boolean finished,
boolean userLeaving, int configChanges){
//当Activity处于finishing状态时,finished参数为true,不过在本例中该值为false
ActivityClientRecord r = mActivities.get(token);
if (r !=null) {
//调用Activity的onUserLeaving函数,
if(userLeaving) performUserLeavingActivity(r);
r.activity.mConfigChangeFlags |=configChanges;
//调用Activity的onPause函数
performPauseActivity(token, finished, r.isPreHoneycomb());
......
try {
//调用AMS的activityPaused函数
ActivityManagerNative.getDefault().activityPaused(token);
}......
}
}
~~~
**ActivityManagerService.java::activityPaused**
~~~
public final void activityPaused(IBinder token) {
......
mMainStack.activityPaused(token, false);
}
~~~
**ActivityStack.java::activityPaused**
~~~
final void activityPaused(IBinder token, booleantimeout) {
ActivityRecord r = null;
synchronized (mService) {
int index= indexOfTokenLocked(token);
if (index>= 0) {
r =mHistory.get(index);
//从消息队列中撤销PAUSE_TIMEOUT_MSG消息
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
if(mPausingActivity == r) {
r.state = ActivityState.PAUSED;//设置ActivityRecord的状态
completePauseLocked();//完成本次Pause操作
}......
}
}
~~~
(3) completePauseLocked分析
**ActivityStack.java::completePauseLocked**
~~~
private final void completePauseLocked() {
ActivityRecord prev = mPausingActivity;
if (prev!= null) {
if(prev.finishing) {
prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
} elseif (prev.app != null) {
if(prev.configDestroy) {
destroyActivityLocked(prev, true, false);
} else {
//①将刚才被暂停的Activity保存到mStoppingActivities中
mStoppingActivities.add(prev);
if(mStoppingActivities.size() > 3) {
//如果被暂停的Activity超过3个,则发送IDLE_NOW_MSG消息,该消息最终
//由我们前面介绍的activeIdleInternal处理
scheduleIdleLocked();
}
}
//设置mPausingActivity为null,这是图6-14②、③分支的分割点
mPausingActivity = null;
}
//②resumeTopActivityLocked将启动目标Activity
if(!mService.isSleeping()) resumeTopActivityLocked(prev);
......
}
~~~
就本例而言,以上代码还算简单,最后还是通过resumeTopActivityLocked来启动目标Activity。当然,由于之前已经设置了mPausingActivity为null,所以最终会走到图6-14中③的分支。
(4) stopActivityLocked分析
根据前面的介绍,此次目标Activity将走完onCreate、onStart和onResume流程,但是被暂停的Activity才刚走完onPause流程,那么它的onStop什么时候调用呢?
答案就在activityIdelInternal中,它将为mStoppingActivities中的成员调用stopActivityLocked函数。
**ActivityStack.java::stopActivityLocked**
~~~
privatefinal void stopActivityLocked(ActivityRecord r) {
if((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
|| (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
if(!r.finishing) {
requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
"no-history");
}
} elseif (r.app != null && r.app.thread != null) {
try {
r.stopped = false;
//设置STOPPING状态,并调用对应的scheduleStopActivity函数
r.state = ActivityState.STOPPING;
r.app.thread.scheduleStopActivity(r, r.visible,
r.configChangeFlags);
}......
}
~~~
对应进程的scheduleStopActivity函数将根据visible的情况,向主线程消息循环发送H. STOP_ACTIVITY_HIDE或H. STOP_ACTIVITY_SHOW消息。不论哪种情况,最终都由handleStopActivity来处理。
**ActivityThread.java::handleStopActivity**
~~~
private void handleStopActivity(IBinder token,boolean show, int configChanges) {
ActivityClientRecord r = mActivities.get(token);
r.activity.mConfigChangeFlags |= configChanges;
StopInfoinfo = new StopInfo();
//调用Activity的onStop函数
performStopActivityInner(r, info, show, true);
......
try { //调用AMS的activityStopped函数
ActivityManagerNative.getDefault().activityStopped(
r.token, r.state, info.thumbnail, info.description);
}
}
~~~
AMS没有为stop设置超时消息处理。严格来说,还是有超时限制的,只是这个超时处理与activityIdleInternal结合起来了。
(5) startPausingLocked总结
总结startPausingLocked流程,如图6-16所示。
:-: ![](http://img.blog.csdn.net/20150803123302838?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
图6-16 startPausingActivity流程总结
图6-16比较简单,读者最好结合代码再把流程走一遍,以加深理解。
9. startActivity总结
Activity的启动就介绍到这里。这一路分析下来,相信读者也和笔者一样觉得此行绝不轻松。先回顾一下此次旅程:
- 行程的起点是am。am是Android中很重要的程序,读者务必要掌握它的用法。我们利用am start命令,发起本次目标Activity的启动请求。
- 接下来进入ActivityManagerService和ActivityStack这两个核心类。对于启动Activity来说,这段行程又可分细分为两个阶段:第一阶段的主要工作就是根据启动模式和启动标志找到或创建ActivityRecord及对应的TaskRecord;第二阶段工作就是处理Activity启动或切换相关的工作。
- 首先讨论了AMS直接创建目标进程并运行Activity的流程,其中涉及目标进程的创建,在目标进程中Android运行环境的初始化,目标Activity的创建以及触发onCreate、onStart及onResume等其生命周期中重要函数调用等相关知识点。
- 接着又讨论了AMS先pause当前Activity,然后再创建目标进程并运行Activity的流程。其中牵扯到两个应用进程和AMS的交互,其难度之大可见一斑。
读者在阅读本节时,务必要区分此旅程中两个阶段工作的重点:其一是找到合适的ActivityRecord和TaskRecord;其二是调度相关进程进行Activity切换。在SDK文档中,介绍最为详细的是第一阶段中系统的处理策略,例如启动模式、启动标志的作用等。第二阶段工作其实是与Android组件调度相关的工作。SDK文档只是针对单个Activity进行生命周期方面的介绍。
坦诚地说,这次旅程略过不少逻辑情况。原因有二,一方面受限于精力和篇幅,另方面是作为调度核心类,和AMS相关的代码及处理逻辑非常复杂,而且其间还夹杂了与WMS的交互逻辑,使复杂度更甚。再者,笔者个人感觉这部分代码绝谈不上高效、严谨和美观,甚至有些丑陋(在分析它们的过程中,远没有研究Audio、Surface时那种畅快淋漓的感觉)。
此处列出几个供读者深入研究的点:
- 各种启动模式、启动标志的处理流程。
- Configuration发生变化时Activity的处理,以及在Activity中对状态保存及恢复的处理流程。
- Activity生命周期各个阶段的转换及相关处理。Android 2.3以后新增的与Fragment的生命周期相关的转换及处理。
>[info]**建议**:在研究代码前,先仔细阅读SDK文档相关内容,以获取必要的感性认识,否则直接看代码很容易迷失方向。
[^①]:关于Zygote的工作原理,请读者阅读卷I第4章“深入理解Zygote”
- 前言
- 第1章 搭建Android源码工作环境
- 1.1 Android系统架构
- 1.2 搭建开发环境
- 1.2.1 下载源码
- 1.2.2 编译源码
- 1.2.3 利用Eclipse调试system_process
- 1.3 本章小结
- 第2章 深入理解Java Binder和MessageQueue
- 2.1 概述
- 2.2 Java层中的Binder架构分析
- 2.2.1 Binder架构总览
- 2.2.2 初始化Java层Binder框架
- 2.2.3 addService实例分析
- 2.2.4 Java层Binder架构总结
- 2.3 心系两界的MessageQueue
- 2.3.1 MessageQueue的创建
- 2.3.2 提取消息
- 2.3.3 nativePollOnce函数分析
- 2.3.4 MessageQueue总结
- 2.4 本章小结
- 第3章 深入理解SystemServer
- 3.1 概述
- 3.2 SystemServer分析
- 3.2.1 main函数分析
- 3.2.2 Service群英会
- 3.3 EntropyService分析
- 3.4 DropBoxManagerService分析
- 3.4.1 DBMS构造函数分析
- 3.4.2 dropbox日志文件的添加
- 3.4.3 DBMS和settings数据库
- 3.5 DiskStatsService和DeviceStorageMonitorService分析
- 3.5.1 DiskStatsService分析
- 3.5.2 DeviceStorageManagerService分析
- 3.6 SamplingProfilerService分析
- 3.6.1 SamplingProfilerService构造函数分析
- 3.6.2 SamplingProfilerIntegration分析
- 3.7 ClipboardService分析
- 3.7.1 复制数据到剪贴板
- 3.7.2 从剪切板粘贴数据
- 3.7.3 CBS中的权限管理
- 3.8 本章小结
- 第4章 深入理解PackageManagerService
- 4.1 概述
- 4.2 初识PackageManagerService
- 4.3 PKMS的main函数分析
- 4.3.1 构造函数分析之前期准备工作
- 4.3.2 构造函数分析之扫描Package
- 4.3.3 构造函数分析之扫尾工作
- 4.3.4 PKMS构造函数总结
- 4.4 APK Installation分析
- 4.4.1 adb install分析
- 4.4.2 pm分析
- 4.4.3 installPackageWithVerification函数分析
- 4.4.4 APK 安装流程总结
- 4.4.5 Verification介绍
- 4.5 queryIntentActivities分析
- 4.5.1 Intent及IntentFilter介绍
- 4.5.2 Activity信息的管理
- 4.5.3 Intent 匹配查询分析
- 4.5.4 queryIntentActivities总结
- 4.6 installd及UserManager介绍
- 4.6.1 installd介绍
- 4.6.2 UserManager介绍
- 4.7 本章学习指导
- 4.8 本章小结
- 第5章 深入理解PowerManagerService
- 5.1 概述
- 5.2 初识PowerManagerService
- 5.2.1 PMS构造函数分析
- 5.2.2 init分析
- 5.2.3 systemReady分析
- 5.2.4 BootComplete处理
- 5.2.5 初识PowerManagerService总结
- 5.3 PMS WakeLock分析
- 5.3.1 WakeLock客户端分析
- 5.3.2 PMS acquireWakeLock分析
- 5.3.3 Power类及LightService类介绍
- 5.3.4 WakeLock总结
- 5.4 userActivity及Power按键处理分析
- 5.4.1 userActivity分析
- 5.4.2 Power按键处理分析
- 5.5 BatteryService及BatteryStatsService分析
- 5.5.1 BatteryService分析
- 5.5.2 BatteryStatsService分析
- 5.5.3 BatteryService及BatteryStatsService总结
- 5.6 本章学习指导
- 5.7 本章小结
- 第6章 深入理解ActivityManagerService
- 6.1 概述
- 6.2 初识ActivityManagerService
- 6.2.1 ActivityManagerService的main函数分析
- 6.2.2 AMS的 setSystemProcess分析
- 6.2.3 AMS的 installSystemProviders函数分析
- 6.2.4 AMS的 systemReady分析
- 6.2.5 初识ActivityManagerService总结
- 6.3 startActivity分析
- 6.3.1 从am说起
- 6.3.2 AMS的startActivityAndWait函数分析
- 6.3.3 startActivityLocked分析
- 6.4 Broadcast和BroadcastReceiver分析
- 6.4.1 registerReceiver流程分析
- 6.4.2 sendBroadcast流程分析
- 6.4.3 BROADCAST_INTENT_MSG消息处理函数
- 6.4.4 应用进程处理广播分析
- 6.4.5 广播处理总结
- 6.5 startService之按图索骥
- 6.5.1 Service知识介绍
- 6.5.2 startService流程图
- 6.6 AMS中的进程管理
- 6.6.1 Linux进程管理介绍
- 6.6.2 关于Android中的进程管理的介绍
- 6.6.3 AMS进程管理函数分析
- 6.6.4 AMS进程管理总结
- 6.7 App的 Crash处理
- 6.7.1 应用进程的Crash处理
- 6.7.2 AMS的handleApplicationCrash分析
- 6.7.3 AppDeathRecipient binderDied分析
- 6.7.4 App的Crash处理总结
- 6.8 本章学习指导
- 6.9 本章小结
- 第7章 深入理解ContentProvider
- 7.1 概述
- 7.2 MediaProvider的启动及创建
- 7.2.1 Context的getContentResolver函数分析
- 7.2.2 MediaStore.Image.Media的query函数分析
- 7.2.3 MediaProvider的启动及创建总结
- 7.3 SQLite创建数据库分析
- 7.3.1 SQLite及SQLiteDatabase家族
- 7.3.2 MediaProvider创建数据库分析
- 7.3.3 SQLiteDatabase创建数据库的分析总结
- 7.4 Cursor 的query函数的实现分析
- 7.4.1 提取query关键点
- 7.4.2 MediaProvider 的query分析
- 7.4.3 query关键点分析
- 7.4.4 Cursor query实现分析总结
- 7.5 Cursor close函数实现分析
- 7.5.1 客户端close的分析
- 7.5.2 服务端close的分析
- 7.5.3 finalize函数分析
- 7.5.4 Cursor close函数总结
- 7.6 ContentResolver openAssetFileDescriptor函数分析
- 7.6.1 openAssetFileDescriptor之客户端调用分析
- 7.6.2 ContentProvider的 openTypedAssetFile函数分析
- 7.6.3 跨进程传递文件描述符的探讨
- 7.6.4 openAssetFileDescriptor函数分析总结
- 7.7 本章学习指导
- 7.8 本章小结
- 第8章 深入理解ContentService和AccountManagerService
- 8.1 概述
- 8.2 数据更新通知机制分析
- 8.2.1 初识ContentService
- 8.2.2 ContentResovler 的registerContentObserver分析
- 8.2.3 ContentResolver的 notifyChange分析
- 8.2.4 数据更新通知机制总结和深入探讨
- 8.3 AccountManagerService分析
- 8.3.1 初识AccountManagerService
- 8.3.2 AccountManager addAccount分析
- 8.3.3 AccountManagerService的分析总结
- 8.4 数据同步管理SyncManager分析
- 8.4.1 初识SyncManager
- 8.4.2 ContentResolver 的requestSync分析
- 8.4.3 数据同步管理SyncManager分析总结
- 8.5 本章学习指导
- 8.6 本章小结