1. 程式人生 > >Android廣播機制一

Android廣播機制一

  廣播機制做為android程序間通訊的一個重要機制被廣泛的使用。我承認已經到了濫用的地步。正因為如此,各方案公司甚至google都已經對它做修改限制,來達到控制大家濫用的目的。(這說明這個機制本身的設計還是很成功的,說明它對於使用者來說,簡單、方便,耦合度低的特點)。
  那麼android是設計broadcast的這套機制的。我們來看一下大致的流程。
  android的廣播機制分為註冊和接收兩塊。使用者將自己感興趣的廣播向系統註冊,系統在接收到相應的廣播後,會找到各個註冊者,並呼叫onReceive。
  
  看呼叫方式,以在activity中呼叫為例:
 

 public
class MainActivity extends Activity { private static final String Tag="TEST"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); IntentFilter filter = new IntentFilter("com.test.broadcast"
); registerReceiver(receiver, filter); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); unregisterReceiver(receiver); } private BroadcastReceiver receiver = new BroadcastReceiver(){ public void
onReceive(Context context, Intent intent) { Log.i(TAG, "Receive ...."); } }; }

然後看Activity中是怎樣處理registerReceiver(receiver, filter);的。發現Activity類中並沒有直接實現該函式。再找它的父類ContextThemeWrapper,也沒有,接著找ContextThemeWrapper的父類ContextWrapper:

    public Intent registerReceiver(
        BroadcastReceiver receiver, IntentFilter filter) {
        return mBase.registerReceiver(receiver, filter);
    }

呼叫了mBase的registerReceiver,mBase又是個什麼東西呢?
它是一個ContextImpl ,為什麼?
這要從launch一個android的應用說起,我把程式碼貼上來:
在ActivityThread.java中有:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
....
Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config);
                        .....
而createBaseContextForActivity程式碼是這樣的:
private Context createBaseContextForActivity(ActivityClientRecord r,
            final Activity activity) {
        ContextImpl appContext = new ContextImpl();
       ...
        Context baseContext = appContext;
        ...
        return baseContext;
    }

Activity.java的attach函式:

 final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config) {
        attachBaseContext(context);
        .   

 @Override protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase);
        mBase = newBase;
    }

所以,mBase是一個ContextImpl的例項。
這是套路!
我們來看Context,ContextThemeWrapper,ContextWrapper和ContextImpl這幾個類之間的關係類圖(公司限制不能上傳圖片或檔案,所以或許有一天這張圖片失效了):
這裡寫圖片描述

再看套路之裝飾模式:
這裡寫圖片描述

是不是很相似的感覺!
這就是套路!
這裡說一下android的命名,其實android的命名還是很統一的,基本上從類或檔案的命名上,就能看出端倪來。XXXWrapper就說明了問題,這對於我們看android程式碼很有幫助,後續會陸續說到android命名來看相關的程式碼。我們不可能把整個android的程式碼都背下來,但是,如果我們掌握了規律,找起程式碼來就會快一些。

繼續跟蹤ContextImpl裡的

    @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, getUserId(),
                filter, broadcastPermission, scheduler, getOuterContext());
    }

轉到registerReceiverInternal:

    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();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        try {
            return ActivityManagerNative.getDefault().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName,
                    rd, filter, broadcastPermission, userId);
        } catch (RemoteException e) {
            return null;
        }
    }

mPackageInfo是一個LoadedApk的例項。看一下它的成員變數。

private final ActivityThread mActivityThread;
    private final ApplicationInfo mApplicationInfo;
    final String mPackageName;
    private final String mAppDir;
    private final String mResDir;
    private final String[] mSharedLibraries;
    private final String mDataDir;
    private final String mLibDir;
    private final File mDataDirFile;
    private final ClassLoader mBaseClassLoader;
    private final boolean mSecurityViolation;
    private final boolean mIncludeCode;
    private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
    Resources mResources;
    private ClassLoader mClassLoader;
    private Application mApplication;

    private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
        = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
    private final ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>> mUnregisteredReceivers
        = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();
    private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
        = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();
    private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mUnboundServices
        = new ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>>();

從它的成員變數看的出,這是個挺重要的類。尤其是成員變數ActivityThread mActivityThread。注意到mReceivers,看上去這個變數記錄了應用的所有Receiver。

if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }

獲得了主執行緒的handler.

rd = mPackageInfo.getReceiverDispatcher(
                    receiver, context, scheduler,
                    mMainThread.getInstrumentation(), true);

這裡的getReceiverDispatcher返回的是IIntentReceiver型別例項,Binder物件。而Binder用於IPC通訊的,那麼這個Binder物件要和誰進行IPC通訊呢?應該是ActivityManagerService。
這個函式的實現:

    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) {
                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>();
                        mReceivers.put(context, map);
                    }
                    map.put(r, rd);
                }
            } else {
                rd.validate(context, handler);
            }
            rd.mForgotten = false;
            return rd.getIIntentReceiver();
        }
    }

先從mReceivers中找rd,這裡為空,所以就new 了一個ReceiverDispatcher,並將它放入mReceivers中記錄下來。key是一個Context,這裡指的就是我們的MainActiviy,所以通過一個activity可以找到對應的map,再通過BroadcastReceiver就可以找到相應的廣播接收發布器ReceiverDispatcher了。(引:http://blog.csdn.net/luoshengyang/article/details/6737352)在新建廣播接收發布器ReceiverDispatcher時,會在建構函式裡面建立一個InnerReceiver例項,這是一個Binder物件,實現了IIntentReceiver介面,可以通過ReceiverDispatcher.getIIntentReceiver函式來獲得,獲得後就會把它傳給ActivityManagerService,以便接收廣播。在ReceiverDispatcher類的建構函式中,還會把傳進來的Handle型別的引數activityThread儲存下來,以便後面在分發廣播的時候使用。
 這樣說來,ActivityManagerService就能找到對應的BroadcastReceiver,並且往對應的執行緒中傳送訊息了。而這個訊息的響應函式應該就是BroadcastReceiver的onReceive函數了。
 回到ContextImpl.registerReceiverInternal函式中,
 

return ActivityManagerNative.getDefault().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName,
                    rd, filter, broadcastPermission, userId);

呼叫了ActivityManagerNative的內部類ActivityManagerProxy.registerReceiver:

    public Intent registerReceiver(IApplicationThread caller, String packageName,
            IIntentReceiver receiver,
            IntentFilter filter, String perm, int userId) throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(packageName);
        data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
        filter.writeToParcel(data, 0);
        data.writeString(perm);
        data.writeInt(userId);
        mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
        reply.readException();
        Intent intent = null;
        int haveIntent = reply.readInt();
        if (haveIntent != 0) {
            intent = Intent.CREATOR.createFromParcel(reply);
        }
        reply.recycle();
        data.recycle();
        return intent;
    }

這裡直接呼叫Binder驅動,說明這個過程在使用IPC通訊。所以真正的執行體轉移到遠端物件去了。這裡使用了代理模式,特徵命名ActivityManagerProxy。實際的實現者是在遠端的ActivityManagerService.
ActivityManagerService.registerReceiver:

 public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
            ...
             ReceiverList rl
                = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
            if (rl == null) {
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                if (rl.app != null) {
                    rl.app.receivers.add(rl);
                } else {
                    try {
                        receiver.asBinder().linkToDeath(rl, 0);
                    } catch (RemoteException e) {
                        return sticky;
                    }
                    rl.linkedToDeath = true;
                }
                mRegisteredReceivers.put(receiver.asBinder(), rl);
                ...
                 BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId);
            rl.add(bf);
            if (!bf.debugCheck()) {
                Slog.w(TAG, "==> For Dynamic broadast");
            }
            mReceiverResolver.addFilter(bf);
           // Enqueue broadcasts for all existing stickies that match
            // this filter.
            if (allSticky != null) {
                ArrayList receivers = new ArrayList();
                receivers.add(bf);

                int N = allSticky.size();
                for (int i=0; i<N; i++) {
                    Intent intent = (Intent)allSticky.get(i);
                    BroadcastQueue queue = broadcastQueueForIntent(intent);
                    BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                            null, -1, -1, null, null, AppOpsManager.OP_NONE, receivers, null, 0,
                            null, null, false, true, true, -1);
                    queue.enqueueParallelBroadcastLocked(r);
                    queue.scheduleBroadcastsLocked();
                }
            }

mRegisteredReceivers.put(receiver.asBinder(), rl);將receiver記錄下來,
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId);
rl.add(bf);
這裡將filter與receiver關聯在了一起,然後記錄下來:
mReceiverResolver.addFilter(bf);

到這裡,整個註冊過程完成。註冊的資訊由客戶端呼叫最終被ActivityManagerService記錄在兩個成員變數mReceiverResolver和mRegisteredReceivers中。