[Android]AMS广播注册(二)

1. 广播注册时序图

2. 动态注册

2.1 ContextImpl 注册流程

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, Context context) {

        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();
                }
                // 查找和context对应的“子哈希表”里的ReceiverDispatcher,如果找不到,就重新new一个
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        try {
            // 开始由Ams分化intent到各个BroadcastReceiver
            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();
        }
    }

示例1

2.2 注册过程涉及对象关系

LoadedApk(mPackageInfo)
private final HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mReceivers
    = new HashMap<Context, HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();

    public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
            Context context, Handler handler,
            Instrumentation instrumentation, boolean registered) {
        synchronized (mReceivers) {
            LoadedApk.ReceiverDispatcher rd = null;

            // BroadcastReceiver 与 ReceiverDispatcher一一对应
            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>();
                        // 建立context与多个BroadcastReceiver的关系
                        mReceivers.put(context, map);
                    }
                    // 每个Broadcast建立与ReceiverDispatcher的关系
                    map.put(r, rd);
                }
            } else {
                rd.validate(context, handler);
            }
            rd.mForgotten = false;
            return rd.getIIntentReceiver();

        }
    }

2.3 各对象映射关系

该表的key项是我们比较熟悉的Context,也就是说可以是Activity、Service或Application。而value项则是另一张“子哈希表”。这是个“表中表”的形式。言下之意就是,每个Context(比如一个activity),是可以注册多个receiver的,这个很好理解。mReceivers里的“子哈希表”的key值为BroadcastReceiver,value项为ReceiverDispatcher,
示意图如下:

image

ActivityManagerNative.getDefault().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName,
                    rd, filter, broadcastPermission);
// AMS codes
ReceiverList rl = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());                    

NOTE:

  • ReceiverList , AMS, LoadedApk.ReceiverDispatcher, IIntentResolver各映射关系
    三处的IIntentReceiver 都是同一个对象

image

2.4 AMS相关涉及代码

HashMap<Binder, ReceiverList> mReceiveredReceivers = new HashMap(); // (3)

class Loaded.ReceiverDispatcher {
    final IIntentReceiver.Stub mIIntentReceiver; // (1)
    final BroadcastReceiver mReceiver;
    final Context mContext;
    final Handler mActivityThread;
    final Instrumentation mInstrumentation;
    final boolean mRegistered;
    final IntentReceiverLeaked mLocation;
    RuntimeException mUnregisterLocation;
}

// RecieverList 相当于IntentFilter的数组
class ReceiverList extends ArrayList<BroadcastFilter>
        implements IBinder.DeathRecipient 
{
    final ActivityManagerService owner; 
    public final IIntentReceiver receiver; // (2)
    public final ProcessRecord app;    
    public final int pid;    
    public final int uid;
    BroadcastRecord curBroadcast = null;
    boolean linkedToDeath = false;
    String stringName;
    . . . . . .
}

class BroadcastFilter extends IntentFilter{
    final ReceiverList receiverList;
    final String packageName;
    final String requiredPermission;
    . . . . . .
    public BroadcastFilter(IntentFilter _filter, ...) {
        super(_filter);
    }
}

NOTE:

  • ReceiverList继承于ArrayList,而BroadcastFilter又继承于IntentFilter,所以ReceiverList可以被理解为一个IntentFilter数组列表。
  • 在由BroadcastQueue分发时,会涉及到LoadedApk.ReceiverDispatcher

3. 静态注册

3.1 描述

NOTE:

静态receiver是指那些在AndroidManifest.xml文件中声明的receiver,它们的信息会在系统启动时,由Package Manager Service(PKMS)解析并记录下来。以后,当AMS调用PKMS的接口来查询“和intent匹配的组件”时,PKMS内部就会去查询当初记录下来的数据,并把结果返回AMS。

有的同学认为静态receiver是常驻内存的,这种说法并不准确。因为常驻内存的只是静态receiver的描述性信息,并不是receiver实体本身。

具体静态广播Receiver详见Ams广播发送原理

在PKMS内部,会有一个针对receiver而设置的Resolver(决策器),其示意图如下:
image

关于PKMS的查询动作的细节,可参考PKMS的相关文档。目前我们只需知道,PKMS向外界提供了queryIntentReceivers()函数,该函数可以返回一个List列表。

我们举个实际的例子:

Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
List<ResolveInfo> ris = null;
try {
    ris = AppGlobals.getPackageManager().queryIntentReceivers(intent, null, 0, 0);
} catch (RemoteException e) {}

这是AMS的systemReady()函数里的一段代码,意思是查找有多少receiver对ACTION_PRE_BOOT_COMPLETED感兴趣。

3.2 ResolveInfo的定义截选如下

public class ResolveInfo implements Parcelable 
{    
    public ActivityInfo activityInfo;    
    public ServiceInfo serviceInfo;    
    public IntentFilter filter;    
    public int priority;    
    public int preferredOrder;    
    public int match;
    . . . . . .
    . . . . . .

NOTE:

  • 总之,当系统希望发出一个广播时,PKMS必须能够决策出,有多少静态receiver对这个广播感兴趣,而且这些receiver的信息分别又是什么。

关于receiver的注册动作,我们就先说这么多。下面我们来看看激发广播时的动作。

4. 激发广播

4.1 Overview

image1

4.2 发送广播的几种方式

public void sendBroadcast(Intent intent)

public void sendBroadcast(Intent intent, int userId)

public void sendBroadcast(Intent intent, String receiverPermission)

public void sendOrderedBroadcast(Intent intent, String receiverPermission)

public void sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)

public void sendStickyBroadcast(Intent intent)

public void sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)

NOTE:

  • 不同类型的广播对应各见的激活方式,详见广播原理概述

4.3 为何sticky广播能收到漏接的广播?

ticky广播,它又是什么呢?简单地说,sticky广播可以保证“在广播递送时尚未注册的receiver”,一旦日后注册进系统,就能够马上接到“错过”的sticky广播

final SparseArray<ArrayMap<String, ArrayList<Intent>>> mStickyBroadcasts =
            new SparseArray<ArrayMap<String, ArrayList<Intent>>>();

// 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(r);
        queue.scheduleBroadcastsLocked();
    }
}

Map<action, ArrayList> allBroadcast = mStickyBroadcasts.get(usrId) //不同的用户有各自的stick broadcast

NOTE:

  • stick广播发送后会一直保存在mStickyBroadcasts, 当注册stick广播时就会由BroadcastQueue 重发一次已经记录的广播

猜你喜欢

转载自blog.csdn.net/s394500839/article/details/76690612
今日推荐