2024年Android最新深入理解Android Crash 流程(2),百度android面试

如果你进阶的路上缺乏方向,可以加入我们的圈子和安卓开发者们一起学习交流!

  • Android进阶学习全套手册

    img

  • Android对标阿里P7学习视频

    img

  • BATJ大厂Android高频面试题

    img

最后,借用我最喜欢的乔布斯语录,作为本文的结尾:

人这一辈子没法做太多的事情,所以每一件都要做得精彩绝伦。
你的时间有限,所以不要为别人而活。不要被教条所限,不要活在别人的观念里。不要让别人的意见左右自己内心的声音。
最重要的是,勇敢的去追随自己的心灵和直觉,只有自己的心灵和直觉才知道你自己的真实想法,其他一切都是次要。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

        while (tr.getCause() != null) {

            tr = tr.getCause();

            if (tr.getStackTrace() != null && tr.getStackTrace().length > 0) {

                rootTr = tr;

            }

            String msg = tr.getMessage();

            if (msg != null && msg.length() > 0) {

                exceptionMessage = msg;

            }

        }

        // Crash 异常类名称 

        exceptionClassName = rootTr.getClass().getName();

        if (rootTr.getStackTrace().length > 0) {

            StackTraceElement trace = rootTr.getStackTrace()[0];

            // 获取 trace 文件名、类名、方法名、Crash 行号

            throwFileName = trace.getFileName();

            throwClassName = trace.getClassName();

            throwMethodName = trace.getMethodName();

            throwLineNumber = trace.getLineNumber();

        } else {

            throwFileName = "unknown";

            ... ... 

        }



        exceptionMessage = sanitizeString(exceptionMessage);

    }



三、handleApplicationCrash处理分析

============================



`handleApplicationCrash` 会通过 `JNI`接口调用`AMS`中的方法。



           //发送 Crash 弹窗handler,直到Dialog  dismiss

            ActivityManager.getService().handleApplicationCrash(

                    mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));



`ActivityManagerService.java`  

`handleApplicationCrash` 通过`JNI` 回调用 `AMS`中的`handleApplicationCrash`方法,进而调用`AMS` 中的内部方法`handleApplicationCrashInner`。  

handleApplicationCrash



*   1.当远程`IBinder`对象为空`Null`时,则进程名为`system_server`;

    

*   2.当远程`IBinder`对象不为空,且`ProcessRecord`为空时,则进程名为`unknown`;

    

*   3.当远程`IBinder`对象不为空,且`ProcessRecord`不为空时,则进程名为`ProcessRecord`对象中相应进程名。

    



//  当app Crash 时候,会调用此方法。

//调用结束后 ,app 进程就会推出

public void handleApplicationCrash(IBinder app,

        ApplicationErrorReport.ParcelableCrashInfo crashInfo) {

    // findAppProcess 详见 3.1 分析

    ProcessRecord r = findAppProcess(app, "Crash");

    // system_server 进程 为Null 

    final String processName = app == null ? "system_server"

            : (r == null ? "unknown" : r.processName);

    //handleApplicationCrashInner 详见 4 分析

    handleApplicationCrashInner("crash", r, processName, crashInfo);

}



`handleApplicationCrashInner`主要是调用 `AppErrors`类中的`crashApplication` 方法处理。



void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,

        ApplicationErrorReport.CrashInfo crashInfo) {

    ... ... 

    //调用APP Error 类方法中的 crashApplication

    mAppErrors.crashApplication(r, crashInfo);

}



### 3.1 findAppProcess



`ActivityManagerService.java`  

`findAppProcess`主要是通过`for`循环遍历查找出`IBinder`对应的`Process`.



private ProcessRecord findAppProcess(IBinder app, String reason) {

    ... ...

    synchronized (this) {

        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 p = apps.valueAt(ia);

                 //当找到目标进程则返回

                if (p.thread != null && p.thread.asBinder() == app) {

                    return p;

                }

            }

        }

        //如果代码执行到这里,表明无法找到应用所在的进程

        return null;

    }

}



其中 `mProcessNames = new ProcessMap<ProcessRecord>();`对于代码`mProcessNames.getMap()`返回的是`mMap`,而`mMap= new ArrayMap<String, SparseArray<ProcessRecord>>()`;



知识延伸:`SparseArray`和`ArrayMap`是`Android`专门针对内存优化而设计的取代`Java API`中的`HashMap`的数据结构。



对于`key`是`int`类型则使用`SparseArray`,可避免自动装箱过程;  

对于`key`为其他类型则使用`ArrayMap`。  

`HashMap`的查找和插入时间复杂度为`O(1)`的代价是牺牲大量的内存来实现的,而`SparseArray`和`ArrayMap`性能略逊于`HashMap`,但更`节省内存`。



再回到`mMap`,这是以进程`name`为`key`,再以`(uid为key,以ProcessRecord为Value的)`结构体作为`value`。下面看看其`get()`和`put()`方法



public E get(String name, int uid) {

    SparseArray<E> uids = mMap.get(name);

    if (uids == null) return null;

    return uids.get(uid);

}



public E put(String name, int uid, E value) {

    SparseArray<E> uids = mMap.get(name);

    if (uids == null) {

        uids = new SparseArray<E>(2);

        mMap.put(name, uids);

    }

    uids.put(uid, value);

    return value;

}



`findAppProcess()`根据`app(IBinder类型)`来查询相应的目标对象`ProcessRecord`。



有了进程记录对象`ProcessRecord`和进程名`processName`,则进入执行`Crash`处理方法 `AppErrors.java`,继续往下看。



四、handleApplicationCrashInner 处理分析

==================================



`ActivityManagerService.java`



void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,

        ApplicationErrorReport.CrashInfo crashInfo) {

     ... ...

    //将错误信息追加到DropBox

    addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);

    //【见小节5】

    mAppErrors.crashApplication(r, crashInfo);

}



其中`addErrorToDropBox`是将`Crash`的信息输出到目录`/data/system/dropbox`。例如`system_server`的`dropbox`文件名为`system_server_crash@xxx.txt (xxx代表的是时间戳)`



五、APP Error info分析

==================



`AppErrors.java`  

AppErrors 主要是 控制`APP Crash`的场景条件。



void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {

    ... ...

    try {

        // 调用内部 crashApplicationInner方法

        crashApplicationInner(r, crashInfo, callingPid, callingUid);

    } finally {

        Binder.restoreCallingIdentity(origId);

    }

}



`crashApplicationInner`内部方法



void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,

        int callingPid, int callingUid) {

     ... ... 

    AppErrorResult result = new AppErrorResult();

    TaskRecord task;

    synchronized (mService) {

         // 如果是通过IActivityController 实例导致的Crash ,则不显示弹窗

        // 详见5.1 

        if (handleAppCrashInActivityController(r, crashInfo, shortMsg, longMsg, stackTrace,

                timeMillis, callingPid, callingUid)) {

            return;

        }

         ... ...

        AppErrorDialog.Data data = new AppErrorDialog.Data();

        data.result = result;

        data.proc = r;

        // 无法势必的进程 也不显示Crash 弹窗【见小节6】

        if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, data)) {

            return;

        }



        final Message msg = Message.obtain();

        msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG;



        task = data.task;

        msg.obj = data;

       //发送消息SHOW_ERROR_MSG,弹出提示crash的对话框,等待用户选择【见小节10】

        mService.mUiHandler.sendMessage(msg);

    }

     //进入阻塞等待,直到用户选择crash对话框"退出"或者"退出并报告"

    int res = result.get();



    Intent appErrorIntent = null;

    MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res);

    if (res == AppErrorDialog.TIMEOUT || res == AppErrorDialog.CANCEL) {

        res = AppErrorDialog.FORCE_QUIT;

    }

… …

}




### 5.1 handleAppCrashInActivityController



`handleAppCrashInActivityController`,通过`IActivityController` 实例导致的`Crash` ,则不显示弹窗.  

`AppError.java`



private boolean handleAppCrashInActivityController(ProcessRecord r,

                                                   ApplicationErrorReport.CrashInfo crashInfo,

                                                   String shortMsg, String longMsg,

                                                   String stackTrace, long timeMillis,

                                                   int callingPid, int callingUid) {

   ... ... 

  // 当存在ActivityController的情况,比如monkey

    try {

        String name = r != null ? r.processName : null;

        int pid = r != null ? r.pid : callingPid;

        int uid = r != null ? r.info.uid : callingUid;

       //调用monkey的 appCrashed

        if (!mService.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) {

                    //调用`makeAppCrashingLocked`,继续处理crash流程

                    // 详见 小结 6 

                    if (!makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, null))

                    {

                        r.kill("crash", true);

                    }

                } else {

                    // Huh.

                    Process.killProcess(pid);

                    ActivityManagerService.killProcessGroup(uid, pid);

                }

            }

            return true;

        }

    } catch (RemoteException e) {

        mService.mController = null;

        Watchdog.getInstance().setActivityController(null);

    }

    return false;

}



该方法主要做的两件事:



*   调用`makeAppCrashingLocked`,继续处理`Crash`流程;

    

*   发送消息`SHOW_ERROR_MSG`,弹出提示`Crash`的对话框,等待用户选择;  

    接下来我们看`makeAppCrashingLocked`实现。

    



六、makeAppCrashingLocked处理分析

===========================



`AppError.java`



private boolean makeAppCrashingLocked(ProcessRecord app,

        String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {

    app.crashing = true;

    //封装crash信息到crashingReport对象

    app.crashingReport = generateProcessError(app,

            ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);

     //【见小节7】

    startAppProblemLocked(app);

    //停止屏幕冻结【见小节8】

    app.stopFreezingAllLocked();

    //【见小节9】

    return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace,

            data);

}



七、startAppProblemLocked处理分析

===========================



`AppError.java`  

`startAppProblemLocked` 该方法主要功能:



*   获取当前用户下的`crash`应用的`error receiver`;

    

*   忽略当前`App`的广播接收;

    



void startAppProblemLocked(ProcessRecord app) {

    // 如果不是当前user正在运行 app,这置为空

    app.errorReportReceiver = null;



    for (int userId : mService.mUserController.getCurrentProfileIds()) {

        if (app.userId == userId) {

            //获取当前用户下的crash应用的error receiver【见小节7.1】

            app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(

                    mContext, app.info.packageName, app.info.flags);

        }

    }

    //忽略当前app的广播接收【见小节7.2】

    mService.skipCurrentReceiverLocked(app);

}



### 7.1 getErrorReportReceiver



`ApplicationErrorReport.java`  

获取当前用户下的`Crash`应用的`error receiver`



public static ComponentName getErrorReportReceiver(Context context,

        String packageName, int appFlags) {

   //检查Settings中的"send_action_app_error"是否使能错误报告的功能

    int enabled = Settings.Global.getInt(context.getContentResolver(),

            Settings.Global.SEND_ACTION_APP_ERROR, 0);

    if (enabled == 0) {

        //1.当未使能时,则直接返回

        return null;

    }



    PackageManager pm = context.getPackageManager();



    // look for receiver in the installer package

    String candidate = null;

    ComponentName result = null;



    try {

        //获取该crash应用的安装器的包名

        candidate = pm.getInstallerPackageName(packageName);

    } catch (IllegalArgumentException e) {

        // the package could already removed

    }



    if (candidate != null) {

        result = getErrorReportReceiver(pm, packageName, candidate);

        if (result != null) {

            //2.当找到该crash应用的安装器,则返回;

            return result;

        }

    }



    //该系统属性名为"ro.error.receiver.system.apps"

    if ((appFlags&ApplicationInfo.FLAG_SYSTEM) != 0) {



        candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);

       // 通过上下文对象传参,调用类内部方法

        result = getErrorReportReceiver(pm, packageName, candidate);

        if (result != null) {

            //3.当crash应用是系统应用时,且系统属性指定error receiver时,则返回;

            return result;

        }

    }



     //该默认属性名为"ro.error.receiver.default"

    candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);

     //4.当默认属性值指定error receiver时,则返回;

      return getErrorReportReceiver(pm, packageName, candidate);

}



`getErrorReportReceiver:`这是同名不同输入参数的另一个方法:



static ComponentName getErrorReportReceiver(PackageManager pm, String errorPackage,

        String receiverPackage) {

    if (receiverPackage == null || receiverPackage.length() == 0) {

        return null;

    }



   //当安装应用程序的安装器Crash,则直接返回

    if (receiverPackage.equals(errorPackage)) {

        return null;

    }

     //ACTION_APP_ERROR值为"android.intent.action.APP_ERROR"

    Intent intent = new Intent(Intent.ACTION_APP_ERROR);

    intent.setPackage(receiverPackage);

    ResolveInfo info = pm.resolveActivity(intent, 0);

    if (info == null || info.activityInfo == null) {

        return null;

    }

    //创建包名为receiverPackage的组件

    return new ComponentName(receiverPackage, info.activityInfo.name);

}



### 7.2 skipCurrentReceiverLocked



`ActivityManagerService.java`  

忽略当前`app`的广播接收



void skipCurrentReceiverLocked(ProcessRecord app) {

    for (BroadcastQueue queue : mBroadcastQueues) {

        // 会调用BroadcastQueue 中的方法【见小节7.2.1】

        queue.skipCurrentReceiverLocked(app);

    }

}



### 7.2.1 skipCurrentReceiverLocked



`BroadcastQueue.java` `skipCurrentReceiverLocked`忽略当前app的广播接收.



public void skipCurrentReceiverLocked(ProcessRecord app) {

    BroadcastRecord r = null;

    //查看app进程中的广播

    if (mOrderedBroadcasts.size() > 0) {

        BroadcastRecord br = mOrderedBroadcasts.get(0);

       // 判断是否一致

        if (br.curApp == app) {

            r = br;

        }

    }

     ... ...

    if (r != null) {

        // 见7.2.2

        skipReceiverLocked(r);

    }

}



### 7.2.2 skipReceiverLocked



`BroadcastQueue.java`



private void skipReceiverLocked(BroadcastRecord r) {

    logBroadcastReceiverDiscardLocked(r);

     //结束app进程的广播结束

    finishReceiverLocked(r, r.resultCode, r.resultData,

            r.resultExtras, r.resultAbort, false);

    //执行广播调度

    scheduleBroadcastsLocked();

}



八、stopFreezingAllLocked处理分析

===========================



`AppError.java`中的 `makeAppCrashingLocked`方法(第6步),会调用`stopFreezingAllLocked` 方法



`ProcessRecord.java`



public void stopFreezingAllLocked() {

    int i = activities.size();

    while (i > 0) {

        i--;

        // 停止进程里所有的`Activity`. 详见8.1 

        activities.get(i).stopFreezingScreenLocked(true);

    }

}



其中`activities`类型为`ArrayList<ActivityRecord>`,停止进程里所有的`Activity`.



#### 8.1 AR.stopFreezingScreenLocked



`ActivityRecord.java`,`stopFreezingScreenLocked`停止进程里所有的`Activity`.



public void stopFreezingScreenLocked(boolean force) {

    if (force || frozenBeforeDestroy) {

        frozenBeforeDestroy = false;

       // mWindowContainerController 见【8.1.1】

        mWindowContainerController.stopFreezingScreen(force);

    }

}



##### 8.1.1mWindowContainerController.stopFreezingScreen



`stopFreezingScreen.java`



public void stopFreezingScreen(boolean force) {

    synchronized(mWindowMap) {

        if (mContainer == null) {

            return;

        }

        if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="

                + mContainer.isHidden() + " freezing=" + mContainer.isFreezingScreen());

        mContainer.stopFreezingScreen(true, force);

    }

}



##### 8.1.1.1 WMS.stopFreezingScreenLocked



`WindowManagerService.java`



@Override

public void stopFreezingScreen() {

     ... ...

    synchronized(mWindowMap) {

        if (mClientFreezingScreen) {

            mClientFreezingScreen = false;

            mLastFinishedFreezeSource = "client";

            final long origId = Binder.clearCallingIdentity();

            try {

       // 详见 8.1.1.2

                stopFreezingDisplayLocked();

            } finally {

                Binder.restoreCallingIdentity(origId);

            }

        }

    }

}



#### 8.1.1.2 stopFreezingDisplayLocked();



`WindowManagerService.java`  

该方法主要功能:



处理屏幕旋转相关逻辑;  

移除冻屏的超时消息;  

屏幕旋转动画的相关操作;  

使能输入事件分发功能;  

`display`冻结时,执行`gc`操作;  

更新当前的屏幕方向;  

向`mH`发送`configuraion`改变的消息



rivate void stopFreezingDisplayLocked() {

if (!mDisplayFrozen) {

    return; //显示没有冻结,则直接返回

}



//往往跟屏幕旋转相关

...



mDisplayFrozen = false;

//从上次冻屏到现在的总时长

mLastDisplayFreezeDuration = (int)(SystemClock.elapsedRealtime() - mDisplayFreezeTime);



//移除冻屏的超时消息

mH.removeMessages(H.APP_FREEZE_TIMEOUT);

mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);



boolean updateRotation = false;

//获取默认的DisplayContent

final DisplayContent displayContent = getDefaultDisplayContentLocked();

final int displayId = displayContent.getDisplayId();

ScreenRotationAnimation screenRotationAnimation =

        mAnimator.getScreenRotationAnimationLocked(displayId);



//屏幕旋转动画的相关操作

if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null

        && screenRotationAnimation.hasScreenshot()) {

    DisplayInfo displayInfo = displayContent.getDisplayInfo();

    boolean isDimming = displayContent.isDimming();

    if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, isDimming)) {

        mExitAnimId = mEnterAnimId = 0;

    }

    //加载动画最大时长为10s

    if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,

            getTransitionAnimationScaleLocked(), displayInfo.logicalWidth,

                displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {

        scheduleAnimationLocked();

    } else {

        screenRotationAnimation.kill();

        mAnimator.setScreenRotationAnimationLocked(displayId, null);

        updateRotation = true;

    }

} else {

    if (screenRotationAnimation != null) {

        screenRotationAnimation.kill();

        mAnimator.setScreenRotationAnimationLocked(displayId, null);

    }

    updateRotation = true;

}

//经过层层调用到InputManagerService服务,IMS服务使能输入事件分发功能

mInputMonitor.thawInputDispatchingLw();



boolean configChanged;

//当display被冻结时不再计算屏幕方向,以避免不连续的状态。

configChanged = updateOrientationFromAppTokensLocked(false);



//display冻结时,执行gc操作

mH.removeMessages(H.FORCE_GC);

mH.sendEmptyMessageDelayed(H.FORCE_GC, 2000);



//mScreenFrozenLock的类型为PowerManager.WakeLock,即释放屏幕冻结的锁

mScreenFrozenLock.release();



if (updateRotation) {

    //更新当前的屏幕方向

    configChanged |= updateRotationUncheckedLocked(false);

}



if (configChanged) {

    //向mH发送configuraion改变的消息

    mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);

}

}




九、 AppErrors.handleAppCrashLocked()

-----------------------------------



`AppErrors.java`



1.当同一进程在时间间隔小于`1分钟`时连续两次`Crash`,则执行的情况下:



#### 对于非`persistent`进程:



*   \[9.1\] mStackSupervisor.handleAppCrashLocked(app);

    

*   \[9.2\] removeProcessLocked(app, false, false, “crash”);

    

*   \[9.3\] mStackSupervisor.resumeTopActivitiesLocked();

    



#### 对于`persistent`进程,则只执行



*   \[9.3\] mStackSupervisor.resumeTopActivitiesLocked();

    



2.否则执行



*   \[9.4\] mStackSupervisor.finishTopCrashedActivitiesLocked(app, reason);

    



boolean handleAppCrashLocked(ProcessRecord app, String reason,

        String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {

    final long now = SystemClock.uptimeMillis();

    final boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),

            Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;



    final boolean procIsBoundForeground =

        (app.curProcState == ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE);



    Long crashTime;

    Long crashTimePersistent;

    boolean tryAgain = false;



    if (!app.isolated) {

        crashTime = mProcessCrashTimes.get(app.info.processName, app.uid);

        crashTimePersistent = mProcessCrashTimesPersistent.get(app.info.processName, app.uid);

    } else {

        crashTime = crashTimePersistent = null;

    }



    // Bump up the crash count of any services currently running in the proc.

     //运行在当前进程中的所有服务的crash次数操作

    for (int i = app.services.size() - 1; i >= 0; i--) {

        // list 所有的Service

        ServiceRecord sr = app.services.valueAt(i);

        // Service 一会自动起来 重置count 为1,否则+1

        if (now > sr.restartTime + ProcessList.MIN_CRASH_INTERVAL) {

            sr.crashCount = 1;

        } else {

            sr.crashCount++;

        }

        // 允许重启正在Crash的服务以及 前台Service,wallpapers 等

        if (sr.crashCount < mService.mConstants.BOUND_SERVICE_MAX_CRASH_RETRY

                && (sr.isForeground || procIsBoundForeground)) {

            tryAgain = true;

        }

    }

    //当同一个进程,连续两次crash的时间间隔小于1分钟时,则认为crash太过于频繁

    if (crashTime != null && now < crashTime + ProcessList.MIN_CRASH_INTERVAL) {



        Slog.w(TAG, "Process " + app.info.processName

                + " has crashed too many times: killing!");

        EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,

                app.userId, app.info.processName, app.uid);

          //【见小节9.1】

        mService.mStackSupervisor.handleAppCrashLocked(app);

        if (!app.persistent) {



            //不再重启非persistent进程,除非用户显式地调用

            EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.userId, app.uid,

                    app.info.processName);

            if (!app.isolated) {

                //将当前app加入到mBadProcesses

                mBadProcesses.put(app.info.processName, app.uid,

                        new BadProcessInfo(now, shortMsg, longMsg, stackTrace));

                mProcessCrashTimes.remove(app.info.processName, app.uid);

            }

            app.bad = true;

            app.removed = true;

            //移除非persistent 进程的所有服务,保证不再重启【见小节9.2】

            mService.removeProcessLocked(app, false, tryAgain, "crash");

             //恢复最顶部的Activity【见小节9.3】

            mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();

            if (!showBackground) {

                return false;

            }

        }

        mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();

    } else {

         //此处reason="force-crash"【见小节9.4】  

        final TaskRecord affectedTask =

                mService.mStackSupervisor.finishTopRunningActivityLockedfinishTopRunningActivityLocked(app, reason);

        if (data != null) {

            data.task = affectedTask;

        }

        if (data != null && crashTimePersistent != null

                && now < crashTimePersistent + ProcessList.MIN_CRASH_INTERVAL) {

            data.repeating = true;

        }

    }



    if (data != null && tryAgain) {

        data.isRestartableForService = true;

    }



    //当桌面Home 进程 应用crash,并且被三方app所取代,那么需要清空桌面应用的偏爱选项。

    final ArrayList<ActivityRecord> activities = app.activities;

    if (app == mService.mHomeProcess && activities.size() > 0

            && (mService.mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {

        for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {

            final ActivityRecord r = activities.get(activityNdx);

            if (r.isActivityTypeHome()) {

                Log.i(TAG, "Clearing package preferred activities from " + r.packageName);

                try {

                     //清空偏爱应用

                    ActivityThread.getPackageManager()

                            .clearPackagePreferredActivities(r.packageName);

                } catch (RemoteException c) {

                    // pm is in same process, this will never happen.

                }

            }

        }

    }



    if (!app.isolated) {

         //无法记录孤立进程的crash时间点,由于他们并没有一个固定身份.

        mProcessCrashTimes.put(app.info.processName, app.uid, now);

        mProcessCrashTimesPersistent.put(app.info.processName, app.uid, now);

    }

     //当app存在crash的handler,那么交给其处理

    if (app.crashHandler != null) mService.mHandler.post(app.crashHandler);

    return true;

}



9.1 ASS.handleAppCrashLocked

============================



`ActivityStackSupervisor.java`



void handleAppCrashLocked(ProcessRecord app) {

    for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {

        final ActivityDisplay display = mActivityDisplays.valueAt(displayNdx);

        for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {

            final ActivityStack stack = display.getChildAt(stackNdx);

            //调用ActivityStack【见小节9.1.1】

            stack.handleAppCrashLocked(app);

        }

    }

}



9.1.1 AS.handleAppCrashLocked

-----------------------------



`ActivityStack.java`



void handleAppCrashLocked(ProcessRecord app) {

    for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {

        final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;

        for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {

            final ActivityRecord r = activities.get(activityNdx);

            if (r.app == app) {

                Slog.w(TAG, "  Force finishing activity "

                        + r.intent.getComponent().flattenToShortString());

                // Force the destroy to skip right to removal.

                r.app = null;

                mWindowManager.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE,

                        false /* alwaysKeepCurrent */);

                //结束当前activity

                finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,

                        "handleAppCrashedLocked");

            }

        }

    }

}



这里的`mTaskHistory`数据类型为`ArrayList`,记录着所有先前的后台`activities`。遍历所有`activities`,找到位于该`ProcessRecord`的所有`ActivityRecord`,并结束该`Acitivity`。



9.2 AMS.removeProcessLocked

---------------------------



`ActivityManagerService.java`



@GuardedBy("this")

boolean removeProcessLocked(ProcessRecord app,

        boolean callerWillRestart, boolean allowRestart, String reason) {

    final String name = app.processName;

    final int uid = app.uid;

    if (DEBUG_PROCESSES) Slog.d(TAG_PROCESSES,

        "Force removing proc " + app.toShortString() + " (" + name + "/" + uid + ")");



    ProcessRecord old = mProcessNames.get(name, uid);

    if (old != app) {

        // This process is no longer active, so nothing to do.

        Slog.w(TAG, "Ignoring remove of inactive process: " + app);

        return false;

    }

    //从mProcessNames移除该进程

    removeProcessNameLocked(name, uid);

    if (mHeavyWeightProcess == app) {

        mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,

                mHeavyWeightProcess.userId, 0));

        mHeavyWeightProcess = null;

    }

    boolean needRestart = false;

    if ((app.pid > 0 && app.pid != MY_PID) || (app.pid == 0 && app.pendingStart)) {

        int pid = app.pid;

        if (pid > 0) {

            synchronized (mPidsSelfLocked) {

                mPidsSelfLocked.remove(pid);

                mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);

            }

            mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);

            if (app.isolated) {

                mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid);

                getPackageManagerInternalLocked().removeIsolatedUid(app.uid);

            }

        }

        boolean willRestart = false;

          //对于非孤立的persistent进程设置成可重启flags

        if (app.persistent && !app.isolated) {

            if (!callerWillRestart) {

                willRestart = true;

            } else {

                needRestart = true;

            }

        }

          // 杀进程【9.2.1】

        app.kill(reason, true);

          //移除进程并清空该进程相关联的activity/service等组件 【9.2.2】

        handleAppDiedLocked(app, willRestart, allowRestart);

        if (willRestart) {

            //此处willRestart=false,不进入该分支

            removeLruProcessLocked(app);

            addAppLocked(app.info, null, false, null /* ABI override */);

        }

    } else {

        mRemovedProcesses.add(app);

    }



    return needRestart;

}



*   `mProcessNames`数据类型为`ProcessMap`,这是以进程名为`key`,记录着所有的`ProcessRecord`信息

    

*   `mPidsSelfLocked`数据类型为`SparseArray`,这是以`pid`为`key`,记录着所有的`ProcessRecord`信息。该对象的同步保护是通过自身锁,而非全局`ActivityManager`锁。

    



9.2.1 app.kill

--------------



`ProcessRecord.java]`



void kill(String reason, boolean noisy) {

    //通过am 杀进程

    if (!killedByAm) {



        // 如果不想让am kill 当前进程,可以在这地方跳过

        if (!mService.mAmsExt.shouldKilledByAm(this.processName, reason)) {

            return;

        }



        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "kill");

        if (mService != null && (noisy || info.uid == mService.mCurOomAdjUid)) {

            mService.reportUidInfoMessageLocked(TAG,

                    "Killing " + toShortString() + " (adj " + setAdj + "): " + reason,

                    info.uid);

        }

        if (pid > 0) {

            EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason);

            // pid > 0 杀进程以及所在的进程组

            Process.killProcessQuiet(pid);

            ActivityManagerService.killProcessGroup(uid, pid);

        } else {

            pendingStart = false;

        }

        if (!persistent) {

            killed = true;

            killedByAm = true;

        }

        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

    }

}



此处reason为“crash”.



9.2.2 handleAppDiedLocked

-------------------------



`ActivityManagerService.java`



// 通过AM 移除当前存在的进程,不存在,则清除当前进程包含的所有内容

@GuardedBy("this")

private final void handleAppDiedLocked(ProcessRecord app,

        boolean restarting, boolean allowRestart) {

    int pid = app.pid;

    final boolean clearLaunchStartTime = !restarting && app.removed && app.foregroundActivities;

    //清除应用中service/receiver/ContentProvider信息

    boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1,

            false /*replacingPid*/);

    if (!kept && !restarting) {

        // 根据LRU 算法移除 app 进程

        removeLruProcessLocked(app);

        if (pid > 0) {

        //从list 移除对应的pid        

            ProcessList.remove(pid);

        }

    }



    if (mProfileProc == app) {

        clearProfilerLocked();

    }



    //清除应用中activity相关信息

    boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app);



    app.clearRecentTasks();



    app.activities.clear();



    if (app.instr != null) {

        Slog.w(TAG, "Crash of app " + app.processName

              + " running instrumentation " + app.instr.mClass);

        Bundle info = new Bundle();

        info.putString("shortMsg", "Process crashed.");

        finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);

    }



    mWindowManager.deferSurfaceLayout();

    try {

        if (!restarting && hasVisibleActivities

                && !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {

            // 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.

   

            mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);

        }

    } finally {

        mWindowManager.continueSurfaceLayout();

    }



    // TODO (b/67683350)

    // When an app process is removed, activities from the process may be relaunched. In the

    // case of forceStopPackageLocked the activities are finished before any window is drawn,

    // and the launch time is not cleared. This will be incorrectly used to calculate launch

    // time for the next launched activity launched in the same windowing mode.

    if (clearLaunchStartTime) {

        final LaunchTimeTracker.Entry entry = mStackSupervisor

                .getLaunchTimeTracker().getEntry(mStackSupervisor.getWindowingMode());

        if (entry != null) {

            entry.mLaunchStartTime = 0;

        }

    }

}



9.3 ASS.resumeFocusedStackTopActivityLocked

===========================================



`ActivityStackSupervisor.java`



boolean resumeFocusedStackTopActivityLocked() {

    return resumeFocusedStackTopActivityLocked(null, null, null);

}

最后

分享一份NDK基础开发资料

详解:Linux网络虚拟化技术

分享内容包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

ibleActivities

                && !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {

            // 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.

   

            mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);

        }

    } finally {

        mWindowManager.continueSurfaceLayout();

    }



    // TODO (b/67683350)

    // When an app process is removed, activities from the process may be relaunched. In the

    // case of forceStopPackageLocked the activities are finished before any window is drawn,

    // and the launch time is not cleared. This will be incorrectly used to calculate launch

    // time for the next launched activity launched in the same windowing mode.

    if (clearLaunchStartTime) {

        final LaunchTimeTracker.Entry entry = mStackSupervisor

                .getLaunchTimeTracker().getEntry(mStackSupervisor.getWindowingMode());

        if (entry != null) {

            entry.mLaunchStartTime = 0;

        }

    }

}



9.3 ASS.resumeFocusedStackTopActivityLocked

===========================================



`ActivityStackSupervisor.java`



boolean resumeFocusedStackTopActivityLocked() {

    return resumeFocusedStackTopActivityLocked(null, null, null);

}

最后

分享一份NDK基础开发资料

[外链图片转存中…(img-E6lG4KM6-1715678730506)]

分享内容包括不限于高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter等全方面的Android进阶实践技术;希望能帮助到大家,也节省大家在网上搜索资料的时间来学习,也可以分享动态给身边好友一起学习!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 25
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值