注册广播(registerReceiver)过程源码分析

注册广播(registerReceiver)过程源码分析

一、简介

本文主要介绍动态注册广播过程。

二、源码分析

广播注册

IntentFilter filter = new IntentFilter(XXX_ACTION);  
registerReceiver(myReceiver, filter);  

registerReceiver的具体实现是在ContextImpl类中

class ContextImpl extends Context {
@Override
	public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
		return registerReceiver(receiver, filter, null, null);
	}
 
	@Override
	public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
			String broadcastPermission, Handler scheduler) {
		return registerReceiverInternal(receiver, filter, broadcastPermission,
			scheduler, getOuterContext());
	}
 
	private Intent registerReceiverInternal(BroadcastReceiver receiver,
			IntentFilter filter, String broadcastPermission,
			Handler scheduler, Context context) {
    IIntentReceiver rd = null;
    if (receiver != null) {
    //1 mPackageInfo != null和context != null都成立,而且条件scheduler == null也成立,于是就调用mMainThread.getHandler来获得一个Handler
        if (mPackageInfo != null && context != null) {
            if (scheduler == null) {
                scheduler = mMainThread.getHandler();
            }
            rd = mPackageInfo.getReceiverDispatcher(
                receiver, context, scheduler,
                mMainThread.getInstrumentation(), true);//2通过mPackageInfo.getReceiverDispatcher函数获得一个IIntentReceiver接口对象rd,这是一个Binder对象
        } else {
            if (scheduler == null) {
                scheduler = mMainThread.getHandler();
            }
            rd = new LoadedApk.ReceiverDispatcher(
                    receiver, context, scheduler, null, true).getIIntentReceiver();
        }
    }
    try {
        final Intent intent = ActivityManager.getService().registerReceiver(
                mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                broadcastPermission, userId, flags);//3注册到ActivityManagerService中去
        if (intent != null) {
            intent.setExtrasClassLoader(getClassLoader());
            intent.prepareToEnterProcess();
        }
        return intent;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}
}

在ContextImpl中经过调用走到registerReceiverInternal函数,在该函数内首先会判断 mPackageInfo、context等是否为空,这里是非空的且scheduler为空所以会调用mMainThread.getHandler来获得一个Handler。这个获取的handler我们并不陌生它就是ActivityThread中的那个H。

public final class ActivityThread {
final H mH = new H();
final Handler getHandler() {
    return mH;
}
}

之后在注释2处通过mPackageInfo.getReceiverDispatcher函数获得一个IIntentReceiver接口对象rd,这是一个Binder接口用来进行跨进程通信,这里补充下ReceiverDispatcher的作用是负责调度广播接受者,即注册完毕后当广播来临时AMS会通过该类来调度接收者,我们来看下其具体实现

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) {//registered传入值为true
            map = mReceivers.get(context);
            if (map != null) {
                rd = map.get(r);//1首先会尝试获取参数r的ReceiverDispatcher如果存在就直接返回
            }
        }
        if (rd == null) {//2 rd为空表示参数r的ReceiverDispatcher不存在构造一个
            rd = new ReceiverDispatcher(r, context, handler,
                    instrumentation, registered);
            if (registered) {
                if (map == null) {
                    map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                    mReceivers.put(context, map);//3 以context为key map为value存入另一个名为 mReceivers的ArrayMap
                }
                map.put(r, rd);//4 构造完后会以r为key rd为value存到一个ArrayMap中
            }
        } else {
            rd.validate(context, handler);
        }
        rd.mForgotten = false;
        return rd.getIIntentReceiver();
    }
}

getReceiverDispatcher的操作就是如果参数r已经存在对应的ReceiverDispatcher直接返回,如果不存在则构造ReceiverDispatcher实例并把其存入map,map存入mReceivers然后返回。

我们来看下ReceiverDispatcher,下面是其构造函数和getIIntentReceiver()

ReceiverDispatcher(BroadcastReceiver receiver, Context context,
        Handler activityThread, Instrumentation instrumentation,
        boolean registered) {
    if (activityThread == null) {
        throw new NullPointerException("Handler must not be null");
    }

    mIIntentReceiver = new InnerReceiver(this, !registered);
    mReceiver = receiver;
    mContext = context;
    mActivityThread = activityThread;
    mInstrumentation = instrumentation;
    mRegistered = registered;
    mLocation = new IntentReceiverLeaked(null);
    mLocation.fillInStackTrace();
}
IIntentReceiver getIIntentReceiver() {
    return mIIntentReceiver;
}

可以看到getReceiverDispatcher最后返回的是一个mIIntentReceiver,而mIIntentReceiver是一个InnerReceiver实例,而InnerReceiver是一个Binder对象,实现了IIntentReceiver接口。

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

以上就完成了通过getReceiverDispatcher来获取IIntentReceiver(rd
)的操作。下面就是把获得的rd传递到AMS,之后AMS收到广播后会通过rd来调度对应的广播接收者。registerReceiverInternal函数中注释3处(ActivityManager.getService().registerReceiver)调用AMS的registerReceiver。

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

public Intent registerReceiver(IApplicationThread caller, String callerPackage,
        IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
        int flags) {
ProcessRecord callerApp = null;

synchronized(this) {
    if (caller != null) {
        callerApp = getRecordForAppLocked(caller);//1 先获取调用进程的ProcessRecord
        if (callerApp == null) {
            throw new SecurityException(
                    "Unable to find app for caller " + caller
                    + " (pid=" + Binder.getCallingPid()
                    + ") when registering receiver " + receiver);
        }
        if (callerApp.info.uid != SYSTEM_UID &&
                !callerApp.pkgList.containsKey(callerPackage) &&
                !"android".equals(callerPackage)) {
            throw new SecurityException("Given caller package " + callerPackage
                    + " is not running in process " + callerApp);
        }
        callingUid = callerApp.info.uid;
        callingPid = callerApp.pid;
    } else {
        callerPackage = null;
        callingUid = Binder.getCallingUid();
        callingPid = Binder.getCallingPid();
    }

}

//...
Iterator<String> actions = filter.actionsIterator();// 获取filter的action
//...
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());//2 在mRegisteredReceivers中查找当前receiver
if (rl == null) {//3 未找到则构造一个ReceiverList
    rl = new ReceiverList(this, callerApp, callingPid, callingUid,
            userId, receiver);
    if (rl.app != null) {
        rl.app.receivers.add(rl);//4 存储到ProcessRecord的receivers中
    } else {
        try {
            receiver.asBinder().linkToDeath(rl, 0);
        } catch (RemoteException e) {
            return sticky;
        }
        rl.linkedToDeath = true;
    }
    mRegisteredReceivers.put(receiver.asBinder(), rl);//5 把构造的ReceiverList存到mRegisteredReceivers中
}
//...
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
        permission, callingUid, userId, instantApp, visibleToInstantApps);//5 将filter和receiver关联起来
rl.add(bf);
if (!bf.debugCheck()) {
    Slog.w(TAG, "==> For Dynamic broadcast");
}
mReceiverResolver.addFilter(bf);//6 将filter和receiver关联起来后存入AMS的mReceiverResolver
}

AMS的registerReceiver首先会获取一个ProcessRecord实例,ProcessRecord是一个进程的记录块,它包含了当前正在运行的某个进程的全部信息。之后在注释2处会尝试在mRegisteredReceivers中查找当前receiver,如果没有找到则构造对应的ReceiverList并存入mRegisteredReceivers中。

这里解释下mRegisteredReceivers是AMS中用来存放已注册的receiver,它是一个HashMap 以receiver IBinder为key,以对应的ReceiverList为value,这样做的好处就是在收到广播时,快速找到对应的广播接收器。
ReceiverList则表示一个注册了一个或多个广播的receiver。这样当收到广播时,AMS可以根据传入的receiver在mRegisteredReceivers快速找到对应的ReceiverList.

经过以上操作就把receiver存到AMS中了,接下来就要把对应的filter和receiver关联起来并存到AMS的mReceiverResolver。

以上就是整个广播注册过程,下篇文章会分析广播的发送过程。

注册广播实质是把receiver存到AMS中(receiver和AMS在不同进程中),这个过程需要receiver与AMS通信,同时当广播发生时AMS需要把receiver感兴趣的广播发送给receiver这个过程需要AMS与receiver进行通信。所以需要建立receiver与AMS间的双向通信,receiver向AMS是通过AMS在本地的binder代理实现的即ActivityManager.getService(),AMS向receiver通信则是通过IIntentReceiver,它是receiver的binder代理。

以上就是注册广播的核心内容,下面我们来梳理下Framework层是如何完成上面整个流程的。

1、首先在receiver端在注册广播时需要准备好IIntentReceiver,因为AMS需要通过它来把广播发送给receiver,在准备好之后便通过AMS在本地的binder代理调用AMS的相关方法,此时会把相关参数一并传给AMS这其中就包含IIntentReceiver和广播所需检查的权限等内容。

2、进入到AMS中主要操作就是合理的存储receiver,这其中涉及几个AMS中用来存储receiver的数据结构:mRegisteredReceivers、ReceiverList、BroadcastFilter、mReceiverResolver。我们先来介绍这几个属性或类的大致作用以方便我们理解整个存储过程。

首先是mRegisteredReceivers,它保存了系统中所有的动态注册的广播,receiver端的IIntentReceiver的binder代理为key,ReceiverList为value。

 /**
     * Keeps track of all IIntentReceivers that have been registered for broadcasts.
     * Hash keys are the receiver IBinder, hash value is a ReceiverList.
     */
     
    final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();

ReceiverList,它在system_server端表示一个注册了一个或多个广播的广播注册器,继承自ArrayList。可以看出它内部保存了广播注册器所对应的的IIntentReceiver、ProcessRecord以及BroadcastFilter

/**
 * A receiver object that has registered for one or more broadcasts.
 * The ArrayList holds BroadcastFilter objects.
 */
final class ReceiverList extends ArrayList<BroadcastFilter>
        implements IBinder.DeathRecipient {
    final ActivityManagerService owner;
    public final IIntentReceiver receiver;
    public final ProcessRecord app;
    public final int pid;
    public final int uid;
    public final int userId;
    BroadcastRecord curBroadcast = null;
    boolean linkedToDeath = false;

    String stringName;

BroadcastFilter,它继承自IntentFilter,也就是说BroadcastFilter代表了注册广播时传入的IntentFilter,IntentFilter是描述要匹配的Intent的结构,也就是说IntentFilter是用来匹配Intent的。

final class BroadcastFilter extends IntentFilter {
    final ReceiverList receiverList;
    final String packageName;
    final String requiredPermission;
    final int owningUid;
    final int owningUserId;
    final boolean instantApp;
    final boolean visibleToInstantApp;

mReceiverResolver,它是IntentResolver类型实例,IntentResolver是用来解析Intent的,此处的mReceiverResolver里面维护了一个BroadcastFilter列表,所以它可以用来解析一个广播的Intent从而找到跟其匹配的BroadcastReceiver。

  /**
     * Resolver for broadcast intents to registered receivers.
     * Holds BroadcastFilter (subclass of IntentFilter).
     */
    final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
            = new IntentResolver<BroadcastFilter, BroadcastFilter>() ;

介绍完相关类和属性,我们来看下AMS端核心代码:

     
      public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
            int flags) {
            ...
            //1、在mRegisteredReceivers查询广播注册器是否注册过
     ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            //rl为null表示当前广播注册器尚未注册过
            if (rl == null) {
                //3、在AMS端创建一个表示广播注册器的ReceiverList对象
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                if (rl.app != null) {
                    //4、并把创建的ReceiverList对象存到广播注册器所在进程对应的LoadedApk的receivers中,LoadedApk是用来保存当前运行app的状态的类,它保存着app的Application、类加载器、receiver、service等信息。LoadedApk.receivers表示其所在进程已注册的所有广播注册器
                    rl.app.receivers.add(rl);
                } else {
                    try {
                        receiver.asBinder().linkToDeath(rl, 0);
                    } catch (RemoteException e) {
                        return sticky;
                    }
                    rl.linkedToDeath = true;
                }
                //5、把创建的ReceiverList存到mRegisteredReceivers中
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            }
            ...
            //6、创建BroadcastFilter,用它代表注册广播时传入的IntentFilter
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            //7、把创建的BroadcastFilter存入rl,这样就把该广播注册器与所对应的IntentFilter在AMS端建立联系
            rl.add(bf);
            if (!bf.debugCheck()) {
                Slog.w(TAG, "==> For Dynamic broadcast");
            }
            //8、把步骤6创建的BroadcastFilter存入mReceiverResolver,这样AMS在收到广播Intent时就会从mReceiverResolver匹配合适的BroadcastFilter。
            mReceiverResolver.addFilter(bf);
            ...
    }

参考链接:
Android应用程序注册广播接收器(registerReceiver)的过程分析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章