0
点赞
收藏
分享

微信扫一扫

Android 10 BroadcastReceiver 工作过程

攻城狮Chova 2021-09-29 阅读 57
Android

简介

本次介绍BroadcastReceiver的工作过程,主要从两方面来讲,一是广播的注册过程,二是广播的发送和接收过程。我们在使用的时候其实都是继承BroadcastReceiver并重写onReceiver方法即可,我们在此方法不能做耗时的工作参考时间为10秒。

广播的注册过程

注册广播有两种方式,一是动态注册通过代码调用registerReceiver方法即可,二是AndroidManifest文件静态注册,一般在安装时由系统自动注册,由PMS(PackageManagerService)来完成注册。现在我们要分析的是动态注册过程,我们先看整个注册过程源码时序图,如图所示:


调用registerReceiver方法后,接着调用registerReceiverInternal方法。在这方法里面做了一些跨进程处理,说明BroadcastReceiver不支持跨进程调用。

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, Context context, int flags) {
        IIntentReceiver rd = null;
        if (receiver != null) {
            if (mPackageInfo != null && context != null) {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                //1
                rd = mPackageInfo.getReceiverDispatcher(
                    receiver, context, scheduler,
                    mMainThread.getInstrumentation(), true);
            } else {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        try {
            //2
            final Intent intent = ActivityManager.getService().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                    broadcastPermission, userId, flags);
            if (intent != null) {
                intent.setExtrasClassLoader(getClassLoader());
                intent.prepareToEnterProcess();
            }
            return intent;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

1)把BroadcastReceiver封装成跨进程可调用的IIntentReceiver类型的rd。IIntentReceiver都是一个Binder接口,方便AMS进程回调。2)开始调用AMS的registerReceiver方法。把registerReceiver方法里代码有些多,分成两块代码来分析。

 public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
            int flags) {
        ProcessRecord callerApp = null;
        synchronized(this) {
            if (caller != null) {
                //1 
                callerApp = getRecordForAppLocked(caller);
            }
            //2
            Iterator<String> actions = filter.actionsIterator();
            if (actions == null) {
                ArrayList<String> noAction = new ArrayList<String>(1);
                noAction.add(null);
                actions = noAction.iterator();
            }

            // Collect stickies of users
            int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
            while (actions.hasNext()) {
                String action = actions.next();
                for (int id : userIds) {
                    ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                    if (stickies != null) {
                        ArrayList<Intent> intents = stickies.get(action);
                        if (intents != null) {
                            if (stickyIntents == null) {
                                stickyIntents = new ArrayList<Intent>();
                            }
                            //3 
                            stickyIntents.addAll(intents);
                        }
                    }
                }
            }
        }
        ArrayList<Intent> allSticky = null;
        if (stickyIntents != null) {
            final ContentResolver resolver = mContext.getContentResolver();
            for (int i = 0, N = stickyIntents.size(); i < N; i++) {
                Intent intent = stickyIntents.get(i);
                if (instantApp &&
                        (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
                    continue;
                }
                if (filter.match(resolver, intent, true, TAG) >= 0) {
                    if (allSticky == null) {
                        allSticky = new ArrayList<Intent>();
                    }
                    //4
                    allSticky.add(intent);
                }
            }
        }

1 找到广播注册者所在的进程。
2 根据filter得到相应的actions。
3 找到匹配传入参数filter粘性广播的intent。
4 把所有粘性广播的intent都存入allSticky,从这里也可以看出这都保存在AMS中。
我们接着分析此方法的第二块代码,如下所示。

 public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
            int flags) {
        
        synchronized (this) {
            if (callerApp != null && (callerApp.thread == null
                    || callerApp.thread.asBinder() != caller.asBinder())) {
                // Original caller already died
                return null;
            }
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            if (rl == null) {
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                if (rl.app != null) {
                    final int totalReceiversForApp = rl.app.receivers.size();
                    rl.app.receivers.add(rl);
                } else {
                    try {
                        receiver.asBinder().linkToDeath(rl, 0);
                    } catch (RemoteException e) {
                        return sticky;
                    }
                    rl.linkedToDeath = true;
                }
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            }
            //1 
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            if (rl.containsFilter(filter)) { } else {
                rl.add(bf);
                if (!bf.debugCheck()) {
                    Slog.w(TAG, "==> For Dynamic broadcast");
                }
                //2
                mReceiverResolver.addFilter(bf);
            }
            return sticky;
        }
    }

1 BroadcastFilter 广播接收者的描述。
2 mReceiverResolver 用来存储广播接收者,当AMS收到广播消息时,从这里面找对应的广播接收者。代码到达这里说明我们广播都注册成功了。

广播的发送和接收过程

当通过send方法来发送广播的时候,AMS查找匹配广播接收者并且把广播发送给他们处理。以下都是发送广播的几种类型
普通广播:依次传递给各个处理器处理。
有序广播:优先级高的处理器先收到消息,可截获消息不让优先级低的处理。
粘性广播:消息发送后都存在系统容器里面,当我注册了接收者都会收到。
现在开始分析广播的发送和接收过程,分析普通广播,首先先看一张源码时序图如图所示:


调用sendBroadcast方法,然后调用AMS的broadcastIntent方法。

@Override
    public void sendBroadcast(Intent intent, String receiverPermission) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        String[] receiverPermissions = receiverPermission == null ? null
                : new String[] {receiverPermission};
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManager.getService().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
                    null, false, false, getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

在broadcastIntent代码中,做了些验证广播的合法性,然后接着调用了broadcastIntentLocked方法,在这方法里面调用了broadcastIntentLocked。

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 realCallingUid,
            int realCallingPid, int userId, boolean allowBackgroundActivityStarts) {
        intent = new Intent(intent);
        ...
        // By default broadcasts do not go to stopped apps.
        //1
        intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
        int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
        if (!ordered && NR > 0) {
            
            final BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                    requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
                    resultCode, resultData, resultExtras, ordered, sticky, false, userId,
                    allowBackgroundActivityStarts, timeoutExempt);
            
            if (!replaced) {
                //2
                queue.enqueueParallelBroadcastLocked(r);
                //3
                queue.scheduleBroadcastsLocked();
            }
            registeredReceivers = null;
            NR = 0;
        }
        return ActivityManager.BROADCAST_SUCCESS;
    }

1 默认添加FLAG_EXCLUDE_STOPPED_PACKAGES,防止无意间或者不必要时候调起了已经停止的应用,如果需要启动停止的应用添加FLAG_INCLUDE_STOPPED_PACKAGES标记即可这两种标记可以共存。
2 把BroadcastRecord存入到BroadcastQueue的mParallelBroadcasts数组里面。
3 然后调用BroadcastQueue的scheduleBroadcastsLocked方法。在这方法里面通过Handler发送消息然后processNextBroadcast方法,传递参数是true,接着调用processNextBroadcastLocked方法。

 final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
        BroadcastRecord r;
        //1
        if (fromMsg) {
            mBroadcastsScheduled = false;
        }
        // First, deliver any non-serialized broadcasts right away.
        //2
        while (mParallelBroadcasts.size() > 0) {
            //3
            r = mParallelBroadcasts.remove(0);
            final int N = r.receivers.size();
            for (int i=0; i<N; i++) {
                Object target = r.receivers.get(i);
                //4
                deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
            }
            addBroadcastToHistoryLocked(r);
        }
    }

这个processNextBroadcastLocked方法有特别多的代码,贴了核心代码出来分析。
1 mBroadcastsScheduled设置成false,对发来BROADCAST_INTENT_MSG消息表示处理。
2 用while循环将mParallelBroadcasts无序的广播发送给广播接收者。
3 取出mParallelBroadcasts存储在此数组的BroadcastRecord类型对象。
4 然后将BroadcastRecord类型的r对象发送给广播接收者。然后我们在调用deliverToRegisteredReceiverLocked方法,如下所示:

 private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
            BroadcastFilter filter, boolean ordered, int index) {
      
        try {
            if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
                if (ordered) {
                    skipReceiverLocked(r);
                }
            } else {
                r.receiverTime = SystemClock.uptimeMillis();
                maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                        new Intent(r.intent), r.resultCode, r.resultData,
                        r.resultExtras, r.ordered, r.initialSticky, r.userId);
                if (r.allowBackgroundActivityStarts && !r.ordered) {
                    postActivityStartTokenRemoval(filter.receiverList.app, r);
                }
            }
           
        } catch (RemoteException e) { }
    }

上述代码省去无数代码,代码主要是检查广播发送者和广播接收者的权限的。权限检查没问题,接着调用performReceiveLocked方法,代码如下:

    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser)
            throws RemoteException {
        // Send the intent to the receiver asynchronously using one-way binder calls.
        if (app != null) {
            if (app.thread != null) {
                // If we have an app thread, do the call through that so it is
                // correctly ordered with other one-way calls.
                try {
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.getReportedProcState());
                } catch (RemoteException ex) {
                }
            } else {
            }
        } else {
            receiver.performReceive(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
        }
    }

检查了应用程序是否在运行,然后调用了ApplicationThread的scheduleRegisteredReceiver,回到了主进程,代码如下:

       public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
                int resultCode, String dataStr, Bundle extras, boolean ordered,
                boolean sticky, int sendingUser, int processState) throws RemoteException {
            updateProcessState(processState, false);scheduleRegisteredReceiver
            receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                    sticky, sendingUser);
        }

然后调用了IIntentReceiver Binder接口的performReceive方法。这个类我们应该非常熟悉了,在我们注册广播的时候,就是把BroadcastReceiver封装在IIntentReceiver这个类的。我们可以看下源码:

      ReceiverDispatcher(BroadcastReceiver receiver, Context context,
                Handler activityThread, Instrumentation instrumentation,
                boolean registered) {
            if (activityThread == null) {
                throw new NullPointerException("Handler must not be null");
            }
            mIIntentReceiver = new InnerReceiver(this, !registered);
            mReceiver = receiver;
            mContext = context;
            mActivityThread = activityThread;
            mInstrumentation = instrumentation;
            mRegistered = registered;
            mLocation = new IntentReceiverLeaked(null);
            mLocation.fillInStackTrace();
        }

ReceiverDispatcher持有InnerReceiver类和BroadcastReceiver类对象引用,是这个类扮演了桥梁的角色让他们有了关联关系。接着我们看看InnerReceiver这个类里面的performReceive方法,代码如下:

     final static class InnerReceiver extends IIntentReceiver.Stub {
            final WeakReference<ReceiverDispatcher> mDispatcher;
            final ReceiverDispatcher mStrongRef;

            InnerReceiver(ReceiverDispatcher rd, boolean strong) {
                mDispatcher = new WeakReference<ReceiverDispatcher>(rd);
                mStrongRef = strong ? rd : null;
            }

            @Override
            public void performReceive(Intent intent, int resultCode, String data,
                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                final ReceiverDispatcher rd;
                if (intent == null) {
                    rd = null;
                } else {
                    rd = mDispatcher.get();
                }
                if (rd != null) {
                    //1
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);
                } else {
                    IActivityManager mgr = ActivityManager.getService();
                    try {
                        if (extras != null) {
                            extras.setAllowFds(false);
                        }
                        mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                }
            }
        }
      }

标记1调用了ReceiverDispatcher的performReceive,接着我们看看,代码如下:

     public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            final Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
            //1
            if (intent == null || !mActivityThread.post(args.getRunnable())) {
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManager.getService();
                    args.sendFinished(mgr);
                }
            }
        }

1 mActivityThread执行了post方法,其实这个类都是H类继承Handler,H类对我们来说非常熟悉,在分析Activity启动流程通过他往主线程发送消息,这里也看出onReceiver方法在主线程里面。Args类通过getRunnable方法new 出来一个Runnable对象,我们看看这个类具体源码,代码如下:

final class Args extends BroadcastReceiver.PendingResult {
                 public final Runnable getRunnable() {
                return () -> {
                    final BroadcastReceiver receiver = mReceiver;
                    final boolean ordered = mOrdered;
                try {
                        ClassLoader cl = mReceiver.getClass().getClassLoader();
                        intent.setExtrasClassLoader(cl);
                        intent.prepareToEnterProcess();
                        setExtrasClassLoader(cl);
                        receiver.setPendingResult(this);
                        receiver.onReceive(mContext, intent);
                    } catch (Exception e) {
                    }
                };
            }
        }

BroadcastReceiver类型的receiver对象执行onReceiver方法,这样广播的注册者收到了广播得到了intent。
以上都是普通广播源码所有分析,如有问题及时修改。

举报

相关推荐

0 条评论