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();    }


原创粉丝点击