Binder死亡通知

Android系统中当应用进程被kill杀掉时,底层会有该进程的Binder服务端的死亡回调通知。在应用进程创建的过程中有一个attachApplicationLocked方法的过程中便会创建死亡通知。

[-> ActivityManagerService.java]

private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
    try {
        //创建binder死亡通知
        AppDeathRecipient adr = new AppDeathRecipient(
                app, pid, thread);
        thread.asBinder().linkToDeath(adr, 0);
        app.deathRecipient = adr;
    } catch (RemoteException e) {
        app.resetPackageList(mProcessStats);
        startProcessLocked(app, "link fail", processName);
        return false;
    }
    ...
}

当binder服务端挂了之后,便会通过binder的DeathRecipient来通知AMS进行相应的清理收尾工作。发生crash的进程会被系统kill掉,那么当该进程会杀,则会回调到binderDied()方法。

1. binderDied

[-> ActivityManagerService.java]

private final class AppDeathRecipient implements IBinder.DeathRecipient {
    public void binderDied() {
        synchronized(ActivityManagerService.this) {
            appDiedLocked(mApp, mPid, mAppThread, true);//【见小节2】
        }
    }
}

2. appDiedLocked

final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread,
        boolean fromBinderDied) {
    ...
    if (!app.killed) {
        if (!fromBinderDied) {
            Process.killProcessQuiet(pid);
        }
        killProcessGroup(app.info.uid, pid);
        app.killed = true;
    }
 
    // Clean up already done if the process has been re-started.
    if (app.pid == pid && app.thread != null &&
            app.thread.asBinder() == thread.asBinder()) {
        boolean doLowMem = app.instrumentationClass == null;
        boolean doOomAdj = doLowMem;
        if (!app.killedByAm) {
            mAllowLowerMemLevel = true;
        } else {
            mAllowLowerMemLevel = false;
            doLowMem = false;
        }
        //【见小节3】
        handleAppDiedLocked(app, false, true);
 
        if (doOomAdj) {
            updateOomAdjLocked();
        }
        if (doLowMem) {
            doLowMemReportIfNeededLocked(app);
        }
    }
    ...
}

3 handleAppDiedLocked

[-> ActivityManagerService.java]

private final void handleAppDiedLocked(ProcessRecord app,
        boolean restarting, boolean allowRestart) {
    int pid = app.pid;
    //清理应用程序service, BroadcastReceiver, ContentProvider相关信息【见小节4】
    boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1);
 
    if (!kept && !restarting) {
        removeLruProcessLocked(app);
        if (pid > 0) {
            ProcessList.remove(pid);
        }
    }
 
    //清理activity相关信息
    boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app);
    app.activities.clear();
    ...
    //恢复栈顶第一个非finish的activity
    if (!restarting && hasVisibleActivities && !mStackSupervisor.resumeTopActivitiesLocked()) {
       mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
   }
}

4 cleanUpApplicationRecordLocked

该方法清理应用程序service, BroadcastReceiver, ContentProvider,process相关信息,为了便于说明将该方法划分为4个部分讲解

4.1 清理service

参数restarting = false, allowRestart =true, index =-1

private final boolean cleanUpApplicationRecordLocked(ProcessRecord app,
        boolean restarting, boolean allowRestart, int index) {
    ...
    mProcessesToGc.remove(app);
    mPendingPssProcesses.remove(app);
 
    //如果存在,则清除crash/anr/wait对话框
    if (app.crashDialog != null && !app.forceCrashReport) {
        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(mProcessStats);
    app.unlinkDeathRecipient(); //解除app的死亡通告
    app.makeInactive(mProcessStats);
    app.waitingToKill = null;
    app.forcingToForeground = null;
    //将app移除前台进程
    updateProcessForegroundLocked(app, false, false);
    app.foregroundActivities = false;
    app.hasShownUi = false;
    app.treatLikeActivity = false;
    app.hasAboveClient = false;
    app.hasClientActivities = false;
    //清理service信息,这个过程也比较复杂,后续再展开
    mServices.killServicesLocked(app, allowRestart);
    boolean restart = false;
}
  • mProcessesToGc:记录着需要尽快执行gc的进程列表
  • mPendingPssProcesses:记录着需要收集内存信息的进程列表

4.2 清理ContentProvider

private final boolean cleanUpApplicationRecordLocked(...) {
    ...
    for (int i = app.pubProviders.size() - 1; i >= 0; i--) {
        //获取该进程已发表的ContentProvider
        ContentProviderRecord cpr = app.pubProviders.valueAt(i);
        final boolean always = app.bad || !allowRestart;
        //ContentProvider服务端被杀,则client端进程也会被杀
        boolean inLaunching = removeDyingProviderLocked(app, cpr, always);
        if ((inLaunching || always) && cpr.hasConnectionOrHandle()) {
            restart = true; //需要重启
        }
 
        cpr.provider = null;
        cpr.proc = null;
    }
    app.pubProviders.clear();
 
    //处理正在启动并且是有client端正在等待的ContentProvider
    if (cleanupAppInLaunchingProvidersLocked(app, false)) {
        restart = true;
    }
 
    //取消已连接的ContentProvider的注册
    if (!app.conProviders.isEmpty()) {
        for (int i = app.conProviders.size() - 1; i >= 0; i--) {
            ContentProviderConnection conn = app.conProviders.get(i);
            conn.provider.connections.remove(conn);
 
            stopAssociationLocked(app.uid, app.processName, conn.provider.uid,
                    conn.provider.name);
        }
        app.conProviders.clear();
    }

4.3 清理BroadcastReceiver

private final boolean cleanUpApplicationRecordLocked(...) {
    ...
    skipCurrentReceiverLocked(app);
 
    // 取消注册的广播接收者
    for (int i = app.receivers.size() - 1; i >= 0; i--) {
        removeReceiverLocked(app.receivers.valueAt(i));
    }
    app.receivers.clear();
}

4.4 清理Process

private final boolean cleanUpApplicationRecordLocked(...) {
    ...
    //当app正在备份时的处理方式
    if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
        ...
        IBackupManager bm = IBackupManager.Stub.asInterface(
                ServiceManager.getService(Context.BACKUP_SERVICE));
        bm.agentDisconnected(app.info.packageName);
    }
 
    for (int i = mPendingProcessChanges.size() - 1; i >= 0; i--) {
        ProcessChangeItem item = mPendingProcessChanges.get(i);
        if (item.pid == app.pid) {
            mPendingProcessChanges.remove(i);
            mAvailProcessChanges.add(item);
        }
    }
    mUiHandler.obtainMessage(DISPATCH_PROCESS_DIED, app.pid, app.info.uid, null).sendToTarget();
 
    if (!app.persistent || app.isolated) {
        removeProcessNameLocked(app.processName, app.uid);
        if (mHeavyWeightProcess == app) {
            mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
                    mHeavyWeightProcess.userId, 0));
            mHeavyWeightProcess = null;
        }
    } else if (!app.removed) {
        //对于persistent应用,则需要重启
        if (mPersistentStartingProcesses.indexOf(app) < 0) {
            mPersistentStartingProcesses.add(app);
            restart = true;
        }
    }
 
    //mProcessesOnHold:记录着试图在系统ready之前就启动的进程。
    //在那时并不启动这些进程,先记录下来,等系统启动完成则启动这些进程。
    mProcessesOnHold.remove(app);
 
    if (app == mHomeProcess) {
        mHomeProcess = null;
    }
    if (app == mPreviousProcess) {
        mPreviousProcess = null;
    }
 
    if (restart && !app.isolated) {
        //仍有组件需要运行在该进程中,因此重启该进程
        if (index < 0) {
            ProcessList.remove(app.pid);
        }
        addProcessNameLocked(app);
        startProcessLocked(app, "restart", app.processName);
        return true;
    } else if (app.pid > 0 && app.pid != MY_PID) {
        //移除该进程相关信息
        boolean removed;
        synchronized (mPidsSelfLocked) {
            mPidsSelfLocked.remove(app.pid);
            mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
        }
        app.setPid(0);
    }
    return false;
}

对于需要重启进程的情形有:

  • mLaunchingProviders:记录着存在client端等待的ContentProvider。应用当前正在启动中,当ContentProvider一旦发布则将该ContentProvider将从该list去除。当进程包含这样的ContentProvider,则需要重启进程。
  • mPersistentStartingProcesses:记录着试图在系统ready之前就启动的进程。在那时并不启动这些进程,先记录下来,等系统启动完成则启动这些进程。当进程属于这种类型也需要重启。

5. 小结

当crash进程执行kill操作后,进程被杀。此时需要掌握binder 死亡通知原理,由于Crash进程中拥有一个Binder服务端ApplicationThread,而应用进程在创建过程调用attachApplicationLocked(),从而attach到system_server进程,在system_server进程内有一个ApplicationThreadProxy,这是相对应的Binder客户端。当Binder服务端ApplicationThread所在进程(即Crash进程)挂掉后,则Binder客户端能收到相应的死亡通知,从而进入binderDied流程。

binder_died

更多参考:https://blog.csdn.net/wxlinwzl/article/details/77749619

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值