«

Android广播Broadcast的启动流程是什么

时间:2024-7-17 16:57     作者:韩俊     分类: Android


这篇“Android广播Broadcast的启动流程是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Android广播Broadcast的启动流程是什么”文章吧。

广播的注册

我们常在

Activity
或
Service
、甚至
Application
中调用
registerReceiver
函数来注册动态广播,该函数其实来自它们共同的父类
ContextWrapper
中。
ContextWrapper
是
Context
的子类,我们会在介绍
Context
的文章介绍它们的关系。

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

这里

Context
类型的
mBase
,在
Activity
的创建过程实际被赋值为
ContextImpl
实例。

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

经过

registerReceiver
重载函数,调用了
registerReceiverInternal
函数。

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

分析一:

传递进来的

BroadcastReceiver
不为
null
,
LoadedApk
类型的
mPackageInfo
只要应用进程启动,该属性就会被赋值,
context
这里指向
Activity
。
scheduler
为
null
,赋值为主线程的
H
类型
mH
对象。分析一,主要通过上面的变量来获得
IIntentReceiver
类型
rd
对象。

getReceiverDispatcher
函数先从缓存检测是否有相同类型的
BroadcastReceiver
对应的
ReceiverDispatcher
。没有的话,则新建并缓存起来。 一个
context
对应多个
BroadcastReceiver
,而一个
BroadcastReceiver
对应用一个
ReceiverDispatcher
。

ReceiverDispatcher
是
LoadedDispatcher
的静态内部类,其内部还有一个
AIDL
类型本地实现静态类
InnerReceiver
。在
ReceiverDispatcher
的构造函数中会创建
InnerReceiver
的实例。

public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
        Context context, Handler handler,
        Instrumentation instrumentation, boolean registered) {
    synchronized (mReceivers) {
        LoadedApk.ReceiverDispatcher rd = null;
        ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
        if (registered) {
            map = mReceivers.get(context);
            if (map != null) {
                rd = map.get(r);
            }
        }
        if (rd == null) {
            rd = new ReceiverDispatcher(r, context, handler,
                    instrumentation, registered);
            if (registered) {
                if (map == null) {
                    map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                    mReceivers.put(context, map);
                }
                map.put(r, rd);
            }
        } else {
            rd.validate(context, handler);
        }
        rd.mForgotten = false;
        return rd.getIIntentReceiver();
    }
}

回到

registerReceiverInternal
函数的分析二,调用了
AMS
的
registerReceiverWithFeature
函数。

该函数是

Broadcast
整个注册过程结束的地方,根据新注册的
BroadcastReceiver
,处理粘性广播的发送和当前注册
Receiver
的添加。

分析一:

粘性广播存储在AMS的

SparseArray<ArrayMap<String, ArrayList<Intent>>>
类型的
mStickyBroadcasts
中。
SparseArray
的
key
为
userId
,而
ArrayMap
的
key
为
action
,
value
为
Intent
。即我们可以通过用户id在
mStickyBroadcasts
找到当前进程对应所有粘性广播(和针对所有进程的粘性广播),然后根据对应的
action
找到对应的
Intent
。这里将他们收集到
stickyIntents
集合中。

分析二:

所有广播的接收者

BroacastReceiver
存储在
AMS
类
HashMap<IBinder, ReceiverList>
类型的
mRegisteredReceivers
中。这里的
IBinder
类型就是应用进程前面创建的
InnerReceiver
类实例在AMS的引用。因为广播接收者
BroadcastReceiver
对应一个或多个
Broadcast
,所以这里通过继承自
ArrayList<BroadcastFilter>
的
ReceiverList
来表达这种关系。通过
BroadcastFilter
来表示当前接收者感兴趣的广播。

分析三:

对匹配到的粘性Intent进入广播队列广播。

    public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
            String callerFeatureId, IIntentReceiver receiver, IntentFilter filter,
            String permission, int userId, int flags) {
        enforceNotIsolatedCaller("registerReceiver");
        //粘性Intent
        ArrayList<Intent> stickyIntents = null;
        ProcessRecord callerApp = null;
        final boolean visibleToInstantApps
                = (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
        int callingUid;
        int callingPid;
        boolean instantApp;
        synchronized(this) {
            if (caller != null) {
                //获得当前引用进程的ProcessRecord
                callerApp = getRecordForAppLocked(caller);
                 ...
                callingUid = callerApp.info.uid;
                callingPid = callerApp.pid;
            } else {
                callerPackage = null;
                callingUid = Binder.getCallingUid();
                callingPid = Binder.getCallingPid();
            }
            //是否快应用(类似小程序)
            instantApp = isInstantApp(callerApp, callerPackage, callingUid);
            userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                    ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
            //分析一:当前注册广播中感兴趣的action列表
            Iterator<String> actions = filter.actionsIterator();
            if (actions == null) {
                ArrayList<String> noAction = new ArrayList<String>(1);
                noAction.add(null);
                actions = noAction.iterator();
            }
            //从历史粘性广播中查找与当前注册的action一致的intent
            //添加到stickyIntents
            // Collect stickies of users
            int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
            while (actions.hasNext()) {
                String action = actions.next();
                for (int id : userIds) {
                    ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                    if (stickies != null) {
                        ArrayList<Intent> intents = stickies.get(action);
                        if (intents != null) {
                            if (stickyIntents == null) {
                                stickyIntents = new ArrayList<Intent>();
                            }
                            stickyIntents.addAll(intents);
                        }
                    }
                }
            }
        }
        //处理content类型的Intent
        ArrayList<Intent> allSticky = null;
        if (stickyIntents != null) {
            final ContentResolver resolver = mContext.getContentResolver();
            // Look for any matching sticky broadcasts...
            for (int i = 0, N = stickyIntents.size(); i < N; i++) {
                Intent intent = stickyIntents.get(i);
                // Don't provided intents that aren't available to instant apps.
                if (instantApp &&
                        (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
                    continue;
                }
                //当前注册广播IntentFilter是否与action一致的intent的匹配
                //处理content类型
                if (filter.match(resolver, intent, true, TAG) >= 0) {
                    if (allSticky == null) {
                        allSticky = new ArrayList<Intent>();
                    }
                    allSticky.add(intent);
                }
            }
        }
        //receiver为null,直接返回null或者第一个粘性intent
        Intent sticky = allSticky != null ? allSticky.get(0) : null;
        if (receiver == null) {
            return sticky;
        }
        synchronized (this) {
            ...
            //分析二:
            //从缓存或新建ReceiverList对象,与Receiver绑定
            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);
                    }
                    //添加到ProcessRecord记录中
                    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,并添加到BroadcastList
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            if (rl.containsFilter(filter)) {
                ...
            } else {
                rl.add(bf);
                //添加到接收者解析器
                mReceiverResolver.addFilter(bf);
            }
            // Enqueue broadcasts for all existing stickies that match
            // this filter.
            //分析三:对匹配到action的粘性广播进行广播
            if (allSticky != null) {
                ArrayList receivers = new ArrayList();
                receivers.add(bf);
                final int stickyCount = allSticky.size();
                for (int i = 0; i < stickyCount; i++) {
                    Intent intent = allSticky.get(i);
                    BroadcastQueue queue = broadcastQueueForIntent(intent);
                    BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                            null, null, -1, -1, false, null, null, OP_NONE, null, receivers,
                            null, 0, null, null, false, true, true, -1, false,
                            false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
                    queue.enqueueParallelBroadcastLocked(r);
                    queue.scheduleBroadcastsLocked();
                }
            }
            return sticky;
        }
    }

广播的解注册

回到

ContextWrapper
的
unregisterReceiver
函数。

#ContextWrapper
public void unregisterReceiver(BroadcastReceiver receiver) {
    mBase.unregisterReceiver(receiver);
}
#ContextImpl
public void unregisterReceiver(BroadcastReceiver receiver) {
    if (mPackageInfo != null) {
        IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher(
                getOuterContext(), receiver);
        try {
            ActivityManager.getService().unregisterReceiver(rd);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    } else {
        throw new RuntimeException("Not supported in system context");
    }
}

这里通过

receiver
和
context
获得
IIntentReceiver
实例
rd
,然后调用AMS的
unregisterReceiver
函数。其中
LoadedApk
的
forgetReceiverDispatcher
函数,主要是从
mReceivers
获取
IIntentReceiver
的实例,并将
receiver
对应的内容从缓存移除。

AMS的

unregisterReceiver
函数。主要是将注册过程添加到
mRegisteredReceivers
、
ProcessProcess
.Receivers、
mReceiverResolver
中对应的内容移除。并终止正在发送的广播。

   public void unregisterReceiver(IIntentReceiver receiver) {
        ...
        final long origId = Binder.clearCallingIdentity();
        try {
            boolean doTrim = false;
            synchronized(this) {
                //获得当前对应的ReceiverList
                ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
                if (rl != null) {
                    //默认情况为null,看看广播发送是否会赋值
                    //从处理逻辑来看,就是广播内容
                    final BroadcastRecord r = rl.curBroadcast;
                    if (r != null &amp;&amp; r == r.queue.getMatchingOrderedReceiver(r)) {
                        final boolean doNext = r.queue.finishReceiverLocked(
                                r, r.resultCode, r.resultData, r.resultExtras,
                                r.resultAbort, false);
                        if (doNext) {
                            doTrim = true;
                            r.queue.processNextBroadcast(false);
                        }
                    }
                    //从processRecord中移除
                    if (rl.app != null) {
                        rl.app.receivers.remove(rl);
                    }
                    //从mRegisteredReceivers和mReceiverResolver移除
                    removeReceiverLocked(rl);
                    if (rl.linkedToDeath) {
                        rl.linkedToDeath = false;
                        rl.receiver.asBinder().unlinkToDeath(rl, 0);
                    }
                }
            }
            // If we actually concluded any broadcasts, we might now be able
            // to trim the recipients' apps from our working set
            if (doTrim) {
                trimApplications(OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
                return;
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }
void removeReceiverLocked(ReceiverList rl) {
    mRegisteredReceivers.remove(rl.receiver.asBinder());
    for (int i = rl.size() - 1; i &gt;= 0; i--) {
        mReceiverResolver.removeFilter(rl.get(i));
    }
}

广播的发送

定位到

ContextWrapper
的
sendBroadcast
函数。

public void sendBroadcast(Intent intent) {
    mBase.sendBroadcast(intent);
}
public void sendBroadcast(Intent intent) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess(this);
        ActivityManager.getService().broadcastIntentWithFeature(mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, nul

标签: android

热门推荐