美文网首页
Android源码学习-BroadcastReceiver工作流

Android源码学习-BroadcastReceiver工作流

作者: m1Ku | 来源:发表于2019-07-09 17:55 被阅读0次

介绍

广播接收者作为四大组件之一,使用时需继承BroadcastReceiver并实现onReceive方法,再将其进行注册后,就可以发送和接收广播了。

private class MyBroadcastReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.e("m1ku","接收到广播");
    }
}

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.m1ku.MyBroadcastReceiver");
registerReceiver(new MyBroadcastReceiver(),intentFilter);

Intent intent = new Intent();
intent.setAction("com.m1ku.MyBroadcastReceiver");
sendBroadcast(intent);

源码分析

广播的主要工作流程分为注册以及发送接收广播,这里分析普通广播的两个工作流程的源码。

广播的动态注册

调用ContextWrapper的registerReceiver

@Override
public Intent registerReceiver(
    BroadcastReceiver receiver, IntentFilter filter) {
    return mBase.registerReceiver(receiver, filter);
}

具体实现还是由ContextImpl的方法完成

@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    return registerReceiver(receiver, filter, null, null);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
        String broadcastPermission, Handler scheduler) {
    return registerReceiverInternal(receiver, getUserId(),
            filter, broadcastPermission, scheduler, getOuterContext(), 0);
}

继续调用registerReceiverInternal

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();
            }
            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 {
        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();
    }
}

由于这里涉及到IPC通信,而广播接收者不能跨进程传输,所以这里通过getReceiverDispatcher方法将其转换为ReceiverDispatcher.InnerReceiver对象,它继承自IIntentReceiver.Stub是一个Binder接口,可以进行跨进程传递,而IntentFilter本身就实现了Parcelable接口。接下来远程调用了AMS的registerReceiver方法。

public Intent registerReceiver(IApplicationThread caller, String callerPackage,
        IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
                               int flags) {
      //...
      mRegisteredReceivers.put(receiver.asBinder(), rl);
      //...
      BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
      rl.add(bf);
      if (!bf.debugCheck()) {
             Slog.w(TAG, "==> For Dynamic broadcast");
      }
      mReceiverResolver.addFilter(bf);
      //...
}

在该方法中将ReceiverDispatcher.InnerReceiver对象和IntentFilter对象保存起来就完成广播的动态注册过程。

广播发送和接收

调用sendBroadcast方法发送广播

@Override
public void sendBroadcast(Intent intent) {
    mBase.sendBroadcast(intent);
}

实现依然在ContextImpl中

@Override
public void sendBroadcast(Intent intent) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess(this);
        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();
    }
}

远程调用AMS的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) {
        //...
        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;
    }
}
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) {
  //...
  // By default broadcasts do not go to stopped apps.
        intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
  //...
    int[] users;
        if (userId == UserHandle.USER_ALL) {
            // Caller wants broadcast to go to all started users.
            users = mUserController.getStartedUserArrayLocked();
        } else {
            // Caller wants broadcast to go to one specific user.
            users = new int[] {userId};
        }

        // Figure out who all will receive this broadcast.
        List receivers = null;
        List<BroadcastFilter> registeredReceivers = null;
        // Need to resolve the intent to interested receivers...
        if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                 == 0) {
            receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
        }
        if (intent.getComponent() == null) {
            if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
                // Query one target user at a time, excluding shell-restricted users
                for (int i = 0; i < users.length; i++) {
                    if (mUserController.hasUserRestriction(
                            UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
                        continue;
                    }
                    List<BroadcastFilter> registeredReceiversForUser =
                            mReceiverResolver.queryIntent(intent,
                                    resolvedType, false /*defaultOnly*/, users[i]);
                    if (registeredReceivers == null) {
                        registeredReceivers = registeredReceiversForUser;
                    } else if (registeredReceiversForUser != null) {
                        registeredReceivers.addAll(registeredReceiversForUser);
                    }
                }
            } else {
                registeredReceivers = mReceiverResolver.queryIntent(intent,
                        resolvedType, false /*defaultOnly*/, userId);
            }
        }
  
  final boolean replacePending =
                (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;

        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing broadcast: " + intent.getAction()
                + " replacePending=" + replacePending);

        int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
        if (!ordered && NR > 0) {
            // If we are not serializing this broadcast, then send the
            // registered receivers separately so they don't wait for the
            // components to be launched.
            if (isCallerSystem) {
                checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                        isProtectedBroadcast, registeredReceivers);
            }
            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);
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
            final boolean replaced = replacePending
                    && (queue.replaceParallelBroadcastLocked(r) != null);
            // Note: We assume resultTo is null for non-ordered broadcasts.
            if (!replaced) {
                queue.enqueueParallelBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
            registeredReceivers = null;
            NR = 0;
        }
}

首先为intent添加一个flag:FLAG_EXCLUDE_STOPPED_PACKAGES,这个flag意思是已经结束的应用不会收到广播。mReceiverResolver已经在注册广播时进行保存赋值,调用mReceiverResolver.queryIntent方法根据传递来的广播的intent查找到匹配的intent-filter列表registeredReceiversForUser,然后使用广播队列queue和registeredReceivers构建了一个BroadcastRecord对象,调用queue.enqueueParallelBroadcastLocked将这个BroadcastRecord保存到mParallelBroadcasts集合中。最后调用queue.scheduleBroadcastsLocked方法将广播发送给指定的接收者

public void scheduleBroadcastsLocked() {
    //...
    if (mBroadcastsScheduled) {
        return;
    }
    mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
    mBroadcastsScheduled = true;
}

使用mHandler发送一个BROADCAST_INTENT_MSG的消息,在handleMessage中调用processNextBroadcast方法

final void processNextBroadcast(boolean fromMsg) {
  BroadcastRecord r;
  //...
    // First, deliver any non-serialized broadcasts right away.
            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);
                }
                            //...
            }
}

遍历接收者并调用deliverToRegisteredReceiverLocked方法

private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
                                               BroadcastFilter filter, boolean ordered, int index) {
  //...
                  performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                        new Intent(r.intent), r.resultCode, r.resultData,
                        r.resultExtras, r.ordered, r.initialSticky, r.userId);
  //...
}

调用performReceiveLocked方法

void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
        Intent intent, int resultCode, String data, Bundle extras,
                          boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
  //...
  app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.repProcState);
  //...
}

这里又调用了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);
    receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
            sticky, sendingUser);
}

在注册流程中我们知道receiver是一个ReceiverDispatcher.InnerReceiver对象,它的performReceive方法如下

@Override
public void performReceive(Intent intent, int resultCode, String data,
        Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
    final LoadedApk.ReceiverDispatcher rd;
  //...
  rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);
  //...
}

调用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);
  //...
if (intent == null || !mActivityThread.post(args.getRunnable())) {
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManager.getService();
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing sync broadcast to " + mReceiver);
                    args.sendFinished(mgr);
                }
          }
  //...
}

mActivityThread是ActivityThread中mH这个Handler对象,用它执行args里的Runnable

public final Runnable getRunnable() {
    return () -> {
        final BroadcastReceiver receiver = mReceiver;
      //...
        ClassLoader cl = mReceiver.getClass().getClassLoader();
        intent.setExtrasClassLoader(cl);
        intent.prepareToEnterProcess();
        setExtrasClassLoader(cl);
        receiver.setPendingResult(this);
        receiver.onReceive(mContext, intent);
      //...
    }
}

在run方法中,调用了BroadcastReceiver的onReceive方法,广播接收者就接收到了广播,这就完成了广播的发送和接收。而由于这里使用的是主线程的mH对象执行的Runnable,所以onReceive执行在主线程中,当然这里是不能做耗时操作的。

相关文章

网友评论

      本文标题:Android源码学习-BroadcastReceiver工作流

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