ブロードキャストの動的登録プロセス

7639 ワード

ブロードキャストの動的登録プロセス
ブロードキャストの登録は、リストファイルの静的登録とコードの動的登録の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にブロードキャストコンポーネントのすべての情報が得られ,後続の送受信イベントを処理できるようになり,ブロードキャストの登録が完了する.放送の送受信の流れについては次の文章でまとめる.