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

寻技术 Android 2023年07月11日 80

这篇“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						
						
						
						
						
						
						
					
关闭

用微信“扫一扫”