IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> framework 广播基础知识和常见问题 -> 正文阅读

[移动开发]framework 广播基础知识和常见问题

基础知识

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

分类

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

常见命令

  1. dumpsys activity broadcasts
    • Registered Receivers: 注册的receivers
    • Receiver Resolver Table:
    • Historical broadcasts [foreground]: 前台广播历史记录
    • Historical broadcasts summary [foreground]: 前台广播历史记录简要
    • Historical broadcasts [background]:后台广播历史记录
    • Historical broadcasts summary [background]: 后台广播历史记录简要
  2. dumpsys activity broadcast-stats :广播的统计

    android.intent.action.DROPBOX_ENTRY_ADDED:
      Number received: 0, skipped: 302
      Total dispatch time: +24s731ms, max: +13s538ms
      Package android: 151 times
      Bg Check Violation com.google.android.gms: 302 times

广播不被处理的情况

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

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

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方法中,会去校验接收端是否都具备广播要求的权限,如果不具备,会跳过此次广播的分发到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中添加
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;
        }

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-31 15:33:43  更:2021-08-31 15:35:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年5日历 -2025/5/3 20:25:08-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码