AMS中的进程管理
AMS对进程的管理仅涉及两个方面
1.调节进程的调度优先级和调度策略
2.调节进程的oom值
调度优先级和调度策略
1.相对于在OS(操作系统)上运行的应用进程个数来说,CPU的资源非常有限
2.调度优先级是OS分配CPU资源给应用进程时(即调度应用进程运行)需要参考的一个指标。一般而言,优先级高的进程将更有机会得到CPU资源
3.除了优先级,还有一个需要考虑的重要因素是,每个进程所分配的时间片及它们的使用情况
Android应用进程分类:Forground类、Visible类、Service类、Background类及Empty类
Forground类
属于该类的进程包括下面几种情况
(1)含一个前端Activity(即onResume函数被调用过了,或者说当前正在显示的那个Activity)
(2)含一个Service,并且该Service和一个前端Activity绑定(例如Music应用包括一个前端界面和一个播放Service,当我们一边听歌一边操作Music界面时,该Service即和一个前端Activity绑定)
(3)含一个调用了startForground的Service,或者该进程的Service正在调用其生命周期的函数(onCreate、onStart或onDestroy)
(4)该进程中有BroadcastReceiver实例正在执行onReceive函数
Visible类
看属于Visible类的进程中没有处于前端的组件,但是用户仍然能看到它们,例如位于一个对话框后的Activity界面。该类进程包括两种
(1)该进程包含一个仅onPaus被调用的Activity(即它还在前台,只不过部分界面被遮住)
(2)包含一个Service,并且该Service和一个Visible(或Forground)的Activity绑定
Service类
该类进程包含一个Service。此Service通过startService启动,并且不属于前面两类进程。这种进程一般在后台默默干活。
Background类
该类进程包含当前不可见的Activity(即它们的onStop被调用过)。系统保存这些进程到一个LRU(最近最少使用)列表。当系统需要回收内存时,该列表中哪些最近最少使用的进程将被杀死
Empty类
这类进程不包含任何组件。为什么会出现这种不包括任何组件的进程呢?是因为,假设该进程进创建一个Activity,它完成工作后主动调用finish函数销毁(destory)自己,之后该进程就会成为Empty进程。系统保留Empty进程的原因是当又重新需要它们时(例如用户在别的进程中通过startActivity启动了它们),可以省去fork进程、创建Android运行环境等一系列漫长而艰苦的工作
应用进程Crash处理
private static class UncaughtHandler implements Thread.UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e) { try { // Don't re-enter -- avoid infinite loops if crash-reporting crashes. if (mCrashing) return; mCrashing = true; if (mApplicationObject == null) { Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e); } else { StringBuilder message = new StringBuilder(); message.append("FATAL EXCEPTION: ").append(t.getName()).append(" "); final String processName = ActivityThread.currentProcessName(); if (processName != null) { message.append("Process: ").append(processName).append(", "); } message.append("PID: ").append(Process.myPid()); Clog_e(TAG, message.toString(), e); } // Bring up crash dialog, wait for it to be dismissed ActivityManagerNative.getDefault().handleApplicationCrash( mApplicationObject, new ApplicationErrorReport.CrashInfo(e)); } catch (Throwable t2) { try { Clog_e(TAG, "Error reporting crash", t2); } catch (Throwable t3) { // Even Clog_e() fails! Oh well. } } finally { // Try everything to make sure this process goes away. Process.killProcess(Process.myPid()); System.exit(10); } } }
AMS
public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) { ProcessRecord r = findAppProcess(app, "Crash"); final String processName = app == null ? "system_server" : (r == null ? "unknown" : r.processName); handleApplicationCrashInner("crash", r, processName, crashInfo); }
private void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) { long timeMillis = System.currentTimeMillis(); String shortMsg = crashInfo.exceptionClassName; String longMsg = crashInfo.exceptionMessage; String stackTrace = crashInfo.stackTrace; if (shortMsg != null && longMsg != null) { longMsg = shortMsg + ": " + longMsg; } else if (shortMsg != null) { longMsg = shortMsg; } AppErrorResult result = new AppErrorResult(); synchronized (this) { if (mController != null) { try { String name = r != null ? r.processName : null; int pid = r != null ? r.pid : Binder.getCallingPid(); int uid = r != null ? r.info.uid : Binder.getCallingUid(); if (!mController.appCrashed(name, pid, shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) { if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")) && "Native crash".equals(crashInfo.exceptionClassName)) { Slog.w(TAG, "Skip killing native crashed app " + name + "(" + pid + ") during testing"); } else { Slog.w(TAG, "Force-killing crashed app " + name + " at watcher's request"); if (r != null) { r.kill("crash", true); } else { // Huh. Process.killProcess(pid); killProcessGroup(uid, pid); } } return; } } catch (RemoteException e) { mController = null; Watchdog.getInstance().setActivityController(null); } } final long origId = Binder.clearCallingIdentity(); // If this process is running instrumentation, finish it. if (r != null && r.instrumentationClass != null) { Slog.w(TAG, "Error in app " + r.processName + " running instrumentation " + r.instrumentationClass + ":"); if (shortMsg != null) Slog.w(TAG, " " + shortMsg); if (longMsg != null) Slog.w(TAG, " " + longMsg); Bundle info = new Bundle(); info.putString("shortMsg", shortMsg); info.putString("longMsg", longMsg); finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info); Binder.restoreCallingIdentity(origId); return; } // Log crash in battery stats. if (r != null) { mBatteryStatsService.noteProcessCrash(r.processName, r.uid); } // If we can't identify the process or it's already exceeded its crash quota, // quit right away without showing a crash dialog. if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace)) { Binder.restoreCallingIdentity(origId); return; } Message msg = Message.obtain(); msg.what = SHOW_ERROR_MSG; HashMap data = new HashMap(); data.put("result", result); data.put("app", r); msg.obj = data; mUiHandler.sendMessage(msg); Binder.restoreCallingIdentity(origId); } int res = result.get(); Intent appErrorIntent = null; synchronized (this) { if (r != null && !r.isolated) { // XXX Can't keep track of crash time for isolated processes, // since they don't have a persistent identity. mProcessCrashTimes.put(r.info.processName, r.uid, SystemClock.uptimeMillis()); } if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) { appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo); } } if (appErrorIntent != null) { try { mContext.startActivityAsUser(appErrorIntent, new UserHandle(r.userId)); } catch (ActivityNotFoundException e) { Slog.w(TAG, "bug report receiver dissappeared", e); } } }
private boolean makeAppCrashingLocked(ProcessRecord app, String shortMsg, String longMsg, String stackTrace) { app.crashing = true; app.crashingReport = generateProcessError(app, ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace); startAppProblemLocked(app); app.stopFreezingAllLocked(); return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace); }
面试:什么情况需要把进程移到前台?
解析:
1)进程中的某个Activity正在与用户进行交互(Activity的onResume()方法被调用)
2)绑定到与当前用户正在交互的activity的service所在的进程
3)进程中的某个service正运行在前台,即这个service的startForeground()方法被调用
4)进程中的某个Service正在执行生命周期回调方法(比如:onCreate()、onStart()或者onDestory())
5)进程中的BroadcastReceiver正在执行onReceive()方法