Framework学习(九)Broadcast的注册、发送和接收过程

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;

}

}

}

继续来看registerReceiverInternal函数的注释4,其实是通过Binder调用的AMS的registerReceiver方法。

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

ActivityManagerService#registerReceiver()

public Intent registerReceiver(IApplicationThread caller, String callerPackage,

IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {

ArrayList stickyIntents = null;

ProcessRecord callerApp = null;

int callingUid;

int callingPid;

synchronized(this) {

Iterator actions = filter.actionsIterator(); //1

if (actions == null) {

ArrayList noAction = new ArrayList(1);

noAction.add(null);

actions = noAction.iterator();

}

// Collect stickies of users

int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };

while (actions.hasNext()) {

String action = actions.next();

//2

for (int id : userIds) {

ArrayMap<String, ArrayList> stickies = mStickyBroadcasts.get(id);

if (stickies != null) {

ArrayList intents = stickies.get(action);

if (intents != null) {

if (stickyIntents == null) {

stickyIntents = new ArrayList();

}

stickyIntents.addAll(intents);

}

}

}

}

}

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

// If intent has scheme “content”, it will need to acccess

// provider that needs to lock mProviderMap in ActivityThread

// and also it may need to wait application response, so we

// cannot lock ActivityManagerService here.

if (filter.match(resolver, intent, true, TAG) >= 0) {

if (allSticky == null) {

allSticky = new ArrayList();

}

allSticky.add(intent); //3

}

}

}

// The first sticky in the list is returned directly back to the client.

Intent sticky = allSticky != null ? allSticky.get(0) : null;

if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);

if (receiver == null) {

return sticky;

}

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()); //4

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;

}

mRegisteredReceivers.put(receiver.asBinder(), rl);

}

BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,

permission, callingUid, userId); //5

rl.add(bf); //6

if (!bf.debugCheck()) {

Slog.w(TAG, “==> For Dynamic broadcast”);

}

mReceiverResolver.addFilter(bf); //7

// Enqueue broadcasts for all existing stickies that match

// this filter.

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, -1, -1, null, null, AppOpsManager.OP_NONE, null, receivers,

null, 0, null, null, false, true, true, -1);

queue.enqueueParallelBroadcastLocked®;

queue.scheduleBroadcastsLocked();

}

}

return sticky;

}

}

注释1处根据传入的IntentFilter类型的filter得到actions列表。

注释2处根据actions列表和userIds(userIds可以理解为应用程序的uid)得到所有的粘性广播的intent,并传入到stickyIntents中。

注释3处将这些粘性广播的intent存入到allSticky列表中,从这里可以看出粘性广播是存储在AMS中的。

注释4处获取ReceiverList列表,ReceiverList继承自ArrayList,用来存储广播接收者。

注释5处创建BroadcastFilter并传入此前创建的ReceiverList,BroadcastFilter用来描述注册的广播接收者。

注释6通过add方法将注释5创建的BroadcastFilter添加到ReceiverList中。

注释7处将BroadcastFilter添加到mReceiverResolver中,这样当AMS接收到广播时就可以从mReceiverResolver中找到对应的广播接收者了。

时序图:

广播的发送


广播有很多类型:无序广播(普通广播)、有序广播、粘性广播和APP内部广播,这里以普通广播为例,来讲解广播的发送过程。

要发送普通广播需要调用sendBroadcast方法,它的实现同样在ContextWrapper中:

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

ContextWrapper#sendBroadcast()

@Override

public void sendBroadcast(Intent intent) {

mBase.sendBroadcast(intent);

}

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

ContextImpl#sendBroadcast()

@Override

public void sendBroadcast(Intent intent) {

warnIfCallingFromSystemProcess();

String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());

try {

intent.prepareToLeaveProcess(this);

//1

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

}

}

注释1处最终会调用AMS的broadcastIntent方法。

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

ActivityManagerService#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) {

synchronized(this) {

intent = verifyBroadcastLocked(intent); //1

final ProcessRecord callerApp = getRecordForAppLocked(caller);

final int callingPid = Binder.getCallingPid();

final int callingUid = Binder.getCallingUid();

final long origId = Binder.clearCallingIdentity();

//2

int res = broadcastIntentLocked(callerApp,

callerApp != null ? callerApp.info.packageName : null,

intent, resolvedType, resultTo, resultCode, resultData, resultExtras,

requiredPermissions, appOp, bOptions, serialized, sticky,

callingPid, callingUid, userId);

Binder.restoreCallingIdentity(origId);

return res;

}

}

注释1处通过verifyBroadcastLocked方法验证广播是否合法。

注释2处调用broadcastIntentLocked方法。

先看看注释1的verifyBroadcastLocked方法:

ActivityManagerService#verifyBroadcastLocked()

final Intent verifyBroadcastLocked(Intent intent) {

// Refuse possible leaked file descriptors

if (intent != null && intent.hasFileDescriptors() == true) { //1

throw new IllegalArgumentException(“File descriptors passed in Intent”);

}

int flags = intent.getFlags(); //2

if (!mProcessesReady) {

// if the caller really truly claims to know what they’re doing, go

// ahead and allow the broadcast without launching any receivers

if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) { //3

// This will be turned into a FLAG_RECEIVER_REGISTERED_ONLY later on if needed.

} else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { //4

Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent

  • " before boot completion");

throw new IllegalStateException(“Cannot broadcast before boot completed”);

}

}

if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {

throw new IllegalArgumentException(

“Can’t use FLAG_RECEIVER_BOOT_UPGRADE here”);

}

return intent;

}

注释1处验证intent是否不为null并且有文件描述符。

注释2处获得intent中的flag。

注释3处如果系统正在启动过程中,判断如果flag设置为FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT(启动检查时只接受动态注册的广播接收者)则不做处理,如果不是则在注释4处判断如果flag没有设置为FLAG_RECEIVER_REGISTERED_ONLY(只接受动态注册的广播接收者)则会抛出异常。

继续来看broadcastIntent的注释2。

ActivityManagerService#broadcastIntentLocked()

final int broadcastIntentLocked(ProcessRecord callerApp,

String callerPackage, Intent intent, String resolvedType,

IIntentReceiver resultTo, int resultCode, String resultData,

Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,

boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {

// Figure out who all will receive this broadcast.

List receivers = null;

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++) {

List registeredReceiversForUser =

mReceiverResolver.queryIntent(intent,

resolvedType, false, users[i]); //1

if (registeredReceivers == null) {

registeredReceivers = registeredReceiversForUser;

} else if (registeredReceiversForUser != null) {

registeredReceivers.addAll(registeredReceiversForUser);

}

}

} else {

registeredReceivers = mReceiverResolver.queryIntent(intent,

resolvedType, false, userId);

}

}

// Merge into one list.

int ir = 0;

if (receivers != null) {

int NT = receivers != null ? receivers.size() : 0;

int it = 0;

ResolveInfo curt = null;

BroadcastFilter curr = null;

//2

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) {

// Insert this broadcast record into the final list.

receivers.add(it, curr);

ir++;

curr = null;

it++;

NT++;

} else {

// Skip to the next ResolveInfo in the final list.

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

//3

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

if (!replaced) {

queue.enqueueOrderedBroadcastLocked®;

queue.scheduleBroadcastsLocked(); //4

}

} else {

}

return ActivityManager.BROADCAST_SUCCESS;

}

代码很长,我们这里只捡重点看。

注释1通过mReceiverResolver查询到所有符合条件的广播接收器,这些接收器是在广播注册的时候放到mReceiverResolver中的,具体可以参考广播注册过程。

注释2将注释1获得的所有广播接收器按照优先级高低存储到receivers列表中,这样receivers列表包含了所有的广播接收者(无序广播和有序广播)。

注释3处创建BroadcastRecord对象并将receivers传进去。

注释4处调用BroadcastQueue的scheduleBroadcastsLocked方法。

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

BroadcastQueue#scheduleBroadcastsLocked()

public void scheduleBroadcastsLocked() {

if (mBroadcastsScheduled) {

return;

}

mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this)); //1

mBroadcastsScheduled = true;

}

注释1处向BroadcastHandler类型的mHandler对象发送了BROADCAST_INTENT_MSG类型的消息,这个消息在BroadcastHandler的handleMessage方法中进行处理。

BroadcastQueue#BroadcastHandler

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;

}

}

}

注释1执行processNextBroadcast方法。processNextBroadcast方法对无序广播和有序广播分别进行处理,旨在将广播发送给广播接收者,下面给出processNextBroadcast方法中对无序广播的处理部分。

BroadcastQueue#processNextBroadcast()

final void processNextBroadcast(boolean fromMsg) {

if (fromMsg) {

mBroadcastsScheduled = false;//1

}

// First, deliver any non-serialized broadcasts right away.

while (mParallelBroadcasts.size() > 0) { //2

r = mParallelBroadcasts.remove(0); //3

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, i); //4

}

addBroadcastToHistoryLocked®;

if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, “Done with parallel broadcast [”

  • mQueueName + "] " + r);

}

}

从前面的代码我们得知fromMsg的值为true,因此注释1处会将mBroadcastsScheduled 设置为flase,表示对于此前发来的BROADCAST_INTENT_MSG类型的消息已经处理了。

注释2处的mParallelBroadcasts列表用来存储无序广播,通过while循环将mParallelBroadcasts列表中的无序广播发送给对应的广播接收者。

注释3处获取每一个mParallelBroadcasts列表中存储的BroadcastRecord类型的r对象。

注释4处将这些r对象描述的广播发送给对应的广播接收者。

BroadcastQueue#deliverToRegisteredReceiverLocked

private void deliverToRegisteredReceiverLocked(BroadcastRecord r,

BroadcastFilter filter, boolean ordered, int index) {

try {

if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {

// Skip delivery if full backup in progress

// If it’s an ordered broadcast, we need to continue to the next receiver.

if (ordered) {

skipReceiverLocked®;

}

} else {

performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,

new Intent(r.intent), r.resultCode, r.resultData,

r.resultExtras, r.ordered, r.initialSticky, r.userId); //1

}

if (ordered) {

r.state = BroadcastRecord.CALL_DONE_RECEIVE;

}

} catch (RemoteException e) {

}

}

省略了很多代码,这些代码是用来检查广播发送者和广播接收者的权限。如果通过了权限的检查,则会调用注释1处的performReceiveLocked方法。

BroadcastQueue#performReceiveLocked

void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

给大家分享一份移动架构大纲,包含了移动架构师需要掌握的所有的技术体系,大家可以对比一下自己不足或者欠缺的地方有方向的去学习提升;

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

entReceiver receiver,

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-VlsUWDYr-1712273080778)]

[外链图片转存中…(img-a2SfMpP7-1712273080779)]

[外链图片转存中…(img-9Tw4ZU6l-1712273080779)]

[外链图片转存中…(img-z6qEDgzQ-1712273080780)]

[外链图片转存中…(img-dCqDuR4a-1712273080780)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

给大家分享一份移动架构大纲,包含了移动架构师需要掌握的所有的技术体系,大家可以对比一下自己不足或者欠缺的地方有方向的去学习提升;

[外链图片转存中…(img-P5N6BatF-1712273080780)]

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
  • 9
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值