android.process.media crash后现象研究之一
来源:互联网 发布:广州橙子网络靠谱吗 编辑:程序博客网 时间:2024/05/22 14:07
android.process.media crash后现象研究
在ActivityManagerService启动android.process.media进程时,在启动进程后会调用attachApplicationLocked,在其中利用Binder的linkToDeath方法来接收进程退出消息。
在进程crash后,如果进程中存在Service在运行或者有Provider等待运行则进程会被自动运行。
ActivityManagerService.java
private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {... // If this application record is still attached to a previous // process, clean it up now. if (app.thread != null) { handleAppDiedLocked(app, true); } String processName = app.processName; try { thread.asBinder().linkToDeath(new AppDeathRecipient( app, pid, thread), 0); } catch (RemoteException e) { app.resetPackageList(); startProcessLocked(app, "link fail", processName); return false; }
一旦监控的进程退出,则AppDeathRecipient.binderDied()将被调用。
private final class AppDeathRecipient implements IBinder.DeathRecipient { final ProcessRecord mApp; final int mPid; final IApplicationThread mAppThread; AppDeathRecipient(ProcessRecord app, int pid, IApplicationThread thread) { mApp = app; //待监听应用进程 mPid = pid; //被监听进程ID mAppThread = thread; //被监听进程的binder句柄 } public void binderDied() { synchronized(ActivityManagerService.this) { dyingPidLocked = mPid; appDiedLocked(mApp, mPid, mAppThread); //调用appDiedLocked dyingPidLocked = -1; } } }
final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread) {... mProcDeaths[0]++; //死亡的进程个数加1,代表自最近启动进程以来死亡的进程数,startProcessLocked中会清零 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); synchronized (stats) { stats.noteProcessDiedLocked(app.info.uid, pid); //从电池用量计数进程表中删除 } // Clean up already done if the process has been re-started. if (app.pid == pid && app.thread != null && app.thread.asBinder() == thread.asBinder()) { if (!app.killedBackground) { Slog.i(TAG, "Process " + app.processName + " (pid " + pid + ") has died."); } EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName); if (localLOGV) Slog.v( TAG, "Dying app: " + app + ", pid: " + pid + ", thread: " + thread.asBinder()); boolean doLowMem = app.instrumentationClass == null; handleAppDiedLocked(app, false); if (doLowMem) { // If there are no longer any background processes running, // and the app that died was not running instrumentation, // then tell everyone we are now low on memory. boolean haveBg = false; for (int i=mLruProcesses.size()-1; i>=0; i--) { ProcessRecord rec = mLruProcesses.get(i); if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) { haveBg = true; break; } } if (!haveBg) { Slog.i(TAG, "Low Memory: No more background processes."); EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size()); long now = SystemClock.uptimeMillis(); for (int i=mLruProcesses.size()-1; i>=0; i--) { ProcessRecord rec = mLruProcesses.get(i); if (rec != app && rec.thread != null && (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) { // The low memory report is overriding any current // state for a GC request. Make sure to do // heavy/important/visible/foreground processes first. if (rec.setAdj <= HEAVY_WEIGHT_APP_ADJ) { rec.lastRequestedGc = 0; } else { rec.lastRequestedGc = rec.lastLowMemory; } rec.reportLowMemory = true; rec.lastLowMemory = now; mProcessesToGc.remove(rec); addProcessToGcListLocked(rec); } } scheduleAppGcsLocked(); } } } else if (app.pid != pid) { // A new process has already been started. Slog.i(TAG, "Process " + app.processName + " (pid " + pid + ") has died and restarted (pid " + app.pid + ")."); EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName); } else { if (DEBUG_PROCESSES) { Slog.d(TAG, "Received spurious death notification for thread " + thread.asBinder()); } if (app.bad) { // When the process is marked "bad" because of its frequent crashes, // WindowManagerService may lose focus window and go into infinite loop. // Find a top alive activity from mHistory to recover from the wrong loop. mMainStack.resumeTopActivityLocked(null); } } }
private final void handleAppDiedLocked(ProcessRecord app, boolean restarting) { cleanUpApplicationRecordLocked(app, restarting, -1); if (!restarting) { mLruProcesses.remove(app); } // Just in case... if (mMainStack.mPausingActivity != null && mMainStack.mPausingActivity.app == app) { if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " +mMainStack.mPausingActivity); mMainStack.mPausingActivity = null; } if (mMainStack.mLastPausedActivity != null && mMainStack.mLastPausedActivity.app == app) { mMainStack.mLastPausedActivity = null; } // Remove this application's activities from active lists. mMainStack.removeHistoryRecordsForAppLocked(app); boolean atTop = true; boolean hasVisibleActivities = false; // Clean out the history list. int i = mMainStack.mHistory.size(); if (localLOGV) Slog.v( TAG, "Removing app " + app + " from history with " + i + " entries"); while (i > 0) { i--; ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i); if (localLOGV) Slog.v( TAG, "Record #" + i + " " + r + ": app=" + r.app); if (r.app == app) { if ((!r.haveState && !r.stateNotNeeded) || r.finishing) { if (localLOGV) Slog.v( TAG, "Removing this entry! frozen=" + r.haveState + " finishing=" + r.finishing); mMainStack.mHistory.remove(i); sendHistoryChangeNoti(r.task.taskId); r.inHistory = false; mWindowManager.removeAppToken(r); if (VALIDATE_TOKENS) { mWindowManager.validateAppTokens(mMainStack.mHistory); } r.removeUriPermissionsLocked(); } else { // We have the current state for this activity, so // it can be restarted later when needed. if (localLOGV) Slog.v( TAG, "Keeping entry, setting app to null"); if (r.visible) { hasVisibleActivities = true; } r.app = null; r.nowVisible = false; if (!r.haveState) { r.icicle = null; } } r.stack.cleanUpActivityLocked(r, true); r.state = ActivityState.STOPPED; } atTop = false; } app.activities.clear(); if (app.instrumentationClass != null) { Slog.w(TAG, "Crash of app " + app.processName + " running instrumentation " + app.instrumentationClass); Bundle info = new Bundle(); info.putString("shortMsg", "Process crashed."); finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info); } if (!restarting) { if (!mMainStack.resumeTopActivityLocked(null)) { // If there was nothing to resume, and we are not already // restarting this process, but there is a visible activity that // is hosted by the process... then make sure all visible // activities are running, taking care of restarting this // process. if (hasVisibleActivities) { mMainStack.ensureActivitiesVisibleLocked(null, 0); } } } }
在此决定是否重启该进程或进程中正在运行的Service,并清除所有Provider及Service记录
/** * Main code for cleaning up a process when it has gone away. This is * called both as a result of the process dying, or directly when stopping * a process when running in single process mode. */ private final void cleanUpApplicationRecordLocked(ProcessRecord app, boolean restarting, int index) { if (index >= 0) { mLruProcesses.remove(index); } mProcessesToGc.remove(app); synchronized(app) { if (!app.bad && (app.crashDialog != null)) { app.crashDialog.dismiss(); } app.crashDialog = null; } if (app.anrDialog != null) { app.anrDialog.dismiss(); app.anrDialog = null; } if (app.waitDialog != null) { app.waitDialog.dismiss(); app.waitDialog = null; } app.crashing = false; app.notResponding = false; app.resetPackageList(); app.thread = null; app.forcingToForeground = null; app.foregroundServices = false; killServicesLocked(app, true); boolean restart = false; int NL = mLaunchingProviders.size(); // Remove published content providers. if (!app.pubProviders.isEmpty()) { Iterator<ContentProviderRecord> it = app.pubProviders.values().iterator(); while (it.hasNext()) { ContentProviderRecord cpr = it.next(); cpr.provider = null; cpr.app = null; // See if someone is waiting for this provider... in which // case we don't remove it, but just let it restart. int i = 0; if (!app.bad) { for (; i<NL; i++) { if (mLaunchingProviders.get(i) == cpr) { restart = true; break; } } } else { i = NL; } if (i >= NL) { removeDyingProviderLocked(app, cpr); NL = mLaunchingProviders.size(); } } app.pubProviders.clear(); } // Take care of any launching providers waiting for this process. if (checkAppInLaunchingProvidersLocked(app, false)) { //仅当有应用依赖与某Provider且此Provider尚未publish则会自动重启crash进程,所有Provider将会在进程运行时被启动 restart = true; } // Unregister from connected content providers. if (!app.conProviders.isEmpty()) { Iterator it = app.conProviders.keySet().iterator(); while (it.hasNext()) { ContentProviderRecord cpr = (ContentProviderRecord)it.next(); cpr.clients.remove(app); } app.conProviders.clear(); } skipCurrentReceiverLocked(app); // Unregister any receivers. if (app.receivers.size() > 0) { Iterator<ReceiverList> it = app.receivers.iterator(); while (it.hasNext()) { removeReceiverLocked(it.next()); } app.receivers.clear(); } // If the app is undergoing backup, tell the backup manager about it if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) { if (DEBUG_BACKUP) Slog.d(TAG, "App " + mBackupTarget.appInfo + " died during backup"); try { IBackupManager bm = IBackupManager.Stub.asInterface( ServiceManager.getService(Context.BACKUP_SERVICE)); bm.agentDisconnected(app.info.packageName); } catch (RemoteException e) { // can't happen; backup manager is local } } // If the caller is restarting this app, then leave it in its // current lists and let the caller take care of it. if (restarting) { return; } if (!app.persistent) { if (DEBUG_PROCESSES) Slog.v(TAG, "Removing non-persistent process during cleanup: " + app); mProcessNames.remove(app.processName, app.info.uid); if (mHeavyWeightProcess == app) { mHeavyWeightProcess = null; mHandler.sendEmptyMessage(CANCEL_HEAVY_NOTIFICATION_MSG); } } else if (!app.removed) { // This app is persistent, so we need to keep its record around. // If it is not already on the pending app list, add it there // and start a new process for it. app.thread = null; app.forcingToForeground = null; app.foregroundServices = false; if (mPersistentStartingProcesses.indexOf(app) < 0) { mPersistentStartingProcesses.add(app); restart = true; } } if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG, "Clean-up removing on hold: " + app); mProcessesOnHold.remove(app); if (app == mHomeProcess) { mHomeProcess = null; mHomeTask = -1; } if (restart) { // We have components that still need to be running in the // process, so re-launch it. mProcessNames.put(app.processName, app.info.uid, app); startProcessLocked(app, "restart", app.processName); //重启crash的应用 } else if (app.pid > 0 && app.pid != MY_PID) { // Goodbye! synchronized (mPidsSelfLocked) { if (dyingPidLocked == -1) { mPidsSelfLocked.remove(app.pid); } else { mPidsSelfLocked.remove(dyingPidLocked); } mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); } // If the dyingPid matches app.pid, there is no race between deatch // and re-birth, so it's ok to clear app.pid here if ((dyingPidLocked == -1) || (dyingPidLocked == app.pid)) { app.setPid(0); } else { if (DEBUG_PROCESSES) Slog.v(TAG, "hhmm - Race, skipped setting app.pid to 0" ); } } }
以下函数将清除进程app内的Service及所有连接,如果allowRestart为true且非多次crash(<2),则将发消息以重启该服务。
private final void killServicesLocked(ProcessRecord app,boolean allowRestart) { // 当进程crash时,allowRestart必为true // Clean up any connections this application has to other services. if (app.connections.size() > 0) { Iterator<ConnectionRecord> it = app.connections.iterator(); while (it.hasNext()) { ConnectionRecord r = it.next(); removeConnectionLocked(r, app, null); } } app.connections.clear(); if (app.services.size() != 0) { //存在Service否? // Any services running in the application need to be placed // back in the pending list. Iterator<ServiceRecord> it = app.services.iterator(); while (it.hasNext()) { ServiceRecord sr = it.next(); synchronized (sr.stats.getBatteryStats()) { sr.stats.stopLaunchedLocked(); } sr.app = null; sr.executeNesting = 0; if (mStoppingServices.remove(sr)) { if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr); } boolean hasClients = sr.bindings.size() > 0; if (hasClients) { Iterator<IntentBindRecord> bindings = sr.bindings.values().iterator(); while (bindings.hasNext()) { IntentBindRecord b = bindings.next(); if (DEBUG_SERVICE) Slog.v(TAG, "Killing binding " + b + ": shouldUnbind=" + b.hasBound); b.binder = null; b.requested = b.received = b.hasBound = false; } } if (sr.crashCount >= 2) { //如果多次crash Slog.w(TAG, "Service crashed " + sr.crashCount + " times, stopping: " + sr); EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH, sr.crashCount, sr.shortName, app.pid); bringDownServiceLocked(sr, true); //移除Service } else if (!allowRestart) { bringDownServiceLocked(sr, true); } else { boolean canceled = scheduleServiceRestartLocked(sr, true); //在此发起请求重起Service // Should the service remain running? Note that in the // extreme case of so many attempts to deliver a command // that it failed, that we also will stop it here. if (sr.startRequested && (sr.stopIfKilled || canceled)) { if (sr.pendingStarts.size() == 0) { sr.startRequested = false; if (!hasClients) { // Whoops, no reason to restart! bringDownServiceLocked(sr, true); } } } } } if (!allowRestart) { app.services.clear(); } } // Make sure we have no more records on the stopping list. int i = mStoppingServices.size(); while (i > 0) { i--; ServiceRecord sr = mStoppingServices.get(i); if (sr.app == app) { mStoppingServices.remove(i); if (DEBUG_SERVICE) Slog.v(TAG, "killServices remove stopping " + sr); } } app.executingServices.clear(); }
- android.process.media crash后现象研究之一
- android.process.media crash后现象研究之二
- system_server crash现象研究
- system_server crash现象研究
- Android Media Scanner Process
- 实例分析:android.process.media由于调用进程crash而退出
- Android - android.process.media意外停止解决方法
- Android 程序crash后重新启动
- Android 多媒体扫描过程(Android Media Scanner Process)
- Android 多媒体扫描过程(Android Media Scanner Process)
- android 多媒体扫描过程(Android Media Scanner Process)
- Android 多媒体扫描过程(Android Media Scanner Process)
- Android 多媒体扫描过程(Android Media Scanner Process)
- Android 多媒体扫描过程(Android Media Scanner Process)
- 【译】Android 多媒体扫描过程(Android Media Scanner Process)
- Android 多媒体扫描过程(Android Media Scanner Process)
- Android 多媒体扫描过程(Android Media Scanner Process)
- Android 多媒体扫描过程(Android Media Scanner Process)
- Tomcat高并发配置
- WPF中的鼠标事件详解
- Oracle分区表 (二)
- Class.getResourceAsStream 和 ClassLoader.getResourceAsStream
- Oracle数据导入导出imp/exp?批处理文件
- android.process.media crash后现象研究之一
- 抗扭强度
- SqlServer教程—第一章(安装和配置SQL Server)
- 阻塞模式和非阻塞模式
- VC 技巧 - 有助学习
- C#导出excel文件
- javascript 判断浏览器方法
- 读解Thread类API
- 产品经理的思考(四) -乔布斯自述的思考