美文网首页
framework 广播基础知识和常见问题

framework 广播基础知识和常见问题

作者: AmyTan | 来源:发表于2022-07-22 16:53 被阅读0次

    基础知识

    framework层广播相关的逻辑主要在AMS.java和BroadcastQueue.java中,代表一个广播的是BroadcastRecord。

    分类

    1. 注册方式:
      • 静态注册: android manifest文件注册,常驻广播,分发慢。
      • 动态注册:代码中注册,非常驻,分发快。
    2. 接收者:
      • 显示广播:指定接收方的class类型
      • 隐式广播:只指定action,uri等, android 8.0开始限制了隐式广播的接收
    3. 发送方式:
      静态注册的广播,一律按照串行广播处理,因为可能会设计到拉起多个进程等,串行广播才有超时处理。
      • 有序广播:串行分发,效率低,可以通过abortBroadcast截断,在入队时会根据优先级对receiver进行排序。
      • 无序广播:默认无序;并行分发;不可以被拦截、终止、修改;无优先级问题;传递数据用intent.putExtra
    4. 处理类型:
      AMS中前台广播和后台广播分别有一个广播队列,互不干扰。
      • 前台广播:发送时添加Intent.FLAG_RECEIVER_FOREGROUND,超时时间10s
      • 后台广播:默认后台,超时时间60s

    常见命令

    1. dumpsys activity broadcasts
      • Registered Receivers: 列出所有已注册的receivers列表
      • Receiver Resolver Table: receiver的解析表
      • Historical broadcasts [foreground]: 前台广播历史记录
      • Historical broadcasts summary [foreground]: 前台广播历史记录简要
      • Historical broadcasts [background]:后台广播历史记录
      • Historical broadcasts summary [background]: 后台广播历史记录简要
     // 已注册的receiver
      * ReceiverList{7657857 3271 com.android.systemui/1000/u0 remote:5d6fdd6}
        app=3271:com.android.systemui/1000 pid=3271 uid=1000 user=0 // 进程相关信息,pid,uid,user等
        Filter #0: BroadcastFilter{b28ef44} // 列出当前receiver的所有BroadcastFilter
          Action: "android.intent.action.CLOSE_SYSTEM_DIALOGS"
    
    // receiver的查询表
    android.intent.action.CLOSE_SYSTEM_DIALOGS:
      BroadcastFilter{cd0b64d 1000/u0 ReceiverList{5cd41e4 2477 system/1000/u0 local:7b2f177}}
      BroadcastFilter{766ac91 1000/u0 ReceiverList{b2bd6b8 2477 system/1000/u0 local:dd6451b}}
      BroadcastFilter{707a39e 1000/u-1 ReceiverList{6db3dd9 2477 system/1000/u-1 local:28e4020}}
      BroadcastFilter{921cf0a 1000/u0 ReceiverList{a168375 3271 com.android.systemui/1000/u0 remote:792eaac}}
      BroadcastFilter{eb0f625 1000/u-1 ReceiverList{f9ba1c 3271 com.android.systemui/1000/u-1 remote:311c78f}}
      BroadcastFilter{b28ef44 1000/u0 ReceiverList{**7657857** 3271 com.android.systemui/1000/u0 remote:5d6fdd6}}
      BroadcastFilter{3dc5af6 1000/u0 ReceiverList{9ad5b91 2477 system/1000/u0 local:ab3e1b8}}
      BroadcastFilter{84a1c2 1000/u0 ReceiverList{27a8e0d 5062 com.miui.securitycenter.remote/1000/u0 remote:49ca0a4}}
      BroadcastFilter{6151148 1000/u0 ReceiverList{6ac8feb 5062 com.miui.securitycenter.remote/1000/u0 remote:17c273a}}
      BroadcastFilter{1525a45 1000/u0 ReceiverList{caf9abc 5062 com.miui.securitycenter.remote/1000/u0 remote:aa646af}}
    
      Historical Broadcast foreground #1: // 前台广播队列第一条广播
        BroadcastRecord{8888912 u0 com.xiaomi.mi_connect_service.mi_mover_endpoint_found} to user 0 // user 0
        Intent { act=com.xiaomi.mi_connect_service.mi_mover_endpoint_found flg=0x11000030 (has extras) } // flag有:FLAG_RECEIVER_FOREGROUND | FLAG_RECEIVER_INCLUDE_BACKGROUND | |FLAG_INCLUDE_STOPPED_PACKAGES | FLAG_EXCLUDE_STOPPED_PACKAGES
          extras: Bundle[{STRIPPED=1}]
        caller=com.xiaomi.mi_connect_service 9219:com.xiaomi.mi_connect_service/1000 pid=9219 uid=1000 // 发送广播app的信息
        requiredPermissions=[com.xiaomi.mi_connect_service.permission.RECEIVE_ENDPOINT]  appOp=-1 // 广播要求receiver的权限
        enqueueClockTime=2021-09-11 16:04:57.623 dispatchClockTime=2021-09-11 16:04:57.623 // 入队时间和分发时间
        dispatchTime=-1m2s207ms (0 since enq) finishTime=-1m2s164ms (+43ms since disp)  // 结束时间 & 分发用时
        resultTo=null resultCode=0 resultData=null // 一般resultCode为0且resultTo为null且无” ordered= “表示静态注册的无序广播
        nextReceiver=1 receiver=null
        Deliver +42ms #0: (manifest) //派发给静态注册的receiver
          priority=0 preferredOrder=0 match=0x108000 specificIndex=-1 isDefault=false //优先级默认为0,
          ActivityInfo: // receiver的信息
            name=com.miui.huanji.ble.MiConnectBleReceiver
            packageName=com.miui.huanji
            enabled=true exported=true directBootAware=false
            resizeMode=RESIZE_MODE_RESIZEABLE
    
    Historical Broadcast background #29: // 后台广播队列第29条
    BroadcastRecord{e0ebea0 u-1 android.intent.action.PHONE_STATE{color}} to user -1 // -1代表user_all
    Intent { act=android.intent.action.PHONE_STATE flg=0x1000010 (has extras) } // intent信息
    extras: Bundle[\{incoming_number=18381098208, state=IDLE}]
    caller=android 1309:system/1000 pid=1309 uid=1000 // 发送广播app的信息
    requiredPermissions=[android.permission.READ_PHONE_STATE, android.permission.READ_CALL_LOG] appOp=-1  // 广播要求receiver的权限
    enqueueClockTime=2021-06-23 11:41:05.687 dispatchClockTime=2021-06-23 11:41:05.687  // 入队时间和分发时间
    dispatchTime=-1m39s763ms (0 since enq) finishTime=-1m39s755ms (+8ms since disp)  // 结束时间 & 分发用时
    // 分发每一个receiver的分发信息以及状态
    // Deliver代表当前receiver已分发到
    Deliver 0 #0: BroadcastFilter{12c9c23 1000/u-1 ReceiverList{5b06152 1309 system/1000/u-1 local:4a651dd}} 
    Deliver 0 #1: BroadcastFilter{672acd7 1000/u0 ReceiverList{5be3456 1780 com.android.systemui/1000/u0 remote:b33e71}}
    Deliver 0 #2: BroadcastFilter{f932daf 1000/u-1 ReceiverList{1ef518e 1780 com.android.systemui/1000/u-1 remote:35e2d89}}
    Deliver 0 #3: BroadcastFilter{d0d467b 1001/u0 ReceiverList{b4a5e0a 1996 com.android.phone/1001/u0 remote:65bee75}}
    Deliver 0 #4: BroadcastFilter{4081988 1002/u0 ReceiverList{661912b 2315 com.xiaomi.bluetooth/1002/u0 remote:34b657a}}
    Deliver 0 #5: BroadcastFilter{b6bda66 1000/u0 ReceiverList{73672c1 5261 com.miui.powerkeeper/1000/u0 remote:bc317a8}}
    // skip表示由于权限等原因,跳过分发到该app
    Skipped 0 #6: BroadcastFilter{ebabe72 10243/u0 ReceiverList{5596f7d 21465 com.smile.gifmaker/10243/u0 remote:96d61d4}} 
    Skipped 0 #7: BroadcastFilter{f7d90ab 10243/u0 ReceiverList{261b2fa 21465 com.smile.gifmaker/10243/u0 remote:ef8c125}}
    Skipped 0 #8: BroadcastFilter{1f05292 10250/u0 ReceiverList{396401d 12339 com.tencent.mobileqq/10250/u0 remote:e8e90f4}}
    Skipped 0 #9: BroadcastFilter{d98737f 10250/u0 ReceiverList{469cc9e 12339 com.tencent.mobileqq/10250/u0 remote:b386ad9}}
    Skipped 0 #10: BroadcastFilter{4e1588 10250/u0 ReceiverList{851fd2b 29070 com.tencent.mobileqq:tool/10250/u0 remote:64a017a}}
    
    1. dumpsys activity broadcast-stats :广播的统计
    android.intent.action.DROPBOX_ENTRY_ADDED:
      Number received: 0, skipped: 302  // 分发0次,跳过302次
      Total dispatch time: +24s731ms, max: +13s538ms // 总分发用时,和最大分发用时
      Package android: 151 times  
      Bg Check Violation com.google.android.gms: 302 times
    

    常见的一些Intent中的flag

    1. FLAG_RECEIVER_REGISTERED_ONLY
      表示当前广播只允许动态注册的receiver接收,避免避免一些系统广播(如TIME_TICK等)拉起静态注册的app进程。
    2. FLAG_RECEIVER_REPLACE_PENDING
      如果广播队列中存在没有被处理的相同广播,则直接替换掉之前的广播,无序再入队分发
    3. FLAG_RECEIVER_FOREGROUND
      发送广播时添加这个flag,广播将会被添加到前台广播队列中。

    AMS中的一些属性

    // 已注册的动态广播的receiver,receiver IBinder为key, ReceiverList为value;ReceiverList继承自ArrayList<BroadcastFilter>
    final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();  
    
    // 记录着已注册广播的receiver的resolver,广播发送时可根据intent和type等查询得到对应的动态广播接收者
    final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
                = new IntentResolver<BroadcastFilter, BroadcastFilter>();
    

    BroadcastRecord的一些属性

    int state; //当前广播状态,初始是idle
    final int[] delivery; // 每一个receiver的处理状态
    final List receivers; // 广播的接收者列表,包括静态注册的ResolveInfo和动态注册的BroadcastFilter
    int nextReceiver; // 下一个要处理的广播接收者的索引,对应于receivers的索引
    IIntentReceiver resultTo; // 有序广播指定的最后一个接收者
    long enqueueClockTime;  // 广播的入队时间
    long dispatchTime; // 分发时间
    long receiverTime; //开始派发广播到app端的时间,用于计算anr超时时间
    long finishTime;  //结束广播时间
    IBinder receiver; // 当前正在处理的receiver(ReceiverDispatcher.InnerReceiver),有序广播和静态注册的才会赋值
    

    ResolveInfo的一些属性

    public int priority; // 优先级
    public int preferredOrder; //偏好优先级
    public int match; // 系统评估活动与IntentFilter的匹配情况。
    public int specificIndex = -1; //仅当由 queryIntentActivityOptions(ComponentName, Intent[], Intent, int)返回时设置,这告诉你这个结果来自哪个给定的特定意图。
    public boolean isDefault; //此过滤器指定了Intent.CATEGORY_DEFAULT,这意味着它将被视为用户可以对此数据执行的默认操作。
    

    广播的状态

    static final int IDLE = 0;  // 广播的初始状态,派发时只处理这种状态的广播
    static final int APP_RECEIVE = 1; // 表示广播正在派发到app进程,静态receiver
    static final int CALL_IN_RECEIVE = 2; // 表示广播正在派发到app进程,有序广播,动态receiver
    static final int CALL_DONE_RECEIVE = 3; // 广播已经派发到app进程,有序广播,动态receiver
    static final int WAITING_SERVICES = 4; // 等待后台service启动
    

    广播接收者的处理状态

        static final int DELIVERY_PENDING = 0; // 默认状态
        static final int DELIVERY_DELIVERED = 1; // 表示已经派发到app进程
        static final int DELIVERY_SKIPPED = 2; // 表示由于某种原因,未派发到app进程
        static final int DELIVERY_TIMEOUT = 3; // 表示派发到app端,超时未结束派发
    

    广播不被处理的情况

    实际上广播不被处理的情况有很多种,这里只是列出常遇到的一些情况。

    接收端未声明广播指定权限

    W/BroadcastQueue: Permission Denial: receiving Intent { act=android.intent.action.ORDER_BROADCAST flg=0x10 } to com.example.myapplication/com.example.receive.MyReceiver requires com.android.permission.ORDER_PERMISSION due to sender com.example.testapplication (uid 10255)

    在BroadcastQueue的deliverToRegisteredReceiverLocked(动态注册)或processNextBroadcastLocked(静态注册)方法中,会去校验接收端是否都具备广播要求的权限,如果不具备,会跳过此次广播的分发到app端。

          if (!skip && r.requiredPermissions != null && r.requiredPermissions.length > 0) {
                for (int i = 0; i < r.requiredPermissions.length; i++) {
                    String requiredPermission = r.requiredPermissions[i];
                    int perm = mService.checkComponentPermission(requiredPermission,
                            filter.receiverList.pid, filter.receiverList.uid, -1, true);
                    if (perm != PackageManager.PERMISSION_GRANTED) {
                        Slog.w(TAG, "Permission Denial: receiving " + r.intent.toString() + " to " + filter.receiverList.app + " (pid=" + filter.receiverList.pid
                                + ", uid=" + filter.receiverList.uid + ")" + " requires " + requiredPermission + " due to sender " + r.callerPackage + " (uid " + r.callingUid + ")");
                        skip = true;
                        break;
                    }
    

    android 8.0对隐式广播的限制

    W BroadcastQueue: Background execution not allowed: receiving Intent { act=android.intent.action.PACKAGE_RESTARTED dat=package:com.android.soundrecorder flg=0x10 (has extras) } to com.xiaomi.misubscreenui/.receiver.LightDeviceStatusReceiver

    限制如下两种情况下的广播分发
    • Intent中添加了FLAG_RECEIVER_EXCLUDE_BACKGROUND
    • Intent中无FLAG_RECEIVER_INCLUDE_BACKGROUND flag的隐式广播
    FLAG_RECEIVER_INCLUDE_BACKGROUND 添加的场景

    也就是如下这些隐式广播处于后台清单文件注册的也能接收到

    • ACTION_BOOT_COMPLETED
    
    @BroadcastBehavior(includeBackground = true)
    public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
    
    
    • allow-implicit-broadcast 列表内的intent会在broadcastIntentLocked中添加
            if (action != null) {
                if (getBackgroundLaunchBroadcasts().contains(action)) {
                    intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
                }
    
    
    20    <!-- Broadcast actions that are currently exempted from O+ background
    21         delivery restrictions. -->
    22    <allow-implicit-broadcast action="android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED" />
    23    <allow-implicit-broadcast action="android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED" />
    24    <allow-implicit-broadcast action="android.intent.action.DATA_SMS_RECEIVED" />
    25    <allow-implicit-broadcast action="android.intent.action.MEDIA_SCANNER_SCAN_FILE" />
    26    <allow-implicit-broadcast action="android.intent.action.PACKAGE_CHANGED" />
    27    <allow-implicit-broadcast action="android.intent.action.SIM_STATE_CHANGED" />
    28    <allow-implicit-broadcast action="android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION" />
    29    <allow-implicit-broadcast action="android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION" />
    30    <allow-implicit-broadcast action="android.provider.Telephony.SECRET_CODE" />
    31    <allow-implicit-broadcast action="android.provider.Telephony.SMS_CB_RECEIVED" />
    32    <allow-implicit-broadcast action="android.provider.Telephony.SMS_DELIVER" />
    33    <allow-implicit-broadcast action="android.provider.Telephony.SMS_RECEIVED" />
    34    <allow-implicit-broadcast action="android.provider.Telephony.SMS_REJECTED" />
    35    <allow-implicit-broadcast action="android.provider.Telephony.WAP_PUSH_DELIVER" />
    36    <allow-implicit-broadcast action="android.provider.Telephony.WAP_PUSH_RECEIVED" />
    37    <allow-implicit-broadcast action="android.telephony.action.CARRIER_CONFIG_CHANGED" />
    38    <allow-implicit-broadcast action="android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED" />
    39    <allow-implicit-broadcast action="android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED" />
    40    <allow-implicit-broadcast action="android.telephony.action.MULTI_SIM_CONFIG_CHANGED" />
    41    <allow-implicit-broadcast action="android.telephony.action.SECRET_CODE" />
    42    <allow-implicit-broadcast action="android.telephony.action.SIM_APPLICATION_STATE_CHANGED" />
    43    <allow-implicit-broadcast action="android.telephony.action.SIM_CARD_STATE_CHANGED" />
    44    <allow-implicit-broadcast action="android.telephony.action.SIM_SLOT_STATUS_CHANGED" />
    
    
    final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj, boolean parallelOnce) {
        .....
        boolean skip = false;
        if (!skip) {
            // 检查当前app的启动权限
            final int allowed = mService.getAppStartModeLocked(
                    info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
                    info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, false, r.callerPackage);
            if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
                    skip = true;
                // 1. FLAG_RECEIVER_EXCLUDE_BACKGROUND , 2. 隐式广播的限制
                } 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());
                    Slog.w(TAG, "Background execution not allowed: receiving " + r.intent + " to "
                            + component.flattenToShortString());
                    skip = true;
                }
            }
        }
     }
    
    

    进程频繁crash

    W BroadcastQueue: Unable to launch app com.bsp.catchlog/1000 for broadcast Intent { act=android.provider.Telephony.SECRET_CODE dat=android_secret_code://284 flg=0x1400010 }: process is bad

    在AppErrors中处理当前crash时会去判断是否标记当前进程为bad进程。
    
        boolean handleAppCrashLocked(ProcessRecord app, String reason,
                String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
          .......
            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);
                mService.mAtmInternal.onHandleAppCrash(app.getWindowProcessController());
                if (!app.isPersistent()) {
                    EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.userId, app.uid,
                            app.info.processName);
                    if (!app.isolated) {
                  
                        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;
                .......
        }
    
    
    而在启动进程时,ProcessList的startProcessLocked中会去判断如果时后台启动且进程为bad,则返回null,终止启动进程
            ProcessRecord app;
            if (!isolated) {
                app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
                if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
                    if (mService.mAppErrors.isBadProcessLocked(info)) {
                        return null;
                    }
                }
    
    
    BroadcastQueue中processNextBroadcastLocked中进程不存在去创建进程时如果失败,就会打印上面那行log
    
            if ((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,
                    // MIUI MOD
                    // (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
                    (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false, r.callerPackage))
                            == null) {
                // Ah, this recipient is unavailable.  Finish it if necessary,
                // and mark the broadcast record as ready for the next.
                Slog.w(TAG, "Unable to launch app "
                        + info.activityInfo.applicationInfo.packageName + "/"
                        + receiverUid + " for broadcast "
                        + r.intent + ": process is bad");
                logBroadcastReceiverDiscardLocked(r);
                finishReceiverLocked(r, r.resultCode, r.resultData,
                        r.resultExtras, r.resultAbort, false);
                scheduleBroadcastsLocked();
                r.state = BroadcastRecord.IDLE;
                return;
            }
    
    

    app迟迟收不到有序广播

    广播队列中存在很多活跃状态的有序广播一直未被分发,所以app未接收到对应广播

      Active Ordered Broadcast background #68:
        BroadcastRecord{4397e66 u0 null} to user 0
        Intent { flg=0x10 cmp=android.app.stubs/.CommandReceiver (has extras) }
          extras: Bundle[mParcelledData.dataSize=280]
        caller=android.app.stubs 0:android.app.stubs/u0a553 pid=9147 uid=10553
        enqueueClockTime=2022-07-21 04:55:24.794 dispatchClockTime=1969-12-31 16:00:00.000 //分发时间无效代表未被分发
        dispatchTime=-- (3h46m21s924ms since enq) receiverTime=-
        resultTo=android.content.IIntentReceiver$Stub$Proxy@9e215a7 resultCode=-1 resultData=null
        resultAbort=false ordered=true (有序) sticky=false initialSticky=false
        ....
    

    查看下当前正在派发的有序广播是谁

      In-Flight Ordered Broadcast background #0: // 后台广播队列正在派发的有序广播
        BroadcastRecord{619f958 u0 android.intent.action.PACKAGE_CHANGED} to user 0 // 这个广播可以派发给处于stopped状态的app
        Intent { act=android.intent.action.PACKAGE_CHANGED dat=package:com.android.test.notificationapp flg=0x5000010 cmp=com.smile.gifmaker/com.yxcorp.gifshow.ad.detail.AppInstalledReceiver (has extras) }
          extras: Bundle[{android.intent.extra.changed_component_name=com.android.test.notificationapp, android.intent.extra.DONT_KILL_APP=true, android.intent.extra.UID=10258, android.intent.extra.changed_component_name_list=[com.android.test.notificationapp], android.intent.extra.user_handle=0, android.intent.extra.REASON=android.intent.action.OVERLAY_CHANGED}]
        caller=null null pid=1568 uid=1000
        enqueueClockTime=2022-07-21 17:39:13.363 dispatchClockTime=2022-07-21 17:42:24.760  // 分发也比较晚
        dispatchTime=-2s650ms (+3m11s397ms since enq) receiverTime=-2s643ms
        resultTo=null resultCode=0 resultData=null
        nextReceiver=3(//当前派发索引为3,即已派发到第三个receiver) receiver=android.os.BinderProxy@c387ee9
        curReceiver=ActivityInfo{8030e35 com.yxcorp.gifshow.ad.detail.AppInstalledReceiver} //当前派发到的receiver
        curApp=ProcessRecord{5182ab1 10877:com.smile.gifmaker/u0a225}  // 当前派发到快手进程
        curComponent={com.smile.gifmaker/com.yxcorp.gifshow.ad.detail.AppInstalledReceiver}
        curSourceDir=/data/app/partner-com.smile.gifmaker_13/base.apk
        state=1 (APP_RECEIVE)  // 广播状态不置为idle,后续的有序广播无法分发
        Deliver +4ms #0: (manifest)
          priority=0 preferredOrder=0 match=0x208000 specificIndex=-1 isDefault=false
          ActivityInfo:
            name=com.android.settings.search.provider.UpdateReceiver
            packageName=com.android.settings
            enabled=true exported=true directBootAware=true
            launchMode=0 flags=0x10000 privateFlags=0x0 theme=0x0
            resizeMode=RESIZE_MODE_RESIZEABLE
            knownActivityEmbeddingCerts={}
        Deliver +3ms #1: (manifest)
          priority=0 preferredOrder=0 match=0x208000 specificIndex=-1 isDefault=false
          ActivityInfo:
            name=com.miui.vsimcore.AppInstallReceiver
            packageName=com.miui.vsimcore
            labelRes=0x7f0b001f nonLocalizedLabel=null icon=0x0 banner=0x0
            enabled=true exported=true directBootAware=false
            launchMode=0 flags=0x10000 privateFlags=0x0 theme=0x0
            resizeMode=RESIZE_MODE_RESIZEABLE
            knownActivityEmbeddingCerts={}
        Deliver 0 #2: (manifest)
          priority=0 preferredOrder=0 match=0x208000 specificIndex=-1 isDefault=false
          ActivityInfo:
            name=com.yxcorp.gifshow.ad.detail.AppInstalledReceiver
            packageName=com.smile.gifmaker
            enabled=true exported=true directBootAware=false
            launchMode=0 flags=0x10000 privateFlags=0x0 theme=0x0
            resizeMode=RESIZE_MODE_RESIZEABLE
            knownActivityEmbeddingCerts={}
    

    接下来看下该进程主线程状态

    // 该app进程多次发生ANR,且type为接收PACKAGE_CHANGED广播
    ANR Reason: Broadcast of Intent { act=android.intent.action.PACKAGE_CHANGED dat=package: flg=0x5000010 cmp=com.smile.gifmaker/com.yxcorp.gifshow.XX.detail.AppInstalledReceiver (has extras) }
    Binder Tracsaction Info:
    
    // 主线程一直处于sleep状态
    BackTrace:
    bgAnr=true@@@type=broadcast@@@e9b396c72ab96f1221c7640874275438@@@stack type:valid stack@@@traces:
      at java.lang.Thread.sleep(Native method)
      - sleeping on <0x0542172b> (a java.lang.Object)
      at java.lang.Thread.sleep(Thread.java:450)
      - locked <0x0542172b> (a java.lang.Object)
      at java.lang.Thread.sleep(Thread.java:355)
      at com.yxcorp.gifshow.permission.s.b(kSourceFile:262150)
      at com.yxcorp.gifshow.permission.s.a(kSourceFile:262219)
      at com.yxcorp.gifshow.permission.s.b(kSourceFile:16777231)
      at com.yxcorp.gifshow.permission.s.a(kSourceFile:16777216)
      at com.yxcorp.gifshow.KwaiApp.onBaseContextAttached(kSourceFile:17563681)
      at com.yxcorp.gifshow.AppLike.onBaseContextAttached(kSourceFile:16842766)
      at com.kwai.hotfix.entry.TinkerApplicationInlineFence.handleMessageImpl(kSourceFile:17367174)
      at com.kwai.hotfix.entry.TinkerApplicationInlineFence.handleMessage_$noinline$(kSourceFile:16777219)
      at com.kwai.hotfix.entry.TinkerApplicationInlineFence.handleMessage(kSourceFile:16777216)
      at com.kwai.hotfix.loader.app.TinkerInlineFenceAction.callOnBaseContextAttached(kSourceFile:33751045)
      at com.kwai.hotfix.loader.app.TinkerApplication.onBaseContextAttached(kSourceFile:16842785)
      at com.kwai.hotfix.loader.app.TinkerApplication.attachBaseContext(kSourceFile:16842763)
      at com.yxcorp.gifshow.App.attachBaseContext(kSourceFile:16842796)
      at android.app.Application.attach(Application.java:346)
      at android.app.Instrumentation.newApplication(Instrumentation.java:1233)
      at android.app.LoadedApk.makeApplicationInner(LoadedApk.java:1479)
      at android.app.LoadedApk.makeApplicationInner(LoadedApk.java:1412)
      at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6895)
      at android.app.ActivityThread.-$$Nest$mhandleBindApplication(unavailable:0)
      at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2211)
      at android.os.Handler.dispatchMessage(Handler.java:106)
    

    结论:该app导致后续有序广播派发,且应用商店更新该app后无此问题

    广播的三千问

    1. 有序广播的receiver在什么时候进行排序?
    2. 广播的入队和分发流程是同步还是异步?
    3. 静态注册的receiver(有序&无序)对应的广播入有序广播队列还是无序(并行)广播队列?
    4. 广播有哪些状态?分别代表什么?
    5. receiver有哪些状态,分别代表什么?
    6. 广播过程中涉及到哪些超时逻辑?
    7. 系统有几个广播队列?
    8. 如何发送有序广播?粘性广播?前台广播?
    9. android O 加入了后台启动限制,主要限制逻辑是?
    10. 什么情况下发送的广播不会入队?
    11. 通过广播Receiver拉起进程的进程优先级有什么特点?
    12. 如何通过log查看广播的是否分发超时?以及广播是否派給对应的receiver?分发状态?
    13. 如果通过log查看广播是否是有序广播?静态注册?
    14. 哪个广播享受总分发超时豁免?
    15. 哪些隐式广播可以派发给后台进程?
    16. 有序广播可以通过什么传递数据?无序广播呢?
    17. 有序广播的resultTo(最终接收者)的派发时机?
    18. 发送受保护的广播有什么限制?
    19. 发送sticky广播有什么限制?
    20. 如何做到广播只派发给动态注册的receiver?
    21. 派发静态广播时,进程不存在,如何处理?
    22. 广播入队前如何获取静态receivers?如何获取动态receivers?

    相关文章

      网友评论

          本文标题:framework 广播基础知识和常见问题

          本文链接:https://www.haomeiwen.com/subject/nuqnbrtx.html