Android廣播的源碼解析

最近打算把Android基礎的一些知識再深入一點,所以就打算從四大組件開始入手,廣播是經常使用的,但是也僅僅只停留在會用,卻不知其原理,就着這個機會把源碼給擼一遍吧。

public class MainActivity extends Activity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        registerReceiver(broadcastReceiver, new IntentFilter("broadcast_test"));
        sendBroadcast(new Intent("broadcast_test"));
    }

    BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if(intent.getAction().equals("broadcast_test")){
                Log.d("broadcast","receice");
            }
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(broadcastReceiver);
    }
}

本文不打算講解廣播的使用方法,就直接從動態註冊廣播開始好了,涉及到的源碼爲Android API 23。

上面demo中的registerReceiver(broadcastReceiver, new IntentFilter("broadcast_test"))執行的是ContextWrapper的方法:

@Override
public Intent registerReceiver(
    BroadcastReceiver receiver, IntentFilter filter) {
    return mBase.registerReceiver(receiver, filter);
}
ContextWrapper的真正方法實現類爲ContextImpl,也就是說mBase是ContextImpl的實例,對於這一塊不是很瞭解的朋友可以看郭霖大神的這篇博客Android Context完全解析,你所不知道的Context的各種細節,由於這部分源碼很多加了/** {@hide} */的註釋,所以在Android Studio裏面不能直接看到相關代碼,我們要到SDK的路徑\sdk\sources\android-23\android\app\下去查看相關代碼。

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

    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();//獲取主線程的Handler
                }
                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的實例對象,mMainThread是ActivityThread的實例對象,IIntentReceiver是有一個接口,其對象rd是一個實現了Binder對象(我沒有找到IIntentReceiver的源碼,是查閱相關資料才知道的)。


public final class LoadedApk {

    /*省略其它代碼*/

    private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
            = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();

    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();//最終返回一個Binder對象
        }
    }

    static final class ReceiverDispatcher {

        final static class InnerReceiver extends IIntentReceiver.Stub {
            /*省略其它代碼*/
        }

        final IIntentReceiver.Stub mIIntentReceiver;

        ReceiverDispatcher(BroadcastReceiver receiver, Context context,
                           Handler activityThread, Instrumentation instrumentation,
                           boolean registered) {
            /*省略其它代碼*/
            mIIntentReceiver = new InnerReceiver(this, !registered);
        }

        IIntentReceiver getIIntentReceiver() {
            return mIIntentReceiver;
        }
    }

}
從LoadedApk的getReceiverDispatcher方法我們可以知道幾點:

1、每一個註冊的廣播接收器都有對應的ReceiverDispatcher(即Binder對象)。

2、廣播接收器和ReceiverDispatcher以鍵值對的形式存在map中。

3、存儲廣播接收器和ReceiverDispatcher的map與context也以鍵值對的形式存儲在map中。

那麼有一個問題來了,LoadedApk到底有什麼用?它的註釋文檔就一句話“Local state maintained about a currently loaded .apk.”,大概意思就是當前加載的APK在內存中的狀態,如果查看代碼還會發現,它存儲的還有Service等。

這時候該走到ContextWrapper.registerReceiverInternal的try-catch代碼塊了,在try中ActivityManagerNative.getDefault()方法返回一個ActivityManagerProxy對象,ActivityManagerProxy相關代碼:

class ActivityManagerProxy implements IActivityManager {
    
    /*省略其它代碼*/
    
    public ActivityManagerProxy(IBinder remote) {
        mRemote = remote;
    }

    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);
        //此處與ActivityServiceManager通信
        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;
    }
}
關鍵代碼mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);涉及到的進程間通信不是今天的內容,真要說我也說不清,我們就不深究了,只要知道它的作用就是調用了ActivityManagerService的註冊方法。ActivityManagerService的代碼就不貼了,簡單來說它的註冊方法就是以調用方法的App的進程ID爲唯一標識,生成一個ReceiverList存放所有註冊的廣播接收器。至此,就完成了廣播接收器的註冊過程,也就是說所有app的廣播接收器都會存在ActivityManagerService中。

接下來就是廣播的發送了,同樣sendBroadcast(new Intent("broadcast_test"))方法的真正實現也是在ContextImpl中

class ContextImpl extends Context {
    
    /*省略其它代碼*/
    
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess();
            ActivityManagerNative.getDefault().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                    getUserId());
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
    }
}
ActivityManagerNative.getDefault()是不是很熟悉呢,沒錯,和註冊一樣都是調用了ActivityManagerProxy的方法

class ActivityManagerProxy implements IActivityManager {

    /*省略其它代碼*/

    public int broadcastIntent(IApplicationThread caller,
                               Intent intent, String resolvedType, IIntentReceiver resultTo,
                               int resultCode, String resultData, Bundle map,
                               String[] requiredPermissions, int appOp, Bundle options, boolean serialized,
                               boolean sticky, int userId) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo != null ? resultTo.asBinder() : null);
        data.writeInt(resultCode);
        data.writeString(resultData);
        data.writeBundle(map);
        data.writeStringArray(requiredPermissions);
        data.writeInt(appOp);
        data.writeBundle(options);
        data.writeInt(serialized ? 1 : 0);
        data.writeInt(sticky ? 1 : 0);
        data.writeInt(userId);
        //此處與ActivityServiceManager通信
        mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);
        reply.readException();
        int res = reply.readInt();
        reply.recycle();
        data.recycle();
        return res;
    }
}
不一樣的方法,還是熟悉的味道。發送廣播也是調用的ActivityManagerService的方法,具體代碼也不貼了(主要是我沒有在6.0的源碼裏找到這個類)。ActivityManagerService在發送的過程中的工作就是根據發送的廣播的Action找到相應的廣播接收器(手機上所有註冊的廣播接收器都在這裏存着了,找一個還不容易嘛)。ActivityManagerService內部有一個Handler會循環處理髮送的廣播,處理的過程就是利用Binder機制將廣播分發給相應的廣播接收器的ReceiverDispatcher

static final class ReceiverDispatcher {

    /*省略其它代碼*/

    final static class InnerReceiver extends IIntentReceiver.Stub {

        final class Args extends BroadcastReceiver.PendingResult implements Runnable {

            public void run() {
                try {
                    ClassLoader cl = mReceiver.getClass().getClassLoader();
                    intent.setExtrasClassLoader(cl);
                    setExtrasClassLoader(cl);
                    receiver.setPendingResult(this);
                    receiver.onReceive(mContext, intent);
                } catch (Exception e) {

                }

            }
        }
    }

}
ReceiverDispatcher實現了Runnable接口,最終會回調到相應BroadcastReceiver的onReceive方法。那麼會在哪個線程中處理這個任務呢,還記得註冊廣播時的scheduler嗎,就是在這個裏面被post進去的。這樣一來,整個廣播的註冊和發送接收事件就完成了。

我這裏只是大致梳理了最基礎的廣播使用過程,沒有對細節深入,仔細探索的話還有粘性廣播的處理、廣播優先級的處理、廣播註銷的處理等等,那我就不再多囉嗦啦。(再囉嗦一句,廣播的這種訂閱--發佈過程就是觀察者模式的體現)







參考資料  《Android源碼設計模式解析與實踐》

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