一.概述
1.1 引言
話說Android開源系統擁有着App不計其數,百家爭鳴,都想在這“大爭之世”尋得系統存活的一席之地。然則系統資源有限,如若都割據為王,再強勁的CPU也會忙不過來,再龐大的內存終會消耗殆盡,再大容量的電池續航終會曇花一現。
面對芸芸眾生,無盡變數,系統以不變應萬變,一招絕殺神技forceStop騰空出世,此處以adb指令的方式為例來說說其內部機理:
am force-stop pkgName am force-stop --user 2 pkgName //只殺用戶userId=2的相關信息
force-stop命令殺掉所有用戶空間下的包名pkgName相關的信息,也可以通過--user來指定用戶Id。 當執行上述am指令時,則會觸發調用Am.java的main()方法,接下來從main方法開始說起。
1.2 Am.main
[-> Am.java]
public static void main(String[] args) { (new Am()).run(args); //【見小節1.3】 }
1.3 Am.run
[-> Am.java]
public void run(String[] args) { ... mArgs = args; mNextArg = 0; mCurArgData = null; onRun(); //【見小節1.4】 ... }
1.4 Am.onRun
[-> Am.java]
public void onRun() throws Exception { //獲取的是Binder proxy對象AMP mAm = ActivityManagerNative.getDefault(); String op = nextArgRequired(); if (op.equals("start")) { ... } else if (op.equals("force-stop")) { runForceStop(); //【見小節1.5】 } ... }
1.5 Am.runForceStop
[-> Am.java]
private void runForceStop() throws Exception { int userId = UserHandle.USER_ALL; String opt; // 當指定用戶時,則解析相應userId while ((opt=nextOption()) != null) { if (opt.equals("--user")) { userId = parseUserArg(nextArgRequired()); } } //【見小節1.6】 mAm.forceStopPackage(nextArgRequired(), userId); }
當不指定userId時,則默認為UserHandle.USER_ALL。
1.6 AMP.forceStopPackage
[-> ActivityManagerNative.java ::AMP]
public void forceStopPackage(String packageName, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeString(packageName); data.writeInt(userId); //【見小節1.7】 mRemote.transact(FORCE_STOP_PACKAGE_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); reply.recycle(); }
1.7 AMN.onTransact
[-> ActivityManagerNative.java]
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code) { case FORCE_STOP_PACKAGE_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); String packageName = data.readString(); int userId = data.readInt(); //【見小節2.1】 forceStopPackage(packageName, userId); reply.writeNoException(); return true; } ... } }
AMP.forceStopPackage來運行在執行adb時所創建的進程,經過Binder Driver后,進入system_server進程的一個binder線程來執行AMN.forceStopPackage,從這開始的操作(包括當前操作)便都運行在system_server系統進程。
1.8 小節

進程絕殺技force-stop,並非任意app可直接調用, 否則App間可以相互停止對方,則豈非天下大亂。該方法的存在便是供系統差遣。一般地,點擊home彈出的清理用戶最近使用app采取的策略便是force-stop.
至於force-stop的觸發方式,除了adb的方式,還可通過獲取ActivityManager再調用其方法forceStopPackage(),不過這是@hide隱藏方法,同樣是需要具有FORCE_STOP_PACKAGES權限。雖然第三方普通app不能直接調用,但對於深入理解Android,還是很有必要知道系統是如何徹底清理進程的過程。接下來,進入AMS來深入探查force-stop的內部機理。
二. force-stop內部機理
2.1 AMS.forceStopPackage
[-> ActivityManagerService.java]
public void forceStopPackage(final String packageName, int userId) { if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) != PackageManager.PERMISSION_GRANTED) { //需要權限permission.FORCE_STOP_PACKAGES throw new SecurityException(); } final int callingPid = Binder.getCallingPid(); userId = handleIncomingUser(callingPid, Binder.getCallingUid(), userId, true, ALLOW_FULL_ONLY, "forceStopPackage", null); long callingId = Binder.clearCallingIdentity(); try { IPackageManager pm = AppGlobals.getPackageManager(); synchronized(this) { int[] users = userId == UserHandle.USER_ALL ? getUsersLocked() : new int[] { userId }; for (int user : users) { int pkgUid = -1; //根據包名和userId來查詢相應的uid pkgUid = pm.getPackageUid(packageName, user); //設置包的狀態為stopped pm.setPackageStoppedState(packageName, true, user); if (isUserRunningLocked(user, false)) { //【見流程2.2】 forceStopPackageLocked(packageName, pkgUid, "from pid " + callingPid); } } } } finally { Binder.restoreCallingIdentity(callingId); } }
這里有一個過程非常重要,那就是setPackageStoppedState()將包的狀態設置為stopped,那么所有廣播都無法接收,除非帶有標記FLAG_INCLUDE_STOPPED_PACKAGES的廣播,系統默認的廣播幾乎都是不帶有該標志,也就意味着被force-stop的應用是無法通過建立手機網絡狀態或者亮滅的廣播來拉起進程。
當使用force stop方式來結束進程時, reason一般都是”from pid “ + callingPid. 當然也有另外,那就是AMS.clearApplicationUserData方法調用forceStopPackageLocked的reason為”clear data”.
2.2 AMS.forceStopPackageLocked
private void forceStopPackageLocked(final String packageName, int uid, String reason) { //[見流程2.3] forceStopPackageLocked(packageName, UserHandle.getAppId(uid), false, false, true, false, false, UserHandle.getUserId(uid), reason); Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED, Uri.fromParts("package", packageName, null)); //系統啟動完畢后,則mProcessesReady=true if (!mProcessesReady) { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); } intent.putExtra(Intent.EXTRA_UID, uid); intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid)); //發送廣播用於停止alarm以及通知 【見小節8.1】 broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.getUserId(uid)); }
清理跟該包名相關的進程和四大組件之外,還會發送廣播ACTION_PACKAGE_RESTARTED,用於清理已注冊的alarm,notification信息。
2.3 AMS.forceStopPackageLocked
//callerWillRestart = false, doit = true; private final boolean forceStopPackageLocked(String packageName, int appId, boolean callerWillRestart, boolean purgeCache, boolean doit, boolean evenPersistent, boolean uninstalling, int userId, String reason) { int i; if (appId < 0 && packageName != null) { // 重新獲取正確的appId appId = UserHandle.getAppId( AppGlobals.getPackageManager().getPackageUid(packageName, 0)); } // doit =true能進入該分支 if (doit) { final ArrayMap<String, SparseArray<Long>> pmap = mProcessCrashTimes.getMap(); for (int ip = pmap.size() - 1; ip >= 0; ip--) { SparseArray<Long> ba = pmap.valueAt(ip); for (i = ba.size() - 1; i >= 0; i--) { boolean remove = false; final int entUid = ba.keyAt(i); if (packageName != null) { if (userId == UserHandle.USER_ALL) { if (UserHandle.getAppId(entUid) == appId) { remove = true; } } else { if (entUid == UserHandle.getUid(userId, appId)) { remove = true; } } } else if (UserHandle.getUserId(entUid) == userId) { remove = true; } if (remove) { ba.removeAt(i); } } if (ba.size() == 0) { pmap.removeAt(ip); } } } //清理Process [見流程3.1] boolean didSomething = killPackageProcessesLocked(packageName, appId, userId, -100, callerWillRestart, true, doit, evenPersistent, packageName == null ? ("stop user " + userId) : ("stop " + packageName)); //清理Activity [見流程4.1] if (mStackSupervisor.finishDisabledPackageActivitiesLocked( packageName, null, doit, evenPersistent, userId)) { ... didSomething = true; } // 結束該包中的Service [見流程5.1] if (mServices.bringDownDisabledPackageServicesLocked( packageName, null, userId, evenPersistent, true, doit)) { ... didSomething = true; } if (packageName == null) { //當包名為空, 則移除當前用戶的所有sticky broadcasts mStickyBroadcasts.remove(userId); } //收集providers [見流程6.1] ArrayList<ContentProviderRecord> providers = new ArrayList<>(); if (mProviderMap.collectPackageProvidersLocked(packageName, null, doit, evenPersistent, userId, providers)) { ... didSomething = true; } for (i = providers.size() - 1; i >= 0; i--) { //清理providers [見流程6.3] removeDyingProviderLocked(null, providers.get(i), true); } //移除已獲取的跟該package/user相關的臨時權限 removeUriPermissionsForPackageLocked(packageName, userId, false); if (doit) { // 清理Broadcast [見流程7.1] for (i = mBroadcastQueues.length - 1; i >= 0; i--) { didSomething |= mBroadcastQueues[i].cleanupDisabledPackageReceiversLocked( packageName, null, userId, doit); } } if (packageName == null || uninstalling) { ... //包名為空的情況 } if (doit) { if (purgeCache && packageName != null) { ... //不進入該分支 } if (mBooted) { //恢復棧頂的activity mStackSupervisor.resumeTopActivitiesLocked(); mStackSupervisor.scheduleIdleLocked(); } } return didSomething; }
對於didSomething只指當方法中所有行為,則返回true.比如killPackageProcessesLocked(),只要殺過一個進程則代表didSomething為true.
該方法的主要功能:
- Process: 調用AMS.killPackageProcessesLocked()清理該package所涉及的進程;
- Activity: 調用ASS.finishDisabledPackageActivitiesLocked()清理該package所涉及的Activity;
- Service: 調用AS.bringDownDisabledPackageServicesLocked()清理該package所涉及的Service;
- Provider: 調用AMS.removeDyingProviderLocked()清理該package所涉及的Provider;
- BroadcastRecevier: 調用BQ.cleanupDisabledPackageReceiversLocked()清理該package所涉及的廣播
接下來,從這5個角度來分別說說force-stop的執行過程.
三. Process
3.1 AMS.killPackageProcessesLocked
//callerWillRestart = false, allowRestart = true, doit = true; private final boolean killPackageProcessesLocked(String packageName, int appId, int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart, boolean doit, boolean evenPersistent, String reason) { ArrayList<ProcessRecord> procs = new ArrayList<>(); //遍歷當前所有運行中的進程 final int NP = mProcessNames.getMap().size(); for (int ip=0; ip<NP; ip++) { SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip); final int NA = apps.size(); for (int ia=0; ia<NA; ia++) { ProcessRecord app = apps.valueAt(ia); if (app.persistent && !evenPersistent) { continue; //不殺persistent進程 } if (app.removed) { //已標記removed的進程,便是需要被殺的進程,加入procs隊列 if (doit) { procs.add(app); } continue; } if (app.setAdj < minOomAdj) { continue; //不殺adj低於預期的進程 } if (packageName == null) { ... //已指定包名的情況 } else { //pkgDeps: 該進程所依賴的包名 final boolean isDep = app.pkgDeps != null && app.pkgDeps.contains(packageName); if (!isDep && UserHandle.getAppId(app.uid) != appId) { continue; } if (userId != UserHandle.USER_ALL && app.userId != userId) { continue; } //pkgList: 運行在該進程的所有包名; if (!app.pkgList.containsKey(packageName) && !isDep) { continue; } } //通過前面所有條件,則意味着該進程需要被殺, 添加到procs隊列 app.removed = true; procs.add(app); } } int N = procs.size(); for (int i=0; i<N; i++) { // [見流程3.2] removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason); } updateOomAdjLocked(); return N > 0; }
一般地force-stop會指定包名,該方法會遍歷當前所有運行中的進程mProcessNames,以下條件同時都不滿足的進程,則會成為被殺的目標進程:(也就是說滿足以下任一條件都可以免死)
- persistent進程:
- 進程setAdj < minOomAdj(默認為-100):
- 非UserHandle.USER_ALL同時, 且進程的userId不相等:多用戶模型下,不同用戶下不能相互殺;
- 進程沒有依賴該packageName, 且進程的AppId不相等;
- 進程沒有依賴該packageName, 且該packageName沒有運行在該進程.
通俗地來說就是:
- forceStop不殺系統persistent進程;
- 當指定用戶userId時,不殺其他用戶空間的進程;
除此之外,以下情況則必然會成為被殺進程:
- 進程已標記
remove=true的進程,則會被殺; - 進程的
pkgDeps中包含該packageName,則會被殺; - 進程的
pkgList中包含該packageName,且該進程與包名所指定的AppId相等則會被殺;
進程的pkgList是在啟動組件或者創建進程的過程向該隊列添加的,代表的是該應用下有組件運行在該進程。那么pkgDeps是指該進程所依賴的包名,調用ClassLoader的過程添加。
3.2 AMS.removeProcessLocked
//callerWillRestart = false, allowRestart = true private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart, boolean allowRestart, String reason) { final String name = app.processName; final int uid = app.uid; //從mProcessNames移除該進程 removeProcessNameLocked(name, uid); if (mHeavyWeightProcess == app) { ... } boolean needRestart = false; if (app.pid > 0 && app.pid != MY_PID) { int pid = app.pid; synchronized (mPidsSelfLocked) { mPidsSelfLocked.remove(pid); mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); } if (app.isolated) { mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid); } boolean willRestart = false; if (app.persistent && !app.isolated) { if (!callerWillRestart) { willRestart = true; //用於標記persistent進程則需重啟進程 } else { needRestart = true; //用於返回值,作用不大 } } //殺掉該進程 app.kill(reason, true); //清理該進程相關的信息 handleAppDiedLocked(app, willRestart, allowRestart); //對於persistent進程,則需要重新啟動該進程 if (willRestart) { removeLruProcessLocked(app); addAppLocked(app.info, false, null /* ABI override */); } } else { mRemovedProcesses.add(app); } return needRestart; }
該方法的主要功能:
- 從mProcessNames, mPidsSelfLocked隊列移除該進程;
- 移除進程啟動超時的消息PROC_START_TIMEOUT_MSG;
- 調用app.kill()來殺進程會同時調用Process.kill和Process.killProcessGroup, 該過程詳見理解殺進程的實現原理
- 調用handleAppDiedLocked()來清理進程相關的信息, 該過程詳見binderDied()過程分析
四. Activity
4.1 ASS.finishDisabledPackageActivitiesLocked
[-> ActivityStackSupervisor.java]
boolean finishDisabledPackageActivitiesLocked(String packageName, Set<String> filterByClasses, boolean doit, boolean evenPersistent, int userId) { boolean didSomething = false; for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) { final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks; final int numStacks = stacks.size(); for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { final ActivityStack stack = stacks.get(stackNdx); // [見流程4.2] if (stack.finishDisabledPackageActivitiesLocked( packageName, filterByClasses, doit, evenPersistent, userId)) { didSomething = true; } } } return didSomething; }
4.2 AS.finishDisabledPackageActivitiesLocked
[-> ActivityStack.java]
// doit = true; boolean finishDisabledPackageActivitiesLocked(String packageName, Set<String> filterByClasses, boolean doit, boolean evenPersistent, int userId) { boolean didSomething = false; TaskRecord lastTask = null; ComponentName homeActivity = null; for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities; int numActivities = activities.size(); for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { ActivityRecord r = activities.get(activityNdx); final boolean sameComponent = (r.packageName.equals(packageName) && (filterByClasses == null || filterByClasses.contains(r.realActivity.getClassName()))) || (packageName == null && r.userId == userId); if ((userId == UserHandle.USER_ALL || r.userId == userId) && (sameComponent || r.task == lastTask) && (r.app == null || evenPersistent || !r.app.persistent)) { ... if (r.isHomeActivity()) { if (homeActivity != null && homeActivity.equals(r.realActivity)) { continue; //不結束home activity } else { homeActivity = r.realActivity; } } didSomething = true; if (sameComponent) { if (r.app != null) { r.app.removed = true; } r.app = null; } lastTask = r.task; //強制結束該Activity [見流程4.3] if (finishActivityLocked(r, Activity.RESULT_CANCELED, null, "force-stop", true)) { // r已從mActivities中移除 --numActivities; --activityNdx; } } } } return didSomething; }
4.3 AS.finishActivityLocked
[-> ActivityStack.java]
final boolean finishActivityLocked(ActivityRecord r, int resultCode, Intent resultData, String reason, boolean oomAdj) { if (r.finishing) { return false; } //[見流程4.3.1] r.makeFinishingLocked(); final TaskRecord task = r.task; final ArrayList<ActivityRecord> activities = task.mActivities; final int index = activities.indexOf(r); if (index < (activities.size() - 1)) { //[見流程4.3.3] task.setFrontOfTask(); if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) { //當該activity會被移除,則將該activity信息傳播給下一個activity ActivityRecord next = activities.get(index+1); next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); } } //暫停按鍵事件的分發 r.pauseKeyDispatchingLocked(); //調整聚焦的activity [見流程4.3.4] adjustFocusedActivityLocked(r, "finishActivity"); //重置activity的回調結果信息 finishActivityResultsLocked(r, resultCode, resultData); //當r為前台可見的activity時 if (mResumedActivity == r) { boolean endTask = index <= 0; //准備關閉該transition mWindowManager.prepareAppTransition(endTask ? AppTransition.TRANSIT_TASK_CLOSE : AppTransition.TRANSIT_ACTIVITY_CLOSE, false); //告知wms來准備從窗口移除該activity mWindowManager.setAppVisibility(r.appToken, false); if (mPausingActivity == null) { //暫停該activity startPausingLocked(false, false, false, false); } if (endTask) { mStackSupervisor.removeLockedTaskLocked(task); } } else if (r.state != ActivityState.PAUSING) { //當r不可見的情況 [見流程4.3.5] return finishCurrentActivityLocked(r, FINISH_AFTER_PAUSE, oomAdj) == null; } return false; }
4.3.1 AR.makeFinishingLocked
[-> ActivityRecord.java]
void makeFinishingLocked() { if (!finishing) { if (task != null && task.stack != null && this == task.stack.getVisibleBehindActivity()) { //處於finishing的activity不應該在后台保留可見性 [見流程4.3.2] mStackSupervisor.requestVisibleBehindLocked(this, false); } finishing = true; if (stopped) { clearOptionsLocked(); } } }
4.3.2 ASS.requestVisibleBehindLocked
boolean requestVisibleBehindLocked(ActivityRecord r, boolean visible) { final ActivityStack stack = r.task.stack; if (stack == null) { return false; //r所在棧為空,則直接返回 } final boolean isVisible = stack.hasVisibleBehindActivity(); final ActivityRecord top = topRunningActivityLocked(); if (top == null || top == r || (visible == isVisible)) { stack.setVisibleBehindActivity(visible ? r : null); return true; } if (visible && top.fullscreen) { ... } else if (!visible && stack.getVisibleBehindActivity() != r) { //設置不可見,且當前top activity跟該activity相同時返回 return false; } stack.setVisibleBehindActivity(visible ? r : null); if (!visible) { //將activity置於不透明的r之上 final ActivityRecord next = stack.findNextTranslucentActivity(r); if (next != null) { mService.convertFromTranslucent(next.appToken); } } if (top.app != null && top.app.thread != null) { //將改變通知給top應用 top.app.thread.scheduleBackgroundVisibleBehindChanged(top.appToken, visible); } return true; }
4.3.3 TaskRecord.setFrontOfTask
[-> TaskRecord.java]
final void setFrontOfTask() { boolean foundFront = false; final int numActivities = mActivities.size(); for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { final ActivityRecord r = mActivities.get(activityNdx); if (foundFront || r.finishing) { r.frontOfTask = false; } else { r.frontOfTask = true; foundFront = true; } } //所有activity都處於finishing狀態. if (!foundFront && numActivities > 0) { mActivities.get(0).frontOfTask = true; } }
- 將該Task中從底部往上查詢, 第一個處於非finishing狀態的ActivityRecord,則設置為根Activity(即r.frontOfTask = true),其他都為false;
- 當所有的activity都處於finishing狀態,則把最底部的activity設置成跟Activity.
4.3.4 AS.adjustFocusedActivityLocked
[-> ActivityStack.java]
private void adjustFocusedActivityLocked(ActivityRecord r, String reason) { if (mStackSupervisor.isFrontStack(this) && mService.mFocusedActivity == r) { ActivityRecord next = topRunningActivityLocked(null); final String myReason = reason + " adjustFocus"; if (next != r) { final TaskRecord task = r.task; boolean adjust = false; //當下一個activity為空, 或者下一個與當前的task不同, 或者要結束的r為根activity. if ((next == null || next.task != task) && r.frontOfTask) { if (task.isOverHomeStack() && task == topTask()) { adjust = true; } else { for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) { final TaskRecord tr = mTaskHistory.get(taskNdx); if (tr.getTopActivity() != null) { break; } else if (tr.isOverHomeStack()) { adjust = true; break; } } } } // 需要調整Activity的聚焦情況 if (adjust) { // 對於非全屏的stack, 則移動角度到下一個可見的棧,而不是直接移動到home棧而屏蔽其他可見的棧. if (!mFullscreen && adjustFocusToNextVisibleStackLocked(null, myReason)) { return; } //當該棧為全屏,或者沒有其他可見棧時, 則把home棧移至頂部 if (mStackSupervisor.moveHomeStackTaskToTop( task.getTaskToReturnTo(), myReason)) { //聚焦已調整完整,則直接返回 return; } } } final ActivityRecord top = mStackSupervisor.topRunningActivityLocked(); if (top != null) { mService.setFocusedActivityLocked(top, myReason); } } }
4.3.5 AS.finishCurrentActivityLocked
final ActivityRecord finishCurrentActivityLocked(ActivityRecord r, int mode, boolean oomAdj) { if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) { if (!mStackSupervisor.mStoppingActivities.contains(r)) { mStackSupervisor.mStoppingActivities.add(r); if (mStackSupervisor.mStoppingActivities.size() > 3 || r.frontOfTask && mTaskHistory.size() <= 1) { mStackSupervisor.scheduleIdleLocked(); } else { mStackSupervisor.checkReadyForSleepLocked(); } } //設置狀態為stopping r.state = ActivityState.STOPPING; if (oomAdj) { mService.updateOomAdjLocked(); } return r; } //清除相關信息 mStackSupervisor.mStoppingActivities.remove(r); mStackSupervisor.mGoingToSleepActivities.remove(r); mStackSupervisor.mWaitingVisibleActivities.remove(r); if (mResumedActivity == r) { mResumedActivity = null; } final ActivityState prevState = r.state; //設置狀態為finishing r.state = ActivityState.FINISHING; if (mode == FINISH_IMMEDIATELY || (mode == FINISH_AFTER_PAUSE && prevState == ActivityState.PAUSED) || prevState == ActivityState.STOPPED || prevState == ActivityState.INITIALIZING) { r.makeFinishingLocked(); //[見流程4.3.6] boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm"); if (activityRemoved) { mStackSupervisor.resumeTopActivitiesLocked(); } return activityRemoved ? null : r; } //需要等到activity執行完pause,進入stopped狀態,才會finish mStackSupervisor.mFinishingActivities.add(r); r.resumeKeyDispatchingLocked(); mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null); return r; }
滿足下面其中之一的條件,則會執行finish以及destroy Activity.
- 模式為FINISH_IMMEDIATELY
- 模式為FINISH_AFTER_PAUSE, 且Activity狀態已處於PAUSED;
- Activity的狀態為STOPPED或INITIALIZING.
4.3.6 AS.destroyActivityLocked
final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, String reason) { boolean removedFromHistory = false; cleanUpActivityLocked(r, false, false); final boolean hadApp = r.app != null; if (hadApp) { if (removeFromApp) { r.app.activities.remove(r); if (mService.mHeavyWeightProcess == r.app && r.app.activities.size() <= 0) { mService.mHeavyWeightProcess = null; mService.mHandler.sendEmptyMessage(ActivityManagerService.CANCEL_HEAVY_NOTIFICATION_MSG); } if (r.app.activities.isEmpty()) { mService.mServices.updateServiceConnectionActivitiesLocked(r.app); mService.updateLruProcessLocked(r.app, false, null); mService.updateOomAdjLocked(); } } boolean skipDestroy = false; try { r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing, r.configChangeFlags); } catch (Exception e) { if (r.finishing) { //當發生crash,則將該activity從history移除 removeActivityFromHistoryLocked(r, reason + " exceptionInScheduleDestroy"); removedFromHistory = true; skipDestroy = true; } } r.nowVisible = false; if (r.finishing && !skipDestroy) { r.state = ActivityState.DESTROYING; Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG, r); mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT); } else { r.state = ActivityState.DESTROYED; r.app = null; } } else { if (r.finishing) { removeActivityFromHistoryLocked(r, reason + " hadNoApp"); removedFromHistory = true; } else { r.state = ActivityState.DESTROYED; r.app = null; } } r.configChangeFlags = 0; return removedFromHistory; }
五. Service
5.1 bringDownDisabledPackageServicesLocked
[-> ActiveServices.java]
//killProcess = true; doit = true; boolean bringDownDisabledPackageServicesLocked(String packageName, Set<String> filterByClasses, int userId, boolean evenPersistent, boolean killProcess, boolean doit) { boolean didSomething = false; if (mTmpCollectionResults != null) { mTmpCollectionResults.clear(); } if (userId == UserHandle.USER_ALL) { for (int i = mServiceMap.size() - 1; i >= 0; i--) { //從mServiceMap中查詢到所有屬於該包下的service [見流程5.2] didSomething |= collectPackageServicesLocked(packageName, filterByClasses, evenPersistent, doit, killProcess, mServiceMap.valueAt(i).mServicesByName); if (!doit && didSomething) { ... } } } else { ServiceMap smap = mServiceMap.get(userId); if (smap != null) { ArrayMap<ComponentName, ServiceRecord> items = smap.mServicesByName; //從mServiceMap中查詢到所有屬於該包下的service [見流程5.2] didSomething = collectPackageServicesLocked(packageName, filterByClasses, evenPersistent, doit, killProcess, items); } } if (mTmpCollectionResults != null) { //結束掉所有收集到的Service [見流程5.3] for (int i = mTmpCollectionResults.size() - 1; i >= 0; i--) { bringDownServiceLocked(mTmpCollectionResults.get(i)); } mTmpCollectionResults.clear(); } return didSomething; }
5.2 collectPackageServicesLocked
[-> ActiveServices.java]
//killProcess = true; doit = true; private boolean collectPackageServicesLocked(String packageName, Set<String> filterByClasses, boolean evenPersistent, boolean doit, boolean killProcess, ArrayMap<ComponentName, ServiceRecord> services) { boolean didSomething = false; for (int i = services.size() - 1; i >= 0; i--) { ServiceRecord service = services.valueAt(i); final boolean sameComponent = packageName == null || (service.packageName.equals(packageName) && (filterByClasses == null || filterByClasses.contains(service.name.getClassName()))); if (sameComponent && (service.app == null || evenPersistent || !service.app.persistent)) { if (!doit) { ... } didSomething = true; if (service.app != null) { service.app.removed = killProcess; if (!service.app.persistent) { service.app.services.remove(service); } } service.app = null; service.isolatedProc = null; if (mTmpCollectionResults == null) { mTmpCollectionResults = new ArrayList<>(); } //將滿足條件service放入mTmpCollectionResults mTmpCollectionResults.add(service); } } return didSomething; }
該方法的主要功能就是收集該滿足條件service放入mTmpCollectionResults.
5.3 bringDownServiceLocked
[-> ActiveServices.java]
private final void bringDownServiceLocked(ServiceRecord r) { for (int conni=r.connections.size()-1; conni>=0; conni--) { ArrayList<ConnectionRecord> c = r.connections.valueAt(conni); for (int i=0; i<c.size(); i++) { ConnectionRecord cr = c.get(i); cr.serviceDead = true; // 斷開service的連接 cr.conn.connected(r.name, null); } } if (r.app != null && r.app.thread != null) { for (int i=r.bindings.size()-1; i>=0; i--) { IntentBindRecord ibr = r.bindings.valueAt(i); if (ibr.hasBound) { bumpServiceExecutingLocked(r, false, "bring down unbind"); mAm.updateOomAdjLocked(r.app); ibr.hasBound = false; //最終調用目標Service.onUnbind()方法 r.app.thread.scheduleUnbindService(r, ibr.intent.getIntent()); } } } r.destroyTime = SystemClock.uptimeMillis(); final ServiceMap smap = getServiceMap(r.userId); smap.mServicesByName.remove(r.name); smap.mServicesByIntent.remove(r.intent); r.totalRestartCount = 0; // [見流程5.4] unscheduleServiceRestartLocked(r, 0, true); //確保service不在pending隊列 for (int i=mPendingServices.size()-1; i>=0; i--) { if (mPendingServices.get(i) == r) { mPendingServices.remove(i); } } //取消service相關的通知 r.cancelNotification(); r.isForeground = false; r.foregroundId = 0; r.foregroundNoti = null; r.clearDeliveredStartsLocked(); r.pendingStarts.clear(); if (r.app != null) { synchronized (r.stats.getBatteryStats()) { r.stats.stopLaunchedLocked(); } r.app.services.remove(r); if (r.app.thread != null) { updateServiceForegroundLocked(r.app, false); bumpServiceExecutingLocked(r, false, "destroy"); mDestroyingServices.add(r); r.destroying = true; mAm.updateOomAdjLocked(r.app); // 最終調用目標service的onDestroy() r.app.thread.scheduleStopService(r); } } if (r.bindings.size() > 0) { r.bindings.clear(); } if (r.restarter instanceof ServiceRestarter) { ((ServiceRestarter)r.restarter).setService(null); } int memFactor = mAm.mProcessStats.getMemFactorLocked(); long now = SystemClock.uptimeMillis(); if (r.tracker != null) { r.tracker.setStarted(false, memFactor, now); r.tracker.setBound(false, memFactor, now); if (r.executeNesting == 0) { r.tracker.clearCurrentOwner(r, false); r.tracker = null; } } smap.ensureNotStartingBackground(r); }
5.4 unscheduleServiceRestartLocked
private final boolean unscheduleServiceRestartLocked(ServiceRecord r, int callingUid, boolean force) { if (!force && r.restartDelay == 0) { return false; } //將Services從重啟列表移除,並重置重啟計數器 boolean removed = mRestartingServices.remove(r); if (removed || callingUid != r.appInfo.uid) { r.resetRestartCounter(); } if (removed) { clearRestartingIfNeededLocked(r); } mAm.mHandler.removeCallbacks(r.restarter); return true; }
六. Provider
6.1 PM.collectPackageProvidersLocked
[-> ProviderMap.java]
boolean collectPackageProvidersLocked(String packageName, Set<String> filterByClasses, boolean doit, boolean evenPersistent, int userId, ArrayList<ContentProviderRecord> result) { boolean didSomething = false; if (userId == UserHandle.USER_ALL || userId == UserHandle.USER_OWNER) { // [見流程6.2] didSomething = collectPackageProvidersLocked(packageName, filterByClasses, doit, evenPersistent, mSingletonByClass, result); } if (!doit && didSomething) { ... //不進入該分支 } if (userId == UserHandle.USER_ALL) { for (int i = 0; i < mProvidersByClassPerUser.size(); i++) { if (collectPackageProvidersLocked(packageName, filterByClasses, doit, evenPersistent, mProvidersByClassPerUser.valueAt(i), result)) { ... didSomething = true; } } } else { //從mProvidersByClassPerUser查詢 HashMap<ComponentName, ContentProviderRecord> items = getProvidersByClass(userId); if (items != null) { didSomething |= collectPackageProvidersLocked(packageName, filterByClasses, doit, evenPersistent, items, result); } } return didSomething; }
- 當userId = UserHandle.USER_ALL時, 則會
mSingletonByClass和mProvidersByClassPerUser結構中查詢所有屬於該package的providers. - 當userId = UserHandle.USER_OWNER時,則會從
mSingletonByClass和mProvidersByClassPerUser中userId相等的 數據結構中查詢所有屬於該package的providers. - 當userId不屬於上述兩者之一時,則會從
mProvidersByClassPerUser中userId相等的查詢所有屬於該package的providers.
6.2 PM.collectPackageProvidersLocked
[-> ProviderMap.java]
private boolean collectPackageProvidersLocked(String packageName, Set<String> filterByClasses, boolean doit, boolean evenPersistent, HashMap<ComponentName, ContentProviderRecord> providers, ArrayList<ContentProviderRecord> result) { boolean didSomething = false; for (ContentProviderRecord provider : providers.values()) { final boolean sameComponent = packageName == null || (provider.info.packageName.equals(packageName) && (filterByClasses == null || filterByClasses.contains(provider.name.getClassName()))); if (sameComponent && (provider.proc == null || evenPersistent || !provider.proc.persistent)) { if (!doit) { ... } didSomething = true; result.add(provider); } } return didSomething; }
6.3 AMS.removeDyingProviderLocked
private final boolean removeDyingProviderLocked(ProcessRecord proc, ContentProviderRecord cpr, boolean always) { final boolean inLaunching = mLaunchingProviders.contains(cpr); //喚醒cpr, 並從mProviderMap中移除provider相關信息 if (!inLaunching || always) { synchronized (cpr) { cpr.launchingApp = null; cpr.notifyAll(); } mProviderMap.removeProviderByClass(cpr.name, UserHandle.getUserId(cpr.uid)); String names[] = cpr.info.authority.split(";"); for (int j = 0; j < names.length; j++) { mProviderMap.removeProviderByName(names[j], UserHandle.getUserId(cpr.uid)); } } for (int i = cpr.connections.size() - 1; i >= 0; i--) { ContentProviderConnection conn = cpr.connections.get(i); if (conn.waiting) { //always = true,不進入該分支 if (inLaunching && !always) { continue; } } ProcessRecord capp = conn.client; conn.dead = true; if (conn.stableCount > 0) { if (!capp.persistent && capp.thread != null && capp.pid != 0 && capp.pid != MY_PID) { //殺掉依賴該provider的client進程 capp.kill("depends on provider " + cpr.name.flattenToShortString() + " in dying proc " + (proc != null ? proc.processName : "??"), true); } } else if (capp.thread != null && conn.provider.provider != null) { capp.thread.unstableProviderDied(conn.provider.provider.asBinder()); cpr.connections.remove(i); if (conn.client.conProviders.remove(conn)) { stopAssociationLocked(capp.uid, capp.processName, cpr.uid, cpr.name); } } } if (inLaunching && always) { mLaunchingProviders.remove(cpr); } return inLaunching; }
當其他app使用該provider, 且建立stable的連接, 那么對於非persistent進程,則會由於依賴該provider的緣故而被殺.
七. Broadcast
7.1 BQ.cleanupDisabledPackageReceiversLocked
[-> BroadcastQueue.java]
boolean cleanupDisabledPackageReceiversLocked( String packageName, Set<String> filterByClasses, int userId, boolean doit) { boolean didSomething = false; for (int i = mParallelBroadcasts.size() - 1; i >= 0; i--) { // 【見流程7.2】 didSomething |= mParallelBroadcasts.get(i).cleanupDisabledPackageReceiversLocked( packageName, filterByClasses, userId, doit); if (!doit && didSomething) { return true; } } for (int i = mOrderedBroadcasts.size() - 1; i >= 0; i--) { didSomething |= mOrderedBroadcasts.get(i).cleanupDisabledPackageReceiversLocked( packageName, filterByClasses, userId, doit); if (!doit && didSomething) { return true; } } return didSomething; }
該方法主要功能:
- 清理並行廣播隊列mParallelBroadcasts;
- 清理有序廣播隊列mOrderedBroadcasts
7.2 BR.cleanupDisabledPackageReceiversLocked
[-> BroadcastRecord.java]
boolean cleanupDisabledPackageReceiversLocked( String packageName, Set<String> filterByClasses, int userId, boolean doit) { if ((userId != UserHandle.USER_ALL && this.userId != userId) || receivers == null) { return false; } boolean didSomething = false; Object o; for (int i = receivers.size() - 1; i >= 0; i--) { o = receivers.get(i); if (!(o instanceof ResolveInfo)) { continue; } ActivityInfo info = ((ResolveInfo)o).activityInfo; final boolean sameComponent = packageName == null || (info.applicationInfo.packageName.equals(packageName) && (filterByClasses == null || filterByClasses.contains(info.name))); if (sameComponent) { ... didSomething = true; //移除該廣播receiver receivers.remove(i); if (i < nextReceiver) { nextReceiver--; } } } nextReceiver = Math.min(nextReceiver, receivers.size()); return didSomething; }
八. Alarm和Notification
在前面[小節2.2]介紹到處理完forceStopPackageLocked(),緊接着便是發送廣播ACTION_PACKAGE_RESTARTED,經過Broadcast廣播分發,最終調用到注冊過該廣播的接收者。
8.1 Alarm清理
[-> AlarmManagerService.java]
class UninstallReceiver extends BroadcastReceiver { public UninstallReceiver() { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); //監聽ACTION_PACKAGE_RESTARTED filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); filter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); filter.addDataScheme("package"); getContext().registerReceiver(this, filter); ... } @Override public void onReceive(Context context, Intent intent) { synchronized (mLock) { String action = intent.getAction(); String pkgList[] = null; if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) { ... } else { ... Uri data = intent.getData(); if (data != null) { String pkg = data.getSchemeSpecificPart(); if (pkg != null) { pkgList = new String[]{pkg}; } } } if (pkgList != null && (pkgList.length > 0)) { for (String pkg : pkgList) { //移除alarm removeLocked(pkg); mPriorities.remove(pkg); for (int i=mBroadcastStats.size()-1; i>=0; i--) { ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.valueAt(i); if (uidStats.remove(pkg) != null) { if (uidStats.size() <= 0) { mBroadcastStats.removeAt(i); } } } } } } } }
調用AlarmManagerService中的removeLocked()方法,從mAlarmBatches和mPendingWhileIdleAlarms隊列中移除包所相關的alarm.
8.2 Notification清理
[-> NotificationManagerService.java]
private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); ... if (action.equals(Intent.ACTION_PACKAGE_ADDED) || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED)) || action.equals(Intent.ACTION_PACKAGE_RESTARTED) || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED)) || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART)) || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL); String pkgList[] = null; boolean queryReplace = queryRemove && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { ... } else { Uri uri = intent.getData(); ... String pkgName = uri.getSchemeSpecificPart(); if (packageChanged) { ... } pkgList = new String[]{pkgName}; } if (pkgList != null && (pkgList.length > 0)) { for (String pkgName : pkgList) { if (cancelNotifications) { //移除Notification cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart, changeUserId, REASON_PACKAGE_CHANGED, null); } } } mListeners.onPackagesChanged(queryReplace, pkgList); mConditionProviders.onPackagesChanged(queryReplace, pkgList); mRankingHelper.onPackagesChanged(queryReplace, pkgList); } } };
調用NotificationManagerService.java 中的cancelAllNotificationsInt()方法,從mNotificationList隊列中移除包所相關的Notification.
九. 級聯誅殺
這里就跟大家分享一段經歷吧,記得之前有BAT的某瀏覽器大廠(具體名稱就匿了),瀏覽器會因為另一個app被殺而導致自己無辜被牽連所殺,並懷疑是ROM定制化導致的bug,於是發郵件向我廠請教緣由。
遇到這個問題,首先將兩個app安裝到Google原生系統,結果是依然會被級聯誅殺,很顯然可以排除廠商ROM定制的緣故,按常理說bug應該可以讓app自行解決。出於好奇,幫他們進一步調查了下這個問題,發現並非無辜被殺,而是force-stop的級聯誅殺所導致的。
簡單來說就是App1調用了getClassLoader()來加載App2,那么App1所運行的進程便會在其pkgDeps隊列中增加App2的包名,在前面[小節3.2]已經提到pkgDeps,殺進程的過程中會遍歷該隊列,當App2被forceStop所殺時,便是級聯誅殺App1。App1既然會調用App2的ClassLoader來加載其方法,那么就建立了一定的聯系,這是Google有意賦予forceStop這個強力殺的功能。
這個故事是想告訴大家在插件化或者反射的過程中要注意這種情況,防止不必要的誤傷。接下來具體說說這個過程是如何建立依賴的。
9.1 CI.getClassLoader
[-> ContextImpl.java]
public ClassLoader getClassLoader() { //【見小節9.2】 return mPackageInfo != null ? mPackageInfo.getClassLoader() : ClassLoader.getSystemClassLoader(); }
9.2 LA.getClassLoader
[-> LoadedApk.java]
public ClassLoader getClassLoader() { synchronized (this) { if (mClassLoader != null) { return mClassLoader; } if (mPackageName.equals("android")) { if (mBaseClassLoader == null) { mClassLoader = ClassLoader.getSystemClassLoader(); } else { mClassLoader = mBaseClassLoader; } return mClassLoader; } if (mRegisterPackage) { //經過Binder,最終調用到AMS.addPackageDependency 【見小節9.3】 ActivityManagerNative.getDefault().addPackageDependency(mPackageName); } ... mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath, libraryPermittedPath, mBaseClassLoader); return mClassLoader; } }
9.3 AMS.addPackageDependency
public void addPackageDependency(String packageName) { synchronized (this) { int callingPid = Binder.getCallingPid(); if (callingPid == Process.myPid()) { return; } ProcessRecord proc; synchronized (mPidsSelfLocked) { proc = mPidsSelfLocked.get(Binder.getCallingPid()); } if (proc != null) { if (proc.pkgDeps == null) { proc.pkgDeps = new ArraySet<String>(1); } //將該包名添加到pkgDeps proc.pkgDeps.add(packageName); } } }
調用ClassLoader來加載啟動包名時,則會將該包名加入到進程的pkgDeps。
十. 總結
forceStop的功能如下:

- Process: 調用AMS.killPackageProcessesLocked()清理該package所涉及的進程;
- Activity: 調用ASS.finishDisabledPackageActivitiesLocked()清理該package所涉及的Activity;
- Service: 調用AS.bringDownDisabledPackageServicesLocked()清理該package所涉及的Service;
- Provider: 調用AMS.removeDyingProviderLocked()清理該package所涉及的Provider;
- BroadcastRecevier: 調用BQ.cleanupDisabledPackageReceiversLocked()清理該package所涉及的廣播
- 發送廣播ACTION_PACKAGE_RESTARTED,用於停止已注冊的alarm,notification.
persistent進程的特殊待遇:
- 進程: AMS.killPackageProcessesLocked()不殺進程
- Service: ActiveServices.collectPackageServicesLocked()不移除不清理service
- Provider: ProviderMap.collectPackageProvidersLocked()不收集不清理provider. 且不殺該provider所連接的client的persistent進程;
功能點歸納:
- force-stop並不會殺persistent進程;
- 當app被force-stop后,無法接收到任何普通廣播,那么也就常見的監聽手機網絡狀態的變化或者屏幕亮滅的廣播來拉起進程肯定是不可行;
- 當app被force-stop后,那么alarm鬧鍾一並被清理,無法實現定時響起的功能;
- app被force-stop后,四大組件以及相關進程都被一一剪除清理,即便多進程架構的app也無法拉起自己;
- 級聯誅殺:當app通過ClassLoader加載另一個app,則會在force-stop的過程中會被級聯誅殺;
- 生死與共:當app與另個app使用了share uid,則會在force-stop的過程,任意一方被殺則另一方也被殺,建立起生死與共的強關系。
既然force-stop多次提到殺進程,那最后簡單說兩句關於保活:正確的保活姿態,應該是在用戶需要時保證千萬別被殺,用戶不需要時別強保活,一切以用戶為出發點。
- 進程是否需要存活,系統上層有AMS來管理緩存進程和空進程,底層有LowMemoryKiller來根據系統可用內存的情況來管理進程是否存活,這樣的策略是從系統整體性角度考慮,為了是給用戶提供更好更流暢的用戶體驗。
- 用戶需要的時候千萬別被殺:謹慎使用插件化和共享uid,除非願意接受級聯誅殺和生死與共的場景;還有就是提高自身app的穩定性,減少crash和anr的發生頻率,這才是正道。
- 用戶不需要的時候別強保活:為了保活,多進程架構,利用各種小技巧來提升優先級等都是不可取的,一招force-stop足以干掉90%以上的保活策略,當然還有一些其他手段及漏洞來保活,系統層面往往還會采取一些特別的方法來禁止保活。博主曾經干過手機底層的性能與功耗優化工作,深知不少app的流氓行徑,嚴重系統的流暢度與手機續航能力。
為了android有更好的用戶體驗,為了不影響手機系統性能,為了不降低手機續航能力,建議大家花更多時間精力在如何提高app的穩健性,如何優化app性能,共同打造Android的良好生態圈。
