Android中杀进程的几种方法 (1) - killBackgroundProcesses
Android中杀进程的几种方法 (1) - killBackgroundProcesses
ActivityManager中提供了几种方式来杀进程,比如有forceStopPackage、removeTask、killBackgroundProcesses等。
下面我们就来看看它们的背后都做了些什么。
removeTask
我们之前已经写了一篇《关于Android的浅杀》来介绍这个方法的变迁,大家可以回忆一下找找感觉。
复习一下removeTask的好处是,相对后面几个,它的逻辑要简单得多。
killBackgroundProcesses
ActivityManager中的killBackgroundProcesses
这是目前(截止至API24)唯一官方公开建议使用的方法,其它的都是隐藏的API。
我们先看一张这个API背后调用的简图:
另外有一个被废弃的restartPackage方法,现在只是killBackgroundProcesses的马甲。
2400 @Deprecated2401 public void restartPackage(String packageName) {2402 killBackgroundProcesses(packageName);2403 }
调用killBackgroundProcesses需要权限android.Manifest.permission.KILL_BACKGROUND_PROCESSES
按照惯例,这个方法肯定是通过IPC调用到AMS中:
2418 public void killBackgroundProcesses(String packageName) {2419 try {2420 ActivityManagerNative.getDefault().killBackgroundProcesses(packageName,2421 UserHandle.myUserId());2422 } catch (RemoteException e) {2423 }2424 }
AMS中的killBackgroundProcesses
我们直接来看AMS中的killBackgroundProcesses:
5202 @Override5203 public void killBackgroundProcesses(final String packageName, int userId) {
首先就是检查KILL_BACKGROUND_PROCESSES的权限:
5204 if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)5205 != PackageManager.PERMISSION_GRANTED &&5206 checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)5207 != PackageManager.PERMISSION_GRANTED) {5208 String msg = "Permission Denial: killBackgroundProcesses() from pid="5209 + Binder.getCallingPid()5210 + ", uid=" + Binder.getCallingUid()5211 + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;5212 Slog.w(TAG, msg);5213 throw new SecurityException(msg);5214 }5215
下面正式开始干活:
5216 userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),5217 userId, true, ALLOW_FULL_ONLY, "killBackgroundProcesses", null);5218 long callingId = Binder.clearCallingIdentity();5219 try {5220 IPackageManager pm = AppGlobals.getPackageManager();5221 synchronized(this) {5222 int appId = -1;5223 try {5224 appId = UserHandle.getAppId(pm.getPackageUid(packageName, 0));5225 } catch (RemoteException e) {5226 }5227 if (appId == -1) {5228 Slog.w(TAG, "Invalid packageName: " + packageName);5229 return;5230 }
真正的逻辑都在killPackageProcessesLocked中。调用进来的时候只有包名和用户ID两个参数,但是killPackageProcessesLocked却搞出来9个参数。
5231 killPackageProcessesLocked(packageName, appId, userId,5232 ProcessList.SERVICE_ADJ, false, true, true, false, "kill background");5233 }5234 } finally {5235 Binder.restoreCallingIdentity(callingId);5236 }5237 }
AMS的killPackageProcessesLocked
5541 private final boolean killPackageProcessesLocked(String packageName, int appId,5542 int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,5543 boolean doit, boolean evenPersistent, String reason) {5544 ArrayList procs = new ArrayList<>();55455546 // Remove all processes this package may have touched: all with the5547 // same UID (except for the system or root user), and all whose name5548 // matches the package name.5549 final int NP = mProcessNames.getMap().size();5550 for (int ip=0; ip5551 SparseArray apps = mProcessNames.getMap().valueAt(ip);5552 final int NA = apps.size();5553 for (int ia=0; ia5554 ProcessRecord app = apps.valueAt(ia);5555 if (app.persistent && !evenPersistent) {5556 // we don't kill persistent processes5557 continue;5558 }5559 if (app.removed) {5560 if (doit) {5561 procs.add(app);5562 }5563 continue;5564 }55655566 // Skip process if it doesn't meet our oom adj requirement.5567 if (app.setAdj < minOomAdj) {5568 continue;5569 }55705571 // If no package is specified, we call all processes under the5572 // give user id.5573 if (packageName == null) {5574 if (userId != UserHandle.USER_ALL && app.userId != userId) {5575 continue;5576 }5577 if (appId >= 0 && UserHandle.getAppId(app.uid) != appId) {5578 continue;5579 }5580 // Package has been specified, we want to hit all processes5581 // that match it. We need to qualify this by the processes5582 // that are running under the specified app and user ID.5583 } else {5584 final boolean isDep = app.pkgDeps != null5585 && app.pkgDeps.contains(packageName);5586 if (!isDep && UserHandle.getAppId(app.uid) != appId) {5587 continue;5588 }5589 if (userId != UserHandle.USER_ALL && app.userId != userId) {5590 continue;5591 }5592 if (!app.pkgList.containsKey(packageName) && !isDep) {5593 continue;5594 }5595 }55965597 // Process has passed all conditions, kill it!5598 if (!doit) {5599 return true;5600 }5601 app.removed = true;5602 procs.add(app);5603 }5604 }
前面各种条件都准备好了之后,针对每一个proc去调用removeProcessLocked.
5606 int N = procs.size();5607 for (int i=0; i5608 removeProcessLocked(procs.get(i), callerWillRestart, allowRestart, reason);5609 }5610 updateOomAdjLocked();5611 return N > 0;5612 }
AMS之removeProcessLocked(4)
5916 private final boolean removeProcessLocked(ProcessRecord app,5917 boolean callerWillRestart, boolean allowRestart, String reason) {5918 final String name = app.processName;5919 final int uid = app.uid;...
下面再调用两个参数的removeProcessNameLocked.
5923 removeProcessNameLocked(name, uid);5924 if (mHeavyWeightProcess == app) {5925 mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,5926 mHeavyWeightProcess.userId, 0));5927 mHeavyWeightProcess = null;5928 }5929 boolean needRestart = false;5930 if (app.pid > 0 && app.pid != MY_PID) {5931 int pid = app.pid;5932 synchronized (mPidsSelfLocked) {5933 mPidsSelfLocked.remove(pid);5934 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);5935 }5936 mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);5937 if (app.isolated) {5938 mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);5939 }5940 boolean willRestart = false;5941 if (app.persistent && !app.isolated) {5942 if (!callerWillRestart) {5943 willRestart = true;5944 } else {5945 needRestart = true;5946 }5947 }
前面的该通知的都通知到了,终于可以正式开杀了。
5948 app.kill(reason, true);5949 handleAppDiedLocked(app, willRestart, allowRestart);5950 if (willRestart) {5951 removeLruProcessLocked(app);5952 addAppLocked(app.info, false, null /* ABI override */);5953 }5954 } else {5955 mRemovedProcesses.add(app);5956 }59575958 return needRestart;5959 }
ProcessRecord之kill
543 void kill(String reason, boolean noisy) {544 if (!killedByAm) {545 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "kill");546 if (noisy) {547 Slog.i(TAG, "Killing " + toShortString() + " (adj " + setAdj + "): " + reason);548 }549 EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason);550 Process.killProcessQuiet(pid);551 Process.killProcessGroup(info.uid, pid);552 if (!persistent) {553 killed = true;554 killedByAm = true;555 }556 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);557 }558 }
Process之killProcessQuiet
非常省事儿,发给一个SIGNAL_KILL出去就是了。
1068 public static final void killProcessQuiet(int pid) {1069 sendSignalQuiet(pid, SIGNAL_KILL);1070 }
Process之killProcessGroup
这个直接用native写的。
public static final native int killProcessGroup(int uid, int pid);
android_util_Process.cpp之android_os_Process_killProcessGroup
JNI函数只是一个简单地对libprocessgroup中的killProcessGroup的封装
1035jint android_os_Process_killProcessGroup(JNIEnv* env, jobject clazz, jint uid, jint pid)1036{1037 return killProcessGroup(uid, pid, SIGKILL);1038}
processgroup.cpp之killProcessGroup
这是我们的逻辑头一次走进/system/core/中,位于/system/core/libprocessgroup/processgroup.cpp
252int killProcessGroup(uid_t uid, int initialPid, int signal)253{254 int processes;255 const int sleep_us = 5 * 1000; // 5ms256 int64_t startTime = android::uptimeMillis();257 int retry = 40;258259 while ((processes = killProcessGroupOnce(uid, initialPid, signal)) > 0) {260 SLOGV("killed %d processes for processgroup %d\n", processes, initialPid);261 if (retry > 0) {262 usleep(sleep_us);263 --retry;264 } else {265 SLOGE("failed to kill %d processes for processgroup %d\n",266 processes, initialPid);267 break;268 }269 }270271 SLOGV("Killed process group uid %d pid %d in %" PRId64 "ms, %d procs remain", uid, initialPid,272 android::uptimeMillis()-startTime, processes);273274 if (processes == 0) {275 return removeProcessGroup(uid, initialPid);276 } else {277 return -1;278 }279}
killProcessGroupOnce
216static int killProcessGroupOnce(uid_t uid, int initialPid, int signal)217{218 int processes = 0;219 struct ctx ctx;220 pid_t pid;221222 ctx.initialized = false;223224 while ((pid = getOneAppProcess(uid, initialPid, &ctx)) >= 0) {225 processes++;226 if (pid == 0) {227 // Should never happen... but if it does, trying to kill this228 // will boomerang right back and kill us! Let's not let that happen.229 SLOGW("Yikes, we've been told to kill pid 0! How about we don't do that.");230 continue;231 }232 if (pid != initialPid) {233 // We want to be noisy about killing processes so we can understand234 // what is going on in the log; however, don't be noisy about the base235 // process, since that it something we always kill, and we have already236 // logged elsewhere about killing it.237 SLOGI("Killing pid %d in uid %d as part of process group %d", pid, uid, initialPid);238 }239 int ret = kill(pid, signal);240 if (ret == -1) {241 SLOGW("failed to kill pid %d: %s", pid, strerror(errno));242 }243 }244245 if (ctx.initialized) {246 close(ctx.fd);247 }248249 return processes;250}
getOneAppProcess
我们再跟一下这个有趣的函数:getOneAppProcess
112static pid_t getOneAppProcess(uid_t uid, int appProcessPid, struct ctx *ctx)113{114 if (!ctx->initialized) {115 int ret = initCtx(uid, appProcessPid, ctx);116 if (ret < 0) {117 return ret;118 }119 }120121 char *eptr;122 while ((eptr = (char *)memchr(ctx->buf_ptr, '\n', ctx->buf_len)) == NULL) {123 int ret = refillBuffer(ctx);124 if (ret == 0) {125 return -ERANGE;126 }127 if (ret < 0) {128 return ret;129 }130 }131132 *eptr = '\0';133 char *pid_eptr = NULL;134 errno = 0;135 long pid = strtol(ctx->buf_ptr, &pid_eptr, 10);136 if (errno != 0) {137 return -errno;138 }139 if (pid_eptr != eptr) {140 return -EINVAL;141 }142143 ctx->buf_len -= (eptr - ctx->buf_ptr) + 1;144 ctx->buf_ptr = eptr + 1;145146 return (pid_t)pid;147}
removeProcessGroup
回头我们再看看removeProcessGroup,还要把对应的目录删掉。
149static int removeProcessGroup(uid_t uid, int pid)150{151 int ret;152 char path[PROCESSGROUP_MAX_PATH_LEN] = {0};153154 convertUidPidToPath(path, sizeof(path), uid, pid);155 ret = rmdir(path);156157 convertUidToPath(path, sizeof(path), uid);158 rmdir(path);159160 return ret;161}
AMS之removeProcessLocked(2)
5872 private final ProcessRecord removeProcessNameLocked(final String name, final int uid) {5873 ProcessRecord old = mProcessNames.remove(name, uid);5874 if (old != null) {5875 old.uidRecord.numProcs--;5876 if (old.uidRecord.numProcs == 0) {5877 // No more processes using this uid, tell clients it is gone.5878 if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,5879 "No more processes in " + old.uidRecord);5880 enqueueUidChangeLocked(old.uidRecord, true);5881 mActiveUids.remove(uid);5882 }5883 old.uidRecord = null;5884 }5885 mIsolatedProcesses.remove(uid);5886 return old;5887 }
AMS之enqueueUidChangeLocked
18855 private final void enqueueUidChangeLocked(UidRecord uidRec, boolean gone) {18856 if (uidRec.pendingChange == null) {18857 if (mPendingUidChanges.size() == 0) {...18860 mUiHandler.obtainMessage(DISPATCH_UIDS_CHANGED_MSG).sendToTarget();18861 }18862 final int NA = mAvailUidChanges.size();18863 if (NA > 0) {18864 uidRec.pendingChange = mAvailUidChanges.remove(NA-1);...18867 } else {18868 uidRec.pendingChange = new UidRecord.ChangeItem();...18871 }18872 uidRec.pendingChange.uidRecord = uidRec;18873 uidRec.pendingChange.uid = uidRec.uid;18874 mPendingUidChanges.add(uidRec.pendingChange);18875 }18876 uidRec.pendingChange.gone = gone;18877 uidRec.pendingChange.processState = uidRec.setProcState;18878 }
DISPATCH_UIDS_CHANGED_MSG消息在Handler中是如何处理的呢?我们查AMS中的UiHandler:
1611 case DISPATCH_UIDS_CHANGED_MSG: {1612 dispatchUidsChanged();1613 } break;
AMS之dispatchUidsChanged
3787 private void dispatchUidsChanged() {3788 int N;3789 synchronized (this) {3790 N = mPendingUidChanges.size();3791 if (mActiveUidChanges.length < N) {3792 mActiveUidChanges = new UidRecord.ChangeItem[N];3793 }3794 for (int i=0; i3795 final UidRecord.ChangeItem change = mPendingUidChanges.get(i);3796 mActiveUidChanges[i] = change;3797 change.uidRecord.pendingChange = null;3798 change.uidRecord = null;3799 }3800 mPendingUidChanges.clear();...3803 }38043805 if (mLocalPowerManager != null) {3806 for (int j=0; j3807 UidRecord.ChangeItem item = mActiveUidChanges[j];3808 if (item.gone) {3809 mLocalPowerManager.uidGone(item.uid);3810 } else {3811 mLocalPowerManager.updateUidProcState(item.uid, item.processState);3812 }3813 }3814 }38153816 int i = mUidObservers.beginBroadcast();3817 while (i > 0) {3818 i--;3819 final IUidObserver observer = mUidObservers.getBroadcastItem(i);3820 if (observer != null) {3821 try {3822 for (int j=0; j3823 UidRecord.ChangeItem item = mActiveUidChanges[j];3824 if (item.gone) {...3827 observer.onUidGone(item.uid);3828 } else {...3832 observer.onUidStateChanged(item.uid, item.processState);3833 }3834 }3835 } catch (RemoteException e) {3836 }3837 }3838 }3839 mUidObservers.finishBroadcast();38403841 synchronized (this) {3842 for (int j=0; j3843 mAvailUidChanges.add(mActiveUidChanges[j]);3844 }3845 }3846 }
AMS之handleAppDiedLocked
最后我们再看一下handleAppDiedLocked,杀了之后,埋的事情也还是要管的。
4564 private final void handleAppDiedLocked(ProcessRecord app,4565 boolean restarting, boolean allowRestart) {4566 int pid = app.pid;
后面大家可以看到这个清理用了180多行的代码,而这还不是全部。
4567 boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1);
mLruProcesses也是要清理的。
4568 if (!kept && !restarting) {4569 removeLruProcessLocked(app);4570 if (pid > 0) {4571 ProcessList.remove(pid);4572 }4573 }45744575 if (mProfileProc == app) {4576 clearProfilerLocked();4577 }
每个Activity负责去做自己的清理,这部分暂时先不分析了,以后用到了再说。
4579 // Remove this application's activities from active lists.4580 boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app);45814582 app.activities.clear();45834584 if (app.instrumentationClass != null) {4585 Slog.w(TAG, "Crash of app " + app.processName4586 + " running instrumentation " + app.instrumentationClass);4587 Bundle info = new Bundle();4588 info.putString("shortMsg", "Process crashed.");4589 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);4590 }45914592 if (!restarting && hasVisibleActivities && !mStackSupervisor.resumeTopActivitiesLocked()) {4593 // If there was nothing to resume, and we are not already4594 // restarting this process, but there is a visible activity that4595 // is hosted by the process... then make sure all visible4596 // activities are running, taking care of restarting this4597 // process.4598 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);4599 }4600 }
AMS之removeLruProcessLocked
不光remove LRU,如果没杀掉的话,这里还会再杀一次。
2811 final void removeLruProcessLocked(ProcessRecord app) {2812 int lrui = mLruProcesses.lastIndexOf(app);2813 if (lrui >= 0) {2814 if (!app.killed) {2815 Slog.wtfStack(TAG, "Removing process that hasn't been killed: " + app);2816 Process.killProcessQuiet(app.pid);2817 killProcessGroup(app.info.uid, app.pid);2818 }2819 if (lrui <= mLruProcessActivityStart) {2820 mLruProcessActivityStart--;2821 }2822 if (lrui <= mLruProcessServiceStart) {2823 mLruProcessServiceStart--;2824 }2825 mLruProcesses.remove(lrui);2826 }2827 }
AMS之cleanUpApplicationRecordLocked
这段就不细解释了,原文贴出来的原因是希望大家都体会到,埋葬还有这么多事情要做的。
15504 private final boolean cleanUpApplicationRecordLocked(ProcessRecord app,15505 boolean restarting, boolean allowRestart, int index) {15506 if (index >= 0) {15507 removeLruProcessLocked(app);15508 ProcessList.remove(app.pid);15509 }1551015511 mProcessesToGc.remove(app);15512 mPendingPssProcesses.remove(app);1551315514 // Dismiss any open dialogs.15515 if (app.crashDialog != null && !app.forceCrashReport) {15516 app.crashDialog.dismiss();15517 app.crashDialog = null;15518 }15519 if (app.anrDialog != null) {15520 app.anrDialog.dismiss();15521 app.anrDialog = null;15522 }15523 if (app.waitDialog != null) {15524 app.waitDialog.dismiss();15525 app.waitDialog = null;15526 }1552715528 app.crashing = false;15529 app.notResponding = false;1553015531 app.resetPackageList(mProcessStats);15532 app.unlinkDeathRecipient();15533 app.makeInactive(mProcessStats);15534 app.waitingToKill = null;15535 app.forcingToForeground = null;15536 updateProcessForegroundLocked(app, false, false);15537 app.foregroundActivities = false;15538 app.hasShownUi = false;15539 app.treatLikeActivity = false;15540 app.hasAboveClient = false;15541 app.hasClientActivities = false;1554215543 mServices.killServicesLocked(app, allowRestart);1554415545 boolean restart = false;1554615547 // Remove published content providers.15548 for (int i = app.pubProviders.size() - 1; i >= 0; i--) {15549 ContentProviderRecord cpr = app.pubProviders.valueAt(i);15550 final boolean always = app.bad || !allowRestart;15551 boolean inLaunching = removeDyingProviderLocked(app, cpr, always);15552 if ((inLaunching || always) && cpr.hasConnectionOrHandle()) {15553 // We left the provider in the launching list, need to15554 // restart it.15555 restart = true;15556 }1555715558 cpr.provider = null;15559 cpr.proc = null;15560 }15561 app.pubProviders.clear();1556215563 // Take care of any launching providers waiting for this process.15564 if (cleanupAppInLaunchingProvidersLocked(app, false)) {15565 restart = true;15566 }1556715568 // Unregister from connected content providers.15569 if (!app.conProviders.isEmpty()) {15570 for (int i = app.conProviders.size() - 1; i >= 0; i--) {15571 ContentProviderConnection conn = app.conProviders.get(i);15572 conn.provider.connections.remove(conn);15573 stopAssociationLocked(app.uid, app.processName, conn.provider.uid,15574 conn.provider.name);15575 }15576 app.conProviders.clear();15577 }1557815579 // At this point there may be remaining entries in mLaunchingProviders15580 // where we were the only one waiting, so they are no longer of use.15581 // Look for these and clean up if found.15582 // XXX Commented out for now. Trying to figure out a way to reproduce15583 // the actual situation to identify what is actually going on.15584 if (false) {15585 for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {15586 ContentProviderRecord cpr = mLaunchingProviders.get(i);15587 if (cpr.connections.size() <= 0 && !cpr.hasExternalProcessHandles()) {15588 synchronized (cpr) {15589 cpr.launchingApp = null;15590 cpr.notifyAll();15591 }15592 }15593 }15594 }1559515596 skipCurrentReceiverLocked(app);1559715598 // Unregister any receivers.15599 for (int i = app.receivers.size() - 1; i >= 0; i--) {15600 removeReceiverLocked(app.receivers.valueAt(i));15601 }15602 app.receivers.clear();1560315604 // If the app is undergoing backup, tell the backup manager about it15605 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {15606 if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG_CLEANUP, "App "15607 + mBackupTarget.appInfo + " died during backup");15608 try {15609 IBackupManager bm = IBackupManager.Stub.asInterface(15610 ServiceManager.getService(Context.BACKUP_SERVICE));15611 bm.agentDisconnected(app.info.packageName);15612 } catch (RemoteException e) {15613 // can't happen; backup manager is local15614 }15615 }1561615617 for (int i = mPendingProcessChanges.size() - 1; i >= 0; i--) {15618 ProcessChangeItem item = mPendingProcessChanges.get(i);15619 if (item.pid == app.pid) {15620 mPendingProcessChanges.remove(i);15621 mAvailProcessChanges.add(item);15622 }15623 }15624 mUiHandler.obtainMessage(DISPATCH_PROCESS_DIED, app.pid, app.info.uid, null).sendToTarget();1562515626 // If the caller is restarting this app, then leave it in its15627 // current lists and let the caller take care of it.15628 if (restarting) {15629 return false;15630 }1563115632 if (!app.persistent || app.isolated) {15633 if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,15634 "Removing non-persistent process during cleanup: " + app);15635 removeProcessNameLocked(app.processName, app.uid);15636 if (mHeavyWeightProcess == app) {15637 mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,15638 mHeavyWeightProcess.userId, 0));15639 mHeavyWeightProcess = null;15640 }15641 } else if (!app.removed) {15642 // This app is persistent, so we need to keep its record around.15643 // If it is not already on the pending app list, add it there15644 // and start a new process for it.15645 if (mPersistentStartingProcesses.indexOf(app) < 0) {15646 mPersistentStartingProcesses.add(app);15647 restart = true;15648 }15649 }15650 if ((DEBUG_PROCESSES || DEBUG_CLEANUP) && mProcessesOnHold.contains(app)) Slog.v(15651 TAG_CLEANUP, "Clean-up removing on hold: " + app);15652 mProcessesOnHold.remove(app);1565315654 if (app == mHomeProcess) {15655 mHomeProcess = null;15656 }15657 if (app == mPreviousProcess) {15658 mPreviousProcess = null;15659 }1566015661 if (restart && !app.isolated) {15662 // We have components that still need to be running in the15663 // process, so re-launch it.15664 if (index < 0) {15665 ProcessList.remove(app.pid);15666 }15667 addProcessNameLocked(app);15668 startProcessLocked(app, "restart", app.processName);15669 return true;15670 } else if (app.pid > 0 && app.pid != MY_PID) {15671 // Goodbye!15672 boolean removed;15673 synchronized (mPidsSelfLocked) {15674 mPidsSelfLocked.remove(app.pid);15675 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);15676 }15677 mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);15678 if (app.isolated) {15679 mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);15680 }15681 app.setPid(0);15682 }15683 return false;15684 }
更多相关文章
- Android客户端和服务器端数据交互的第四种方法
- Android选项卡的几种实现方法
- MTK 添加宏控方法
- Android AsyncTask onProgressUpdate 方法的些许研究
- Android Studio中genymotion安装方法
- Android使用HttpClient方法和易错问题
- Android开机自启动程序设置及控制方法思路浅谈
- android获取当前运行Activity名字的方法
- 将system_server进程配置成Android Application进程