註冊廣播(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)的過程分析

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