Android 廣播啓動流程

概述

我們從三個方面來分析廣播的流程

  • 廣播的註冊
  • 廣播的發送
  • 廣播的處理

廣播的註冊

廣播的註冊分爲靜態註冊和動態註冊,我們主要分析動態註冊

首先我們從context.registerReceiver()這個方法開始,看他內部調用了ContextWrapper#registerReceiver方法

ContextWrapper.java

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

mBase的實現類是ContextImpl

ContextImpl.java

public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    return registerReceiver(receiver, filter, null, null);
}

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

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId, IntentFilter filter, String broadcastPermission, Handler scheduler, Context context) {
    IIntentReceiver rd = null;
    if (receiver != null) {
        if (mPackageInfo != null && context != null) {
            if (scheduler == null) {
                //將主線程Handler賦予scheuler
                scheduler = mMainThread.getHandler();
            }
            //註釋1
            //獲取IIntentReceiver對象
            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
        //調用AMP.registerReceiver
        return ActivityManagerNative.getDefault().registerReceiver(
                mMainThread.getApplicationThread(), mBasePackageName,
                rd, filter, broadcastPermission, userId);
    } catch (RemoteException e) {
        return null;
    }
}

我們先看一下註釋1,他的主要作用是獲取IIntentReceiver對象,其中mPackageInfoLoadedApk類型,我們看一下IIntentReceiver到底是什麼

LoadedApk.java

  static final class ReceiverDispatcher {

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

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

IIntentReceiver原來是一個Binder接口,用於廣播的跨進程通信,他在LoadedApk.ReceiverDispatcher.InnerReceiver中實現

ActivityManagerService.java

接下來我們看一下註釋2,ActivityManagerNative.getDefault().registerReceiver,其中ActivityManagerNative.getDefault()這個最終會指向ActivityManagerService,這也是一個Binder用於進程間的通信,我們看一下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);
            ...
            //獲取IntentFilter中的actions,這個就是平時所加的action
            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) {
                   //從mStickyBroadcasts中查看用戶的sticky Inten
                    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);
                        }
                    }
                }
            }
        }
        ...


        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();
                    if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {
                        throw new IllegalStateException("Too many receivers, total of "
                                + totalReceiversForApp + ", registered for pid: "
                                + rl.pid + ", callerPackage: " + callerPackage);
                    }
                    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);
            }
            ...
            //創建BroadcastFilter,並添加到接受者隊列
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            if (rl.containsFilter(filter)) {
                Slog.w(TAG, "Receiver with filter " + filter
                        + " already registered for pid " + rl.pid
                        + ", callerPackage is " + callerPackage);
            } else {
                rl.add(bf);
                if (!bf.debugCheck()) {
                    Slog.w(TAG, "==> For Dynamic broadcast");
                }
                //新建的BroadcastFilter,添加到mReceiverResolver隊列中
                mReceiverResolver.addFilter(bf);
            }
            ...

            return sticky;
        }
    }

這個方法有點長,其中mRegisteredReceivers記錄着所有已經註冊的廣播

註冊廣播小結

  • 傳遞的參數是BroadcastReceiverIntentFilter
  • 創建LoadedApk.ReceiverDispatcher.InnerReceiver,該對象是一個Binder
  • 通過AMSInnerReceiver對象的代理類,註冊到system_server進程
  • 如果廣播沒有被註冊過,則創建廣播接受者隊列ReceiverList,並添加到AMS.mRegisteredReceivers(已註冊廣播隊列);
  • 創建BroadcastFilter,並添加到AMS.mReceiverResolverReceiverList

發送廣播

發送廣播是調用sendBroadcast(),其實真正乾貨的是ContextImpl類,廣播分很多種,有序廣播和無序廣播,粘性廣播,這裏我們只分析無序掛廣播

ContextImpl.java

public void sendBroadcast(Intent intent) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess();
        // 調用AMP.broadcastIntent 
        ActivityManagerNative.getDefault().broadcastIntent(
                mMainThread.getApplicationThread(), intent, resolvedType, null,
                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                getUserId());
    } catch (RemoteException e) {
        ...
    }
}

還是很熟悉的代碼,最終還是會調用到ActivityManagerService#broadcastIntent方法

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 = verifyBroadcastLocked(intent);
            //獲取調用者進程記錄對象
            final ProcessRecord callerApp = getRecordForAppLocked(caller);
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            //註釋1
            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;
        }
    }

註釋1處,調用了broadcastIntentLocked方法

private final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle options, boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
    ...
    if ((receivers != null && receivers.size() > 0)
        || resultTo != null) {
    //根據intent的flag來判斷前臺隊列或者後臺隊列
    BroadcastQueue queue = broadcastQueueForIntent(intent);
    //註釋1
    //創建BroadcastRecord
    BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
            callerPackage, callingPid, callingUid, resolvedType,
            requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
            resultData, resultExtras, ordered, sticky, false, userId);

    boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
    if (!replaced) {
        //將BroadcastRecord加入到有序廣播隊列
        queue.enqueueOrderedBroadcastLocked(r);
        //註釋2
        //處理廣播
        queue.scheduleBroadcastsLocked();
    }
}

    return ActivityManager.BROADCAST_SUCCESS;
}

這個方法很長,前面省略了很多,前面的工作主要是,把靜態註冊和動態註冊的廣播,按照優先級不同存儲在不同的列表中,然後把倆個列表合併到recevers列表中,這樣recevers列表就包含了所有的廣播接收者,然後再註釋1處創建BroadcastRecord對象並把recevers傳入,然後再註釋2處調用BroadcastQueuescheduleBroadcastsLocked方法處理廣播

處理廣播

不管哪種廣播最終都會調用scheduleBroadcastsLocked方法來處理廣播

BroadcastQueue.java

   public void scheduleBroadcastsLocked() {
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                + mQueueName + "]: current="
                + mBroadcastsScheduled);

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

此處的HandlerBroadcastHandler,消息在BroadcastHandler中處理

BroadcastHandler.java

private final class BroadcastHandler extends Handler {

    public void handleMessage(Message msg) {
        switch (msg.what) {
            case BROADCAST_INTENT_MSG: {
                processNextBroadcast(true); 
            } break;
            ...
    }
}

調用了processNextBroadcast方法,該方法對無序廣播和有序廣播分別進行處理,旨在把廣播發送給廣播接受者

BroadcastQueue.java

final void processNextBroadcast(boolean fromMsg) {
    synchronized(mService) {
        //part1: 處理無序廣播
        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);
                //分發廣播給已註冊的receiver 
                deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
            }
            addBroadcastToHistoryLocked(r);//將廣播添加歷史統計
        }
        ...
    }    

通過deliverToRegisteredReceiverLocked方法,把廣播分發給對應的廣播接收者

private void deliverToRegisteredReceiverLocked(BroadcastRecord r, BroadcastFilter filter, boolean ordered) {
    ...
    //檢查發送者是否有BroadcastFilter所需權限
    //以及接收者是否有發送者所需的權限等等
    //當權限不滿足要求,則skip=true。
    ...
        // 處理廣播
        performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                new Intent(r.intent), r.resultCode, r.resultData,
                r.resultExtras, r.ordered, r.initialSticky, r.userId);
        if (ordered) {
            r.state = BroadcastRecord.CALL_DONE_RECEIVE;
        }
        ...
    }
}

這個方法主要是檢查權限,如果權限通過就調用performReceiveLocked處理廣播

private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
    //通過binder異步機制,向receiver發送intent
    if (app != null) {
        if (app.thread != null) {
            //調用ApplicationThreadProxy類對應的方法 
            app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                    data, extras, ordered, sticky, sendingUser, app.repProcState);
        } else {
            //應用進程死亡,則Recevier並不存在
            throw new RemoteException("app.thread must not be null");
        }
    } else {
        //調用者進程爲空,則執行該分支
        receiver.performReceive(intent, resultCode, data, extras, ordered,
                sticky, sendingUser);
    }
}

這個方法表示,如果廣播接受者的進程還存在,則通過Binder發送廣播,這裏的app.thread指的是ApplicationThread,我們看一下scheduleRegisteredReceiver這個方法

ActivityThread.java

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

他調用了IIntentReceiverperformReceive方法,前面說過IIntentReceiver用於廣播的跨進程通信,具體實現在LoadedApk.ReceiverDispatcher.InnerReceive

LoadedApk.java

public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
    LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
    if (rd != null) {
        rd.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser);
    } else {
       ...
    }
}
   public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            //註釋1
            final Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
            if (intent == null) {
                Log.wtf(TAG, "Null intent received");
            } else {
                if (ActivityThread.DEBUG_BROADCAST) {
                    int seq = intent.getIntExtra("seq", -1);
                    Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()
                            + " seq=" + seq + " to " + mReceiver);
                }
            }
            if (intent == null || !mActivityThread.post(args.getRunnable())) {//註釋2
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManager.getService();
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing sync broadcast to " + mReceiver);
                    args.sendFinished(mgr);
                }
            }
        }

註釋1處把廣播的intent對象封裝爲Args,註釋2處利用mActivityThread的post傳入了Arg對象,mActivityThread是一個Handler指向內部類H,註釋2處的args.getRunnable(),就是要處理的邏輯,我們看下這個getRunnable

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

再註釋1處,調用了onReceive方法,這樣註冊的廣播接受者,就收到了消息

參考:http://gityuan.com/2016/06/04/broadcast-receiver/

Android 進階解密

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章