ANR源码分析之Broadcast Timeout

本文深入探讨了Android应用中的Broadcast Timeout问题,分析了广播超时的流程。内容涉及静态与动态注册广播、普通广播、有序广播、Sticky广播的执行方式,以及串行执行广播的超时时间(前台10s,后台60s)。重点讲解了sendBroadcast方法在ContextImpl中的实现,以及BroadcastQueue中关于广播队列超时和等待策略的细节。
摘要由CSDN通过智能技术生成

 在上篇文章中,介绍了InputDispatcher Timeout的流程。本篇文章将介绍Broadcast Timeout的流程。 我们知道广播根据注册的方式的可以分为静态注册广播和动态注册广播,根据发送方式可以分为普通广播、有序广播、Sticky广播以及APP内广播。广播执行的方式有两种,一种是串行执行,另外一种是并发执行。并发执行的广播是不存在超时的情况,例如动态注册的非有序的广播。而串行执行的广播是有超时时间的,前台广播是10s,后台广播是60s。可以通过设置Intent.FLAG_RECEIVER_FOREGROUND标志位,将广播设置为前台广播,默认情况下,广播都是后台广播。静态注册的和有序的广播都是串行执行的。

 Broadcast Timeout的整体流程如下图所示:



1.sendBroadcast方法(ContextImpl.java)
 广播的发送是通过context.sendBroadcast()方法来实现的,Context类是一个抽象的类,具体的由ContextImpl类来实现。
 framework/core/java/android/app/ContextImpl.java

 /*
    * 发送广播
    */
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManagerNative.getDefault().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();
        }
    }
2.broadcastIntent方法(ActivityManagerService.java)
   frameworks/base/core/java/com/android/server/am/ActivityManagerService.java
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) {
        enforceNotIsolatedCaller("broadcastIntent");
        synchronized(this) {
            //验证广播intent是否有效
            intent = verifyBroadcastLocked(intent);
           
            //获取调用者进程记录对象
            final ProcessRecord callerApp = getRecordForAppLocked(caller);
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            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;
        }
    }

 在broadcastIntent方法中有两个布尔值参数serialized和sticky来共同决定是普通广播,有序广播还是sticky广播,参数如下:

类型 serialized sticky
sendBroadcast false false
sendOrderedBroadcast true false
sendStickyBroadcast false true


3.broadcastIntentLocked方法(ActivityManagerService.java)
 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);
       // 增加该标志,则广播不会发送到已停止的package
        intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);


        // 当没有启动完成,不允许启动新的进程
        if (!mProcesse
ANR(Application Not Responding)错误是指应用程序在主线程上执行了太多的工作,导致界面无法响应用户的事件,从而出现了“应用程序无响应”的错误提示。在这种情况下,如果您的应用程序正在执行服务,那么该错误可能是由于服务执行超时导致的。 以下是解决这个问题的一些方法: 1. 使用IntentService: IntentService 是一种专门用于执行异步任务的服务。它可以在后台执行任务,并在完成任务后自动停止。使用 IntentService 可以避免在主线程上执行任务,从而避免 ANR 错误。 2. 使用线程池:如果您的应用程序需要在服务中执行大量的异步任务,可以使用线程池来管理这些任务。线程池可以在后台执行任务,并控制任务的数量和执行顺序,从而避免在主线程上执行过多的工作。 3. 使用HandlerThread:HandlerThread 是一种特殊的线程,它可以接收消息并在消息队列中处理这些消息。使用 HandlerThread 可以在后台执行任务,并避免在主线程上执行过多的工作。 4. 使用JobScheduler:JobScheduler 是一种 Android 系统提供的调度服务,它可以在特定的时间间隔或特定的条件下执行任务。使用 JobScheduler 可以避免在主线程上执行任务,并在系统空闲时执行任务,从而避免 ANR 错误。 请注意,如果您的应用程序需要执行长时间运行的任务,最好将这些任务移到后台线程中执行,以避免 ANR 错误。同时,还应该尽可能地优化代码,避免在主线程上执行过多的工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值