ブロードキャストの動的登録プロセス
7639 ワード
ブロードキャストの動的登録プロセス
ブロードキャストの登録は、リストファイルの静的登録とコードの動的登録の2つの形式に分けられます.ここでは、動的登録のプロセスを分析します.次に、動的登録の使用コードを見てみましょう.
コードを使用してブロードキャストを動的に登録するときにregisterReceiverメソッドを呼び出して登録します.このメソッドに従うと、親ContextWrapperのregisterReceiverメソッドが呼び出されます.
ContextWrapperのregisterReceiverメソッドではまたmBaseメソッドが呼び出され、mBaseの具体的な実装タイプはContextImpl(『Contextの作成プロセス』を参照)であり、ContextImplのregisterReceiverメソッドを参照してください.
コメント1では、リロード方法が呼び出されました.
注釈2でregisterReceiverInternalメソッドが呼び出されました.
注記3のrdはIintentReceiverタイプである、IintentReceiverはaidlインタフェースであるため、rdはプロセス間通信をサポートするものであり、注記4からrdオブジェクトがmPackageInfoであることが分かる.getReceiverDispatcherメソッドで取得した、mPackageInfoのタイプはLoadedApkで、ソースコードを見てください:
注釈6にはmapセットが作成され、注釈8によって記憶されているkeyは私たちが登録したBroadcastReceiverオブジェクトであり、valueはLoadedApkであることがわかる.ReceiverDispatcherオブジェクト(空の場合はコメント7で作成)では、ReceiverDispatcherはLoadedApkの静的内部クラスです.ReceiverDispatcherの構造方法を参照してください.
ReceiverDispatcherの構築方法でIintentReceiverオブジェクトが作成されました.このオブジェクトがmPackageInfoです.getReceiverDispatcherの戻り値は、具体的にはInnerReceiverであるが、InnerReceiverはIententReceiverを継承し実現する.Stub、だからInnerReceiverオブジェクトはプロセス間通信をサポートして、同時に私達のreceiverオブジェクトをmReceiverに割り当てて保存して、このようにReceiverDispatcherは同時にローカルのBroadcastReceiverオブジェクトとプロセス間をサポートするInnerReceiver対象を持って、このようにそれらの2つの仕事を便利に支配することができて、プロセス間の仕事はInnerReceiverオブジェクトに任せて完成する必要があります.onReceiverメソッドをコールバックする必要がある場合は、クライアント定義のBroadcastReceiverオブジェクトのonReceiverメソッドを呼び出します.
ContextImplのregisterReceiverInternalメソッドに戻ると、rdオブジェクトはプロセスにまたがることができ、このオブジェクトはAMSのregisterReceiverメソッドのパラメータ(注釈5)として扱われ、AMSとAppは2つの独立したプロセスであるためActivity Management.getService().registerReceiverはプロセス間通信のプロセスであり、我々自身のBroadcastReceiverオブジェクトはAppプロセスのコンポーネントであり、直接プロセス間転送を行うことができないため、それに対応するプロセス間転送可能なIintentReceiverオブジェクトrdを作成してプロセス間転送を完了し、AMSのregisterReceiverメソッドに引き続き追跡し、どのように登録されているかを見てみましょう.
AMSのregisterReceiverメソッドでは,アノテーション9にIintentReceiverオブジェクト情報を保存し,アノテーション10にIntentFilterオブジェクト情報を保存することで,AMSにブロードキャストコンポーネントのすべての情報が得られ,後続の送受信イベントを処理できるようになり,ブロードキャストの登録が完了する.放送の送受信の流れについては次の文章でまとめる.
ブロードキャストの登録は、リストファイルの静的登録とコードの動的登録の2つの形式に分けられます.ここでは、動的登録のプロセスを分析します.次に、動的登録の使用コードを見てみましょう.
// BroadcastReceiver
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//TODO
}
};
//
IntentFilter filter = new IntentFilter();
filter.addAction("cn.znh.receiver.filter.action");
registerReceiver(receiver, filter);
コードを使用してブロードキャストを動的に登録するときにregisterReceiverメソッドを呼び出して登録します.このメソッドに従うと、親ContextWrapperのregisterReceiverメソッドが呼び出されます.
Context mBase;
@Override
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter) {
return mBase.registerReceiver(receiver, filter);
}
ContextWrapperのregisterReceiverメソッドではまたmBaseメソッドが呼び出され、mBaseの具体的な実装タイプはContextImpl(『Contextの作成プロセス』を参照)であり、ContextImplのregisterReceiverメソッドを参照してください.
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
// 1
return registerReceiver(receiver, filter, null, null);
}
コメント1では、リロード方法が呼び出されました.
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
// 2
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext(), 0);
}
注釈2でregisterReceiverInternalメソッドが呼び出されました.
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
// 3
IIntentReceiver rd = null;
if (receiver != null) {
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
// 4
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 {
// 5 AMS registerReceiver
final Intent intent = ActivityManager.getService().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
broadcastPermission, userId, flags);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
intent.prepareToEnterProcess();
}
return intent;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
注記3のrdはIintentReceiverタイプである、IintentReceiverはaidlインタフェースであるため、rdはプロセス間通信をサポートするものであり、注記4からrdオブジェクトがmPackageInfoであることが分かる.getReceiverDispatcherメソッドで取得した、mPackageInfoのタイプはLoadedApkで、ソースコードを見てください:
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
Context context, Handler handler,
Instrumentation instrumentation, boolean registered) {
synchronized (mReceivers) {
LoadedApk.ReceiverDispatcher rd = null;
// 6
ArrayMap map = null;
if (registered) {
map = mReceivers.get(context);
if (map != null) {
rd = map.get(r);
}
}
if (rd == null) {
// 7
rd = new ReceiverDispatcher(r, context, handler,
instrumentation, registered);
if (registered) {
if (map == null) {
map = new ArrayMap();
mReceivers.put(context, map);
}
// 8
map.put(r, rd);
}
} else {
rd.validate(context, handler);
}
rd.mForgotten = false;
return rd.getIIntentReceiver();
}
}
注釈6にはmapセットが作成され、注釈8によって記憶されているkeyは私たちが登録したBroadcastReceiverオブジェクトであり、valueはLoadedApkであることがわかる.ReceiverDispatcherオブジェクト(空の場合はコメント7で作成)では、ReceiverDispatcherはLoadedApkの静的内部クラスです.ReceiverDispatcherの構造方法を参照してください.
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();
}
ReceiverDispatcherの構築方法でIintentReceiverオブジェクトが作成されました.このオブジェクトがmPackageInfoです.getReceiverDispatcherの戻り値は、具体的にはInnerReceiverであるが、InnerReceiverはIententReceiverを継承し実現する.Stub、だからInnerReceiverオブジェクトはプロセス間通信をサポートして、同時に私達のreceiverオブジェクトをmReceiverに割り当てて保存して、このようにReceiverDispatcherは同時にローカルのBroadcastReceiverオブジェクトとプロセス間をサポートするInnerReceiver対象を持って、このようにそれらの2つの仕事を便利に支配することができて、プロセス間の仕事はInnerReceiverオブジェクトに任せて完成する必要があります.onReceiverメソッドをコールバックする必要がある場合は、クライアント定義のBroadcastReceiverオブジェクトのonReceiverメソッドを呼び出します.
ContextImplのregisterReceiverInternalメソッドに戻ると、rdオブジェクトはプロセスにまたがることができ、このオブジェクトはAMSのregisterReceiverメソッドのパラメータ(注釈5)として扱われ、AMSとAppは2つの独立したプロセスであるためActivity Management.getService().registerReceiverはプロセス間通信のプロセスであり、我々自身のBroadcastReceiverオブジェクトはAppプロセスのコンポーネントであり、直接プロセス間転送を行うことができないため、それに対応するプロセス間転送可能なIintentReceiverオブジェクトrdを作成してプロセス間転送を完了し、AMSのregisterReceiverメソッドに引き続き追跡し、どのように登録されているかを見てみましょう.
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
int flags) {
........................
// 9 IIntentReceiver
mRegisteredReceivers.put(receiver.asBinder(), rl);
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId, instantApp, visibleToInstantApps);
if (rl.containsFilter(filter)) {
Slog.w(TAG, "Receiver with filter " + filter
+ " already registered for pid " + rl.pid
+ ", callerPackage is " + callerPackage);
} else {
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
// 10 IntentFilter
mReceiverResolver.addFilter(bf);
}
........................
}
AMSのregisterReceiverメソッドでは,アノテーション9にIintentReceiverオブジェクト情報を保存し,アノテーション10にIntentFilterオブジェクト情報を保存することで,AMSにブロードキャストコンポーネントのすべての情報が得られ,後続の送受信イベントを処理できるようになり,ブロードキャストの登録が完了する.放送の送受信の流れについては次の文章でまとめる.