💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
1. binderDied函数分析 **ActvityManagerService.java::AppDeathRecipientbinderDied** ~~~ public void binderDied() { //注意,该函数也是通过Binder线程调用的,所以此处要加锁 synchronized(ActivityManagerService.this) { appDiedLocked(mApp, mPid, mAppThread); } } ~~~ 最终的处理函数是appDiedLocked,其中所传递的3个参数保存了对应死亡进程的信息。来看appDiedLocked的代码:: **ActvityManagerService.java::appDiedLocked** ~~~ final void appDiedLocked(ProcessRecord app, intpid, IApplicationThread thread) { ...... if(app.pid == pid && app.thread != null && app.thread.asBinder() == thread.asBinder()) { //当内存低到水位线时,LMK模块也会杀死进程。对AMS来说,需要区分进程死亡是LMK导致的 //还是其他原因导致的。App instrumentationClass一般都为空,故此处doLowMem为true booleandoLowMem = app.instrumentationClass == null; //①下面这个函数非常重要 handleAppDiedLocked(app, false, true); if(doLowMem) { boolean haveBg = false; //如果系统中还存在oom_adj大于HIDDEN_APP_MIN_ADJ的进程,就表明不是LMK模块因 //内存不够而导致进程死亡的 for(int i=mLruProcesses.size()-1; i>=0; i--) { ProcessRecord rec = mLruProcesses.get(i); if (rec.thread != null && rec.setAdj >= ProcessList.HIDDEN_APP_MIN_ADJ){ haveBg = true;//还有后台进程,故可确定系统内存尚未吃紧 break; } }//for循环结束 //如果没有后台进程,表明系统内存已吃紧 if(!haveBg) { long now = SystemClock.uptimeMillis(); for(int i=mLruProcesses.size()-1; i>=0; i--) { .....//将这些进程按一定规则加到mProcessesToGc中,尽量保证 //heavy/important/visible/foreground的进程位于mProcessesToGc数组 //的前端 }//for循环结束 /* 发送GC_BACKGROUND_PROCESSES_MSG消息给mHandler,该消息的处理过程就是: 调用应用进程的scheduleLowMemory或processInBackground函数。其中, scheduleLowMemory将触发onLowMemory回调被调用,而processInBackground将 触发应用进程进行一次垃圾回收 读者可自行阅读该消息的处理函数performAppGcsIfAppropriateLocked */ scheduleAppGcsLocked(); }// if(!haveBg)判断结束 }//if(doLowMem)判断结束 } ~~~ 以上代码中有一个关键函数handleAppDiedLocked,下面来看它的处理过程。 2. handleAppDiedLocked函数分析 **ActivityManagerService.java::handleAppDiedLocked** ~~~ private final voidhandleAppDiedLocked(ProcessRecord app, boolean restarting, boolean allowRestart) { //①在本例中,传入的参数为restarting=false, allowRestart=true cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1); if(!restarting) { mLruProcesses.remove(app); } ......//下面还有一部分代码处理和Activity相关的收尾工作,读者可自行阅读 } ~~~ 重点看上边代码中的cleanUpApplicationRecordLocked函数,该函数的主要功能就是处理Service、ContentProvider及BroadcastReceiver相关的收尾工作。先来看Service方面的工作。 (1) cleanUpApplicationRecordLocked之处理Service **ActivityManagerService.java::cleanUpApplicationRecordLocked** ~~~ privatefinal void cleanUpApplicationRecordLocked(ProcessRecord app, boolean restarting, boolean allowRestart, int index) { if (index>= 0) mLruProcesses.remove(index); mProcessesToGc.remove(app); //如果该Crash进程有对应打开的对话框,则关闭它们,这些对话框包括crash、anr和wait等 if(app.crashDialog != null) { app.crashDialog.dismiss(); app.crashDialog = null; } ......//处理anrDialog、waitDialog //清理app的一些参数 app.crashing = false; app.notResponding = false; ...... //处理该进程中所驻留的Service或它和别的进程中的Service建立的Connection关系 //该函数是AMS Service处理流程中很重要的一环,读者要仔细阅读 killServicesLocked(app,allowRestart); ~~~ cleanUpApplicationRecordLocked函数首先处理几个对话框(dialog),然后调用killServicesLocked函数做相关处理。作为Service流程的一部分,读者需要深入研究。 (2) cleanUpApplicationRecordLocked之处理ContentProvider 再来看cleanUpApplicationRecordLocked下一阶段的工作,主要和ContentProvider有关。 **ActivityManagerService.java::cleanUpApplicationRecordLocked** ~~~ booleanrestart = false; int NL = mLaunchingProviders.size(); if(!app.pubProviders.isEmpty()) { //得到该进程中发布的ContentProvider信息 Iterator<ContentProviderRecord> it = app.pubProviders.values().iterator(); while(it.hasNext()) { ContentProviderRecord cpr = it.next(); cpr.provider = null; cpr.proc = null; int i = 0; if(!app.bad && allowRestart) { for (; i<NL; i++) { /* 如果有客户端进程在等待这个已经死亡的ContentProvider,则系统会 尝试重新启动它,即设置restart变量为true */ if (mLaunchingProviders.get(i) == cpr) { restart = true; break; } }//for循环结束 } else i = NL; if(i >= NL) { /* 如果没有客户端进程等待这个ContentProvider,则调用下面这个函数处理它,我们 在卷I的第10章曾提过一个问题,即ContentProvider进程被杀死 后,系统该如何处理那些使用了该ContentProvider的客户端进程。例如,Music和 MediaProvider之间有交互,如果杀死了MediaProvider,Music会怎样呢? 答案是系统会杀死Music,证据就在removeDyingProviderLocked函数 中,读者可自行阅读其内部处理流程 */ removeDyingProviderLocked(app, cpr); NL = mLaunchingProviders.size(); } }// while(it.hasNext())循环结束 app.pubProviders.clear(); } //下面这个函数的功能是检查本进程中的ContentProvider是否存在于 // mLaunchingProviders中,如果存在,则表明有客户端在等待,故需考虑是否重启本进程或者 //杀死客户端(当死亡进程变成bad process的时,需要杀死客户端) if(checkAppInLaunchingProvidersLocked(app, false)) restart = true; ...... ~~~ 从以上的描述中可知,ContentProvider所在进程和其客户端进程实际上有着非常紧密而隐晦(之所以说其隐晦,是因为SDK中没有任何说明)的关系。在目前软件开发追求模块间尽量保持松耦合关系的大趋势下,Android中的ContentProvider和其客户端这种紧耦合的设计思路似乎不够明智。不过,这种设计是否是不得已而为之呢?读者不妨探讨一下,如果有更合适的解决方案,期待能一起分享。 (3) cleanUpApplicationRecordLocked之处理BroadcastReceiver **ActivityManagerService.java::cleanUpApplicationRecordLocked** ~~~ skipCurrentReceiverLocked(app); //从AMS中去除接收者 if(app.receivers.size() > 0) { Iterator<ReceiverList> it = app.receivers.iterator(); while(it.hasNext()) { removeReceiverLocked(it.next()); } app.receivers.clear(); } if(mBackupTarget != null && app.pid == mBackupTarget.app.pid) { //处理Backup信息 } mHandler.obtainMessage(DISPATCH_PROCESS_DIED, app.pid, app.info.uid,null).sendToTarget(); //注意该变量名为restarting,前面设置为restart. if(restarting) return; if(!app.persistent) { mProcessNames.remove(app.processName, app.info.uid); if(mHeavyWeightProcess == app) { ......//处理HeavyWeightProcess } } elseif (!app.removed) { if(mPersistentStartingProcesses.indexOf(app) < 0) { mPersistentStartingProcesses.add(app); restart = true; } } mProcessesOnHold.remove(app); if (app== mHomeProcess) mHomeProcess = null; if(restart) {//如果需要重启,则调用startProcessLocked处理它 mProcessNames.put(app.processName, app.info.uid, app); startProcessLocked(app, "restart", app.processName); } elseif (app.pid > 0 && app.pid != MY_PID) { synchronized (mPidsSelfLocked) { mPidsSelfLocked.remove(app.pid); mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); } app.setPid(0); } } ~~~ 在这段代码中,除了处理BrodcastReceiver方面的工作外,还包括其他方面的收尾工作。最后,如果要重启该应用,则需调用startProcessLocked函数进行处理。这部分代码不再详述,读者可自行阅读。