android N进程启动流程(二)(上一个activity的暂停、进程启动、绑定进程与创建application)
来源:互联网 发布:蜂群算法 多目标规划 编辑:程序博客网 时间:2024/06/07 19:03
android N进程启动流程(二)(上一个activity的暂停、进程启动、绑定进程与创建application)
第二部分将分为:上一个activity的暂停、进程启动、绑定进程与创建application
5. 上一个activity的暂停
图5.1 上一个activity的暂停
接着章节3.6的startActivityUnchecked中会调用最后有调用resumeFocusedStackTopActivityLocked,我们接下去从这里开始讲解。
5.1 resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java)
resumeFocusedStackTopActivityLocked恢复当前focus的堆栈stack中的顶端活动对象top activity
1) 上面章节3.6中setTaskFromReuseOrCreateNewTask->computeStackFocus->mSupervisor.getStack已经创建了mTargetStack,并将其添加到ActivityDisplay的mStack中去。
2) 章节3.6中moveToFront的insertTaskAtTop中也设置了需要启动的应用如test2.com.myapplication成为堆栈顶端Top的进程
3) 章节4.2中setFocusStackUnchecked也设置了mTargetStack为test2
//上面章节3.6中setTaskFromReuseOrCreateNewTask已经创建了mTargetStack, //章节3.6中moveToFront的insertTaskAtTop中也设置了需要启动的应用如test2.com.myapplication //成为堆栈顶端Top的进程 boolean resumeFocusedStackTopActivityLocked( ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) { if (targetStack != null && isFocusedStack(targetStack)) { //targetStack不为null,而且isFocusedStack也是test2,故此处是会进来的 return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions); } //... }
5.2 resumeTopActivityUncheckedLocked(ActivityStack.java)
resumeFocusedStackTopActivityLocked恢复当前focus堆栈stack中的顶端活动对象
1) 此处的stack this对象是test2上一章节5.1中说的mTargetStack
2) 此时是第一次看到resumeTopActivityInnerLocked,故是第一次进入,传递的prev是test2.com.myapplication我们先看第一次进入该函数的处理逻辑(第二次的请忽略先)
3) 此处逻辑依次是resumeTopActivityUncheckedLocked->resumeTopActivityInnerLocked->pauseBackStacks
4) 第一次进入由于在pauseBackStacks返回有需要pause的应用,故pausing==true,pauseBackStacks做完不久就直接返回了
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) { //.... result = resumeTopActivityInnerLocked(prev, options); //.... } //第一次进来的时候prev是test2.com.myapplication(所以会先pause上一个应用如com.android.launcher); //第二次进来是prev是com.android.launcher,此时launcher已经pause了, //会进入下一个应用的resume流程(如test2.com.myapplication) private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) { //... //第一次进来topRunningActivityLocked是test2,第二次进来也是test2, //此处是在moveActivityStackToFront中已经设置过了 final ActivityRecord next = topRunningActivityLocked(); //... //此处allPausedActivitiesComplete是true,不会进入这里, //说明之前已经没有需要pause的应用(第一次进来mPausingActivity还没有设置过==null) //或者pause完成(第二次进来) if (!mStackSupervisor.allPausedActivitiesComplete()) { … return false; } //... //是否有设置标志位在pausing的时候resume,默认没有设置都是false final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0; //此处判断是否有需要pasue的进程(是所有stack而不仅仅是当前stack), //第一次进来会pause launcher(launcher的堆栈中有mResumedActivity, //但是章节4.2已经将焦点切换到test2)故反馈pausing==true,第二次直接返回pausing==false boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, true, dontWaitForPause); //mResumedActivity一直都是null(由于当前mTargetStack是新new出来的给进程test2使用), //只有在test2 resume之后才会设置,如在minimalResumeActivityLocked之后设置,故不会走下面的逻辑 if (mResumedActivity != null) { //... } //第一次走的pausing是true(代表有需要暂停的应用,如launcher),第二次pausing是false if (pausing) { //... //第一次进来到这里就结束了 return true; //此处一般都是不走的mResumedActivity == null,第二次pausing是false, //但是还是有activity继续resume(allResumedActivitiesComplete返回false) } else if (mResumedActivity == next && next.state == ActivityState.RESUMED && mStackSupervisor.allResumedActivitiesComplete()) { ... return true; } //第二次时会进来这里prev != next,此处next代表test2.com.myapplication, //prev代表com.android.launcher if (prev != null && prev != next) { if (!mStackSupervisor.mWaitingVisibleActivities.contains(prev) && next != null && !next.nowVisible) { //等待prev的界面launcher隐藏,此处在mStackSupervisor的 //processStoppingActivitiesLocked时才会remove mStackSupervisor.mWaitingVisibleActivities.add(prev); } else { //... } //... //第二次进来时prev == com.android.launcher if (prev != null) { //launcher是没有finishing的,不进入这里 if (prev.finishing) { //... //准备resume test2.com.myapplication时prev代表com.android.launcher,会进来这里 } else { //prev.task不等于next.task,mLaunchTaskBehind是false, //WMS中传输类型是TRANSIT_TASK_OPEN mWindowManager.prepareAppTransition(prev.task == next.task ? TRANSIT_ACTIVITY_OPEN : next.mLaunchTaskBehind ? TRANSIT_TASK_OPEN_BEHIND : TRANSIT_TASK_OPEN, false); } } else { //... } //... //此处next(test2.com.myapplication)进程都还没有起来,不会进入这里 if (next.app != null && next.app.thread != null) { //... //next(test2.com.myapplication)进入的是else } else { //第一次启动hasBeenLaunched肯定是false,所以会进入此处 if (!next.hasBeenLaunched) { next.hasBeenLaunched = true; } else { ... } //这里才是真正启动test2进程的地方 mStackSupervisor.startSpecificActivityLocked(next, true, true); } //... }
5.3 pauseBackStacks(ActivityStackSupervisor.java)
pauseBackStacks遍历ActivityDisplay显示设备中的所有栈,当循环到luancher的时候,由于launcher已经不是focus的stack栈,但是它的mResumedActivity仍然存在,代表这个activity需要进行pause暂停的操作。
boolean pauseBackStacks(boolean userLeaving, boolean resuming, boolean dontWait) { //... //遍历stacks当前显示设备的所有堆栈 final ActivityStack stack = stacks.get(stackNdx); //stack是launcher,isFocusedStack是false,mResumedActivity是launcher不等于null if (!isFocusedStack(stack) && stack.mResumedActivity != null) { //launcher的stack进行pause的操作,注意resuming是true,dontWait是false, //userLeaving是true,在章节3.6 startActivityUnchecked->setInitialState中设置 someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming, dontWait); //... }
5.4 startPausingLocked(ActivityStack.java)
1) startPausingLocked这个函数是启动应用暂停pause(如此处的是上一个应用launcher),设置当前状态为pausing
2) 进入ActivityThread处理暂停任务之前会在eventlog中输出am_pause_activity的信息,表示将要开始该应用的暂停了
3) 不过最重要的函数还是ActivityThread的schedulePauseActivity,该函数会处理pause任务
//userLeaving==true, uiSleeping==false, resuming==true, dontWait==false final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming, boolean dontWait) { //第一次进来mPausingActivity是null,应用没有暂停就没有所谓的mPausingActivity if (mPausingActivity != null) { //... } //mResumedActivity是当前resume的activity,此处是launcher ActivityRecord prev = mResumedActivity; //注意此处pause之后将设置mResumedActivity==null,代表没有该Stack没有resume的activity了 mResumedActivity = null; //launcher设置为正在pause的进程 mPausingActivity = prev; //设置上一个暂停的应用 mLastPausedActivity = prev; //标定该进程在PAUSING状态 prev.state = ActivityState.PAUSING; //此处next是test2,章节4.2的insertTaskAtTop已经设置过 final ActivityRecord next = mStackSupervisor.topRunningActivityLocked(); //pause应用会触发cpu状态更新,可以使用adb shell dumpsys cpuinfo查询 mService.updateCpuStats(); //prev是launcher,里面的app和thread都是已经创建的,所有此处会进入 if (prev.app != null && prev.app.thread != null) { try { //event log中的am_pause_activity,代表应用的pause开始 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY, prev.userId, System.identityHashCode(prev), prev.shortComponentName); //cpu前后台切换,用于耗电统计 mService.updateUsageStats(prev, false); //ActivityThread里面的方法是handle(异步),此处才是activity的真正的pause执行的地方 prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing, userLeaving, prev.configChangeFlags, dontWait); //... //mPausingActivity就是launcher,所以会进来此处。 if (mPausingActivity != null) { //uiSleeping==false if (!uiSleeping) { //应用的pause的时候,会暂停接收输入事件,此时系统触摸了不反馈给上层 prev.pauseKeyDispatchingLocked(); } //dontWait==false,章节5.2中设置dontWaitForPause if (dontWait) { //只有当dontWait是true的时候才会走这里,就是不等待pause完成 completePauseLocked(false); return false; } else { //launcher的最后onpause会走到这里来 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG); msg.obj = prev; prev.pauseTime = SystemClock.uptimeMillis(); //设置pause的超时时间为500ms mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT); //返回ture,代表有响应的activity正在pausing, //故在章节5.2 resumeTopActivityInnerLocked运行完该函数后不久就返回了 return true; } } else { //... }
ps:上面也看到了pause的时候会限制输入事件,如果应用一直重启又挂掉又重启,此时如果不停调用pause/finish的话会限制输入事件的分发pauseKeyDispatchingLocked,当然这种情况只是极端情况,一般不会出现
5.5 schedulePauseActivity(ActivityThread.java)
1) schedulePauseActivity这个是通过handler(一直想吐槽这个hander也类名也太简洁了的点吧,一个”H”就搞定)在UI主线程里面做的事情
2) 主要流程是schedulePauseActivity->PAUSE_ACTIVITY->handlePauseActivity->performPauseActivity->performPauseActivityIfNeeded
3) 我们主要关注performPauseActivityIfNeeded当前activity暂停(这部分本章节讲解)、activityPaused通知AMS上一个activity暂停完成(这部分下一章里讲解)。
//ActivityThread给外部提供的接口,pause暂停是通过应用的主线程进行处理 public final void schedulePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges, boolean dontReport) { int seq = getLifecycleSeq(); //... //finished等于false,走的是PAUSE_ACTIVITY,userLeaving==true,dontReport==dontWait==false sendMessage( finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY, token, (userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0), configChanges, seq); } //handler传递,调用的是handlePauseActivity case PAUSE_ACTIVITY: { //... //进入pause的处理 handlePauseActivity((IBinder) args.arg1, false, (args.argi1 & USER_LEAVING) != 0, args.argi2, (args.argi1 & DONT_REPORT) != 0, args.argi3); //... } break; //finished是false,userLeaving==true,dontReport==false private void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges, boolean dontReport, int seq) { ActivityClientRecord r = mActivities.get(token); ... if (r != null) { //userLeaving一般都是true if (userLeaving) { //会进入此处,会调用activity.performUserLeaving,当离开用户可视的时候会调用 performUserLeavingActivity(r); } //... //此处是pause上一个应用launcher,isPreHoneycomb是android3.0之前用的,此处是false performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity"); //dontReport一般没有设置都是false,故一般都是进入此处的 if (!dontReport) { try { //通知AMS上一个应用完成pause了,这里接下去就会resume下一个应用(先启动进程), //下一章会讲到 ActivityManagerNative.getDefault().activityPaused(token); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } mSomeActivitiesChanged = true; } } final Bundle performPauseActivity(ActivityClientRecord r, boolean finished, boolean saveState, String reason) { //saveState是false,不跑这里 if (!r.activity.mFinished && saveState) { callCallActivityOnSaveInstanceState(r); } //这里才是pause activity的地方 performPauseActivityIfNeeded(r, reason); // 将当前pause的应用的OnActivityPausedListener暂停监听去除 ArrayList<OnActivityPausedListener> listeners; synchronized (mOnPauseListeners) { listeners = mOnPauseListeners.remove(r.activity); } //... for (int i = 0; i < size; i++) { //此处是调用注册了该activity thread的监听onPaused的回调, //如NfcAdapter.java中的ActivityThread.currentActivityThread() //.registerOnActivityPausedListener(activity,mForegroundDispatchListener); listeners.get(i).onPaused(r.activity); } //... }
5.6 performPauseActivityIfNeeded(ActivityThread.java)
1) 通过代理类Instrumentation调用callActivityOnPause,其调用的是activity的performPause(分别会调用mFragments.dispatchPause、activity的onPause,application的ActivityLifecycleCallback生命周期回调方法onActivityPaused)
2) OnPause调用完成后会在event log中写入am_on_paused_called,代表activity的OnPause已经完成(如果你使用onpause有问题,可以从am_pause_activity到am_on_paused_called之间所花费的时间做初步判断)
3) 注意OnPause完成之后paused会赋值为true,代表当前是暂停状态
private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) { if (r.paused) { //如果之前paused==true了就直接返回,activitythread创建设置成false, //oncreate将设置成ture,onresume将设置成false //上一个activity的上一个状态是onresume,正在pause,故此处是paused==false return; } try { //这里解释一下mCalled,这个值是用来判断是否有调用activity生命周期的函数 r.activity.mCalled = false; //这就就是具体调用activity的performPause的地方 //(包括mFragments.dispatchPause、activity的onPause, //application的ActivityLifecycleCallback生命周期回调方法onActivityPaused), //运行完之后mCalled会设置成true mInstrumentation.callActivityOnPause(r.activity); //写event log,am_on_paused_called,说明pause已经调用 EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(), r.activity.getComponentName().getClassName(), reason); //... //运行了之后设置标致位paused==true r.paused = true; }
到目前为止基本上把上一个activity的OnPause流程讲解完了。
6. 进程启动(一)am_proc_start
讲了一大堆,是不是发现我们需要启动的进程test2怎么还没到呢,流程有点长,目前android的默认架构就是这样,大家耐心的继续看下去,我们这一章节就开始讲到进程启动(这部分应该很多文章都有提到,了解的同学可以不必细看)。
其实这些流程只是学习作用,对我们了解android架构有一定帮助,解决问题(仅针对那些代码不规范自己改出来的问题)时有帮助,不过这些都不是关注的重点,我们关注的是如何优化整个流程,如果没有明确这个目的,对我们来说是没有很大提升的。路漫漫其修远,我们先把流程梳理清楚,一步步来…
图6.1 进程启动(一)
6.1 activityPaused(ActivityManagerService.java)
在章节5.5中的ActivityManagerNative.getDefault().activityPaused(token)
,这个函数的意思是告诉AMS,上一个应用已经完成OnPause了,接下去的工作可以继续下去。
public final void activityPaused(IBinder token) { //... //调用的是ActivityStack的activityPausedLocked,第二个参数timeout==false stack.activityPausedLocked(token, false); //... }
其中token是上一个应用的Ibinder对象,我们认为是launcher就行了
6.2 activityPausedLocked(ActivityStack.java)
1) 通知launcher自身Stack栈中的activityPausedLocked,当前已经完成pause暂停操作了,可以将之前章节5.4中说的PAUSE_TIMEOUT_MSG超时去掉。
2) mPausingActivity也是在章节5.4开始暂停的时候设置的,如果发现真正暂停的应用和完成暂停的应用是一个,代表暂停完成,调用completePauseLocked,并传递resumeNext==true,代表需要resume下一个应用
//AMS调用的timeout==false final void activityPausedLocked(IBinder token, boolean timeout) { //代表该task仍在堆栈中,此时launcher是launcher的paused final ActivityRecord r = isInStackLocked(token); if (r != null) { //pause已经完成,不需要PAUSE_TIMEOUT_MSG了 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r); //之前在startPausingLocked的时候设置了当前pause的应用, //这个时候AMS返回代表pause成功,会进入这里 if (mPausingActivity == r) { //pause成功,传递的参数是resumeNext==true,代表需要resume下一个应用 completePauseLocked(true); return; } else { ... }
6.3 completePauseLocked(true)
1) mWaitingVisibleActivities这里代表的是需要隐藏的可视界面,到目前为止我们没有设置过,这个是在第二次进入章节5.2 resumeTopActivityInnerLocked的时候才会设置。(准备resume恢复下一个应用test2,上一个应用launcher就会放入等待隐藏的列表mWaitingVisibleActivities中)
2) 非睡眠或者关机状态的时候会进入下一个activity的resume操作resumeFocusedStackTopActivityLocked
3) 最后ensureActivitiesVisibleLocked(ActivityStackSupervisor.java/ActivityStack.java)会更新界面相关操作,属于WMS范畴,本文不过多涉及
{
//启动进程后会更新界面,此处仅仅把流程列出来,由于这篇文章本身太长了,不想在额外增加内容 ensureActivitiesVisibleLocked ->ensureActivityConfigurationLocked ->makeVisibleAndRestartIfNeeded->startSpecificActivityLocked() ->screenshotActivitiesLocked ->makeInvisible->addToStopping->scheduleIdleLocked
}
private void completePauseLocked(boolean resumeNext) { //prev,mPausingActivity是launcher ActivityRecord prev = mPausingActivity; //prev是不等于null的会进来这里 if (prev != null) { //state在startPausingLocked时设置了ActivityState.PAUSING, //所以一般情况wasStopping都是false final boolean wasStopping = prev.state == ActivityState.STOPPING; //重新设置标志位是ActivityState.PAUSED,这个是已经暂停的状态 prev.state = ActivityState.PAUSED; //一般情况launcher启动应用,prev.finishing==false,故不会进入这里面 if (prev.finishing) { //... //prev.app是launcher } else if (prev.app != null) { //pause com.android.launcher时,此处会进来,prev就是com.android.launcher, //wasStopping==false,visible==true //第一次进来时mWaitingVisibleActivities还没有prev(resumeTopActivityInnerLocked //第二次运行是才会设置),故不会进来这个 if (mStackSupervisor.mWaitingVisibleActivities.remove(prev)) { //... } //这个是在pause之后重新启动,一般都是false if (prev.deferRelaunchUntilPaused) { //... //wasStopping==false,也不走这里 } else if (wasStopping) { //... //由于visible==true,也不是在睡眠状态,这里也不会进来 } else if ((!prev.visible && !hasVisibleBehindActivity()) || mService.isSleepingOrShuttingDownLocked()) { //... } } else { //这里实在app在onpause过程中died掉才会进入,正常不会运行 prev = null; } if (prev != null) { //如果界面是冻屏的话,由于界面不再可见,将移除冻屏状态 prev.stopFreezingScreenLocked(true /*force*/); } //mPausingActivity设置为null,此时pause已经全部完成 mPausingActivity = null; } //上面都是AMS进来的activityPausedLocked,resumeNext == true if (resumeNext) { //之前的moveActivityStackToFront中有设置过focus stack为test2 final ActivityStack topStack = mStackSupervisor.getFocusedStack(); //非睡眠或者关机会进入这里 if (!mService.isSleepingOrShuttingDownLocked()) { //一般进入这里,会resume 下一个应用(next), //同步的,执行了Process.start之后才会继续往下跑 mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null); } else { ... } if (prev != null) { //重新恢复接收输入事件 prev.resumeKeyDispatchingLocked(); //如果是在使用电池 if (prev.app != null && prev.cpuTimeAtResume > 0 && mService.mBatteryStatsService.isOnBattery()) { //cpuTimeAtResume是在activity resume的时候设置的, //代表从resume到pause的时间,将作为前台运行时间 long diff = mService.mProcessCpuTracker.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume; //... //addForegroundTimeLocked这个是电量估算的时候用的,判断该activity前台运行的时常 if (ps != null) { ps.addForegroundTimeLocked(diff); //... } //当前已经是onpause暂停了,清空进入resume的时间 prev.cpuTimeAtResume = 0; } //有界面可视的时候mAppVisibilitiesChangedSinceLastPause==true(setVisible时设置), //所以这里会进来 if (mStackSupervisor.mAppVisibilitiesChangedSinceLastPause) { //... //launcher已经pause,设置mAppVisibilitiesChangedSinceLastPause==false mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = false; } //最后是更新显示界面,这里是第一次调用ensureActivitiesVisibleLocked, //遍历所有stack的ensureActivitiesVisibleLocked mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); }
6.4 resumeFocusedStackTopActivityLocked/startSpecificActivityLocked(ActivityStackSupervisor.java)
resumeFocusedStackTopActivityLocked在章节5.1-5.2已经看过,此处传递的targetStack是test2,pre是launcher,resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java) -> resumeTopActivityUncheckedLocked(ActivityStack.java) -> resumeTopActivityInnerLocked -> startSpecificActivityLocked(ActivityStackSupervisor.java),启动的是next==test2
这里就不翻回去讲了,接下去讲startSpecificActivityLocked(ActivityStackSupervisor.java)
这个启动应用的函数(注意此处是第一次进入,章节6.3提到的那一次是第二次进入,是在之后)
//r==test2,andResume==true,checkConfig==true void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { //... //当进程都未启动时不走这里,thread肯定是null,热启动相关逻辑本次不讨论 if (app != null && app.thread != null) { ... } //AMS中去启动进程 mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, "activity", r.intent.getComponent(), false, false, true); }
6.5 startProcessLocked(ActivityManagerService.java)
重要看到startProcessLocked启动进程相关名字,这个是AMS的启动进程的api。
先关注第一次进入的逻辑:
1) 新建一个进程对象的实例new ProcessRecord,该对象可以代表一个进程
2) 判断应用是32位还是64位的,用于虚拟机参数配置
3) Process.start进程启动
4) event log写入am_proc_start,代表进程已经启动,这句话出来的时候应用进程已经创建
//9个参数(r.processName==test2, r.info.applicationInfo, true, 0, //"activity", r.intent.getComponent(), false, false, true) final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated, boolean keepIfLarge) { //注意此处entryPoint==null return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType, hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge, null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */, null /* crashHandler */); } //14个参数,新建ProcessRecord final ProcessRecord startProcessLocked(String processName, ...) { long startTime = SystemClock.elapsedRealtime(); ProcessRecord app; //isolated(孤立应用)是false,knownToBeDead是true if (!isolated) { //第一次进来app肯定是null app = getProcessRecordLocked(processName, info.uid, keepIfLarge); //... //设置了后台运行,桌面启动应用一般都不会走这里 if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) { ... } else { //重新计算崩溃次数(crash大于等于2次服务将不会再启动) mAppErrors.resetProcessCrashTimeLocked(info); //... } } //这个是用来设置启动进程时cpu的策略,可以加快app启动速度 //默认没有用到,需要设置USE_SCHED_BOOST才会生效 nativeMigrateToBoost(); //3s钟后会关闭启动进程的cpu策略,同样此处默认没有用到 mHandler.sendMessageDelayed(msg, APP_BOOST_MESSAGE_DELAY); //第一次进入时没有启动过app/thread是null,pid是没有的. //第二次进来时此处app是有了,pid也生成了,但是thread还没有 //第一次没启动不走这里,第二次会进来 if (app != null && app.pid > 0) { //knownToBeDead是true,第二次进来app.thread还是null,故会进来, //第二次是从章节6.3中ensureActivitiesVisibleLocked调用过来的 if ((!knownToBeDead && !app.killed) || app.thread == null) { //第二次进程已经创建了,直接返回 //... return app; } //... } //... //第一次走这里,app是null if (app == null) { //这个是google的,用于调试卡顿的,不过除了特别有问题一般情况不会出现问题, //50ms去掉系统或许更快,如果是给用户的稳定版本可以考虑把这段调试代码删除 checkTime(startTime, "startProcess: creating new process record"); //此处是new ProcessRecord app = newProcessRecordLocked(info, processName, isolated, isolatedUid); //... //新建ProcessRecord完成,该监控操作(newProcessRecordLocked)完成 checkTime(startTime, "startProcess: done creating new process record"); } //监控进程启动的时常是否超时 checkTime(startTime, "startProcess: stepping in to startProcess"); //这里才是真正的启动进程的地方 startProcessLocked( app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs); checkTime(startTime, "startProcess: done starting proc!"); //如果有pid产生代表进程创建完成 return (app.pid != 0) ? app : null; } //真正启动进程的地方 private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) { //... if (app.pid > 0 && app.pid != MY_PID) {//第一次启动app.pid == -1,不走这里 ... } //... updateCpuStats();//启动进程也会更新CPU状态 try { try { //用于检测是否可以启动,如:是否安装,是否正在冻屏等 AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId); } //isolated初始值是false if (!app.isolated) { //... //返回应用用户组的gid,如果是uid不一样,同一个应用该值也会不一样 permGids = pm.getPackageGids(app.info.packageName, MATCH_DEBUG_TRIAGED_MISSING, app.userId); MountServiceInternal mountServiceInternal = LocalServices.getService( MountServiceInternal.class); //获取应用读写外部存储的权限 //如果是孤立应用(uid是99000-99999)将返回MOUNT_EXTERNAL_NONE; //能读返回MOUNT_EXTERNAL_READ,能写返回MOUNT_EXTERNAL_WRITE mountExternal = mountServiceInternal.getExternalStorageMountMode(uid, app.info.packageName); //... } //... //android:multiArch="true"代表所有架构都支持,一般都不设置, //一般应用库文件需要判断是否32位还算64位,判断方法使用 //com_android_internal_content_NativeLibraryHelper.cpp的findSupportedAbi //requiredAbi就是为了兼容32位&64位系统设计的 String requiredAbi = (abiOverride != null) ? abiOverride : app.info.primaryCpuAbi; if (requiredAbi == null) { //此处如果应用没有设置实在32位还是64位运行的化, //默认使用属性值ro.product.cpu.abilist的第一个值arm64-v8a(64bit), //armeabi-v7a(32bit),armeabi(32bit) requiredAbi = Build.SUPPORTED_ABIS[0]; } String instructionSet = null; if (app.info.primaryCpuAbi != null) { //通过应用的库文件获取虚拟机要使用那种参数 instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi); } //上面传递的entryPoint==null,isActivityProcess==true boolean isActivityProcess = (entryPoint == null); //将ActivityThread作为应用默认的入口函数entryPoint if (entryPoint == null) entryPoint = "android.app.ActivityThread"; //此处才是调用Process.start启动进程的地方 Process.ProcessStartResult startResult = Process.start(entryPoint, app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet, app.info.dataDir, entryPointArgs);//此处才是调用Process.start启动进程的地方 //此处就是event log中am_proc_start EventLog.writeEvent(EventLogTags.AM_PROC_START, UserHandle.getUserId(uid), startResult.pid, uid, app.processName, hostingType, hostingNameStr != null ? hostingNameStr : ""); //设置进程的pid app.setPid(startResult.pid); //一般usingWrapper==false app.usingWrapper = startResult.usingWrapper; //代表正在运行 app.removed = false; app.killed = false; //代表没有给AMS杀死 app.killedByAm = false; synchronized (mPidsSelfLocked) { //process start之后就会有pid了,此处是test2.com.myapplication的pid会生成 //会将该pid放入AMS的pid列表中 this.mPidsSelfLocked.put(startResult.pid, app); if (isActivityProcess) {//isActivityProcess==true //10s没有启动将不再启动,该app,Process.start虚拟机进程创建是同步的, //但是attachApplicationLocked是异步的,在attachApplication的时候 //会remove这个超时PROC_START_TIMEOUT_MSG mHandler.sendMessageDelayed(msg, startResult.usingWrapper ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT); ... }
7. 进程启动(二)Process.start
Process.start这个是新建进程通用的系统方法,代码位置:
frameworks/base/core/java/android/os/Process.java。
接下去从这个开始,这里面大家熟悉的内容可能更多。
图7.1 进程启动(二)
7.1 Process.start(Process.java)
我们注意传递的参数processClass是android.app.ActivityThread,niceName是processName,debugFlags一般都是等于0,mountExternal代表是否可读写外部存储,targetSdkVersion是这个应用的targetSdkVersion,seInfo是签名相关(默认是”default”),abi是这个应用要运行的cpu架构(32还是64位),instructionSet是指的是arm或者arm64,appDataDir一般指的是/data这个目录,zygoteArgs==null。
后面这些参数都会有用到,对于理解流程有很大的帮助。
//processClass是android.app.ActivityThread,niceName是processName, //debugFlags一般都是等于0,mountExternal代表是否可读写外部存储, //targetSdkVersion是这个应用的targetSdkVersion,seInfo是签名相关(默认是”default”), //abi是这个应用要运行的cpu架构(32还是64位),instructionSet是指的是arm或者arm64, //appDataDir一般指的是/data这个目录,zygoteArgs==null public static final ProcessStartResult start(final String processClass, final String niceName, int uid, int gid, int[] gids, int debugFlags, int mountExternal, int targetSdkVersion, String seInfo, String abi, String instructionSet, String appDataDir, String[] zygoteArgs) { try { //通过虚拟机来创建新的进程 return startViaZygote(processClass, niceName, uid, gid, gids, debugFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, zygoteArgs); //... }
7.2 startViaZygote-> zygoteSendArgsAndGetResult
1) startViaZygote通将参数全部转化成Zygote的数组String
2) openZygoteSocketIfNeeded/zygoteSocket.connect创建Socket链接,并获取输入输出流对象
3) zygoteSendArgsAndGetResult通过Socket与底层交互,传递相应的事件内容,并获取返回的结果
private static ProcessStartResult startViaZygote(final String processClass, //... ArrayList<String> argsForZygote = new ArrayList<String>(); //...添加虚拟机参数 //最后添加的是ActivityThread应用的入口类 argsForZygote.add(processClass); //extraArgs==null,所以后面没有参数了 if (extraArgs != null) { for (String arg : extraArgs) { argsForZygote.add(arg); } } //注意openZygoteSocketIfNeeded是connect Socket, //zygoteSendArgsAndGetResult是向Socket传递参数 return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote); } private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx { if (primaryZygoteState == null || primaryZygoteState.isClosed()) { try { //ZYGOTE_SOCKET的名字是"zygote",连接socket primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET); //... } public static ZygoteState connect(String socketAddress) throws IOException { //... try { //这里是connect的地方,会通知相应的链接对象 zygoteSocket.connect(new LocalSocketAddress(socketAddress, LocalSocketAddress.Namespace.RESERVED)); //输入流,是用来读东西的,例如设备有数据输出,然后我们读取 zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream()); //输出流是用来写东西的,例如写东西然后输出到什么位置 zygoteWriter = new BufferedWriter(new OutputStreamWriter( zygoteSocket.getOutputStream()), 256); //... } private static ProcessStartResult zygoteSendArgsAndGetResult( ZygoteState zygoteState, ArrayList<String> args) throws ZygoteStartFailedEx { try { //... //第一个先写的是参数大小 writer.write(Integer.toString(args.size())); writer.newLine(); for (int i = 0; i < sz; i++) { String arg = args.get(i); //传递设置参数 writer.write(arg); writer.newLine(); } //清空输出流,并写入,运行完成之后代表写入成功,此时Socket会接受到相应消息 writer.flush(); //... //读取返回的pid数据 result.pid = inputStream.readInt(); //读取返回的usingWrapper数据 result.usingWrapper = inputStream.readBoolean(); ... }
7.3 ZygoteInit.main(ZygoteInit.java)
1) 开机运行app_process进程(init.zygote*.rc->app_process)->app_main.main->ZygoteInit.main,Zygote受精卵进程是由init进程创建,如下通过ps可知:init进程是Zygote64受精卵进程的父进程,而system_server是通过zygote64受精卵进程创建的。(pid是该进程的id,ppid是其父进程的id)
USER PID PPID VSIZE RSS WCHAN PC NAMEroot 1 0 28524 1932 SyS_epoll_ 0000000000 S /initroot 428 1 1771768 22020 poll_sched 0000000000 S zygote64 //此处代表是64bit的system 996 428 2086288 190084 SyS_epoll_ 0000000000 S system_server
2) 获取当前操作系统的32&64位架构abiList,这个在socket connect的时候用于
2) 注册zygote的LocalServerSocket对象(Socket的服务端,可以给别人connect)
3) 启动系统服务startSystemServer
4) 等待Socket消息的通知来执行相应的任务runSelectLoop
5) MethodAndArgsCaller的run方法
//开机运行app_process进程(init.zygote*.rc->app_process)->app_main.main->ZygoteInit.main public static void main(String argv[]) { //... try { //Socket的名字是zygote String socketName = "zygote"; String abiList = null; for (int i = 1; i < argv.length; i++) { //第一次进来会设置startSystemServer==true if ("start-system-server".equals(argv[i])) { startSystemServer = true; } else if (argv[i].startsWith(ABI_LIST_ARG)) { //读的是系统属性ro.product.cpu.abilist64或者ro.product.cpu.abilist32里面的值 abiList = argv[i].substring(ABI_LIST_ARG.length()); //... //android的Socket名字:ANDROID_SOCKET_ + zygote registerZygoteSocket(socketName); //event log中会出现boot_progress_preload_start EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); //重新加载Cache,Classes,Resources,OpenGL,SharedLibraries, //TextResources,WebView,AndroidKeyStoreProvider preload(); //event log中会出现boot_progress_preload_end EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); //... //做GC,清除一些软引用对象 gcAndFinalize(); //... //在初始化时unmount根目录"/storage" Zygote.nativeUnmountStorageOnInit(); //允许zygote创建进程 ZygoteHooks.stopZygoteNoThreadCreation(); //如果需要启动系统服务则进入这里 if (startSystemServer) { //启动系统服务system_server,先后调用fork顺序是init //->zygote64(64位系统)->system_server,如果是系统进程的话, //这里是永远不会返回的startSystemServer->handleSystemServerProcess //->RuntimeInit.zygoteInit->SystemServer.main/run->Looper.loop() //->(pollInner/epoll_wait)Looper.cpp, //这个除了Loop里面调用mQueue.quit是不会退出的 startSystemServer(abiList, socketName); } //会跑下来的是zygote进程,zygote进程会一直在此运行 runSelectLoop(abiList); closeServerSocket(); } catch (MethodAndArgsCaller caller) { //对于此处zygote frok的子进程会进入此处,抛出MethodAndArgsCaller异常, //会执行run方法,其实是反射调用ActivityThread.main,这个后面会讲到 caller.run(); //... }
ps: Zygote进程是用来fork各个子进程的,如system_server就是其创建的,其中zygote64是所有64位进程的父进程,zygote是所有32位进程的父进程。
7.4 runSelectLoop
runSelectLoop循环等待Socket的数据反馈,这里写的是Select的Loop,目前androidN使用的方法是Os.poll不再有1024个Socket的限制(androidL和之前的版本使用的是select方法),后续android版本升级的话可能使用epoll(目前上层的Looper、MessageQueue就是使用epoll)
1) 循环遍历等待Socket缓冲区有可读的数据
2) Socket.connect时会创建新的ZygoteConnection
3) ZygoteConnection执行runOnce
4) 创建子进程后,子进程退出循环,父进程继续等待下一个Socket数据
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller { //... // sServerSocket是AMS Process.java中的ZYGOTE_SOCKET链接的对象, 用来创建进程 //sServerSocket是LocalServerSocket,代表整个socket //fds是所有zygote Socket相关的文件描述符 fds.add(sServerSocket.getFileDescriptor()); //peers是ZygoteConnection对象,是zygote链接之后的对象 peers.add(null); while (true) { //... //events代表等待的事件类型,POLLIN类型代表我们只关心缓冲区是否有数据可读 pollFds[i].events = (short) POLLIN; //... try { //poll函数与select类似都是,可以监视多个描述符,-1代表永不超时, //轮询一遍之后等待,当设备驱动发生自身资源可读写后,会唤醒其等待队列上睡眠的进程 Os.poll(pollFds, -1); } //... for (int i = pollFds.length - 1; i >= 0; --i) { //revents域是文件描述符的操作结果事件掩码,POLLIN代表有数据可读 if ((pollFds[i].revents & POLLIN) == 0) { continue; } //i==0是就是外部有创建socket的时候,如Socket.connect, //这个时候Os.poll中LocalServerSocket会有数据返回, //此时LocalServerSocket会accept并创建新的ZygoteConnection if (i == 0) { //创建新的受精卵的Socket链接ZygoteConnection ZygoteConnection newPeer = acceptCommandPeer(abiList); //添加到ZygoteConnection数组peers peers.add(newPeer); //添加到zygote Socket相关的文件描述符数组中去 fds.add(newPeer.getFileDesciptor()); //非第一次运行时,如果之前创建的Socket链接对象ZygoteConnection有数据可以读, //如OutputStream(zygoteWriter就是输出流)有写入,那么此处会有数据, //进入runOnce函数。 } else { //创建子进程会抛出MethodAndArgsCaller的异常, //给ZygoteInit.main捕获,然后运行ActivityThread的main函数, //子进程抛出异常后退出该循环,但是Zygote父进程还算会继续循环的 boolean done = peers.get(i).runOnce(); //创建子进程后,父进程也就是zygote进程才会进入这里 //... } } } }
runSelectLoop函数就是在监听Socket端是否有数据可以读,如果有数据来了,那么就是创建进程,这个Zygote进程主要作用就是创建进程(子进程的一些基本信息都不用再初始化,因为Zygote已经初始过了,相当于优化了启动进程的流程)。
7.5 runOnce(ZygoteConnection.java)
1) 读取相应的参数列表
2) 创建子进程forkAndSpecialize(Zygote.forkAndSpecialize -> com_android_internal_os_Zygote_nativeForkAndSpecialize/ForkAndSpecializeCommon/fork(com_android_internal_os_Zygote.cpp)),通过jni调用com_android_internal_os_Zygote_nativeForkAndSpecialize,最后调用的是fork函数,该函数用于创建进程,具体在这里不展开,具体可以参考之前的一篇文章Android上层如何调用一个底层函数
的章节2.1.3 com_android_internal_os_Zygote.cpp本地函数
里面有关于fork的讲解。最终子进程返回的是pid==0,父进程返回的是子进程的pid。
3) 处理父进程的内容handleParentProc,如返回给AMS章节6.5中startProcessLocked的Process.start,其值是Process.ProcessStartResult startResult,包含子进程pid
4) 处理子进程的内容handleChildProc,这个放在下一节讲解
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { ... try { //读取相应的参数列表 args = readArgumentList(); descriptors = mSocket.getAncillaryFileDescriptors(); } //... //invokeWith==null,目前没有设置 if (parsedArgs.invokeWith != null) { //... } //... int [] fdsToClose = { -1, -1 }; FileDescriptor fd = mSocket.getFileDescriptor(); if (fd != null) { //客户端的文件描述符 fdsToClose[0] = fd.getInt$(); } fd = ZygoteInit.getServerSocketFileDescriptor(); if (fd != null) { //服务端的文件描述符 fdsToClose[1] = fd.getInt$(); } //调用native fork进程的地方 //此处是fock进程(Zygote.forkAndSpecialize //->com_android_internal_os_Zygote_nativeForkAndSpecialize //->ForkAndSpecializeCommon/fork(com_android_internal_os_Zygote.cpp)) pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet, parsedArgs.appDataDir); //... try { //如果是子进程pid会等于0,父进程此处pid会返回子进程的pid if (pid == 0) { //... //处理子进程逻辑 handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); //子进程是永远不会到这个位置来的,因为之前已经抛出MethodAndArgsCaller异常 return true; } else { //... //处理父进程逻辑 return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); } ... } private String[] readArgumentList() throws IOException { //... try { //读取第一个参数 String s = mSocketReader.readLine(); //第一个参数上面章节7.2 Process.java中zygoteSendArgsAndGetResult写的就是参数个数 argc = Integer.parseInt(s); } //传递的参数最多是1024个,超过的话系统可能受到DOS攻击 if (argc > MAX_ZYGOTE_ARGC) { throw new IOException("max arg count exceeded"); } for (int i = 0; i < argc; i++) { //读出每一个参数返回result数组中去 result[i] = mSocketReader.readLine(); ... } private boolean handleParentProc(int pid, FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) { if (pid > 0) { //如果返回的pid大于0,说明子进程创建成功,此时设置子进程的pid setChildPgid(pid); } //... try { //传递pid回去,最后写入章节7.2中zygoteSendArgsAndGetResult的result.pid mSocketOutStream.writeInt(pid); //传递是否wrapped进程,此处一般都是false mSocketOutStream.writeBoolean(usingWrapper); } //... return false; }
8. 绑定进程am_proc_bound
上一章节我们知道了Process.start用于创建进程,父进程会直接返回子进程的pid,那么接下去我们需要从子进程处理的内容开始分析,看看子进程是怎样关联到上层的application中去的,这里讲解第一步am_proc_bound
图8.1 绑定进程
8.1 handleChildProc(ZygoteConnection.java)
1) 关闭相应的子进程Socket链接
2) 设置进程的名字,这个时候通过ps就可以看到进程名字变成应用声明的进程(如果没有定义android:process
那么默认该进程名字就是应用的包名)
3) RuntimeInit.zygoteInit子进程的初始化
private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) throws ZygoteInit.MethodAndArgsCaller { //关闭自己的Socket closeSocket(); //关闭ZygoteInit中服务端的Socket ZygoteInit.closeServerSocket(); //... if (parsedArgs.niceName != null) { //自己设置自己的名字,此处设置进程名字为之前传进来的processName Process.setArgV0(parsedArgs.niceName); } //这里是不运行的 if (parsedArgs.invokeWith != null) { //... //此处会进来 } else { //运行初始化RuntimeInit中的进程(受精卵)初始化zygoteInit RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null /* classLoader */); } }
ps:Process.setArgV0会通过prctl(PR_SET_NAME…),裁剪后(process_name.c),只保留processName后面15个字符(kernel实际还会裁剪到最后一个字符,其实是14个字符),设置进程名字(内核标识进程的名字是task_struc->comm).
进程的名字在某些地方显示不是无限长的,如在systrace显示的进程名字就不超过15个字符。
8.2 zygoteInit(RuntimeInit.java)
1) log重定向redirectLogStreams
2) 通用设置初始化commonInit
3) 初始化zygote:nativeZygoteInit
4) 应用初始化applicationInit
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { //重新定向log的输入地方,此处设置log输出到Android log中 redirectLogStreams(); //一些通用设置的初始化 commonInit(); //初始化zygote,这里AppRuntime继承的是AndroidRuntime,运行的是启动线程池startThreadPool nativeZygoteInit(); //应用初始化,此处是接下来运行的地方 applicationInit(targetSdkVersion, argv, classLoader); } private static final void commonInit() { //... //设置默认的异常捕获 Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler()); TimezoneGetter.setInstance(new TimezoneGetter() { @Override public String getId() { //设置时区id return SystemProperties.get("persist.sys.timezone"); } }); //设置时区 TimeZone.setDefault(null); LogManager.getLogManager().reset(); //Android log相关初始化 new AndroidConfig(); String userAgent = getDefaultUserAgent(); //网络用户代理初始化 System.setProperty("http.agent", userAgent); //网络Socket相关 NetworkManagementSocketTagger.install(); //... initialized = true; }
8.3 applicationInit
1) 设置虚拟机GC回收比例,正在使用的对象/堆栈大小 = 0.75
2) 设置虚拟机sdk的版本号
3) 获取相应的参数,如args.startClass就是在章节7.2 startViaZygote设置的processClass(ActivityThread)
4) 通过反射查找ActivityThread的main函数,并将其作为MethodAndArgsCaller异常的参数
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { //设置退出时不调用onExit()函数 nativeSetExitWithoutCleanup(true); //设置GC回收后的比例,正在使用的对象/堆栈大小 = 0.75,对应于dalvik.vm.heaptargetutilization VMRuntime.getRuntime().setTargetHeapUtilization(0.75f); //设置sdk的版本号,这个是进程启动Process.start时就传递过来的 VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion); //获取相应的参数,如args.startClass就是第一个非"--"开头的参数 final Arguments args; try { args = new Arguments(argv); } //... //反射调用main函数,注意startClass是Process.start时传递进来的android.app.ActivityThread invokeStaticMain(args.startClass, args.startArgs, classLoader); } private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) throws ZygoteInit.MethodAndArgsCaller { //... //查找android.app.ActivityThread类 cl = Class.forName(className, true, classLoader); //... //查找其中的main函数 m = cl.getMethod("main", new Class[] { String[].class }); //... //获取函数的调用属性 int modifiers = m.getModifiers(); //必须是静态而且是public的方法,否则抛出RuntimeException异常 if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) { throw new RuntimeException( "Main method is not public and static on " + className); } //抛出MethodAndArgsCaller异常 throw new ZygoteInit.MethodAndArgsCaller(m, argv); }
在章节7.3 ZygoteInit.main方法里面有捕获MethodAndArgsCaller异常,并调用MethodAndArgsCaller的run方法。
8.4 MethodAndArgsCaller.run()
反射调用ActivityThread的main静态函数
public static class MethodAndArgsCaller extends Exception implements Runnable { //... public MethodAndArgsCaller(Method method, String[] args) { //mMethod是ActivityThread的main方法 mMethod = method; //mArgs一般都是null mArgs = args; } public void run() { try { //调用方法method,传递的是args参数,传递第一个参数是类对象为null,代表静态函数 mMethod.invoke(null, new Object[] { mArgs }); //...
到这里进程已经启动完成,将进入应用相关流程
8.5 MethodAndArgsCaller.run()
1) 消息队列初始化Looper.prepareMainLooper
2) 新建ActivityThread并附着thread.attach
3) 进入消息队列的循环Looper.loop
public static void main(String[] args) { //默认是没有用到SamplingProfilerIntegration的, //该类用于监听性能数据,包含进程名字、应用信息、线程启动与关闭, //还有默认persist.sys.profiler_ms毫秒dump一次该进程堆栈信息 SamplingProfilerIntegration.start(); //在严格模式或者调试的时候打开,默认不打卡 CloseGuard.setEnabled(false); //初始化环境(这里主要是存储设备的环境,用user id初始化) Environment.initForCurrentUser(); //主要是libcore中使用event log的方法,Reporter的report类似于EventLog.writeEvent EventLogger.setReporter(new EventLoggingReporter()); //配置文件目录在/data/misc/user/1000 final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); //设置认证相关的目录cacerts-added,cacerts-removed TrustedCertificateStore.setDefaultUserDirectory(configDir); //设置进程名字为<pre-initialized>,这个很快在handleBindApplication时就会给修改 Process.setArgV0("<pre-initialized>"); //消息队列初始化,主进程是不允许退出的,无法调用MessageQueue.quit退出 Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); //新建一个ActivityThread并attach附着,这个跟接下去的attachApplication相关 thread.attach(false); if (sMainThreadHandler == null) { //获取thread的handler,将其作为应用的主线程 sMainThreadHandler = thread.getHandler(); } if (false) { //用户调试log,用于消息队列Message的事件分发log输出, //调试消息队列的时候可以打开 Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } //Looper.loop()里面是个for (;;)死循环,只要Message不为null,会一直运行 //Looper.loop() -> MessageQueue.next() //-> nativePollOnce(android_os_MessageQueue.cpp) //->(pollOnce/pollInner/epoll_wait) Looper.cpp, //这个Message==null情况只有调用MessageQueue.quit才会发生, //目前没有看到主动调用MessageQueue.quit,故这个消息队列循环是不会退出的 Looper.loop(); //如果进入到这里代表程序出错了,这里程序正常运行是不会进来的 throw new RuntimeException("Main thread loop unexpectedly exited"); }
在调用静态方法ActivityThread.main之后会新建一个ActivityThread对象,相当于该进程的主线程(UI线程),创建之后首先跑的就是ActivityThread的attach函数
8.6 attach
这里我们主要关注attachApplication,也就是AMS的应用附着即可
private void attach(boolean system) { //... //是否system,应用启动肯定不是system,会进入此处 if (!system) { //... //设置ddms中的进程名字为"<pre-initialized>",临时的 android.ddm.DdmHandleAppName.setAppName("<pre-initialized>", UserHandle.myUserId()); //设置ApplicationObject为ActivityThread RuntimeInit.setApplicationObject(mAppThread.asBinder()); final IActivityManager mgr = ActivityManagerNative.getDefault(); try { //此处就是attachApplication mgr.attachApplication(mAppThread); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } //Java允许在类中定义一个名为finalize()的方法。 //它的工作原理是:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法。 //并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存 //BinderInternal里面实现的是Object finalize, //当资源释放的时候会调用finalize,然后会调用 BinderInternal.addGcWatcher(new Runnable() { //ActivityThread对象没有再使用时会进行回收 @Override public void run() { if (!mSomeActivitiesChanged) { return; } Runtime runtime = Runtime.getRuntime(); //这个是HeapGrowthLimit,正常应用虚拟机内存最大值dalvik.vm.heapgrowthlimit, //AndroidRuntime.cpp/runtime.cc/heap.cc long dalvikMax = runtime.maxMemory(); long dalvikUsed = runtime.totalMemory() - runtime.freeMemory(); //当前使用内存,如果最大内存的3/4将进行activity的释放操作 if (dalvikUsed > ((3*dalvikMax)/4)) { //... mSomeActivitiesChanged = false; try { //此处释放指的是activity的ondestroy, //目前可以destroy的activity是处于onstop状态的activity mgr.releaseSomeActivities(mAppThread); //... //让DropBox在libcore可用 DropBox.setReporter(new DropBoxReporter()); }
8.7 attachApplication/attachApplicationLocked
1) 首先是ActivityManagerNative.java的attachApplication会传递ActivityThread和调用者的pid给到AMS的attachApplicationLocked
2) eventlog中设置服务绑定进程am_proc_bound,说明进程启动完成,而且该进程的主线程ActivityThread已经创建,并且通知到AMS中
3) ActivityThread的绑定应用bindApplication, 这个会在下面章节讲解
4) 由于我们这个例子是桌面启动应用,那么最后mStackSupervisor.attachApplicationLocked堆栈中的绑定应用会真正启动activity活动对象,这个会在下面章节讲解
//ActivityManagerNative.java public final void attachApplication(IApplicationThread thread) { ... attachApplicationLocked(thread, callingPid); ... //ActivityManagerService.java private final boolean attachApplicationLocked(IApplicationThread thread, int pid) { //... ProcessRecord app; //调用者非系统进程,且调用者的pid大于0 if (pid != MY_PID && pid >= 0) { synchronized (mPidsSelfLocked) { //在进程启动Process.start后就将pid添加进入mPidsSelfLocked了(父进程调用) //现在是子进程调用,这个时候已经添加 app = mPidsSelfLocked.get(pid); //... //app.thread还没有设置过,下面makeActive将进行设置,会将app.thread设置成 //IApplicationThread(在ActivityThread中),app.thread不为null了 if (app.thread != null) { //... } //... try { AppDeathRecipient adr = new AppDeathRecipient( app, pid, thread); //设置binder died掉之后的的回调地方是binderDied thread.asBinder().linkToDeath(adr, 0); //设置目前谁在监控死亡状态 app.deathRecipient = adr; //... //eventlog中设置服务绑定am_proc_bound EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName); //设置ProcessRecord的IApplicationThread(在ActivityThread中) app.makeActive(thread, mProcessStats); //默认设置一个adj app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ; //... //用户更新电量估算mBatteryStatsService的FOREGROUND时间 updateProcessForegroundLocked(app, false, false); //... //判断是否解锁 app.unlocked = StorageManager.isUserKeyUnlocked(app.userId); //去除进程启动超时的msg PROC_START_TIMEOUT_MSG, //此处有ActivityThread回传,代表进程启动完成 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); //一般情况normalMode都是true boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info); //generateApplicationProvidersLocked是开始创建应用的ContentProvider对象 List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null; //... //一般不会进入这里,这里是自动化测试的时候会进来 if (app.instrumentationClass != null) { //... } //... //应用兼容性相关,该参数会传入AcitiviyThread中 app.compat = compatibilityInfoForPackageLocked(appInfo); //一般profilerInfo==null ProfilerInfo profilerInfo = profileFile == null ? null : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop); //回到AcitiviyThread中的bindApplication,processName==test2, //instrument相关都等于null,mBinderTransactionTrackingEnabled/ //enableTrackAllocation/isRestrictedBackupMode默认等于false, //normalMode默认是true,persistent代表是否常驻内存,compat是兼容性相关, //isolated==false,getCommonServicesLocked是将PMS、WMS、ALARM相关服务传入, //mCoreSettingsObserver用于监听一些参数变化(长按超时,12/24小时显示时间变化, //调试界面属性),bindApplication是异步的 thread.bindApplication(processName, appInfo, providers, app.instrumentationClass, profilerInfo, app.instrumentationArguments, app.instrumentationWatcher, app.instrumentationUiAutomationConnection, testMode, mBinderTransactionTrackingEnabled, enableTrackAllocation, isRestrictedBackupMode || !normalMode, app.persistent, new Configuration(mConfiguration), app.compat, getCommonServicesLocked(app.isolated), mCoreSettingsObserver.getCoreSettingsLocked()); //将进程添加进入mLruProcesses中 //mLruProcesses保存的是正在运行应用的列表,第一个是最近使用的 updateLruProcessLocked(app, false, null); //触发GC的时间重新计算 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis(); //... //一般normalMode都是true if (normalMode) { try { //如果是activity导致的进程启动,activity从这里开始启动 //此处用于am_restart_activity,此处设置了didSomething = true if (mStackSupervisor.attachApplicationLocked(app)) { didSomething = true; } //... //一般badApp==false if (!badApp) { try { //如果之前该进程有需要启动的服务,此处开始启动服务 //启动进程了之后才会去启动服务 didSomething |= mServices.attachApplicationLocked(app, processName); //... if (!badApp && isPendingBroadcastProcessLocked(pid)) { try { //如果该进程之前有挂起的广播,现在可以开始发送了 didSomething |= sendPendingBroadcastsLocked(app); // ...
到目前为止绑定进程的逻辑已经讲解完了,接下去我们仅需要关注thread.bindApplication和mStackSupervisor.attachApplicationLocked这2个函数
9 创建application
这一章节将会讲到application的实例化、application进程上下文context的创建、application的OnCreate
图9.1 创建application
9.1 bindApplication(ActivityThread.java)
我们关注的重点:
1) getPackageInfoNoCheck新建new LoadedApk,该类用于加载apk
2) makeApplication新建一个Application对象new newApplication(这里面会createAppContext创建application的进程上下文context)
3) callApplicationOnCreate调用Application的OnCreate
private void handleBindApplication(AppBindData data) { //设置art实时编译更加敏感,更新art配置相关信息的计数count会乘10=((10000/500)/2), //会让art更容易更新配置(如做实时编译还是解释执行等) VMRuntime.registerSensitiveThread(); //... //设置process的启动时间,这个主要是给上层调用的 Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis()); //AMS传递进来的参数全部放在data上 mBoundApplication = data; //进程启动时如果你没有设置固定方向或者手动改变方向,这个config就是AMS中的mConfiguration mConfiguration = new Configuration(data.config); mCompatConfiguration = new Configuration(data.config); mProfiler = new Profiler(); //一般情况initProfilerInfo都是null,除了使用instrumentation(如自动化测试相关会使用到) if (data.initProfilerInfo != null) { ... } //此处会通过prctl(PR_SET_NAME...),裁剪后(process_name.c) //只保留processName后面15个字符(kernel实际还会裁剪到最后一个字符,其实是14个字符), //设置进程名字(内核标识进程的名字是task_struc->comm). Process.setArgV0(data.processName); //此处设置的是ddms调试使用的名字 android.ddm.DdmHandleAppName.setAppName(data.processName, UserHandle.myUserId()); //常驻内存的进程 if (data.persistent) { //如果在不能使用GPU加速(如低内存设备 //或者显示定义config_avoidGfxAccel为ture的情况都会进来) if (!ActivityManager.isHighEndGfx()) { //当前进程停止使用硬件渲染,这里的作用主要是为了减少运存RAM的消耗, //对于低内存手机,这个是有帮助的 ThreadedRenderer.disable(false); } } //... //回复系统默认时区 TimeZone.setDefault(null); //设置默认的语言 LocaleList.setDefault(data.config.getLocales()); //... //新建new LoadedApk,该类用于加载apk data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo); //... //可以通过config对分辨率进行设置,默认是没有设置的 updateDefaultDensity(); //设置是否24小时 final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24)); DateFormat.set24HourTimePref(is24Hr); //... //网络代理相关设置 final IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); if (b != null) { final IConnectivityManager service = IConnectivityManager.Stub.asInterface(b); try { final ProxyInfo proxyInfo = service.getProxyForNetwork(null); Proxy.setHttpProxySystemProperty(proxyInfo); //... //新建一个appContext final ContextImpl appContext = ContextImpl.createAppContext(this, data.info); //... //应用一般是isIsolated == false,这里讲的不是系统进程,是普通app的进程的启动,故会进入此处 if (!Process.isIsolated() && !"android".equals(appContext.getPackageName())) { //获取应用缓存目录,如("/data/user_de/0/com.android.settings/cache") final File cacheDir = appContext.getCacheDir(); //... //获取应用代码缓存目录,"/data/user_de/0/com.android.settings/code_cache" //此处主要是存放的opengl和renderscript部分的缓存代码 //类似于com.android.opengl.shaders_cache、com.android.renderscript.cache这样的数据 final File codeCacheDir = deviceContext.getCodeCacheDir(); } //... //ii非自动化测试一般都是null if (ii != null) { ... } else { //一般情况下走的是这里 mInstrumentation = new Instrumentation(); } //设置虚拟机堆栈最大能增长到的内存是多少,根据largeHeap属性判断是否大应用 if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) { //如果是大应用的话,应用虚拟机内存可以增长到堆栈大小dalvik.vm.heapsize dalvik.system.VMRuntime.getRuntime().clearGrowthLimit(); } else { //默认只能增长到dalvik.vm.heapgrowthlimit受限制的堆栈大小 dalvik.system.VMRuntime.getRuntime().clampGrowthLimit(); } // allowThreadDiskWrites在应用oncreate的时候允许写的操作, //返回的值是就得策略,此处仅用于临时修改 final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites(); try { //restrictedBackupMode是flase,data.info是上面new的LoadedApk, //这里面的createAppContext和上面的createAppContext传递的参数是一样的 //此处会新建一个Application对象new newApplication,此处是Application的实例化 //此处传递的第二个参数instrumentation==null,故application不会在此处OnCreate Application app = data.info.makeApplication(data.restrictedBackupMode, null); //保存当前的Application对象 mInitialApplication = app; //一般没有限制备份模式,restrictedBackupMode == false if (!data.restrictedBackupMode) { //如果apk有provider就会进入这里(如静态注册的providers) if (!ArrayUtils.isEmpty(data.providers)) { //初始化app中的所有provider installContentProviders(app, data.providers); //... } } try { //如果没有复写Instrumentation,一般此处没有做任何事情 mInstrumentation.onCreate(data.instrumentationArgs); } //... try { //此处调用的就是Application的OnCreate方法, //activity的OnCreate后面会讲到,这里先调用的是Application的OnCreate mInstrumentation.callApplicationOnCreate(app); //... }
9.2 getPackageInfoNoCheck/getPackageInfo
getPackageInfoNoCheck/getPackageInfo返回的是LoadedApk,用于加载apk
public final LoadedApk getPackageInfoNoCheck(ApplicationInfo ai, CompatibilityInfo compatInfo) { return getPackageInfo(ai, compatInfo, null, false, true, false); } //(ai, compatInfo, null, false, true, false); private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo, ClassLoader baseLoader, boolean securityViolation, boolean includeCode, boolean registerPackage) { //... //此处apk是包含代码的,故是从mPackages取,第一次进来此处是null ref = mPackages.get(aInfo.packageName); LoadedApk packageInfo = ref != null ? ref.get() : null; //新建LoadedApk加载apk的类 packageInfo = new LoadedApk(this, aInfo, compatInfo, baseLoader, securityViolation, includeCode && (aInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0, registerPackage); //... //将新建的LoadedApk放到mPackages中 mPackages.put(aInfo.packageName, new WeakReference<LoadedApk>(packageInfo)); //... return packageInfo; }
9.3 makeApplication(LoadedApk.java)
1) 创建Application的进程上下文
2) 调用代理Instrumentation新建Application
3) Application实例化、Application设置进程上下文context
//LoadedApk.java //forceDefaultAppClass==false,instrumentation==null public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) { //... Application app = null; //如果应用没有重载Application类的话,直接使用默认的"android.app.Application" String appClass = mApplicationInfo.className; if (forceDefaultAppClass || (appClass == null)) { appClass = "android.app.Application"; } try { java.lang.ClassLoader cl = getClassLoader(); //... //创建Application的进程上下文 ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this); //调用代理Instrumentation新建Application app = mActivityThread.mInstrumentation.newApplication( cl, appClass, appContext); appContext.setOuterContext(app); } //... return app; } //Instrumentation.java public Application newApplication(ClassLoader cl, String className, Context context) throws InstantiationException, IllegalAccessException, ClassNotFoundException { return newApplication(cl.loadClass(className), context); } static public Application newApplication(Class<?> clazz, Context context) ... { //Application类的实例化,如类非静态变量等会在此处生成 Application app = (Application)clazz.newInstance(); //调用Application的attach附着,用于设置进程上下文context app.attach(context); return app; } //Application.java final void attach(Context context) { //设置base应用基本的进程上下文 attachBaseContext(context); //设置类的加载器 mLoadedApk = ContextImpl.getImpl(context).mPackageInfo; }
现在有了Application这个对象,下面接着会进行Application的OnCreate
9.4 callApplicationOnCreate(Instrumentation.java)
callApplicationOnCreate这个函数通过代理调用Application的OnCreate
//Instrumentation.java public void callApplicationOnCreate(Application app) { app.onCreate(); } //Application.java public void onCreate() { }
进程启动会先调用Application的OnCreate,这个也是算在应用启动生命周期内的。
目前Application创建了,Application的OnCreate也调用了,接下去就是Activity相关的逻辑。
- android N进程启动流程(二)(上一个activity的暂停、进程启动、绑定进程与创建application)
- Android Application Launch [ 创建进程--〉绑定App-->启动Activity/Start Service/...]
- android N进程启动流程(一)(捕获输入事件、准备创建activity、焦点切换)
- Android N Phone进程启动流程
- Android N Phone进程启动流程
- Android启动流程分析(二) init进程的启动
- Android进程启动流程
- android进程启动流程
- android 启动新 app 的activity 新进程的创建
- Android runtime机制(二)zygote进程的启动流程
- android init进程启动的大致流程
- Android System进程启动流程
- Android 应用进程启动流程
- Android 应用进程启动流程
- Android 应用进程启动流程
- Android 应用进程启动流程
- 程序启动与进程创建
- Zygote进程的启动流程
- 实现自定义图片View圆形、圆角,椭圆
- gulp一些内容
- 极大极小搜索
- Android Notification(一) Notification 的 requestCode 与 id
- Reforcement Learning ---- Multi-armed Bandits
- android N进程启动流程(二)(上一个activity的暂停、进程启动、绑定进程与创建application)
- webpack学习笔记一
- 查看windows机器的cpu信息
- 决策树,信息熵,信息增益,Gini
- 生成文字水印、图片水印、缩列图
- Mac下左侧project不显示,或者project中的目录结构不显示
- 跨境电商系统的一个架构演进
- leetcode486动态规划&playerAB从数组两端挑数字,求最大player
- C# SQL代码字符拼接