Android AOSP 6.0.1 sendBroadcast發送廣播流程分析

上一節中分析了廣播註冊流程,那麼 sendBroadcast 又經過了那些步驟?

在 DemoService 的 onStartCommand 調用 sendBroadcast,發送之前攜帶了一個 String 類型的字符串。

package com.demo.framework

import android.app.Service
import android.content.Intent
import android.os.IBinder
import android.util.Log

class DemoService : Service() {

    companion object {
        const val TAG = "DemoService"
    }

    override fun onBind(intent: Intent): IBinder? {
        Log.d(TAG, "onBind")
        return null
    }

    override fun onCreate() {
        Log.d(TAG, "onCreate")
        super.onCreate()
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Log.d(TAG, "onStartCommand flags=$flags,startId=$startId")
        val intent = Intent(MainActivity.ACTION)
        intent.putExtra(MainActivity.VALUE_KEY, "DemoService Hello!")
        sendBroadcast(intent)
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onDestroy() {
        Log.d(TAG, "onDestroy")
        super.onDestroy()
    }
}

sendBroadcast 方法來自 ContextWrapper 類,最終調用了 ContextImpl 類中的 sendBroadcast 方法。

frameworks/base/core/java/android/content/ContextWrapper.java

public class ContextWrapper extends Context {
    ......
    @Override
    public void sendBroadcast(Intent intent) {
        mBase.sendBroadcast(intent);
    }
    ......
}

ContextImpl 類 sendBroadcast 方法中拿到 ActivityManagerProxy 對象,然後調用其 broadcastIntent 方法。mMainThread.getApplicationThread() 返回 ApplicationThread 對象。

frameworks/base/core/java/android/app/ContextImpl.java

class ContextImpl extends Context {
    ......
    @Override
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess();
            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 new RuntimeException("Failure from system", e);
        }
    }
    ......
}

ActivityManagerProxy 的 broadcastIntent 方法最終是調用其內部的一個 Binder 代理對象 mRemote 向 ActivityManagerService 發送一個類型爲 BROADCAST_INTENT_TRANSACTION 的進程間通信請求。

frameworks/base/core/java/android/app/ActivityManagerNative.java

class ActivityManagerProxy implements IActivityManager
{
    ......
    public int broadcastIntent(IApplicationThread caller,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle map,
            String[] requiredPermissions, int appOp, Bundle options, boolean serialized,
            boolean sticky, int userId) throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo != null ? resultTo.asBinder() : null);
        data.writeInt(resultCode);
        data.writeString(resultData);
        data.writeBundle(map);
        data.writeStringArray(requiredPermissions);
        data.writeInt(appOp);
        data.writeBundle(options);
        data.writeInt(serialized ? 1 : 0);
        data.writeInt(sticky ? 1 : 0);
        data.writeInt(userId);
        mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);
        reply.readException();
        int res = reply.readInt();
        reply.recycle();
        data.recycle();
        return res;
    } 
    ......
}

此函數接着調用 broadcastIntentLocked 方法。

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public final class ActivityManagerService extends ActivityManagerNative
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    ......
    public final int broadcastIntent(IApplicationThread caller,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle resultExtras,
            String[] requiredPermissions, int appOp, Bundle options,
            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();
            int res = broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null,
                    intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                    requiredPermissions, appOp, null, serialized, sticky,
                    callingPid, callingUid, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }
    ......
}        

以上函數準備了必要的參數,下一步調用 broadcastIntentLocked 方法。

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public final class ActivityManagerService extends ActivityManagerNative
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    ......
    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) {
        intent = new Intent(intent);

        // 默認情況下,廣播不會轉到已停止的應用程序
        intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

        // 如果還沒有完成啓動,不能允許啓動新的進程
        if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
        }

        userId = handleIncomingUser(callingPid, callingUid, userId,
                true, ALLOW_NON_FULL, "broadcast", callerPackage);

        // 確保正在接收此廣播的用戶正在運行。 如果沒有,我們將跳過它。
        if (userId != UserHandle.USER_ALL && !isUserRunningLocked(userId, false)) {
            if ((callingUid != Process.SYSTEM_UID
                    || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
                    && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
                Slog.w(TAG, "Skipping broadcast of " + intent
                        + ": user " + userId + " is stopped");
                return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
            }
        }

        BroadcastOptions brOptions = null;
        if (options != null) {
            brOptions = new BroadcastOptions(options);
            if (brOptions.getTemporaryAppWhitelistDuration() > 0) {
                // 檢查是否允許調用者這樣做。注意,我們正在檢查實際的真實調用者,因爲實際上是誰提供了參數。
                if (checkComponentPermission(
                        android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
                        Binder.getCallingPid(), Binder.getCallingUid(), -1, true)
                        != PackageManager.PERMISSION_GRANTED) {
                    String msg = "Permission Denial: " + intent.getAction()
                            + " broadcast from " + callerPackage + " (pid=" + callingPid
                            + ", uid=" + callingUid + ")"
                            + " requires "
                            + android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
                    Slog.w(TAG, msg);
                    throw new SecurityException(msg);
                }
            }
        }

        /*
         * 防止非系統代碼(此處定義爲非持久性進程)發送受保護的廣播。
         */
        int callingAppId = UserHandle.getAppId(callingUid);
        if (callingAppId == Process.SYSTEM_UID || callingAppId == Process.PHONE_UID
            || callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID
            || callingAppId == Process.NFC_UID || callingUid == 0) {
            // Always okay.
        } else if (callerApp == null || !callerApp.persistent) {
            try {
                if (AppGlobals.getPackageManager().isProtectedBroadcast(
                        intent.getAction())) {
                    String msg = "Permission Denial: not allowed to send broadcast "
                            + intent.getAction() + " from pid="
                            + callingPid + ", uid=" + callingUid;
                    Slog.w(TAG, msg);
                    throw new SecurityException(msg);
                } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(intent.getAction())) {
                    // 兼容性的特殊情況:我們不希望應用程序發送這個,
                    // 但從歷史上看,它沒有受到保護,因此,與其讓它受保護,不如從調用者做限制。
                    if (callerApp == null) {
                        String msg = "Permission Denial: not allowed to send broadcast "
                                + intent.getAction() + " from unknown caller.";
                        Slog.w(TAG, msg);
                        throw new SecurityException(msg);
                    } else if (intent.getComponent() != null) {
                        // 它們足夠好,可以發送到顯式組件...驗證它是否已發送到調用應用程序。
                        if (!intent.getComponent().getPackageName().equals(
                                callerApp.info.packageName)) {
                            String msg = "Permission Denial: not allowed to send broadcast "
                                    + intent.getAction() + " to "
                                    + intent.getComponent().getPackageName() + " from "
                                    + callerApp.info.packageName;
                            Slog.w(TAG, msg);
                            throw new SecurityException(msg);
                        }
                    } else {
                        // 限制廣播到自己的包中。
                        intent.setPackage(callerApp.info.packageName);
                    }
                }
            } catch (RemoteException e) {
                Slog.w(TAG, "Remote exception", e);
                return ActivityManager.BROADCAST_SUCCESS;
            }
        }

        final String action = intent.getAction();
        if (action != null) {
            switch (action) {
                case Intent.ACTION_UID_REMOVED:
                case Intent.ACTION_PACKAGE_REMOVED:
                case Intent.ACTION_PACKAGE_CHANGED:
                case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
                case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
                    // 處理特殊意圖:如果此廣播是從程序包管理器發出的有關刪除程序包的信息,
                    // 則我們需要從歷史記錄棧中刪除其所有 Activity。
                    
                    // 權限不滿足,拋出 SecurityException 異常
                    if (checkComponentPermission(
                            android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
                            callingPid, callingUid, -1, true)
                            != PackageManager.PERMISSION_GRANTED) {
                        String msg = "Permission Denial: " + intent.getAction()
                                + " broadcast from " + callerPackage + " (pid=" + callingPid
                                + ", uid=" + callingUid + ")"
                                + " requires "
                                + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
                        Slog.w(TAG, msg);
                        throw new SecurityException(msg);
                    }
                    switch (action) {
                        case Intent.ACTION_UID_REMOVED:
                            final Bundle intentExtras = intent.getExtras();
                            final int uid = intentExtras != null
                                    ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
                            if (uid >= 0) {
                                mBatteryStatsService.removeUid(uid);
                                mAppOpsService.uidRemoved(uid);
                            }
                            break;
                        case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
                            // 如果資源不可用,則強制停止所有這些包並刷新屬性緩存。
                            String list[] =
                                    intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                            if (list != null && list.length > 0) {
                                for (int i = 0; i < list.length; i++) {
                                    forceStopPackageLocked(list[i], -1, false, true, true,
                                            false, false, userId, "storage unmount");
                                }
                                mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
                                sendPackageBroadcastLocked(
                                        IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list,
                                        userId);
                            }
                            break;
                        case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
                            mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
                            break;
                        case Intent.ACTION_PACKAGE_REMOVED:
                        case Intent.ACTION_PACKAGE_CHANGED:
                            Uri data = intent.getData();
                            String ssp;
                            if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
                                boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);
                                boolean fullUninstall = removed &&
                                        !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                                final boolean killProcess =
                                        !intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false);
                                if (killProcess) {
                                    forceStopPackageLocked(ssp, UserHandle.getAppId(
                                            intent.getIntExtra(Intent.EXTRA_UID, -1)),
                                            false, true, true, false, fullUninstall, userId,
                                            removed ? "pkg removed" : "pkg changed");
                                }
                                if (removed) {
                                    sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
                                            new String[] {ssp}, userId);
                                    if (fullUninstall) {
                                        mAppOpsService.packageRemoved(
                                                intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);

                                        // 刪除給此包授予的所有權限
                                        removeUriPermissionsForPackageLocked(ssp, userId, true);

                                        removeTasksByPackageNameLocked(ssp, userId);
                                        mBatteryStatsService.notePackageUninstalled(ssp);
                                    }
                                } else {
                                    cleanupDisabledPackageComponentsLocked(ssp, userId, killProcess,
                                            intent.getStringArrayExtra(
                                                    Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST));
                                }
                            }
                            break;
                    }
                    break;
                case Intent.ACTION_PACKAGE_ADDED:
                    // 添加軟件包的特殊情況:默認情況下,打開兼容模式。
                    Uri data = intent.getData();
                    String ssp;
                    if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
                        final boolean replacing =
                                intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                        mCompatModePackages.handlePackageAddedLocked(ssp, replacing);

                        try {
                            ApplicationInfo ai = AppGlobals.getPackageManager().
                                    getApplicationInfo(ssp, 0, 0);
                            mBatteryStatsService.notePackageInstalled(ssp,
                                    ai != null ? ai.versionCode : 0);
                        } catch (RemoteException e) {
                        }
                    }
                    break;
                case Intent.ACTION_TIMEZONE_CHANGED:
                    // 如果這是更改時區的操作,請排隊一條消息,以重置當前所有正在運行的進程的時區。 該消息將在廣播發生之前排隊。
                    mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
                    break;
                case Intent.ACTION_TIME_CHANGED:
                    // 如果用戶設置了時間,則讓所有正在運行的進程知道。
                    final int is24Hour =
                            intent.getBooleanExtra(Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT, false) ? 1
                                    : 0;
                    mHandler.sendMessage(mHandler.obtainMessage(UPDATE_TIME, is24Hour, 0));
                    BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
                    synchronized (stats) {
                        stats.noteCurrentTimeChangedLocked();
                    }
                    break;
                case Intent.ACTION_CLEAR_DNS_CACHE:
                    mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
                    break;
                case Proxy.PROXY_CHANGE_ACTION:
                    ProxyInfo proxy = intent.getParcelableExtra(Proxy.EXTRA_PROXY_INFO);
                    mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
                    break;
            }
        }

        // 如果需要,添加到粘性列表。
        if (sticky) {
            // 檢查粘性廣播權限
            if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
                    callingPid, callingUid)
                    != PackageManager.PERMISSION_GRANTED) {
                String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
                        + callingPid + ", uid=" + callingUid
                        + " requires " + android.Manifest.permission.BROADCAST_STICKY;
                Slog.w(TAG, msg);
                throw new SecurityException(msg);
            }
            if (requiredPermissions != null && requiredPermissions.length > 0) {
                Slog.w(TAG, "Can't broadcast sticky intent " + intent
                        + " and enforce permissions " + Arrays.toString(requiredPermissions));
                return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
            }
            if (intent.getComponent() != null) {
                throw new SecurityException(
                        "Sticky broadcasts can't target a specific component");
            }
            // 我們在這裏直接使用 userId,因爲“all”目標被維護爲一組單獨的粘性廣播。
            if (userId != UserHandle.USER_ALL) {
                // 但是首先,如果這不是對所有用戶的廣播,那麼要確保它與現有的對所有用戶的廣播不衝突
                ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(
                        UserHandle.USER_ALL);
                if (stickies != null) {
                    ArrayList<Intent> list = stickies.get(intent.getAction());
                    if (list != null) {
                        int N = list.size();
                        int i;
                        for (i=0; i<N; i++) {
                            if (intent.filterEquals(list.get(i))) {
                                throw new IllegalArgumentException(
                                        "Sticky broadcast " + intent + " for user "
                                        + userId + " conflicts with existing global broadcast");
                            }
                        }
                    }
                }
            }
            ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
            if (stickies == null) {
                stickies = new ArrayMap<>();
                mStickyBroadcasts.put(userId, stickies);
            }
            ArrayList<Intent> list = stickies.get(intent.getAction());
            if (list == null) {
                list = new ArrayList<>();
                stickies.put(intent.getAction(), list);
            }
            final int stickiesCount = list.size();
            int i;
            for (i = 0; i < stickiesCount; i++) {
                if (intent.filterEquals(list.get(i))) {
                    // 這個粘性已經存在,替換它。
                    list.set(i, new Intent(intent));
                    break;
                }
            }
            if (i >= stickiesCount) {
                list.add(new Intent(intent));
            }
        }

        int[] users;
        if (userId == UserHandle.USER_ALL) {
            // 調用者希望廣播到所有已啓動的用戶。
            users = mStartedUserArray;
        } else {
            // 調用者希望廣播到一個特定的用戶。
            users = new int[] {userId};
        }

        // 找出誰都將收到此廣播。
        List receivers = null;
        List<BroadcastFilter> registeredReceivers = null;
        // 需要解決的意圖感興趣接收者…
        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 == Process.SHELL_UID) {
                // 一次查詢一個目標用戶,不包括受 shell 限制的用戶
                UserManagerService ums = getUserManagerLocked();
                for (int i = 0; i < users.length; i++) {
                    if (ums.hasUserRestriction(
                            UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
                        continue;
                    }
                    List<BroadcastFilter> registeredReceiversForUser =
                            mReceiverResolver.queryIntent(intent,
                                    resolvedType, false, users[i]);
                    if (registeredReceivers == null) {
                        registeredReceivers = registeredReceiversForUser;
                    } else if (registeredReceiversForUser != null) {
                        registeredReceivers.addAll(registeredReceiversForUser);
                    }
                }
            } else {
                registeredReceivers = mReceiverResolver.queryIntent(intent,
                        resolvedType, false, userId);
            }
        }
        // 這個flag 將會將之前的 Intent 替代掉。
        // 加了這個 flag,在發送一系列的這樣的 Intent 之後, 
        // 中間有些 Intent 有可能在你還沒有來得及處理的時候,就被替代掉了。
        final boolean replacePending =
                (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;

        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueing broadcast: " + intent.getAction()
                + " replacePending=" + replacePending);
        // 處理動態廣播接收者
        int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
        if (!ordered && NR > 0) {
            // 如果我們不序列化這個廣播,那麼將它向註冊的接收者單獨發送,這樣就不會等待組件被啓動。
            // 獲取廣播隊列,我們保留兩個廣播隊列和相關的簿記,一個隊列處於前臺優先級,一個隊列用於正常(背景優先級)廣播。
            final BroadcastQueue queue = broadcastQueueForIntent(intent);
            // 構建 BroadcastRecord 對象,其內部記錄了廣播的很多信息
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, resolvedType, requiredPermissions,
                    appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData,
                    resultExtras, ordered, sticky, false, userId);
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
            // replaceParallelBroadcastLocked 函數檢查 queue 中是否包含具有相同意圖的 BroadcastRecord,這裏 replaced 爲 false
            final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
            if (!replaced) {
                queue.enqueueParallelBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
            registeredReceivers = null;
            NR = 0;
        }

        // 合併到一個列表中。
        int ir = 0;
        if (receivers != null) {
            // PACKAGE_ADDED 的特殊情況:不允許添加的包看到此廣播。
            // 這可以防止它們將此作爲後門,以便在安裝後立即運行。
            // 也許將來我們想要爲應用程序提供一個特殊的安裝廣播或類似的東西,但是我們想要慎重地做出這個決定。
            String skipPackages[] = null;
            if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
                    || Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
                    || Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
                Uri data = intent.getData();
                if (data != null) {
                    String pkgName = data.getSchemeSpecificPart();
                    if (pkgName != null) {
                        skipPackages = new String[] { pkgName };
                    }
                }
            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
                skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
            }
            if (skipPackages != null && (skipPackages.length > 0)) {
                for (String skipPackage : skipPackages) {
                    if (skipPackage != null) {
                        int NT = receivers.size();
                        for (int it=0; it<NT; it++) {
                            ResolveInfo curt = (ResolveInfo)receivers.get(it);
                            if (curt.activityInfo.packageName.equals(skipPackage)) {
                                receivers.remove(it);
                                it--;
                                NT--;
                            }
                        }
                    }
                }
            }

            int NT = receivers != null ? receivers.size() : 0;
            int it = 0;
            ResolveInfo curt = null;
            BroadcastFilter curr = null;
            while (it < NT && ir < NR) {
                if (curt == null) {
                    curt = (ResolveInfo)receivers.get(it);
                }
                if (curr == null) {
                    curr = registeredReceivers.get(ir);
                }
                if (curr.getPriority() >= curt.priority) {
                    // 將此廣播記錄插入最終列表。
                    receivers.add(it, curr);
                    ir++;
                    curr = null;
                    it++;
                    NT++;
                } else {
                    // 跳到最終列表中的下一個 ResolveInfo。
                    it++;
                    curt = null;
                }
            }
        }
        while (ir < NR) {
            if (receivers == null) {
                receivers = new ArrayList();
            }
            receivers.add(registeredReceivers.get(ir));
            ir++;
        }
        // 處理靜態廣播接收者
        if ((receivers != null && receivers.size() > 0)
                || resultTo != null) {
            BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, resolvedType,
                    requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
                    resultData, resultExtras, ordered, sticky, false, userId);

            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
                    + ": prev had " + queue.mOrderedBroadcasts.size());
            if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
                    "Enqueueing broadcast " + r.intent.getAction());

            boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
            if (!replaced) {
                queue.enqueueOrderedBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
        }

        return ActivityManager.BROADCAST_SUCCESS;
    }
    ......
}        

  1. receivers 是對這個廣播感興趣的靜態 BroadcastReceiver 列表;collectReceiverComponents 通過 PackageManager 獲取了與這個廣播匹配的靜態 BroadcastReceiver 信息;
  2. mReceiverResolver 存儲了動態註冊的 BroadcastReceiver 的信息。

由於在我們的代碼中,使用動態註冊的方式,所以 receivers 爲 null,接下來調用了下面兩個函數:

queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();

第一個函數是將 BroadcastRecord 入隊;第二個函數調度發送廣播。queue 是一個 BroadcastQueue 類型對象,我們保留兩個廣播隊列和相關的簿記,一個用於前臺優先級,另一個用於普通的(後臺優先級)廣播。

frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

public final class BroadcastQueue {
    ......
    public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
        mParallelBroadcasts.add(r);
        r.enqueueClockTime = System.currentTimeMillis();
    }
    ......
    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;
    }
    .....
}

enqueueParallelBroadcastLocked 函數非常簡單,只是將 BroadcastRecord 對象 r 添加到 mParallelBroadcasts,mParallelBroadcasts 代表將立即執行的所有活動廣播的列表(無需等待另一個廣播完成)。目前,它只包含對已註冊的接收者的廣播,後臺優先級廣播和前臺優先級廣播分別排隊。

scheduleBroadcastsLocked 只是通過 mHandler 發送了一個 BROADCAST_INTENT_MSG 類型的消息。mBroadcastsScheduled 標誌代表我們當前有一個 BROADCAST_INTENT_MSG 消息在處理。

frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

public final class BroadcastQueue {
    ......
    final BroadcastHandler mHandler;

    private final class BroadcastHandler extends Handler {
        public BroadcastHandler(Looper looper) {
            super(looper, null, true);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BROADCAST_INTENT_MSG: {
                    if (DEBUG_BROADCAST) Slog.v(
                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
                    processNextBroadcast(true);
                } break;
                ......
            }
        }
    };
    .....
}

BROADCAST_INTENT_MSG 類型消息最後會在 BroadcastHandler 類中 handleMessage 方法處理,下一步調用 processNextBroadcast 方法。

frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

public final class BroadcastQueue {
    ......
    final void processNextBroadcast(boolean fromMsg) {
        synchronized(mService) {
            BroadcastRecord r;

            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast ["
                    + mQueueName + "]: "
                    + mParallelBroadcasts.size() + " broadcasts, "
                    + mOrderedBroadcasts.size() + " ordered broadcasts");

            mService.updateCpuStats();
            // fromMsg 爲 true,這裏把 mBroadcastsScheduled 置爲了 false,以便 scheduleBroadcastsLocked 方法中不再 return,可以繼續下一步
            if (fromMsg) {
                mBroadcastsScheduled = false;
            }

            // 首先,立即傳送任何非序列化廣播。
            while (mParallelBroadcasts.size() > 0) {
                r = mParallelBroadcasts.remove(0);
                r.dispatchTime = SystemClock.uptimeMillis();
                r.dispatchClockTime = System.currentTimeMillis();
                final int N = r.receivers.size();
                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
                        + mQueueName + "] " + r);
                for (int i=0; i<N; i++) {
                    Object target = r.receivers.get(i);
                    if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                            "Delivering non-ordered on [" + mQueueName + "] to registered "
                            + target + ": " + r);
                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
                }
                addBroadcastToHistoryLocked(r);
                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
                        + mQueueName + "] " + r);
            }
            ......
        }
    }
    .....
}

r.receivers 是一個 List 對象,對其中的每個 BroadcastFilter 對象都執行 deliverToRegisteredReceiverLocked 方法。

frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

public final class BroadcastQueue {
    ......
    private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
            BroadcastFilter filter, boolean ordered) {
        boolean skip = false;
        ......
        if (!skip) {
            // 如果這不是作爲一個有序廣播發送的,那麼我們就不希望觸及跟蹤有序廣播當前狀態的字段。
            if (ordered) {
                ......
            }
            try {
                if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
                        "Delivering to " + filter + " : " + 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 (ordered) {
                    r.state = BroadcastRecord.CALL_DONE_RECEIVE;
                }
            } catch (RemoteException e) {
                Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
                ......
            }
        }
    }
    ......
}

下一步進入 performReceiveLocked 方法。

frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

public final class BroadcastQueue {
    ......
    private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
        // 使用 one-way binder 調用將意圖異步發送給接收者。
        if (app != null) {
            if (app.thread != null) {
                // 如果我們有一個應用程序線程,通過它來執行調用,以便它與其他 one-way 調用一起被正確排序。
                app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                        data, extras, ordered, sticky, sendingUser, app.repProcState);
            } else {
                // 應用程序已經死亡。接收方不存在。
                throw new RemoteException("app.thread must not be null");
            }
        } else {
            receiver.performReceive(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
        }
    }
    ......
}

app.thread 最終指向的是一個 ApplicationThreadProxy 對象,然後調用其 scheduleRegisteredReceiver 方法。

frameworks/base/core/java/android/app/ApplicationThreadNative.java

class ApplicationThreadProxy implements IApplicationThread {
    ......
    public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
            int resultCode, String dataStr, Bundle extras, boolean ordered,
            boolean sticky, int sendingUser, int processState) throws RemoteException {
        Parcel data = Parcel.obtain();
        data.writeInterfaceToken(IApplicationThread.descriptor);
        data.writeStrongBinder(receiver.asBinder());
        intent.writeToParcel(data, 0);
        data.writeInt(resultCode);
        data.writeString(dataStr);
        data.writeBundle(extras);
        data.writeInt(ordered ? 1 : 0);
        data.writeInt(sticky ? 1 : 0);
        data.writeInt(sendingUser);
        data.writeInt(processState);
        mRemote.transact(SCHEDULE_REGISTERED_RECEIVER_TRANSACTION, data, null,
                IBinder.FLAG_ONEWAY);
        data.recycle();
    }
    ......
}

ApplicationThreadProxy 中的 scheduleRegisteredReceiver 方法,最終遠程調用 ApplicationThread 中的 scheduleRegisteredReceiver 方法。

frameworks/base/core/java/android/app/ActivityThread.java

    private class ApplicationThread extends ApplicationThreadNative {
        ......
        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);
        }
        ......
    }

先來研究一下 IIntentReceiver 接口,它在 AIDL 文件中定義,我們都知道 AIDL 是用來跨進程通信的。

frameworks/base/core/java/android/content/IIntentReceiver.aidl

package android.content;

import android.content.Intent;
import android.os.Bundle;

/**
 * 用於發送 Intent 廣播的系統私有 API。這是作爲註冊 Intent 廣播的一部分提供給 activity 管理器的,並在它接收到 Intent 時調用。
 *
 * {@hide}
 */
oneway interface IIntentReceiver {
    void performReceive(in Intent intent, int resultCode, String data,
            in Bundle extras, boolean ordered, boolean sticky, int sendingUser);
}

以下是編譯此 AIDL 後的 java 代碼,需要重點研究一下 asInterface 方法中調用的 queryLocalInterface 方法,它的作用是嘗試爲此 Binder 對象檢索接口的本地實現。 如果返回 null,則需要實例化代理類以通過 transact() 方法遠程調用。

package android.content;

public interface IIntentReceiver extends android.os.IInterface {
    public void performReceive(android.content.Intent intent, int resultCode, java.lang.String data, android.os.Bundle extras, boolean ordered, boolean sticky, int sendingUser) throws android.os.RemoteException;

    /**
     * 本地端 IPC 實現存根類。
     */
    public static abstract class Stub extends android.os.Binder implements android.content.IIntentReceiver {
        static final int TRANSACTION_performReceive = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        private static final java.lang.String DESCRIPTOR = "android.content.IIntentReceiver";

        /**
         * 構造 Stub 對象,並將其附加到接口
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * 將 IBinder 對象強制轉換爲 android.content.IIntentReceiver 接口,在需要時生成代理。
         */
        public static android.content.IIntentReceiver asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof android.content.IIntentReceiver))) {
                return ((android.content.IIntentReceiver) iin);
            }
            return new android.content.IIntentReceiver.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            java.lang.String descriptor = DESCRIPTOR;
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(descriptor);
                    return true;
                }
                case TRANSACTION_performReceive: {
                    data.enforceInterface(descriptor);
                    android.content.Intent _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = android.content.Intent.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    int _arg1;
                    _arg1 = data.readInt();
                    java.lang.String _arg2;
                    _arg2 = data.readString();
                    android.os.Bundle _arg3;
                    if ((0 != data.readInt())) {
                        _arg3 = android.os.Bundle.CREATOR.createFromParcel(data);
                    } else {
                        _arg3 = null;
                    }
                    boolean _arg4;
                    _arg4 = (0 != data.readInt());
                    boolean _arg5;
                    _arg5 = (0 != data.readInt());
                    int _arg6;
                    _arg6 = data.readInt();
                    this.performReceive(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6);
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        private static class Proxy implements android.content.IIntentReceiver {
            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }

            @Override
            public android.os.IBinder asBinder() {
                return mRemote;
            }

            public java.lang.String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }

            @Override
            public void performReceive(android.content.Intent intent, int resultCode, java.lang.String data, android.os.Bundle extras, boolean ordered, boolean sticky, int sendingUser) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    if ((intent != null)) {
                        _data.writeInt(1);
                        intent.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    _data.writeInt(resultCode);
                    _data.writeString(data);
                    if ((extras != null)) {
                        _data.writeInt(1);
                        extras.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    _data.writeInt(((ordered) ? (1) : (0)));
                    _data.writeInt(((sticky) ? (1) : (0)));
                    _data.writeInt(sendingUser);
                    mRemote.transact(Stub.TRANSACTION_performReceive, _data, null, android.os.IBinder.FLAG_ONEWAY);
                } finally {
                    _data.recycle();
                }
            }
        }
    }
}

那麼調用實現 IIntentReceiver 接口對象的 performReceive 方法,實際上是一個繼承自 IIntentReceiver.Stub 抽象類。我們在動態註冊廣播一節已經知道,我們註冊的時候實際上獲取的是一個 InnerReceiver 對象,它繼承自 IIntentReceiver.Stub。所以最後一定執行的是其 performReceive 方法。

frameworks/base/core/java/android/app/LoadedApk.java

public final class LoadedApk {
    ......
    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;
            }
            public void performReceive(Intent intent, int resultCode, String data,
                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
                if (ActivityThread.DEBUG_BROADCAST) {
                    int seq = intent.getIntExtra("seq", -1);
                    Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq
                            + " to " + (rd != null ? rd.mReceiver : null));
                }
                if (rd != null) {
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);
                } else {
                    // activity 管理器在此過程中將廣播分發到已註冊的接收者,但是在發送廣播之前,接收者尚未註冊。
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing broadcast to unregistered receiver");
                    IActivityManager mgr = ActivityManagerNative.getDefault();
                    try {
                        if (extras != null) {
                            extras.setAllowFds(false);
                        }
                        mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
                    } catch (RemoteException e) {
                        Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver");
                    }
                }
            }
        }
        ......
    }
    ......
}

在 InnerReceiver performReceive 方法中,先從弱引用中獲取 LoadedApk.ReceiverDispatcher 對象,然後調用其 performReceive 方法。

frameworks/base/core/java/android/app/LoadedApk.java

public final class LoadedApk {
    ......
    static final class ReceiverDispatcher {
        ......
        public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            if (ActivityThread.DEBUG_BROADCAST) {
                int seq = intent.getIntExtra("seq", -1);
                Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
                        + " to " + mReceiver);
            }
            Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
            if (!mActivityThread.post(args)) {
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManagerNative.getDefault();
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing sync broadcast to " + mReceiver);
                    args.sendFinished(mgr);
                }
            }
        }
    }
    ......
}

首先創建一個 Args 對象,然後使用 Handler post 此對象,它實現了 run 方法,接着就會執行它的 run 方法。由於我們發送的是一個普通廣播,因此是非順序的,ordered = false,內部 if 分支不再進入。

frameworks/base/core/java/android/app/LoadedApk.java

public final class LoadedApk {
    ......
    static final class ReceiverDispatcher {
        ......
        final class Args extends BroadcastReceiver.PendingResult implements Runnable {
            private Intent mCurIntent;
            private final boolean mOrdered;

            public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
                    boolean ordered, boolean sticky, int sendingUser) {
                super(resultCode, resultData, resultExtras,
                        mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
                        sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
                mCurIntent = intent;
                mOrdered = ordered;
            }
            
            public void run() {
                final BroadcastReceiver receiver = mReceiver;
                ......
                final Intent intent = mCurIntent;
                mCurIntent = null;
                ......
                try {
                    ClassLoader cl =  mReceiver.getClass().getClassLoader();
                    intent.setExtrasClassLoader(cl);
                    setExtrasClassLoader(cl);
                    receiver.setPendingResult(this);
                    receiver.onReceive(mContext, intent);
                } catch (Exception e) {
                    ......
                }
                ......
            }
        }
        ......
    }
    ......
}

run 方法中的 BroadcastReceiver 對象是我們註冊的時候傳入的,最後就會執行我們自定義的 Receiver(MainActivityBroadcastReceiver)中的 onReceive 方法。

接下來打印 Log 跟蹤一下以上調用過程。

07-16 05:23:41.244 2323-2323/com.demo.framework D/lhw: ContextWrapper sendBroadcast intent=Intent { act=com.demo.framework.ACTION (has extras) }
07-16 05:23:41.244 2323-2323/com.demo.framework D/lhw: ContextImpl sendBroadcast intent=Intent { act=com.demo.framework.ACTION (has extras) }
07-16 05:23:41.245 2323-2323/com.demo.framework V/lhw: ActivityManagerProxy broadcastIntent caller=android.app.ActivityThread$ApplicationThread@4ad6d55,intent=Intent { act=com.demo.framework.ACTION (has extras) },resolvedType=null,resultTo=null,resultCode=-1,resultData=null,map=null,appOp=-1,options=null,serialized=false,sticky=false,userId=0
07-16 05:23:41.245 770-1644/system_process V/lhw: ActivityManagerService broadcastIntent caller=android.app.ApplicationThreadProxy@363d099,intent=Intent { act=com.demo.framework.ACTION (has extras) },resolvedType=null,resultTo=null,resultCode=-1,resultData=null,resultExtras=null,appOp=-1,options=null,serialized=false,sticky=false,userId=0
07-16 05:23:41.245 770-1644/system_process V/lhw: ActivityManagerService broadcastIntentLocked callerApp=ProcessRecord{a649f5e 2323:com.demo.framework/u0a124},callerPackage=com.demo.framework,intent=Intent { act=com.demo.framework.ACTION (has extras) },resolvedType=null,resultTo=null,resultCode=-1,resultData=null,resultExtras=null,appOp=-1,options=null,ordered=false,sticky=false,callingPid=2323,callingUid=10124,userId=0
07-16 05:23:41.245 770-1644/system_process V/lhw: ActivityManagerService broadcastIntentLocked replaced=false
07-16 05:23:41.245 770-1644/system_process V/lhw: BroadcastQueue enqueueParallelBroadcastLocked r=BroadcastRecord{61aaf3f u0 com.demo.framework.ACTION}
07-16 05:23:41.245 770-1644/system_process V/lhw: BroadcastQueue scheduleBroadcastsLocked
07-16 05:23:41.245 770-803/system_process V/lhw: BroadcastHandler handleMessage BROADCAST_INTENT_MSG
07-16 05:23:41.245 770-803/system_process V/lhw: BroadcastQueue processNextBroadcast fromMsg=true
07-16 05:23:41.245 770-803/system_process V/lhw: BroadcastQueue deliverToRegisteredReceiverLocked r=BroadcastRecord{61aaf3f u0 com.demo.framework.ACTION},filter=BroadcastFilter{5c0e7dc u0 ReceiverList{c66144f 2323 com.demo.framework/10124/u0 remote:4792eae}},ordered=false
07-16 05:23:41.245 770-803/system_process V/lhw: BroadcastQueue performReceiveLocked app=ProcessRecord{a649f5e 2323:com.demo.framework/u0a124},receiver=android.content.IIntentReceiver$Stub$Proxy@87d70b0,intent=Intent { act=com.demo.framework.ACTION flg=0x10 (has extras) },resultCode=-1,data=null,extras=null,ordered=false,sticky=false,sendingUser=0
07-16 05:23:41.245 770-803/system_process V/lhw: ApplicationThreadProxy scheduleRegisteredReceiver receiver=android.content.IIntentReceiver$Stub$Proxy@87d70b0,intent=Intent { act=com.demo.framework.ACTION flg=0x10 (has extras) },resultCode=-1,dataStr=null,extras=null,ordered=false,sticky=false,sendingUser=0,processState=2
07-16 05:23:41.245 2323-2341/com.demo.framework V/lhw: ApplicationThread scheduleRegisteredReceiver receiver=android.app.LoadedApk$ReceiverDispatcher$InnerReceiver@9e5a36a,intent=Intent { act=com.demo.framework.ACTION flg=0x10 (has extras) },resultCode=-1,dataStr=null,extras=null,ordered=false,sticky=false,sendingUser=0,processState=2
07-16 05:23:41.246 2323-2341/com.demo.framework V/lhw: InnerReceiver performReceive intent=Intent { act=com.demo.framework.ACTION flg=0x10 (has extras) },resultCode=-1,datanull,extras=null,ordered=false,sticky=false,sendingUser=0
07-16 05:23:41.246 2323-2341/com.demo.framework V/lhw: ReceiverDispatcher  performReceive intent=Intent { act=com.demo.framework.ACTION flg=0x10 (has extras) },resultCode=-1,datanull,extras=null,ordered=false,sticky=false,sendingUser=0
07-16 05:23:41.248 2323-2323/com.demo.framework V/lhw: Args run ordered=false,mContext=com.demo.framework.MainActivity@bf19c05,intent=Intent { act=com.demo.framework.ACTION flg=0x10 (has extras) }
07-16 05:23:41.252 2323-2323/com.demo.framework D/MainActivity: MainActivityBroadcastReceiver onReceive str=DemoService Hello!

最後畫一張時序圖作爲總結。
sendBroadcast

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