文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

ActivityManagerService广播并行发送与串行发送怎么实现

2023-07-05 07:57

关注

这篇文章主要讲解了“ActivityManagerService广播并行发送与串行发送怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“ActivityManagerService广播并行发送与串行发送怎么实现”吧!

"并行"广播的发送

本文以 ActivityManagerService之广播(1): 注册与发送 为基础,分析“串行”和“并行”广播的发送流程,并介绍广播 ANR 的原理。

// 1. 获取广播队列final BroadcastQueue queue = broadcastQueueForIntent(intent);// 2. 创建广播记录BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,        callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,        requiredPermissions, excludedPermissions, appOp, brOptions, registeredReceivers,        resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId,        allowBackgroundActivityStarts, backgroundActivityStartsToken,        timeoutExempt);// 3. 广播记录加入到并行队列中queue.enqueueParallelBroadcastLocked(r);// 4. 调度发送广播queue.scheduleBroadcastsLocked();

第3步,把广播记录保存到并行队列中

// BroadcastQueue.javapublic void enqueueParallelBroadcastLocked(BroadcastRecord r) {    // mParallelBroadcasts 类型为 ArrayList<BroadcastRecord>    mParallelBroadcasts.add(r);    enqueueBroadcastHelper(r);}

第4步,调度发送广播,最终会调用如下方法

// BroadcastQueue.java// 此时,参数 fromMsg 为 true,skipOomAdj 为 falsefinal void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {    BroadcastRecord r;    mService.updateCpuStats();    if (fromMsg) {        mBroadcastsScheduled = false;    }    // 遍历"并行"广播队列    while (mParallelBroadcasts.size() > 0) {        r = mParallelBroadcasts.remove(0);        r.dispatchTime = SystemClock.uptimeMillis();        r.dispatchClockTime = System.currentTimeMillis();        final int N = r.receivers.size();        for (int i=0; i<N; i++) {            Object target = r.receivers.get(i);            // 广播发送给动态接收器            deliverToRegisteredReceiverLocked(r,                    (BroadcastFilter) target, false, i);        }        addBroadcastToHistoryLocked(r);    }    // ... 省略"串行"广播的发送 ...}

虽然名为“并行”广播,但是仍然是从队列取出广播,然后逐个发送给动态接收器。很显然,这里的行为与“并行”的含义并不一致?那么广播的“并行”发送究竟是什么意思?

接着看“并行”广播如何发送给动态接收器的

private void deliverToRegisteredReceiverLocked(BroadcastRecord r,        BroadcastFilter filter, boolean ordered, int index) {    // ... 省略一大堆的权限或者异常检测 ...    // 一个广播可能有多个接收者,因此需要一个数组来保存发送的状态    r.delivery[index] = BroadcastRecord.DELIVERY_DELIVERED;    // ordered 目前为 false    if (ordered) {        // ...        }    } else if (filter.receiverList.app != null) {        // 马上要发送广播给接收方,因此要暂时解冻接收方的进程        mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(filter.receiverList.app);    }    try {        if (filter.receiverList.app != null && filter.receiverList.app.isInFullBackup()) {            // ... 处于备份状态中 ...        } else {            r.receiverTime = SystemClock.uptimeMillis();            // 保存允许从后台启动activity的token            maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);            // 添加到省电模式白名单中            maybeScheduleTempAllowlistLocked(filter.owningUid, r, r.options);            // 执行广播的发送            performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,                    new Intent(r.intent), r.resultCode, r.resultData,                    r.resultExtras, r.ordered, r.initialSticky, r.userId);            // parallel broadcasts are fire-and-forget, not bookended by a call to            // finishReceiverLocked(), so we manage their activity-start token here            if (filter.receiverList.app != null                    && r.allowBackgroundActivityStarts && !r.ordered) {                postActivityStartTokenRemoval(filter.receiverList.app, r);            }        }        // ordered 目前为 false        if (ordered) {            r.state = BroadcastRecord.CALL_DONE_RECEIVE;        }    } catch (RemoteException e) {        // ...    }}

抛开一些细节,直接看 performReceiveLocked()

// BroadcastQueue.javavoid performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,        Intent intent, int resultCode, String data, Bundle extras,        boolean ordered, boolean sticky, int sendingUser)        throws RemoteException {    // 动态广播接收器的进程,应该是存在的    if (app != null) {        final IApplicationThread thread = app.getThread();        if (thread != null) {            try {                // 发送广播给接收方进程                thread.scheduleRegisteredReceiver(receiver, intent, resultCode,                        data, extras, ordered, sticky, sendingUser,            } catch (RemoteException ex) {               // ...            }        } else {            throw new RemoteException("app.thread must not be null");        }    } else {        // ...    }}

很简单,就是通过进程 attach 的 IApplicationThread 接口,发送广播给进程。这个过程,暂时先不分析,后面会分析到。

那么,现在来回答一下,何为“并行”广播?其实这个答案,我也是对比了串行广播的发送过程,才得出来的。所谓的"并行"发送,实际上就是把广播逐个发送给动态接收器,但是不需要等待前一个接收器反馈处理结果,就可以发送下一个。而“串行”广播的发送,是需要等待前一个广播接收器反馈处理结果后,才能调度发送下一个广播。

“串行”广播的发送

// 1.获取广播队列BroadcastQueue queue = broadcastQueueForIntent(intent);// 2.创建广播记录BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,        callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,        requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,        receivers, resultTo, resultCode, resultData, resultExtras,        ordered, sticky, false, userId, allowBackgroundActivityStarts,        backgroundActivityStartsToken, timeoutExempt);// 3.广播记录加入到串行队列中queue.enqueueOrderedBroadcastLocked(r);// 4.调度发送广播queue.scheduleBroadcastsLocked();

第3步,广播加入到串行队列中

// BroadcastQueue.javapublic void enqueueOrderedBroadcastLocked(BroadcastRecord r) {    mDispatcher.enqueueOrderedBroadcastLocked(r);    enqueueBroadcastHelper(r);}
// BroadcastDispatcher.javavoid enqueueOrderedBroadcastLocked(BroadcastRecord r) {    mOrderedBroadcasts.add(r);}

并行发送的广播保存到 BroadcastQueue#mParallelBroadcasts 中,而串行发送的广播保存到 BroadcastDispatcher#mOrderedBroadcasts 中,为何要这样设计呢?有兴趣的读者可以研究下。

第4步,“串行”广播的调度发送,仍然使用的是 processNextBroadcastLocked() 方法,但是代码量是非常的大,下面将把函数分段解析。

processNextBroadcastLocked() 函数有400多行代码,这个函数里有很多东西都可以抽出来的,但是随着版本的更新,这块代码一直没有优化过。

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {    BroadcastRecord r;    mService.updateCpuStats();    if (fromMsg) {        mBroadcastsScheduled = false;    }    // 把并行广播发送给动态接收器    while (mParallelBroadcasts.size() > 0) {        // ...    }    // 1. 处理 receiver 进程正在启动的情况    if (mPendingBroadcast != null) {        // 检测 receiver 进程是否死亡        boolean isDead;        if (mPendingBroadcast.curApp.getPid() > 0) {            synchronized (mService.mPidsSelfLocked) {                ProcessRecord proc = mService.mPidsSelfLocked.get(                        mPendingBroadcast.curApp.getPid());                isDead = proc == null || proc.mErrorState.isCrashing();            }        } else {            final ProcessRecord proc = mService.mProcessList.getProcessNamesLOSP().get(                    mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid);            isDead = proc == null || !proc.isPendingStart();        }        if (!isDead) {            // 进程仍然存活,结束此次广播的处理流程,继续等待            // 等待什么呢?等待广播进程起来,并与 AMS 完成 attach application            // 在 attach application 的过程中,会完成广播的发送            return;        } else {            // 进程死亡,继续处理下一个广播            mPendingBroadcast.state = BroadcastRecord.IDLE;            mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;            mPendingBroadcast = null;        }    }

当发送一个广播给 receiver 时,如果 receiver 进程没有启动,那么会先 fork 一个 receiver 进程,然后用 mPendingBroadcast 保存待发送的广播。当 receiver 进程起来的时候,会与 AMS 执行 attach application 过程,在这个过程中,会自动把 mPendingBroadcast 保存的广播发送给 receiver 进程。

因此,这里检测到 mPendingBroadcast 不为 null 时,那么 receiver 进程肯定在启动中,只要 receiver 进程没有死亡,就什么也不用做,因为广播会自动发送给 receiver 进程。

接着看下一步的处理

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {    // ...    // 把并行广播发送给动态接收器    while (mParallelBroadcasts.size() > 0) {        // ...    }    // 1. 处理 receiver 进程正在启动的情况    if (mPendingBroadcast != null) {        // ...    }    boolean looped = false;    // 2. 通过 do-while 循环,找到一个现在可以处理的广播    do {        final long now = SystemClock.uptimeMillis();        // 获取一个待处理的广播        r = mDispatcher.getNextBroadcastLocked(now);        if (r == null) {            // ... 没有广播需要处理 ...            return;        }        boolean forceReceive = false;        // 处理严重超时的广播,有两种情况        // 一种情况是,在系统还没有起来前,发送的广播得不到执行,发生严重超时        // 另外一种情况是,在系统起来后,有一些超时豁免的广播,发生了严重超时        int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;        if (mService.mProcessesReady && !r.timeoutExempt && r.dispatchTime > 0) {            if ((numReceivers > 0) &&                    (now > r.dispatchTime + (2 * mConstants.TIMEOUT * numReceivers))) {                broadcastTimeoutLocked(false); // forcibly finish this broadcast                forceReceive = true;                r.state = BroadcastRecord.IDLE;            }        }        if (r.state != BroadcastRecord.IDLE) {            return;        }        // 当前广播因为某种原因,终止处理,然后处理下一个广播         if (r.receivers == null || r.nextReceiver >= numReceivers                || r.resultAbort || forceReceive) {            // ...            // 通知 BroadcastDispatcher ,不处理这个广播了            mDispatcher.retireBroadcastLocked(r);            r = null;            looped = true;            // 下一次循环,获取下一个广播来处理            continue;        }        // 处理推迟发送广播的情况        if (!r.deferred) {            final int receiverUid = r.getReceiverUid(r.receivers.get(r.nextReceiver));            if (mDispatcher.isDeferringLocked(receiverUid)) {                // ...                // 保存推迟发送的广播                mDispatcher.addDeferredBroadcast(receiverUid, defer);                r = null;                looped = true;                // 下一次循环时,获取下一个广播来处理                continue;            }        }    } while (r == null);

先从整体看,通过一个 do-while 循环,最终是为了找到下一个处理的广播。为何要用一个循环来寻找呢? 因为广播可能没有接收器,或者已经严重超时,又或者广播需要推迟发送。所以要通过一个循环,找到一个能立即发送的广播。

由于本文主要是为了分析广播发送的整体流程,对于有些细节,只做注释而不做细致分析。需要深入研究的读者,可以在本文的基础上继续分析。

继续接着看下一步

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {    BroadcastRecord r;    mService.updateCpuStats();    if (fromMsg) {        mBroadcastsScheduled = false;    }    // 把并行广播发送给动态接收器    while (mParallelBroadcasts.size() > 0) {        // ...    }    // 1. 处理 receiver 进程正在启动的情况    if (mPendingBroadcast != null) {        // ...    }    boolean looped = false;    // 2. 通过 do-while 循环,找到一个现在可以处理的广播    do {        final long now = SystemClock.uptimeMillis();        // 获取一个待处理的广播        r = mDispatcher.getNextBroadcastLocked(now);        // ...    } while (r == null);    // 走到这里,表示已经获取了一个现在可以处理的广播    int recIdx = r.nextReceiver++;    // 3. 在发送广播之前,先发送一个超时消息    r.receiverTime = SystemClock.uptimeMillis();    if (recIdx == 0) {        // 在广播开始发送给第一个接收器时,记录发送的时间        r.dispatchTime = r.receiverTime;        r.dispatchClockTime = System.currentTimeMillis();    }    if (! mPendingBroadcastTimeoutMessage) {        long timeoutTime = r.receiverTime + mConstants.TIMEOUT;        setBroadcastTimeoutLocked(timeoutTime);    }

在广播发送给一个 receiver 之前,会先发送一个超时消息。从广播准备发送给一个 receiver 算起,到 receiver 处理完广播,并反馈给 AMS,如果这个时间段超过了一个时间阈值,就会引发 ANR。触发 ANR 的代码设计非常巧妙,后面会具体分析这个过程。

接着看下一步

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {    // ...    // 把并行广播发送给动态接收器    while (mParallelBroadcasts.size() > 0) {        // ...    }    // 1. 处理 receiver 进程正在启动的情况    if (mPendingBroadcast != null) {        // ...    }    boolean looped = false;    // 2. 通过 do-while 循环,找到一个现在可以处理的广播    do {        // ...    } while (r == null);    int recIdx = r.nextReceiver++;    // ...    // 3. 在发送广播之前,先发送一个超时消息    // 当广播处理超时时,会触发 ANR    if (! mPendingBroadcastTimeoutMessage) {        long timeoutTime = r.receiverTime + mConstants.TIMEOUT;        setBroadcastTimeoutLocked(timeoutTime);    }    final BroadcastOptions brOptions = r.options;    // 4. 获取一个 receiver    final Object nextReceiver = r.receivers.get(recIdx);    // 5. 如果这个接收器是动态接收器,先把广播发送给它    // 注意,这里处理的是有序广播发送给动态接收器的情况    if (nextReceiver instanceof BroadcastFilter) {        BroadcastFilter filter = (BroadcastFilter)nextReceiver;        // 发送广播给动态接收器        deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);        if (r.receiver == null || !r.ordered) {            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["                    + mQueueName + "]: ordered="                    + r.ordered + " receiver=" + r.receiver);            r.state = BroadcastRecord.IDLE;            scheduleBroadcastsLocked();        } else {            if (filter.receiverList != null) {                maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);            }        }        // 注意,把广播发送给 动态receiver 后,直接返回        return;    }

现在一切就绪,那么开始获取一个 receiver,当这个 receiver 是一个动态接收器时,直接发送广播给它,这个发送过程前面已经分析过。

注意,这里处理的情况是,把有序广播发送给动态接收器。并且发送完成后,直接 return, 也就是结束了此次广播的发送流程。

一个广播可能有多个接收器,为何这里只发送给一个动态接收器,就直接返回了? 这就是从“串行”广播的本质,需要等待当前的广播接收器处理完广播,并返回结果后,才能把广播发送给下一个广播接收器。

接着看下一步

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {    // ...    // 把并行广播发送给动态接收器    while (mParallelBroadcasts.size() > 0) {        // ...    }    // 1. 处理 receiver 进程正在启动的情况    if (mPendingBroadcast != null) {        // ...    }    boolean looped = false;    // 2. 通过 do-while 循环,找到一个现在可以处理的广播    do {        final long now = SystemClock.uptimeMillis();        // 获取一个待处理的广播        r = mDispatcher.getNextBroadcastLocked(now);        // ...    } while (r == null);    // 走到这里,表示已经获取了一个现在可以处理的广播    int recIdx = r.nextReceiver++;    // 3. 在发送广播之前,先发送一个超时消息    r.receiverTime = SystemClock.uptimeMillis();    // ...    if (! mPendingBroadcastTimeoutMessage) {        long timeoutTime = r.receiverTime + mConstants.TIMEOUT;        setBroadcastTimeoutLocked(timeoutTime);    }    final BroadcastOptions brOptions = r.options;    // 4. 获取一个 receiver    final Object nextReceiver = r.receivers.get(recIdx);    // 5. 如果这个接收器是动态接收器,先把广播发送给它    // 注意,这里处理的是有序广播发送给动态接收器的情况    if (nextReceiver instanceof BroadcastFilter) {        // ...        return;    }    // 走到这里,表示当前的广播接收器,是静态接收器    // 获取静态接收器的信息    ResolveInfo info =        (ResolveInfo)nextReceiver;    ComponentName component = new ComponentName(            info.activityInfo.applicationInfo.packageName,            info.activityInfo.name);    boolean skip = false;    // 6. 检测是否不需要把广播发送给静态接收器    // ... 省略一大堆的检测代码 ...    String targetProcess = info.activityInfo.processName;    ProcessRecord app = mService.getProcessRecordLocked(targetProcess,            info.activityInfo.applicationInfo.uid);    if (!skip) {        // 检测是否允许把广播发送给静态接收器        final int allowed = mService.getAppStartModeLOSP(                info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,                info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, false);        // 例如,大于等于 O+ 版本的 app ,不允许广播发送给静态接收器        if (allowed != ActivityManager.APP_START_MODE_NORMAL) {            // ephemeral app 会返回这个模式            if (allowed == ActivityManager.APP_START_MODE_DISABLED) {                skip = true;            } else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)                    || (r.intent.getComponent() == null                        && r.intent.getPackage() == null                        && ((r.intent.getFlags()                                & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0)                        && !isSignaturePerm(r.requiredPermissions))) {                // 打破以上任意一个条件,即可把广播发送给静态接收器                mService.addBackgroundCheckViolationLocked(r.intent.getAction(),                        component.getPackageName());                skip = true;            }        }    }    // 跳过当前广播的发送    if (skip) {        // ...        return;    }

如果这个 reciever 是静态接收器,那么在把广播发送给它之前,首先得进行一大堆的检测。最常见的就是权限,但是这里展示了一段 Android O+ 限制广播发送给静态接收器的限制,有兴趣的读者可以详细分析。

接着看下一步

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {    // ...    // 把并行广播发送给动态接收器    while (mParallelBroadcasts.size() > 0) {        // ...    }    // 1. 处理 receiver 进程正在启动的情况    if (mPendingBroadcast != null) {        // ...    }    boolean looped = false;    // 2. 通过 do-while 循环,找到一个现在可以处理的广播    do {        final long now = SystemClock.uptimeMillis();        // 获取一个待处理的广播        r = mDispatcher.getNextBroadcastLocked(now);        // ...    } while (r == null);    // 走到这里,表示已经获取了一个现在可以处理的广播    int recIdx = r.nextReceiver++;    // 3. 在发送广播之前,先发送一个超时消息    r.receiverTime = SystemClock.uptimeMillis();    // ...    if (! mPendingBroadcastTimeoutMessage) {        long timeoutTime = r.receiverTime + mConstants.TIMEOUT;        setBroadcastTimeoutLocked(timeoutTime);    }    final BroadcastOptions brOptions = r.options;    // 4. 获取一个 receiver    final Object nextReceiver = r.receivers.get(recIdx);    // 5. 如果这个接收器是动态接收器,先把广播发送给它    // 注意,这里处理的是有序广播发送给动态接收器的情况    if (nextReceiver instanceof BroadcastFilter) {        // ...        return;    }    // 走到这里,表示当前的广播接收器,是静态接收器    ResolveInfo info =        (ResolveInfo)nextReceiver;    ComponentName component = new ComponentName(            info.activityInfo.applicationInfo.packageName,            info.activityInfo.name);    boolean skip = false;    // 6. 检测是否不需要把广播发送给静态接收器    // ... 省略一大堆的检测代码 ...    String targetProcess = info.activityInfo.processName;    ProcessRecord app = mService.getProcessRecordLocked(targetProcess,            info.activityInfo.applicationInfo.uid);    // ...    // 跳过当前广播的发送    if (skip) {        // ...        return;    }    // 现在可以把广播发送给静态接收器了    // ...    // 7. 静态接收器的进程正在运行,那么就把广播发送给它    if (app != null && app.getThread() != null && !app.isKilled()) {        try {            app.addPackage(info.activityInfo.packageName,                    info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);            maybeAddAllowBackgroundActivityStartsToken(app, r);            // 发送广播给广播进程            processCurBroadcastLocked(r, app);            // 注意,广播发送给这个静态接收器后,直接结束此次广播的处理            return;        } catch (RemoteException e) {            // ...        }    }}

如果没有限制,那么现在就可以把广播发送给静态接收器。

如果静态接收器所在的进程已经运行了,那么把广播发送给这个进程,这个过程与前面发送广播给动态接收器的过程非常类似,这里就不分析了。

注意,这里把广播发送给一个静态接收器,也是直接 return,懂了吧?

接着往下看

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {    // ...    // 把并行广播发送给动态接收器    while (mParallelBroadcasts.size() > 0) {        // ...    }    // 1. 处理 receiver 进程正在启动的情况    if (mPendingBroadcast != null) {        // ...    }    boolean looped = false;    // 2. 通过 do-while 循环,找到一个现在可以处理的广播    do {        final long now = SystemClock.uptimeMillis();        // 获取一个待处理的广播        r = mDispatcher.getNextBroadcastLocked(now);        // ...    } while (r == null);    // 走到这里,表示已经获取了一个现在可以处理的广播    int recIdx = r.nextReceiver++;    // 3. 在发送广播之前,先发送一个超时消息    r.receiverTime = SystemClock.uptimeMillis();    // ...    if (! mPendingBroadcastTimeoutMessage) {        long timeoutTime = r.receiverTime + mConstants.TIMEOUT;        setBroadcastTimeoutLocked(timeoutTime);    }    final BroadcastOptions brOptions = r.options;    // 4. 获取一个 receiver    final Object nextReceiver = r.receivers.get(recIdx);    // 5. 如果这个接收器是动态接收器,先把广播发送给它    // 注意,这里处理的是有序广播发送给动态接收器的情况    if (nextReceiver instanceof BroadcastFilter) {        // ...        return;    }    // 走到这里,表示当前的广播接收器,是静态接收器    ResolveInfo info =        (ResolveInfo)nextReceiver;    ComponentName component = new ComponentName(            info.activityInfo.applicationInfo.packageName,            info.activityInfo.name);    boolean skip = false;    // 6. 检测是否不需要把广播发送给静态接收器    // ...    // 跳过当前广播的发送    if (skip) {        r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;        r.receiver = null;        r.curFilter = null;        r.state = BroadcastRecord.IDLE;        r.manifestSkipCount++;        // 发送下一个广播        scheduleBroadcastsLocked();        return;    }    // 现在可以把广播发送给静态接收器了    // ...    // 7. 静态接收器的进程正在运行,那么就把广播发送给它    if (app != null && app.getThread() != null && !app.isKilled()) {        // ...    }    // 8. 静态接收器的进程没有运行,fork it!    r.curApp = mService.startProcessLocked(targetProcess,            info.activityInfo.applicationInfo, true,            r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,            new HostingRecord("broadcast", r.curComponent), isActivityCapable            ? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY,            (r.intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false);    // 处理 fork 进程失败的情况    if (r.curApp == null) {        // ...        return;    }    maybeAddAllowBackgroundActivityStartsToken(r.curApp, r);    // fork 进程成功,保存广播数据,等待进程起来后,再处理这个广播    mPendingBroadcast = r;    mPendingBroadcastRecvIndex = recIdx;}

刚才已经处理了静态接收器的进程存在的情况,那么现在处理进程不存在的情况,因此首先得 fork 进程。当成功 fork 进程后,保存待发送的广播的数据,例如,用 mPendingBroadcast 保存广播,然后当进程启动时,与 AMS 进行 attach application 时,会自动把广播发送给该进程。这个过程后面会分析。

注意,此时函数已经结束,而广播正在发送给一个正在启动的进程。很显然,需要等待这个广播的处理结果,才能继续下一个广播的发送,这也符合“串行”广播的定义。

广播发送给正在启动的进程

刚才,我们分析到一个过程,当静态接收器所在的进程没有启动的时候,首先 fork 进程,那么广播之后是如何发送给进程的呢?

首先,我们知道当进程启动后,会执行 attach application 过程,最终会调用 AMS 如下方法

// ActivityManagerService.java    private boolean attachApplicationLocked(@NonNull IApplicationThread thread,            int pid, int callingUid, long startSeq) {        // ...        try {            // ...            if (app.getIsolatedEntryPoint() != null) {                // ...            } else if (instr2 != null) {                // ...            } else {                // 初始化进程环境                thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,                        null, null, null, testMode,                        mBinderTransactionTrackingEnabled, enableTrackAllocation,                        isRestrictedBackupMode || !normalMode, app.isPersistent(),                        new Configuration(app.getWindowProcessController().getConfiguration()),                        app.getCompat(), getCommonServicesLocked(app.isolated),                        mCoreSettingsObserver.getCoreSettingsLocked(),                        buildSerial, autofillOptions, contentCaptureOptions,                        app.getDisabledCompatChanges(), serializedSystemFontMap);            }            // ...        } catch (Exception e) {            // ...        }        // ....        // 处理正在等待宿主进程起来的广播        if (!badApp && isPendingBroadcastProcessLocked(pid)) {            try {                // 发送队列中正在等待进程起来的广播                didSomething |= sendPendingBroadcastsLocked(app);                checkTime(startTime, "attachApplicationLocked: after sendPendingBroadcastsLocked");            } catch (Exception e) {                // ...            }        }        // ...        return true;    }    boolean sendPendingBroadcastsLocked(ProcessRecord app) {        boolean didSomething = false;        for (BroadcastQueue queue : mBroadcastQueues) {            didSomething |= queue.sendPendingBroadcastsLocked(app);        }        return didSomething;    }

看到了,AMS 首先对进程进行了初始化,然后就会把等待进程启动的广播,发送给它。

// BroadcastQueue.javapublic boolean sendPendingBroadcastsLocked(ProcessRecord app) {    boolean didSomething = false;    // mPendingBroadcast 保存的就是等待进程启动启动后,需要发送的广播。    final BroadcastRecord br = mPendingBroadcast;    if (br != null && br.curApp.getPid() > 0 && br.curApp.getPid() == app.getPid()) {        if (br.curApp != app) {            Slog.e(TAG, "App mismatch when sending pending broadcast to "                    + app.processName + ", intended target is " + br.curApp.processName);            return false;        }        try {            mPendingBroadcast = null;            // 发送广播给进程            processCurBroadcastLocked(br, app);            didSomething = true;        } catch (Exception e) {            // ...        }    }    return didSomething;}

mPendingBroadcast 保存的就是等待进程启动启动后,需要发送的广播。现在进程已经启动,立即发送广播

// BroadcastQueue.javaprivate final void processCurBroadcastLocked(BroadcastRecord r,        ProcessRecord app) throws RemoteException {    final IApplicationThread thread = app.getThread();    if (thread == null) {        throw new RemoteException();    }    if (app.isInFullBackup()) {        skipReceiverLocked(r);        return;    }    // 更新正在处理广播的 receiver 数据    r.receiver = thread.asBinder();    r.curApp = app;    // 保存当前正在运行的 receiver    final ProcessReceiverRecord prr = app.mReceivers;    prr.addCurReceiver(r);    app.mState.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);    mService.updateLruProcessLocked(app, false, null);    mService.enqueueOomAdjTargetLocked(app);    mService.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);    r.intent.setComponent(r.curComponent);    boolean started = false;    try {        mService.notifyPackageUse(r.intent.getComponent().getPackageName(),                                  PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);        // 通知进程启动 receiver 来处理广播        thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,                mService.compatibilityInfoForPackage(r.curReceiver.applicationInfo),                r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,                app.mState.getReportedProcState());        started = true;    } finally {        if (!started) {            // ...        }    }}

现在 AMS 通知 receiver 所在的进程来处理广播

// ActivityThread.javaprivate class ApplicationThread extends IApplicationThread.Stub {    private static final String DB_INFO_FORMAT = "  %8s %8s %14s %14s  %s";    public final void scheduleReceiver(Intent intent, ActivityInfo info,            CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,            boolean sync, int sendingUser, int processState) {        updateProcessState(processState, false);        // 广播数据包装成 ReceiverData        ReceiverData r = new ReceiverData(intent, resultCode, data, extras,                sync, false, mAppThread.asBinder(), sendingUser);        r.info = info;        r.compatInfo = compatInfo;        sendMessage(H.RECEIVER, r);    }

最终调用 handleReceiver() 处理广播数据

private void handleReceiver(ReceiverData data) {    unscheduleGcIdler();    String component = data.intent.getComponent().getClassName();    LoadedApk packageInfo = getPackageInfoNoCheck(            data.info.applicationInfo, data.compatInfo);    IActivityManager mgr = ActivityManager.getService();    Application app;    BroadcastReceiver receiver;    ContextImpl context;    try {        // 1. 创建 Application 对象,并调用 Application#onCreate()        app = packageInfo.makeApplication(false, mInstrumentation);        // ...        // 2. 创建 BroadcastReceiver 对象        receiver = packageInfo.getAppFactory()                .instantiateReceiver(cl, data.info.name, data.intent);    } catch (Exception e) {        // ...    }    try {        sCurrentBroadcastIntent.set(data.intent);        receiver.setPendingResult(data);        // 3. 执行 BroadcastReceiver#onReceive()        receiver.onReceive(context.getReceiverRestrictedContext(),                data.intent);    } catch (Exception e) {        // ...    } finally {        sCurrentBroadcastIntent.set(null);    }    // 4. 返回广播的处理结果给 AMS    if (receiver.getPendingResult() != null) {        data.finish();    }}

这里的过程很清晰明了吧,直接看最后一步,把广播的处理结果反馈给 AMS

// BroadcastReceiver.javapublic final void finish() {    if (mType == TYPE_COMPONENT) {        final IActivityManager mgr = ActivityManager.getService();        if (QueuedWork.hasPendingWork()) {            // ...        } else {            sendFinished(mgr);        }    } else if (mOrderedHint &amp;&amp; mType != TYPE_UNREGISTERED) {        // ...    }}public void sendFinished(IActivityManager am) {    synchronized (this) {        if (mFinished) {            throw new IllegalStateException("Broadcast already finished");        }        mFinished = true;        try {            if (mResultExtras != null) {                mResultExtras.setAllowFds(false);            }            if (mOrderedHint) {                // 有序广播的反馈                am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,                        mAbortBroadcast, mFlags);            } else {                // 非有序广播的费奎                am.finishReceiver(mToken, 0, null, null, false, mFlags);            }        } catch (RemoteException ex) {        }    }}

现在看下 AMS 如何处理这个反馈的结果

// ActivityManagerService.javapublic void finishReceiver(IBinder who, int resultCode, String resultData,        Bundle resultExtras, boolean resultAbort, int flags) {    // ...    final long origId = Binder.clearCallingIdentity();    try {        boolean doNext = false;        BroadcastRecord r;        BroadcastQueue queue;        synchronized(this) {            if (isOnOffloadQueue(flags)) {                queue = mOffloadBroadcastQueue;            } else {                queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0                        ? mFgBroadcastQueue : mBgBroadcastQueue;            }            // 1. 匹配进程正在处理的广播            r = queue.getMatchingOrderedReceiver(who);            // 2. 完成当前 receiver 广播的处理流程            if (r != null) {                doNext = r.queue.finishReceiverLocked(r, resultCode,                    resultData, resultExtras, resultAbort, true);            }            // 3. 发送广播给下一个 receiver,或者发送下一个广播            if (doNext) {                r.queue.processNextBroadcastLocked( false,  true);            }            // updateOomAdjLocked() will be done here            trimApplicationsLocked(false, OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);        }    } finally {        Binder.restoreCallingIdentity(origId);    }}

看到了,只有当前 receiver 处理完广播,才会发送广播给下一个 receiver,这就是“串行”广播的本质。

广播 ANR

最后,来探讨一个广播 ANR 的原理,本来我以为很简单的,就是发送一个超时消息嘛。但是当我细看的时候,我发现这个 ANR 设计的很巧妙,我觉得我们可以学习下,因此这里单独拿出来分析。

这里,我得提醒大家一点,只有“串行”广播才会发生 ANR,因为它要等待 receiver 的处理结果。

根据前面分析,“串行”广播发送给 receiver 前,会发送一个超时消息,如下

// BroadcastQueue.javaif (! mPendingBroadcastTimeoutMessage) {    long timeoutTime = r.receiverTime + mConstants.TIMEOUT;    setBroadcastTimeoutLocked(timeoutTime);}

当这个消息被执行的时候,会调用如下代码

// BroadcastQueue.javafinal void broadcastTimeoutLocked(boolean fromMsg) {    if (fromMsg) {        mPendingBroadcastTimeoutMessage = false;    }    if (mDispatcher.isEmpty() || mDispatcher.getActiveBroadcastLocked() == null) {        return;    }    long now = SystemClock.uptimeMillis();    // 获取当前正在处理的广播    BroadcastRecord r = mDispatcher.getActiveBroadcastLocked();    if (fromMsg) {        // 系统还没有就绪        if (!mService.mProcessesReady) {            return;        }        // 广播超时被豁免        if (r.timeoutExempt) {            if (DEBUG_BROADCAST) {                Slog.i(TAG_BROADCAST, "Broadcast timeout but it's exempt: "                        + r.intent.getAction());            }            return;        }        // 1. 广播没有超时        long timeoutTime = r.receiverTime + mConstants.TIMEOUT;        if (timeoutTime > now) {            // 发送下一个超时消息            setBroadcastTimeoutLocked(timeoutTime);            return;        }    }    if (r.state == BroadcastRecord.WAITING_SERVICES) {        // ...        return;    }    // 2. 走到这里,表示广播超时,触发 ANR    final boolean debugging = (r.curApp != null && r.curApp.isDebugging());    r.receiverTime = now;    if (!debugging) {        r.anrCount++;    }    ProcessRecord app = null;    String anrMessage = null;    Object curReceiver;    if (r.nextReceiver > 0) {        curReceiver = r.receivers.get(r.nextReceiver-1);        r.delivery[r.nextReceiver-1] = BroadcastRecord.DELIVERY_TIMEOUT;    } else {        curReceiver = r.curReceiver;    }    logBroadcastReceiverDiscardLocked(r);    // 获取 receiver 进程    if (curReceiver != null && curReceiver instanceof BroadcastFilter) {        BroadcastFilter bf = (BroadcastFilter)curReceiver;        if (bf.receiverList.pid != 0                && bf.receiverList.pid != ActivityManagerService.MY_PID) {            synchronized (mService.mPidsSelfLocked) {                app = mService.mPidsSelfLocked.get(                        bf.receiverList.pid);            }        }    } else {        app = r.curApp;    }    if (app != null) {        anrMessage = "Broadcast of " + r.intent.toString();    }    if (mPendingBroadcast == r) {        mPendingBroadcast = null;    }    // 强制结束当前广播的发送流程    finishReceiverLocked(r, r.resultCode, r.resultData,            r.resultExtras, r.resultAbort, false);    // 调度下一次的广播发送    scheduleBroadcastsLocked();    // app 不处于 debug 模式,引发 ANR    if (!debugging && anrMessage != null) {        mService.mAnrHelper.appNotResponding(app, anrMessage);    }}

第2步,引发 ANR ,很简单,就是因为整个发送与反馈过程超时了。

而第1步,就是处理不超时的情况。这里大家是不是很疑惑,移除超时消息不是在接收到广播反馈后进行的吗? 我可以负责地告诉你,并不是!那这里第1步怎么理解呢?

首先这个超时消息一定触发,但是触发这个超时消息,并不代表一定会引发 ANR。

假如当前 receiver 的广播处理流程,在超时时间之前就完成了,那么 AMS 会调度广播发送给下一个 receiver。

于是,针对下一个 receiver ,会更新 r.receiverTime,那么第一步此时计算出来的 timeoutTime 是下一个 receiver 的广播超时时间,很显然是大于 now 的,于是就不会走第2步的 ANR 流程。

最后利用这个 timeoutTime,为下一个 receiver 再发送一个超时消息,简直是完美!

至于为何不在广播反馈的时候,移除这个超时消息,我心中有一点小小的想法,但是也不能确定是不是这个原因,才这样设计的。不过,对我来说,这一招,我算是学会了。

感谢各位的阅读,以上就是“ActivityManagerService广播并行发送与串行发送怎么实现”的内容了,经过本文的学习后,相信大家对ActivityManagerService广播并行发送与串行发送怎么实现这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯