android--廣播接收者BroadcastReceiver的註冊過程

前面文章《android--監聽SMS》中簡單實現了接受短信信息的功能,下面棘突分析一下源碼是怎麼實現的。 java

廣播接收者的註冊分爲靜態註冊和動態註冊,在AndroidManifest.xml中配置的屬於靜態註冊,而動態註冊須要調用context中的registerReceiver方法進行註冊。 android

此次咱們對動態註冊進行分析 app


一、代碼以下: ide


IntentFilter counterActionFilter = new IntentFilter(CounterService.BROADCAST_COUNTER_ACTION);
		registerReceiver(counterActionReceiver, counterActionFilter);


註釋: this

(1)、IntentFilter 顧名思義,IntentFilter對象負責過濾掉組件沒法響應和處理的Intent,只將本身關心的Intent接收進來進行處理。 IntentFilter實行「白名單」管理,即只列出組件樂意接受的Intent,但IntentFilter只會過濾隱式Intent,顯式的Intent會直接傳送到目標組件。 Android組件能夠有一個或多個IntentFilter,每一個IntentFilter之間相互獨立,只須要其中一個驗證經過則可。 spa


建立IntentFilter對象的源碼: debug

public class IntentFilter implements Parcelable {

private int mPriority;
private final ArrayList<String> mActions;

public IntentFilter(String action) {
        mPriority = 0;
        mActions = new ArrayList<String>();
        addAction(action);
}
。。。
}

把CounterService.BROADCAST_COUNTER_ACTION字符串放到了mActions中。 代理


2、registerReceiver的源碼: code


public class ContextWrapper extends Context {
    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
}

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

mBase是ContextImpl對象。 xml

三、mBase.registerReceiver(receiver, filter)的源碼:

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) {
            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(),
                    rd, filter, broadcastPermission);
        } catch (RemoteException e) {
            return null;
        }
}

。。。
}

註釋:

(1)經過getReceiverDispatcher()將廣播接收者封裝成實現IintentReceiver接口的binder本地對象rd

3.1 mPackageInfo.getReceiverDispatcher()的源碼:

public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
            Context context, Handler handler,
            Instrumentation instrumentation, boolean registered) {
        synchronized (mReceivers) {
            LoadedApk.ReceiverDispatcher rd = null;
            HashMap<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 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                        mReceivers.put(context, map);
                    }
                    map.put(r, rd);
                }
            } else {
                rd.validate(context, handler);
            }
            return rd.getIIntentReceiver();
        }
    }

3.2 new ReceiverDispatcher 的源碼:

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;
            }
}

final IIntentReceiver.Stub mIIntentReceiver;
final BroadcastReceiver mReceiver;
final Context mContext;
final Handler mActivityThread;
final Instrumentation mInstrumentation;
final boolean mRegistered;

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;
        }

mReceiver表示廣播接受者

mContext表示activity組件,也就是這個廣播接受者在哪個activity中註冊的。

mActivityThread表示與activity相關的handle

mIIntentReceiver指向了建立的ReceiverDispatcher對象。

(2)ActivityManagerNative. getDefault()得到是ActivityManagerProxy對象


總結:activity組件在註冊一個廣播接收者時,並非真的將廣播接收者註冊到ActivityManagerService中,而是將與它相關聯的IntentReceiver對象註冊到ActivityManagerService中,當ActivityManagerService接受到一個廣播的時候,他就會根據廣播的類型在內部找到對應的IntentReceiver對象,而後再經過他找到廣播接收者。

四、ActivityManagerProxy中怎麼實現的registerReceiver方法 ,源碼:


public Intent registerReceiver(IApplicationThread caller,
            IIntentReceiver receiver,
            IntentFilter filter, String perm) throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
        filter.writeToParcel(data, 0);
        data.writeString(perm);
        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代理對象mRemote向ActivityManagerService發送一個類型爲REGISTER_RECEIVER_TRANSACTION的進程間通訊請求。

五、ActivityManagerService中的源碼:


public final class ActivityManagerService extends ActivityManagerNative
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

public Intent registerReceiver(IApplicationThread caller,
            IIntentReceiver receiver, IntentFilter filter, String permission) {
        synchronized(this) {
            ProcessRecord callerApp = null;
            if (caller != null) {
                callerApp = getRecordForAppLocked(caller);
                if (callerApp == null) {
                    throw new SecurityException(
                            "Unable to find app for caller " + caller
                            + " (pid=" + Binder.getCallingPid()
                            + ") when registering receiver " + receiver);
                }
            }

            List allSticky = null;

            // Look for any matching sticky broadcasts...
            Iterator actions = filter.actionsIterator();
            if (actions != null) {
                while (actions.hasNext()) {
                    String action = (String)actions.next();
                    allSticky = getStickiesLocked(action, filter, allSticky);
                }
            } else {
                allSticky = getStickiesLocked(null, filter, allSticky);
            }

            // The first sticky in the list is returned directly back to
            // the client.
            Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;

            if (DEBUG_BROADCAST) Slog.v(TAG, "Register receiver " + filter
                    + ": " + sticky);

            if (receiver == null) {
                return sticky;
            }

            ReceiverList rl
                = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
            if (rl == null) {
                rl = new ReceiverList(this, callerApp,
                        Binder.getCallingPid(),
                        Binder.getCallingUid(), 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, permission);
            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);
                    BroadcastRecord r = new BroadcastRecord(intent, null,
                            null, -1, -1, null, receivers, null, 0, null, null,
                            false, true, true);
                    if (mParallelBroadcasts.size() == 0) {
                        scheduleBroadcastsLocked();
                    }

                    mParallelBroadcasts.add(r);
                }
            }

            return sticky;
        }
    }

。。。
}

註釋:

建立一個BroadcastFilter,用來描述正在註冊的廣播接收者。廣播註冊到這就分析完了。

相關文章
相關標籤/搜索