Broadcast(四)有序广播

接上一篇,我们看看这2个方法做了什么

queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();

// mOrderedBroadcasts增加一条广播
public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
    mOrderedBroadcasts.add(r);
    r.enqueueClockTime = System.currentTimeMillis();
}

第二篇解析了scheduleBroadcastsLocked最终调用processNextBroadcast,step1也解析过,本文接着看step234

final void processNextBroadcast(boolean fromMsg) {
    //全程保持AMS锁,其他线程(app进程binder通信)都需要等待此方法处理完毕
    synchronized(mService) {
        //step1:处理全部无序广播,遍历动态注册的接收者并通知
        //step2:获取第一条有序广播
        //step3:获取第一个接收者,设置超时
        //step4:如果是动态注册的接收者,通知并return
        //step5:如果是静态注册的接收者,校验权限
        //step6:通知接收者
    }
}

step2:获取第一条有序广播

do {
    // mOrderedBroadcasts如果没值则return
    // 这里再重复说下,sendBroadcast有静态注册的接收者或者sendOrderedBroadcast
    // mOrderedBroadcasts会增加一条记录,不会为空
    if (mOrderedBroadcasts.size() == 0) {
        // No more broadcasts pending, so all done!
        mService.scheduleAppGcsLocked();
        if (looped) {
            // If we had finished the last ordered broadcast, then
            // make sure all processes have correct oom and sched
            // adjustments.
            mService.updateOomAdjLocked();
        }
        return;
    }
    r = mOrderedBroadcasts.get(0);
    boolean forceReceive = false;
    ...
} while (r == null);

step3:获取第一个接收者,设置超时

// Get the next receiver...
int recIdx = r.nextReceiver++;

// Keep track of when this receiver started, and make sure there
// is a timeout message pending to kill it if need be.
r.receiverTime = SystemClock.uptimeMillis();
if (recIdx == 0) {
    r.dispatchTime = r.receiverTime;
    r.dispatchClockTime = System.currentTimeMillis();
}
if (! mPendingBroadcastTimeoutMessage) {
    long timeoutTime = r.receiverTime + mTimeoutPeriod;
    setBroadcastTimeoutLocked(timeoutTime);
}
...
final Object nextReceiver = r.receivers.get(recIdx);

超时时间就是mTimeoutPeriod

BroadcastQueue(ActivityManagerService service, Handler handler,
               String name, long timeoutPeriod, boolean allowDelayBehindServices) {
    mService = service;
    mHandler = new BroadcastHandler(handler.getLooper());
    mQueueName = name;
    mTimeoutPeriod = timeoutPeriod;
    mDelayBehindServices = allowDelayBehindServices;
}

我们看AMS里

static final int BROADCAST_FG_TIMEOUT = 10*1000;
static final int BROADCAST_BG_TIMEOUT = 60*1000;

mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
        "foreground", BROADCAST_FG_TIMEOUT, false);
mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
        "background", BROADCAST_BG_TIMEOUT, true);

所以是前台广播10s超时,后台广播(默认是后台广播)60s超时
setBroadcastTimeoutLocked设置超时,关于超时和ANR见后续文章[Broadcast(五)ANR]
step4:如果是动态注册的接收者,通知并return

 if (nextReceiver instanceof BroadcastFilter) {
    BroadcastFilter filter = (BroadcastFilter)nextReceiver;
    // 通知接收者,见[Broadcast(二)registerReceiver时sticky广播]
    deliverToRegisteredReceiverLocked(r, filter, r.ordered);
    if (r.receiver == null || !r.ordered) {
        // The receiver has already finished, so schedule to
        // process the next one.
        r.state = BroadcastRecord.IDLE;
        scheduleBroadcastsLocked();
    } else {
        if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
            scheduleTempWhitelistLocked(filter.owningUid,
                    brOptions.getTemporaryAppWhitelistDuration(), r);
        }
    }
    return;
}

step5:如果是静态注册的接收者,校验权限

ResolveInfo info =
        (ResolveInfo)nextReceiver;
ComponentName component = new ComponentName(
        info.activityInfo.applicationInfo.packageName,
        info.activityInfo.name);

boolean skip = false;
int perm = mService.checkComponentPermission(info.activityInfo.permission,
        r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
        info.activityInfo.exported);
if (perm != PackageManager.PERMISSION_GRANTED) {
    skip = true;
} else if (info.activityInfo.permission != null) {
    final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission);
    if (opCode != AppOpsManager.OP_NONE
            && mService.mAppOpsService.noteOperation(opCode, r.callingUid,
            r.callerPackage) != AppOpsManager.MODE_ALLOWED) {
        skip = true;
    }
}
if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
        r.requiredPermissions != null && r.requiredPermissions.length > 0) {
    for (int i = 0; i < r.requiredPermissions.length; i++) {
        String requiredPermission = r.requiredPermissions[i];
        try {
            perm = AppGlobals.getPackageManager().
                    checkPermission(requiredPermission,
                            info.activityInfo.applicationInfo.packageName,
                            UserHandle
                                    .getUserId(info.activityInfo.applicationInfo.uid));
        } catch (RemoteException e) {
            perm = PackageManager.PERMISSION_DENIED;
        }
        if (perm != PackageManager.PERMISSION_GRANTED) {
            skip = true;
            break;
        }
        int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
        if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
                && mService.mAppOpsService.noteOperation(appOp,
                info.activityInfo.applicationInfo.uid, info.activityInfo.packageName)
                != AppOpsManager.MODE_ALLOWED) {
            skip = true;
            break;
        }
    }
}
if (!skip && r.appOp != AppOpsManager.OP_NONE
        && mService.mAppOpsService.noteOperation(r.appOp,
        info.activityInfo.applicationInfo.uid, info.activityInfo.packageName)
        != AppOpsManager.MODE_ALLOWED) {
    skip = true;
}
if (!skip) {
    skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
            r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid);
}
boolean isSingleton = false;
try {
    isSingleton = mService.isSingleton(info.activityInfo.processName,
            info.activityInfo.applicationInfo,
            info.activityInfo.name, info.activityInfo.flags);
} catch (SecurityException e) {
    skip = true;
}
if ((info.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) {
    if (ActivityManager.checkUidPermission(
            android.Manifest.permission.INTERACT_ACROSS_USERS,
            info.activityInfo.applicationInfo.uid)
            != PackageManager.PERMISSION_GRANTED) {
        skip = true;
    }
}
if (r.curApp != null && r.curApp.crashing) {
    // If the target process is crashing, just skip it.
    skip = true;
}
if (!skip) {
    boolean isAvailable = false;
    try {
        isAvailable = AppGlobals.getPackageManager().isPackageAvailable(
                info.activityInfo.packageName,
                UserHandle.getUserId(info.activityInfo.applicationInfo.uid));
    } catch (Exception e) {
        // all such failures mean we skip this receiver
    }
    if (!isAvailable) {
        skip = true;
    }
}

if (skip) {
    r.receiver = null;
    r.curFilter = null;
    r.state = BroadcastRecord.IDLE;
    scheduleBroadcastsLocked();
    return;
}
...
// Broadcast is being executed, its package can't be stopped.
try {
    AppGlobals.getPackageManager().setPackageStoppedState(
            r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid));
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
}

step6:通知接收者

// Is this receiver's application already running?
ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
        info.activityInfo.applicationInfo.uid, false);
if (app != null && app.thread != null) {
    try {
        app.addPackage(info.activityInfo.packageName,
                info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
        processCurBroadcastLocked(r, app);
        return;
    } catch (RemoteException e) {
    } catch (RuntimeException e) {
        r.state = BroadcastRecord.IDLE;
        return;
    }
    ...

processCurBroadcastLocked

private final void processCurBroadcastLocked(BroadcastRecord r,
                                             ProcessRecord app) throws RemoteException {
    if (app.thread == null) {
        throw new RemoteException();
    }
    r.receiver = app.thread.asBinder();
    r.curApp = app;
    app.curReceiver = r;
    app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
    mService.updateLruProcessLocked(app, false, null);
    mService.updateOomAdjLocked();

    // Tell the application to launch this receiver.
    r.intent.setComponent(r.curComponent);

    boolean started = false;
    try {
        mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
        app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
                r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
                app.repProcState);
        started = true;
    } finally {
        if (!started) {
            r.receiver = null;
            r.curApp = null;
            app.curReceiver = null;
        }
    }
}

至此只处理了一个receiver,其他receiver呢,我们看下时序图

app receiver处理完毕会通知system,然后接着执行processNextBroadcast,每次执行时r.nextReceiver++

int recIdx = r.nextReceiver++;
...
final Object nextReceiver = r.receivers.get(recIdx);
...
ResolveInfo info = (ResolveInfo)nextReceiver;
...
ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
    info.activityInfo.applicationInfo.uid, false);
if (app != null && app.thread != null) {
    try {
        app.addPackage(info.activityInfo.packageName,
                info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
        processCurBroadcastLocked(r, app);
...

到最后receivers.get(recIdx)就取不到值了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容