Android廣播工作過程分析

上一篇文章已經(jīng)介紹了廣播的類型蘸吓,如何注冊(cè)廣播蔗候,如何發(fā)送廣播以及使用過程應(yīng)該注意的一些點(diǎn)洒琢。本文將從源碼的角度來分析注冊(cè)尝哆、發(fā)送仰禀、執(zhí)行廣播的過程。

一.靜態(tài)廣播注冊(cè)

靜態(tài)注冊(cè)指的是在AndroidManifest.xml中注冊(cè)的廣播秦叛,這些冊(cè)信息的維護(hù)主要有兩個(gè)過程:系統(tǒng)啟動(dòng)的時(shí)候掃描系統(tǒng)中安裝的apk的注冊(cè)信息晦溪,安裝、卸載的時(shí)候更新注冊(cè)信息挣跋。

當(dāng)系統(tǒng)啟動(dòng)的時(shí)候會(huì)啟動(dòng)PackageManagerService三圆,從其main方法開始。

public static PackageManagerService main(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {
    // Self-check for initial settings.
    PackageManagerServiceCompilerMapping.checkProperties();
    
    //創(chuàng)建了一個(gè)PackageManagerService實(shí)例
    PackageManagerService m = new PackageManagerService(context, installer,
            factoryTest, onlyCore);
    m.enableSystemUserPackages();
    
    //注冊(cè)這個(gè)Service
    ServiceManager.addService("package", m);
    return m;
}

它的main方法主要通過它的構(gòu)造方法創(chuàng)建了一個(gè)實(shí)例避咆,并注冊(cè)了這個(gè)Service舟肉,它的構(gòu)造方法實(shí)現(xiàn)如下:

public PackageManagerService(Context context, Installer installer,
        boolean factoryTest, boolean onlyCore) {

    ......
    synchronized (mPackages) {
        ......
        File dataDir = Environment.getDataDirectory();
        mAppInstallDir = new File(dataDir, "app");
        mAppLib32InstallDir = new File(dataDir, "app-lib");
        mEphemeralInstallDir = new File(dataDir, "app-ephemeral");
        mAsecInternalPath = new File(dataDir, "app-asec").getPath();
        mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
        ......
        // Collect ordinary system packages.
        final File systemAppDir = new File(Environment.getRootDirectory(), "app");
        scanDirTracedLI(systemAppDir, mDefParseFlags
                | PackageParser.PARSE_IS_SYSTEM
                | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
        //掃描其他路徑            
}

構(gòu)造方法中的代碼比較多,這里只保留了部分關(guān)鍵代碼查库,從代碼中的掃描的路徑可以了解到Android系統(tǒng)中的應(yīng)用都安裝在哪路媚,這里只分析掃描系統(tǒng)應(yīng)用的過程,即/system/app這個(gè)目錄樊销,其他路徑類似整慎。這個(gè)過程涉及到的方法比較多,先上一張時(shí)序序圖:

靜態(tài)注冊(cè)廣播時(shí)序圖

構(gòu)造方法之后围苫,沿著路徑往下到 scanPackageLI 方法才有我們比較關(guān)心的代碼裤园。

/**
 *  Scans a package and returns the newly parsed package.
 *  Returns {@code null} in case of errors and the error code is stored in mLastScanError
 */
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
        long currentTime, UserHandle user) throws PackageManagerException {
    if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
    PackageParser pp = new PackageParser();
    pp.setSeparateProcesses(mSeparateProcesses);
    pp.setOnlyCoreApps(mOnlyCore);
    pp.setDisplayMetrics(mMetrics);

    if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
        parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
    }

    Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
    final PackageParser.Package pkg;
    try {
    
        //這里調(diào)用了PackageParser的parsePackage方法來解析apk文件
        pkg = pp.parsePackage(scanFile, parseFlags);
    } catch (PackageParserException e) {
        throw PackageManagerException.from(e);
    } finally {
        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    }
    
    //最后又調(diào)用一個(gè)重載方法
    return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
}

這個(gè)方法里主要調(diào)用了兩個(gè)方法:PackageParser的parsePackage方法和一個(gè)重載的scanPackageLI方法,按照順序剂府,先看parsePackage方法拧揽。

public Package parsePackage(File packageFile, int flags) throws PackageParserException {
    if (packageFile.isDirectory()) {
        return parseClusterPackage(packageFile, flags);
    } else {
        return parseMonolithicPackage(packageFile, flags);
    }
}

這個(gè)方法比較簡(jiǎn)單,區(qū)分文件和目錄來調(diào)用不同的方法,這里研究parseClusterPackage這條路徑(路徑參考上面的時(shí)序圖)淤袜,沿著這條路徑往下万俗,直到parseBaseApplication方法,這里有我們所關(guān)心的代碼饮怯。

/**
 * Parse the {@code application} XML tree at the current parse location in a
 * <em>base APK</em> manifest.
 * <p>
 * When adding new features, carefully consider if they should also be
 * supported by split APKs.
 */
private boolean parseBaseApplication(Package owner, Resources res,
        XmlResourceParser parser, int flags, String[] outError)
    throws XmlPullParserException, IOException {
    TypedArray sa = res.obtainAttributes(parser,
                com.android.internal.R.styleable.AndroidManifestApplication);
                
    //省略部分非關(guān)鍵代碼
    ....
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }

            String tagName = parser.getName();
            if (tagName.equals("activity")) {
                Activity a = parseActivity(owner, res, parser, flags, outError, false,
                        owner.baseHardwareAccelerated);
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.activities.add(a);
            
            //解析receiver節(jié)點(diǎn)并保存到owner.receivers
            } else if (tagName.equals("receiver")) {
                Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.receivers.add(a);
            }    
            
            //省略解析其他組件分支的代碼
            ......
    }        
}        

可以看到闰歪,原來是解析各個(gè)apk文件的AndroidManifest.xml文件中所有注冊(cè)的receiver,并且其添加到Package的成員變量receivers中蓖墅,這樣我們?cè)赑MS中拿到Package對(duì)象就能得到這個(gè)應(yīng)用的所用靜態(tài)注冊(cè)的廣播库倘。接下來就回到了PMS中(通常跟蹤源碼到返回的時(shí)候意味著離目標(biāo)也已經(jīng)不遠(yuǎn)了)。

當(dāng)返回到PMS后论矾,又調(diào)用了一個(gè)重載的scanPackageLI方法教翩,沿著路徑往下,到scanPackageDirtyLI方法又出現(xiàn)關(guān)鍵代碼贪壳。

private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg,
            final int policyFlags, final int scanFlags, long currentTime, UserHandle user)
            throws PackageManagerException {
    ....        
    //省略其他非關(guān)鍵代碼
    
    //這個(gè)pkg就是剛才PackageParser中解析得到的
    N = pkg.receivers.size();
    r = null;
    for (i=0; i<N; i++) {
        PackageParser.Activity a = pkg.receivers.get(i);
        a.info.processName = fixProcessName(pkg.applicationInfo.processName,
                a.info.processName, pkg.applicationInfo.uid);
        //將所有靜態(tài)注冊(cè)的廣播添加到mReceivers集合中        
        mReceivers.addActivity(a, "receiver");
        if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
            if (r == null) {
                r = new StringBuilder(256);
            } else {
                r.append(' ');
            }
            r.append(a.info.name);
        }
    }
    .....
}        

看到這里終于松了一口氣饱亿,原來所有的靜態(tài)注冊(cè)的廣播最終是保存在PMS的成員變量mReceivers中,當(dāng)發(fā)送廣播時(shí)闰靴,AMS就會(huì)到這里來查詢所有匹配的靜態(tài)廣播接收者彪笼,進(jìn)而將廣播發(fā)送給它們。下面的就是AMS中查詢靜態(tài)廣播接收者的代碼蚂且。

二.動(dòng)態(tài)注冊(cè)廣播

動(dòng)態(tài)注冊(cè)廣播我們通常需要這么做

IntentFilter filter = new IntentFilter("jdqm.intent.action.TEST");
registerReceiver(receiver, filter);

從調(diào)用context.registerReceiver方法到注冊(cè)完成的大致的過程為:

動(dòng)態(tài)注冊(cè)廣播時(shí)序圖

從ContextWapper的registerReceiver方法開始

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

直接調(diào)用了mBase的registerReceiver方法配猫,這個(gè)mBase實(shí)際上是ContextImp的實(shí)例,ContextImp的registerReceiver方法也是將處理邏輯放到了該類的registerReceiverInternal方法中杏死,該方法的實(shí)現(xiàn)如下:

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
        IntentFilter filter, String broadcastPermission,
        Handler scheduler, Context context) {
    //使用IItentReceiver(這是一個(gè)Binder對(duì)象)來中轉(zhuǎn)實(shí)現(xiàn)跨進(jìn)程通信    
    IIntentReceiver rd = null;
    if (receiver != null) {
    
        //mPackageInfo是LoadedApk的實(shí)例
        if (mPackageInfo != null && context != null) {
            if (scheduler == null) {
                //這個(gè)Handler是主線程中mH
                scheduler = mMainThread.getHandler();
            }
            
            //通過getReceiverDispatcher獲取對(duì)應(yīng)的IItentReceiver對(duì)象
            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 {
        //通過Binder機(jī)制泵肄,向AMS發(fā)起注冊(cè)請(qǐng)求,后續(xù)的邏輯就到AMS中了
        final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
                mMainThread.getApplicationThread(), mBasePackageName,
                rd, filter, broadcastPermission, userId);
        if (intent != null) {
            intent.setExtrasClassLoader(getClassLoader());
            intent.prepareToEnterProcess();
        }
        return intent;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

在這個(gè)方法中通過調(diào)用getReceiverDispatcher方法淑翼,將廣播記錄在LoadedApk的成員變量mReceivers中腐巢。另外 ActivityManagerNative.getDefault()得到的是ActivityManagerService在客戶端的一個(gè)代理對(duì)象,通過它我們就可以調(diào)用ActivityManagerService的registerReceiver方法:

public Intent registerReceiver(IApplicationThread caller, String callerPackage,
        IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
    ......
    //省略前面代碼
    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) {
                rl.app.receivers.add(rl);
            } else {
                try {
                    receiver.asBinder().linkToDeath(rl, 0);
                } catch (RemoteException e) {
                    return sticky;
                }
                rl.linkedToDeath = true;
            }
            
            //動(dòng)態(tài)注冊(cè)的廣播都保存在這個(gè)集合中
            mRegisteredReceivers.put(receiver.asBinder(), rl);
        } else if (rl.uid != callingUid) {
            throw new IllegalArgumentException(
                    "Receiver requested to register for uid " + callingUid
                    + " was previously registered for uid " + rl.uid);
        } else if (rl.pid != callingPid) {
            throw new IllegalArgumentException(
                    "Receiver requested to register for pid " + callingPid
                    + " was previously registered for pid " + rl.pid);
        } else if (rl.userId != userId) {
            throw new IllegalArgumentException(
                    "Receiver requested to register for user " + userId
                    + " was previously registered for user " + rl.userId);
        }
        BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                permission, callingUid, userId);
                
        //關(guān)聯(lián)IntentFilter        
        rl.add(bf);
        if (!bf.debugCheck()) {
            Slog.w(TAG, "==> For Dynamic broadcast");
        }
        mReceiverResolver.addFilter(bf);
        //省略后面代碼
        ......
    }
}

到這里我們得出結(jié)論:動(dòng)態(tài)注冊(cè)的廣播存儲(chǔ)在AMS的成員變量mRegisteredReceivers中玄括。

三.發(fā)送廣播

發(fā)送廣播過程的時(shí)序圖如下:

發(fā)送廣播時(shí)序圖

首先從ContextWrapper#sendBroadcast(Intent)方法開始.

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

ContextImp#sendBroadcast(Intent)

@Override
public void sendBroadcast(Intent intent) {
    warnIfCallingFromSystemProcess();
    //這個(gè)resolvedType實(shí)際上是MIME類型
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess(this);
        
        //通過Binder機(jī)制冯丙,向AMS發(fā)起請(qǐng)求
        ActivityManagerNative.getDefault().broadcastIntent(
                mMainThread.getApplicationThread(), intent, resolvedType, null,
                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                getUserId());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

前面提到過ActivityManagerNative.getDefault()返回的是AMS在客戶端的代理對(duì)象,通過它來調(diào)用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) {
    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();
        
        //進(jìn)一步調(diào)用broadcastIntentLocked來處理
        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;
    }
}

可以看到在這個(gè)方法內(nèi)部又進(jìn)一步調(diào)用broadcastIntentLocked來處理银还,這個(gè)方法代碼很多,下面只列出部分:

//Android3.1之后洁墙,默認(rèn)情況下,Intent會(huì)添加了下面這個(gè)flag,所以默認(rèn)情況下不會(huì)啟動(dòng)處于停止?fàn)顟B(tài)的應(yīng)用戒财。
// By default broadcasts do not go to stopped apps.
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
......

// 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) {
    //收集匹配靜態(tài)注冊(cè)的廣播接收者    
    receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}
if (intent.getComponent() == null) {
    if (userId == UserHandle.USER_ALL && callingUid == Process.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 =
                    mReceiverReHHsolver.queryIntent(intent,
                            resolvedType, false, users[i]);
            if (registeredReceivers == null) {
                registeredReceivers = registeredReceiversForUser;
            } else if (registeredReceiversForUser != null) {
                registeredReceivers.addAll(registeredReceiversForUser);
            }
        }
    } else {
        //收集匹配動(dòng)態(tài)注冊(cè)的廣播接受者
        registeredReceivers = mReceiverResolver.queryIntent(intent,
                resolvedType, false, userId);
    }
}

......
//動(dòng)態(tài)注冊(cè)的無序廣播
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);
final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
if (!replaced) {
   //將動(dòng)態(tài)注冊(cè)的無序廣播添加的無序廣播隊(duì)列
    queue.enqueueParallelBroadcastLocked(r);
    queue.scheduleBroadcastsLocked();
}
....

//receivers保存的是所有的靜態(tài)廣播热监,動(dòng)態(tài)注冊(cè)的有序廣播
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) {
        //將構(gòu)造的BroadcastRecord添加的有序廣播的隊(duì)列
        queue.enqueueOrderedBroadcastLocked(r);
        queue.scheduleBroadcastsLocked();
    }
} else {
    // There was nobody interested in the broadcast, but we still want to record
    // that it happened.
    if (intent.getComponent() == null && intent.getPackage() == null
            && (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
        // This was an implicit broadcast... let's record it for posterity.
        addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);
    }
}

從這方法的實(shí)現(xiàn)可以看到,首先收集了所有的符合的動(dòng)態(tài)注冊(cè)饮寞、靜態(tài)注冊(cè)的接收者孝扛,然后將動(dòng)態(tài)無序廣播列吼、所有靜態(tài)和動(dòng)態(tài)有序包裝成兩個(gè)BroadcastRecord對(duì)象,添加到BroadcastQueue的兩個(gè)集合中苦始,這兩個(gè)集合是:

final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();
final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();

然后調(diào)用用BroadcastQueue的scheduleBroadcastsLocked方法進(jìn)處理這兩個(gè)集合寞钥。scheduleBroadcastsLocked方法的實(shí)現(xiàn)如下:

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

這里邏輯也很簡(jiǎn)單,通過mHandler發(fā)送了一條BROADCAST_INTENT_MSG消息陌选,這個(gè)Handler的實(shí)現(xiàn)如下:

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");
                //關(guān)鍵代碼
                processNextBroadcast(true);
            } break;
            case BROADCAST_TIMEOUT_MSG: {
                synchronized (mService) {
                    broadcastTimeoutLocked(true);
                }
            } break;
            case SCHEDULE_TEMP_WHITELIST_MSG: {
                DeviceIdleController.LocalService dic = mService.mLocalDeviceIdleController;
                if (dic != null) {
                    dic.addPowerSaveTempWhitelistAppDirect(UserHandle.getAppId(msg.arg1),
                            msg.arg2, true, (String)msg.obj);
                }
            } break;
        }
    }
}

可以發(fā)現(xiàn)理郑,調(diào)用了processNextBroadcast方法來處理:

final void processNextBroadcast(boolean fromMsg) {
    synchronized(mService) {
        BroadcastRecord r;
        mService.updateCpuStats();
        if (fromMsg) {
            mBroadcastsScheduled = false;
        }
        
        //首先處理mParallelBroadcasts這個(gè)集合,這意味著mParallelBroadcasts集合的廣播接受者比mOrderedBroadcasts集合的廣播接收者先收到廣播
        // First, deliver any non-serialized broadcasts right away.
        while (mParallelBroadcasts.size() > 0) {
        
           //一個(gè)廣播對(duì)應(yīng)著一個(gè)BroadcastRecord實(shí)例
            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);
                //動(dòng)態(tài)注冊(cè)的無序廣播        
                deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
            }
            
            //記錄廣播的歷史
            addBroadcastToHistoryLocked(r);
            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
                    + mQueueName + "] " + r);
        }

        // Now take care of the next serialized one...

        // If we are waiting for a process to come up to handle the next
        // broadcast, then do nothing at this point.  Just in case, we
        // check that the process we're waiting for still exists.
        if (mPendingBroadcast != null) {
            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
                    "processNextBroadcast [" + mQueueName + "]: waiting for "
                    + mPendingBroadcast.curApp);

            boolean isDead;
            synchronized (mService.mPidsSelfLocked) {
                ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);
                isDead = proc == null || proc.crashing;
            }
            if (!isDead) {
                // It's still alive, so keep waiting
                return;
            } else {
                Slog.w(TAG, "pending app  ["
                        + mQueueName + "]" + mPendingBroadcast.curApp
                        + " died before responding to broadcast");
                mPendingBroadcast.state = BroadcastRecord.IDLE;
                mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
                mPendingBroadcast = null;
            }
        }

        boolean looped = false;
        
        do {
            if (mOrderedBroadcasts.size() == 0) {
            ......   
        } while (r == null);
        
        .....
        
        // Is this receiver's application already running?
        if (app != null && app.thread != null) {
            try {
                app.addPackage(info.activityInfo.packageName,
                        info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
                //當(dāng)進(jìn)程跑起來后        
                processCurBroadcastLocked(r, app);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when sending broadcast to "
                      + r.curComponent, e);
            } catch (RuntimeException e) {
                Slog.wtf(TAG, "Failed sending broadcast to "
                        + r.curComponent + " with " + r.intent, e);
                // If some unexpected exception happened, just skip
                // this broadcast.  At this point we are not in the call
                // from a client, so throwing an exception out from here
                // will crash the entire system instead of just whoever
                // sent the broadcast.
                logBroadcastReceiverDiscardLocked(r);
                finishReceiverLocked(r, r.resultCode, r.resultData,
                        r.resultExtras, r.resultAbort, false);
                scheduleBroadcastsLocked();
                // We need to reset the state if we failed to start the receiver.
                r.state = BroadcastRecord.IDLE;
                return;
            }

            // If a dead object exception was thrown -- fall through to
            // restart the application.
        }
}

可以發(fā)現(xiàn)咨油,先處理了mParallelBroadcasts您炉,然后才處理mOrderedBroadcasts,這兩個(gè)集合的處理邏輯是有些差異的役电,按順序先看mParallelBroadcasts赚爵,這個(gè)集合是通過deliverToRegisteredReceiverLocked來處理,而這個(gè)方法又進(jìn)一步調(diào)用了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.repProcState);
            // TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
            // DeadObjectException when the process isn't actually dead.
            //} catch (DeadObjectException ex) {
            // Failed to call into the process.  It's dying so just let it die and move on.
            //    throw ex;
            } catch (RemoteException ex) {
                // Failed to call into the process. It's either dying or wedged. Kill it gently.
                synchronized (mService) {
                    Slog.w(TAG, "Can't deliver broadcast to " + app.processName
                            + " (pid " + app.pid + "). Crashing it.");
                    app.scheduleCrash("can't deliver broadcast");
                }
                throw ex;
            }
        } else {
            // Application has died. Receiver doesn't exist.
            throw new RemoteException("app.thread must not be null");
        }
    } else {
        receiver.performReceive(intent, resultCode, data, extras, ordered,
                sticky, sendingUser);
    }
}

app.thread就是ActivityThread的一個(gè)代理對(duì)象法瑟,通過它就可以調(diào)用ActivityThread的scheduleRegisteredReceiver方法:

// This function exists to make sure all receiver dispatching is
// correctly ordered, since these are one-way calls and the binder driver
// applies transaction ordering per object for such calls.
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);
}

繼續(xù)調(diào)用IIntentReceiver.performReceive方法來完成后續(xù)動(dòng)作冀膝,又將邏輯切回到了我們注冊(cè)廣播時(shí)的LoadedApk.ReceiverDispatcher的performReceive中,這就回到了注冊(cè)廣播的主線程了霎挟。

public void performReceive(Intent intent, int resultCode, String data,
        Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
    //創(chuàng)建了一個(gè)Args對(duì)象畸写,Args實(shí)現(xiàn)了Runable接口    
    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);
        }
    }
    
    //mActivityThread是 ActivityThread#mH
    if (intent == null || !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);
        }
    }
}

創(chuàng)建了一個(gè)Args對(duì)象,Args實(shí)現(xiàn)了Runnable接口氓扛,然后mActivityThread.post(args)將這個(gè)Runnable 拋給了mH枯芬,Args的run方法實(shí)現(xiàn)如下:

public void run() {
    ......
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
    try {
        ClassLoader cl =  mReceiver.getClass().getClassLoader();
        intent.setExtrasClassLoader(cl);
        intent.prepareToEnterProcess();
        setExtrasClassLoader(cl);
        receiver.setPendingResult(this);
        
        //直接通過注冊(cè)時(shí)的引用,調(diào)用其onReceive方法
        receiver.onReceive(mContext, intent);
    } catch (Exception e) {
        if (mRegistered && ordered) {
            if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                    "Finishing failed broadcast to " + mReceiver);
            sendFinished(mgr);
        }
        if (mInstrumentation == null ||
                !mInstrumentation.onException(mReceiver, e)) {
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            throw new RuntimeException(
                "Error receiving broadcast " + intent
                + " in " + mReceiver, e);
        }
    }
    
    if (receiver.getPendingResult() != null) {
        finish();
    }
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}

到這里終于看到了廣播接受者的onReceive(mContext, intent)方法被執(zhí)行了采郎。mParallelBroadcasts的處理邏輯分析完了千所,接下來分析mOrderedBroadcasts的處理邏輯,從前面廣播注冊(cè)的邏輯得知蒜埋,mOrderedBroadcasts包含所有靜態(tài)注冊(cè)的廣播和動(dòng)態(tài)注冊(cè)的有序廣播淫痰,其中動(dòng)態(tài)注冊(cè)的有序廣播的處理邏輯與前面無序的處理過程類似。現(xiàn)在重點(diǎn)看下靜態(tài)注冊(cè)的廣播整份,從processNextBroadcast方法中可以看到是調(diào)用了processCurBroadcastLocked來處理mOrderedBroadcasts中靜態(tài)注冊(cè)的廣播待错。

private final void processCurBroadcastLocked(BroadcastRecord r,
        ProcessRecord app) throws RemoteException {

    r.receiver = app.thread.asBinder();
    r.curApp = app;
    app.curReceiver = r;
    app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
    mService.updateLruProcessLocked(app, false, null);
    mService.updateOomAdjLocked();

    // Tell the application to launch this receiver.
    r.intent.setComponent(r.curComponent);

    boolean started = false;
    try {
        if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
                "Delivering to component " + r.curComponent
                + ": " + r);
        mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
                                  PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
        //關(guān)鍵代碼
        app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
                r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
                app.repProcState);
        if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                "Process cur broadcast " + r + " DELIVERED for app " + app);
        started = true;
    } finally {
        if (!started) {
            if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                    "Process cur broadcast " + r + ": NOT STARTED!");
            r.receiver = null;
            r.curApp = null;
            app.curReceiver = null;
        }
    }
}

通過ActivityThread的代理對(duì)象app.thread調(diào)用其scheduleReceiver方法,其實(shí)現(xiàn)如下:

public final void scheduleReceiver(Intent intent, ActivityInfo info,
        CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
        boolean sync, int sendingUser, int processState) {
    updateProcessState(processState, false);
    ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
            sync, false, mAppThread.asBinder(), sendingUser);
    r.info = info;
    r.compatInfo = compatInfo;
    sendMessage(H.RECEIVER, r);
}

private void sendMessage(int what, Object obj) {
        sendMessage(what, obj, 0, 0, false);
}

private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
    if (DEBUG_MESSAGES) Slog.v(
        TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
        + ": " + arg1 + " / " + obj);
    Message msg = Message.obtain();
    msg.what = what;
    msg.obj = obj;
    msg.arg1 = arg1;
    msg.arg2 = arg2;
    if (async) {
        msg.setAsynchronous(true);
    }
    mH.sendMessage(msg);
}

最終通過mH發(fā)送了一條H.RECEIVER消息烈评,對(duì)應(yīng)what為RECEIVER的處理:

case RECEIVER:
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");
    handleReceiver((ReceiverData)msg.obj);
    maybeSnapshot();
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    break;
                    

緊接著調(diào)用handleReceiver來處理:

private void handleReceiver(ReceiverData data) {
    // If we are getting ready to gc after going to the background, well
    // we are back active so skip it.
    unscheduleGcIdler();

    String component = data.intent.getComponent().getClassName();

    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);

    IActivityManager mgr = ActivityManagerNative.getDefault();

    BroadcastReceiver receiver;
    try {
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        data.intent.setExtrasClassLoader(cl);
        data.intent.prepareToEnterProcess();
        data.setExtrasClassLoader(cl);
        
        //創(chuàng)建了一個(gè)廣播接收者實(shí)例
        receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
    } catch (Exception e) {
        if (DEBUG_BROADCAST) Slog.i(TAG,
                "Finishing failed broadcast to " + data.intent.getComponent());
        data.sendFinished(mgr);
        throw new RuntimeException(
            "Unable to instantiate receiver " + component
            + ": " + e.toString(), e);
    }

    try {
        Application app = packageInfo.makeApplication(false, mInstrumentation);

        if (localLOGV) Slog.v(
            TAG, "Performing receive of " + data.intent
            + ": app=" + app
            + ", appName=" + app.getPackageName()
            + ", pkg=" + packageInfo.getPackageName()
            + ", comp=" + data.intent.getComponent().toShortString()
            + ", dir=" + packageInfo.getAppDir());

        ContextImpl context = (ContextImpl)app.getBaseContext();
        sCurrentBroadcastIntent.set(data.intent);
        receiver.setPendingResult(data);
        
        //廣播接收者的onReceive方法被執(zhí)行了
        receiver.onReceive(context.getReceiverRestrictedContext(),
                data.intent);
    } catch (Exception e) {
        if (DEBUG_BROADCAST) Slog.i(TAG,
                "Finishing failed broadcast to " + data.intent.getComponent());
        data.sendFinished(mgr);
        if (!mInstrumentation.onException(receiver, e)) {
            throw new RuntimeException(
                "Unable to start receiver " + component
                + ": " + e.toString(), e);
        }
    } finally {
        sCurrentBroadcastIntent.set(null);
    }

    if (receiver.getPendingResult() != null) {
        data.finish();
    }
}

靜態(tài)注冊(cè)的廣播接收者通常是沒有運(yùn)行的火俄,所以在這里先是創(chuàng)建了一個(gè)接收者的實(shí)例,然后調(diào)用它的onReceive方法讲冠。

三.總結(jié):

  1. 靜態(tài)注冊(cè)注冊(cè)的廣播瓜客,在PMS啟動(dòng)的時(shí)候掃描系統(tǒng)中安裝的apk文件,并解析它們的AndroidManifest.xml文件,將所有注冊(cè)的廣播保存在PMS的成員變量mReceivers中谱仪;

  2. 動(dòng)態(tài)注冊(cè)的廣播存儲(chǔ)在AMS的成員變量mRegisteredReceivers中玻熙;

  3. 發(fā)送廣播的處理邏輯在AMS中,AMS負(fù)責(zé)從mReceivers和mRegisteredReceivers這兩個(gè)集合查詢出與IntentFilter匹配的接收者疯攒,并將它們添加到BroadcastQueue的mParallelBroadcasts(動(dòng)態(tài)注冊(cè)的無序廣播)或者mOrderedBroadcasts(有序廣播和所有的靜態(tài)廣播)中;

  4. 在BroadcastQueue先處理mParallelBroadcasts嗦随,所以動(dòng)態(tài)注冊(cè)的無序廣播會(huì)先收到廣播;

  5. 當(dāng)有應(yīng)用安裝,卸載時(shí)(實(shí)際的邏輯在PMS中)敬尺,靜態(tài)注冊(cè)的廣播自然是在PMS中進(jìn)行更新注冊(cè)信息枚尼,接著再發(fā)送廣播到AMS中更新動(dòng)態(tài)注冊(cè)廣播;

  6. 動(dòng)態(tài)廣播的onReceive方法是在LoadedApk#ReceiverDispatcher#Args的run方法中被調(diào)用筷转;靜態(tài)廣播的onReceive是在ActivityThread的handleReceiver方法中被調(diào)用姑原,而它們都是跑在目標(biāo)進(jìn)程的主線程中。

以上源碼均來自 Android25呜舒。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末锭汛,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子袭蝗,更是在濱河造成了極大的恐慌唤殴,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件到腥,死亡現(xiàn)場(chǎng)離奇詭異朵逝,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)乡范,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門配名,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人晋辆,你說我怎么就攤上這事渠脉。” “怎么了瓶佳?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵芋膘,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我霸饲,道長(zhǎng)为朋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任厚脉,我火速辦了婚禮习寸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘器仗。我一直安慰自己融涣,他們只是感情好童番,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布精钮。 她就那樣靜靜地躺著威鹿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪轨香。 梳的紋絲不亂的頭發(fā)上忽你,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音臂容,去河邊找鬼科雳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛脓杉,可吹牛的內(nèi)容都是我干的糟秘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼球散,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼尿赚!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蕉堰,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤凌净,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后屋讶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體冰寻,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年皿渗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了斩芭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡乐疆,死狀恐怖划乖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情诀拭,我是刑警寧澤迁筛,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站耕挨,受9級(jí)特大地震影響细卧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜筒占,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一贪庙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧翰苫,春花似錦止邮、人聲如沸这橙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)屈扎。三九已至,卻和暖如春撩匕,著一層夾襖步出監(jiān)牢的瞬間鹰晨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工止毕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留模蜡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓扁凛,卻偏偏與公主長(zhǎng)得像忍疾,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子谨朝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容