sendBroadcast静态广播源码分析

Android  源码分析  2023年12月15日 pm12:12发布12个月前更新 城堡大人
188 0 0

前言

本次分析一下Android P开机后发送静态广播源码分析,记录一下,方便自己查阅。

部分流程跟前面的源码分析《startActivity源码分析》和《startService源码分析》都比较类似,所以重复的步骤就省略。

PS:启动startActivity的比较复杂,流程多,但搞懂了这个,startService和sendBroadcast的分析就更简单。

正文

静态和动态广播区别

  1. 生存期

    静态广播的生存期比动态广播的长很多。

  2. 优先级

    动态广播的优先级比静态广播高。

  3. 注册方式

    (1)静态广播需要AndroidManifest.xml注册和声明

    (2)动态广播通过registerReceiver()注册和unregisterReceiver()反注册

这先分析静态广播

#MainActivity.java中
Intent intent = new Intent();
intent.setPackage("com.biumall.server");
intent.setAction("com.biumall.server.ACTION_ONE");
sendBroadcast(intent);

静态广播注册,在AndroidManifest.xml中添加

<receiver
    android:name="com.biumall.server.receiver.StaticReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter android:priority="9999">
        <action android:name="com.biumall.server.ACTION_ONE" />
    </intent-filter>
</receiver>

广播的发送最终在ContextImpl.java中,我们从这里开始跟踪。

ContextImpl.java

sendBroadcast()
@Override
public void sendBroadcast(Intent intent) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess(this);
        //ActivityManager.getService()获取的是ActivityManagerService
        ActivityManager.getService().broadcastIntent(
                mMainThread.getApplicationThread(), intent, resolvedType, null,
                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                getUserId());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

进入ActivityManagerService.broadcastIntent()

ActivityManagerService.java

broadcastIntent()
public final int broadcastIntent(IApplicationThread caller,
        Intent intent, String resolvedType, IIntentReceiver resultTo,
        int resultCode, String resultData, Bundle resultExtras,
        String[] requiredPermissions, int appOp, Bundle bOptions,
        boolean serialized, boolean sticky, int userId) {
    //略
    synchronized(this) {
        //验证广播合法性
        intent = verifyBroadcastLocked(intent);
        //略
        //继续,进入broadcastIntentLocked
        int res = broadcastIntentLocked(callerApp,
                callerApp != null ? callerApp.info.packageName : null,
                intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                requiredPermissions, appOp, bOptions, serialized, sticky,
                callingPid, callingUid, userId);
        Binder.restoreCallingIdentity(origId);
        return res;
    }
}
broadcastIntentLocked()

很长,不重要的大部分省略。

@GuardedBy("this")
final int broadcastIntentLocked(ProcessRecord callerApp,
        String callerPackage, Intent intent, String resolvedType,
        IIntentReceiver resultTo, int resultCode, String resultData,
        Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
        boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
    intent = new Intent(intent);
    //略 发送的是普通的广播,
    final String action = intent.getAction();
    //bOptions为null 
    if (bOptions != null) {
       //略
    }
    final boolean isProtectedBroadcast;
    try {
        //没有添加入包含名单,false
        isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
    } catch (RemoteException e) {
        return ActivityManager.BROADCAST_SUCCESS;
    }

    final boolean isCallerSystem;
    //判断是否系统应用发送
    switch (UserHandle.getAppId(callingUid)) {
        case ROOT_UID:
        case SYSTEM_UID:
        case PHONE_UID:
        case BLUETOOTH_UID:
        case NFC_UID:
        case SE_UID:
            isCallerSystem = true;
            break;
        default:
            isCallerSystem = (callerApp != null) && callerApp.persistent;
            break;
    }
    //我这是系统应用发送
    if (!isCallerSystem) {
        //略
    }
    //略
    //不是粘性广播,上面传入的也是false
    if (sticky) { 
        //略
    }
    //略
    List<BroadcastFilter> registeredReceivers = null;
    //获取广播接收者list
    if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)== 0) {
        //这部分搜集的后面有空跟着一下
        receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
    }
    //发送广播时没有指定
    if (intent.getComponent() == null) {
        //略
    }
    //false
    final boolean replacePending =
            (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
    //registeredReceivers为null,没有进入上面的赋值
    int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
    //传入的ordered = false, NR= 0,跳过
    if (!ordered && NR > 0) {
        //略
    }
    //略
    //isCallerSystem为true没我这是系统应用发送广播
    if (isCallerSystem) {
        //检查权限
        checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                isProtectedBroadcast, receivers);
    }
    //receivers广播接收者列表,不为null,且size()大于0
    if ((receivers != null && receivers.size() > 0)
            || resultTo != null) {
        //广播队列,这里会判断是前台广播还是后台广播
        BroadcastQueue queue = broadcastQueueForIntent(intent);
        //广播记录
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
                resultData, resultExtras, ordered, sticky, false, userId);
        //此处replacePending为false
        final BroadcastRecord oldRecord =
                replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
        //oldrecord为null
        if (oldRecord != null) {
            //略
        } else {
            //[重]
            //添加BroadcastRecord到队列 mOrderedBroadcasts.add();
            queue.enqueueOrderedBroadcastLocked(r);
            //安排发送广播
            queue.scheduleBroadcastsLocked();
        }
    } else {
        //略
    }
    return ActivityManager.BROADCAST_SUCCESS;
}

BroadcastQueue.java

enqueueOrderedBroadcastLocked()
public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
    //添加广播到mOrderedBroadcasts
    mOrderedBroadcasts.add(r);
    enqueueBroadcastHelper(r);
}
scheduleBroadcastsLocked()
public void scheduleBroadcastsLocked() {
    if (mBroadcastsScheduled) {
        return;
    }
    //发送BROADCAST_INTENT_MSG
    mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
    //这里会吧mBroadcastsScheduled置为true
    mBroadcastsScheduled = true;
}
handleMessage()
@Override
public void handleMessage(Message msg) {
    switch (msg.what) {
        case BROADCAST_INTENT_MSG: {
            //发送下一个广播
            processNextBroadcast(true);
        } break;
        case BROADCAST_TIMEOUT_MSG: {
            //广播超时处理
            synchronized (mService) {
                broadcastTimeoutLocked(true);
            }
        } break;
    }
}
processNextBroadcast()
final void processNextBroadcast(boolean fromMsg) {
    synchronized (mService) {
        //fromMsg=true
        processNextBroadcastLocked(fromMsg, false);
    }
}
processNextBroadcastLocked()

进入这里就分两步了

  1. 广播接收者的进程启动过,就走processCurBroadcastLocked()

  2. 广播接收者的进程没启动过,需先启动进程startProcessLocked(),然后出了队列中的广播

如果进程没有启动,需要先启动(多了这部分),最后也会启动processCurBroadcastLocked()

当然,我们下面也发现了,优先处理了动态注册的的广播,然后再去执行后面静态广播。

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
    BroadcastRecord r;
    //略
    //fromMsg传入的为true
    if (fromMsg) {
        mBroadcastsScheduled = false;
    }
    //处理动态注册的广播,我们这是第一次给应用发静态广播
    //这里size()=0
    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);
    }

    //mPendingBroadcast为null
    //mPendingBroadcast是在后面进行赋值,的表示Pending中的广播。
    //不过,这里不是很了解,跳过吧
    if (mPendingBroadcast != null) {
        //略
    }
    boolean looped = false;
    do {
        //mOrderedBroadcasts在enqueueOrderedBroadcastLocked添加的
        //mOrderedBroadcasts.size()>0
        if (mOrderedBroadcasts.size() == 0) {
            //略
            return;
        }
        //获取列表中的第一个
        r = mOrderedBroadcasts.get(0);
        boolean forceReceive = false;
        //numReceivers有一个,就是我们要发送的广播
        //当然,我们只针对我们发送的分析。
        int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
        //mService.mProcessesReady为true
        // r.dispatchTime=0,还在队列中,没法安排发送
        if (mService.mProcessesReady && r.dispatchTime > 0) {
            //略
        }
        //r.state 为 0 ,BroadcastRecord.IDLE 空闲
        if (r.state != BroadcastRecord.IDLE) {
            return;
        }
        //r.receivers 广播接收者
        //r.nextReceiver 下一个广播接收者,我这只有一个,所以为0
        //r.resultAbort false 终止广播值?这不太懂
        //forceReceive false 强制接受? 哈哈也不懂,,
        //反正,不满足条件
        if (r.receivers == null || r.nextReceiver >= numReceivers
                || r.resultAbort || forceReceive) {
            //略
        }
    } while (r == null);
    //上面知道nextReceiver为0
    //先赋值,后++,所以recIdx = 0
    int recIdx = r.nextReceiver++;
    //赋值接收时间
    r.receiverTime = SystemClock.uptimeMillis();
    //recIdx为0
    if (recIdx == 0) {
        //设置投递时间
        r.dispatchTime = r.receiverTime;
        r.dispatchClockTime = System.currentTimeMillis();
    }
    //mPendingBroadcastTimeoutMessage为false
    //还没设置超时广播
    if (! mPendingBroadcastTimeoutMessage) {
        long timeoutTime = r.receiverTime + mTimeoutPeriod;
        //设置广播超时60s时ANR(mTimeoutPeriod = 60)
        setBroadcastTimeoutLocked(timeoutTime);
    }

    final BroadcastOptions brOptions = r.options;
    //就是获取第一个广播接收者
    final Object nextReceiver = r.receivers.get(recIdx);
    // nextReceiver是ResolveInfo对象。,不是BroadcastFilter实例
    //不进入下面
    if (nextReceiver instanceof BroadcastFilter) {
        //略
        return;
    }
    ResolveInfo info =(ResolveInfo)nextReceiver;
    ComponentName component = new ComponentName(
            info.activityInfo.applicationInfo.packageName,
            info.activityInfo.name);
    boolean skip = false;
    //略
    //获取进程记录
    ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
            info.activityInfo.applicationInfo.uid, false);
    //开头说了,我开机第一次就发送静态广播,接收广播的进程是没提前启动的
    //因此获取的app是为null

    //略

    r.manifestCount++;
    r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
    r.state = BroadcastRecord.APP_RECEIVE;
    r.curComponent = component;
    r.curReceiver = info.activityInfo;
    //略
    // 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) {
        Slog.w(TAG, "processNextBroadcastLocked Failed trying to unstop package "
                + r.curComponent.getPackageName() + ": " + e);
    }
    //如果不为null,表示进程已经启动
    //如果启动了就走这里
    if (app != null && app.thread != null && !app.killed) {
        try {
            app.addPackage(info.activityInfo.packageName,
                    info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
            //处理当前广播
            processCurBroadcastLocked(r, app, skipOomAdj);
            return;
        } catch (RemoteException e) {
            Slog.w(TAG, "processNextBroadcastLocked Exception when sending broadcast to "
                  + r.curComponent, e);
        } catch (RuntimeException e) {
            logBroadcastReceiverDiscardLocked(r);
            finishReceiverLocked(r, r.resultCode, r.resultData,
                    r.resultExtras, r.resultAbort, false);
            scheduleBroadcastsLocked();
            r.state = BroadcastRecord.IDLE;
            return;
        }
    }
    //走这里是进程没有启动
    //启动新的进程ActivityManagerService.startProcessLocked()
    if ((r.curApp=mService.startProcessLocked(targetProcess,
            info.activityInfo.applicationInfo, true,
            r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
            "broadcast", r.curComponent,
            (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
                    == null) {
        //启动失败就走这里,否则不进来
        //略
        return;
    }

    //mPendingBroadcast赋值,记录BroadcastRecord
    mPendingBroadcast = r;
    mPendingBroadcastRecvIndex = recIdx;
}

由于开头说了,我们是第一次发送静态广播,也即是App=null

也就是执行ActivityManagerService.startProcessLocked()流程。

进程的启动

这部分跟《startActivity之进程启动》重合了,都是一样的流程。最后启动ActivityThread.main()。

而ActivityThread.main()到ActivityManagerService.attachApplicationLocked()这部分代码跟《startService()源码分析》和《startActivity源码分析2》基本一致。

因此,我们直接跳过重复的部分,直接进入ActivityManagerService.attachApplicationLocked()

ActivityManagerService.java

attachApplicationLocked()
@GuardedBy("this")
private final boolean attachApplicationLocked(IApplicationThread thread,
        int pid, int callingUid, long startSeq) {

    //重复部分略,有需要的可看对应文章


    //启动Activity 
    if (normalMode) {
        try {
            //Activity
            if (mStackSupervisor.attachApplicationLocked(app)) {
                didSomething = true;
            }
        } catch (Exception e) {
            badApp = true;
        }
    }
    //启动服务
    if (!badApp) {
        try {
            //Service
            didSomething |= mServices.attachApplicationLocked(app, processName);
        } catch (Exception e) {
            badApp = true;
        }
    }
    //启动广播
    if (!badApp && isPendingBroadcastProcessLocked(pid)) {
        try {
            //Broadcasts
            didSomething |= sendPendingBroadcastsLocked(app);
        } catch (Exception e) {
            badApp = true;
        }
    }
    //略
    return true;
}

这里我们只关注广播的发送

if (!badApp && isPendingBroadcastProcessLocked(pid)) {
    try {
        didSomething |= sendPendingBroadcastsLocked(app);
    } catch (Exception e) {
        badApp = true;
    }
}
sendPendingBroadcastsLocked()
// The app just attached; send any pending broadcasts that it should receive
boolean sendPendingBroadcastsLocked(ProcessRecord app) {
    boolean didSomething = false;
    for (BroadcastQueue queue : mBroadcastQueues) {
        //根据app进行查询前台和后台的BroadcastQueue
        //看BroadcastQueue.sendPendingBroadcastsLocked()
        didSomething |= queue.sendPendingBroadcastsLocked(app);
    }
    return didSomething;
}

mBroadcastQueues包含两个变量,在ActivityManagerService()中初始化

public ActivityManagerService(Context systemContext) {
    //略
    //BROADCAST_FG_TIMEOUT 前台 10s
    mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
        "foreground", BROADCAST_FG_TIMEOUT, false);
    //BROADCAST_BG_TIMEOUT 后台 60s
    mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
            "background", BROADCAST_BG_TIMEOUT, true);
    mBroadcastQueues[0] = mFgBroadcastQueue;
    mBroadcastQueues[1] = mBgBroadcastQueue;
    //略
}

BroadcastQueue.java

sendPendingBroadcastsLocked()
public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
    boolean didSomething = false;
    final BroadcastRecord br = mPendingBroadcast;
    //之前存储的是后台BroadcastQueue,(之前备注了60s超时ANR处)
    if (br != null && br.curApp.pid > 0 && br.curApp.pid == app.pid) {
        if (br.curApp != app) {
            return false;
        }
        try {
            mPendingBroadcast = null;
            //满足条件后就执行这个,处理广播
            processCurBroadcastLocked(br, app, false);
            didSomething = true;
        } catch (Exception e) {
            logBroadcastReceiverDiscardLocked(br);
            finishReceiverLocked(br, br.resultCode, br.resultData,
                    br.resultExtras, br.resultAbort, false);
            scheduleBroadcastsLocked();
            br.state = BroadcastRecord.IDLE;
            throw new RuntimeException(e.getMessage());
        }
    }
    return didSomething;
}
processCurBroadcastLocked()

这里也不是真正处理广播的,最终又调用了ActivityThread0

private final void processCurBroadcastLocked(BroadcastRecord r,
        ProcessRecord app, boolean skipOomAdj) throws RemoteException {
    if (app.thread == null) {
        throw new RemoteException();
    }
    if (app.inFullBackup) {
        skipReceiverLocked(r);
        return;
    }
    r.receiver = app.thread.asBinder();
    r.curApp = app;
    app.curReceivers.add(r);
    app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
    mService.updateLruProcessLocked(app, false, null);
    if (!skipOomAdj) {
        mService.updateOomAdjLocked();
    }
    r.intent.setComponent(r.curComponent);
    boolean started = false;
    try {
        mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
                                  PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
        //看这里ActivityThread.ApplicationThread.scheduleReceiver
        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.curReceivers.remove(r);
        }
    }
}

ActivityThread.java

是内部ApplicationThread的方法

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 r = new ReceiverData(intent, resultCode, data, extras,
            sync, false, mAppThread.asBinder(), sendingUser);
    r.info = info;
    r.compatInfo = compatInfo;
    //发送H.RECEIVER
    sendMessage(H.RECEIVER, r);
}
handleMessage()
public void handleMessage(Message msg) {
    //略
    case RECEIVER:
        handleReceiver((ReceiverData)msg.obj);
        break;
    //略
}
handleReceiver()

这里才真正发送广播给接收者:receiver.onReceive()

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 {
        //获取Application,之前makeApplication过
        app = packageInfo.makeApplication(false, mInstrumentation);
        context = (ContextImpl) app.getBaseContext();
        if (data.info.splitName != null) {
            context = (ContextImpl) context.createContextForSplit(data.info.splitName);
        }
        java.lang.ClassLoader cl = context.getClassLoader();
        data.intent.setExtrasClassLoader(cl);
        data.intent.prepareToEnterProcess();
        data.setExtrasClassLoader(cl);
        //获取广播接收者
        receiver = packageInfo.getAppFactory()
                .instantiateReceiver(cl, data.info.name, data.intent);
    } catch (Exception e) {
        data.sendFinished(mgr);
        throw new RuntimeException(
            "Unable to instantiate receiver " + component
            + ": " + e.toString(), e);
    }

    try {
        sCurrentBroadcastIntent.set(data.intent);
        receiver.setPendingResult(data);
        //调用onReceive()
        receiver.onReceive(context.getReceiverRestrictedContext(),
                data.intent);
    } catch (Exception e) {
        data.sendFinished(mgr);
        if (!mInstrumentation.onException(receiver, e)) {
            throw new RuntimeException(
                "Unable to start receiver " + component
                + ": " + e.toString(), e);
        }
    } finally {
        sCurrentBroadcastIntent.set(null);
    }

    if (receiver.getPendingResult() != null) {
        data.finish();
    }
}

至此,静态广播发送分析就结束了。

参考文章

直接本站搜索关键字即可。

 历史上的今天

  1. 2021: ListView的item中当文本出现阿拉伯语时会显示怪异(0条评论)
版权声明 1、 本站名称: 笔友城堡
2、 本站网址: https://www.biumall.com/
3、 本站部分文章来源于网络,仅供学习与参考,如有侵权,请留言

暂无评论

暂无评论...

随机推荐

[摘]Android开发之Shape详细解读

这篇文章总结得很详细,因此摘抄于此,以便自己查询和学习。原文如下日常开发中,我们会遇到一些Button、Textview...等控件的背景是圆角矩形、圆形...等,和android默认的控件背景矩形不一致,此时shape的作用就体现出来了,我们可以根据shape属性画出很多我们意想不到的背景图...

龙应台:我为什么要求你读书

那天我问你,“你将来想做什么”,我注意到,你很不屑于回答我这个问题,所以跟我胡诌一通。是因为你们这个时代的人,对未来太自信,所以不屑与像我这一代人年轻时一样,讲究勤勤恳恳、如履薄冰,还是其实你们对于未来太没信心,所以假装出一种嘲讽和狂妄的姿态,来闪避我的追问?我几乎要相信,你是在假装潇洒了。今天的...

[摘]字符乱码之特征

前言开发中,遇见乱码是难免的,看到网上有大牛整理的《字符乱码之特征》,因此摘抄于此,方便自己查阅。好记性不如烂笔头正文这里有介绍古文码、口字码、符号码、拼音码、问句码、锟拷码参考文章《字符乱码之特征》

周国平:事故

火车轮子下一团污秽 是男人还是女人叫什么名字这有什么重要 为什么开来的是警察而不是一大块肥皂 假如一个人消失了不要去寻找人应该像声音一样死去只留下寂静

林清玄:什么才是有品质的生活

有好多人喜欢讲生活品质,他们认为花的钱多、花得起钱就是生活品质了。于是,有愈来愈多的人,在吃饭时一掷万金,在买衣时一掷万金,拼命的挥霍金钱,当我们问他为什么要如此,他的答案是理直气壮的——“为了追求生活品质!为了讲究生活品质!”生活?品质?这两样东西到底意味着什么呢?如果说有钱能满足许多的物质...

Ubuntu16安装openjdk-7

Ubuntu16.04 安装openjdk-7-jdksudo apt-get install openjdk-7-jre 或者sudo apt-get install openjdk-7-jdkUbuntu16.04的安装源已经默认没有openjdk7了,所以要自己手动添加仓库,如下:...