当前位置: 代码迷 >> Android >> Android播音机制剖析【android广播系列一】
  详细解决方案

Android播音机制剖析【android广播系列一】

热度:60   发布时间:2016-04-28 01:14:30.0
Android广播机制剖析【android广播系列一】

广播是android四大组件之一,所以广播的重要性也是显而易见的,最近需要做个功能,需要对广播的机制深入了解,所以我就整理下思路。平时我们写代码的时候,广播只是用来通知机制的,不是用来通信机制,通信机制还是要用binder机制来实现。但是现在市场上的第三方app大部分都是滥用广播,用广播来监听一些事件来实现自启动或者后台启动。这就误解了谷歌的意思。本来很好的组件,被大家滥用,导致用户老是感觉手机的程序控制不住,老是后台偷偷启动。小白用户甚至更不理解了。好了现在言归正传。
android广播按发送方式分为三种:

  • 无序广播
  • 有序广播 :OrderedBroadcast
  • 粘连广播 :StickyBroadcast

广播按照注册方式分为两种:

  • 静态广播
  • 动态广播

    摘录老罗文章“广播机制是一种基于消息发布和订阅的事件驱动模型,即广播发送者负责发布消息,而广播接收者需要先订阅消息,然后才能接收到消息。在广播机制中,广播发送者事先不需要知道广播接收者的存在的,这样就能大大降低广播发送者和广播接收者之间的耦合度,进而提高系统的可扩展性和可维护性。”
    广播的正真机制就两种情况,注册广播的机制,和接收广播的机制,我们先来谈谈注册广播的流程。
    注册广播的流程:分为动态注册和静态注册两种;
    (1)先来说说动态注册广播
    Step1:说明: ReceiverDispatcher是frameworks/base/core/java/android/app/LoadedApk.java的内部类,这个类是保存广播接收者的组件(Activity或者Service),负责将这个被注册的广播接收者和注册它的组件关联在一起。

    static final class ReceiverDispatcher {    final static class InnerReceiver extends IIntentReceiver.Stub {        . . . . . .        . . . . . .    }    // 请注意这个域!它就是传到外面的rd。    final IIntentReceiver.Stub mIIntentReceiver;       final BroadcastReceiver mReceiver;    final Context mContext;    final Handler mActivityThread;    final Instrumentation mInstrumentation;    final boolean mRegistered;    final IntentReceiverLeaked mLocation;    RuntimeException mUnregisterLocation;    boolean mForgotten;    . . . . . .

Step2:好了先说说需要了解的知识。registerReceiver(),是通过context来注册的,调用过程最后调用到ContextImpl这个对象中,

@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter)  {        return registerReceiver(receiver, filter, null, null);}@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) {       return registerReceiverInternal(receiver, filter, broadcastPermission,  scheduler, getOuterContext());}

Step3:我们接着来看看registerReceiverInternal()这个方法:

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();            }            // 查找和context对应的“子哈希表”里的ReceiverDispatcher,//如果找不到,就重新new一个            rd = mPackageInfo.getReceiverDispatcher(receiver, context, scheduler,                                                    mMainThread.getInstrumentation(), true);        } else {            if (scheduler == null)  {                scheduler = mMainThread.getHandler();            }            rd = new LoadedApk.ReceiverDispatcher(..., ...);        }        . . . . . .    }        try  {                return ActivityManagerNative.getDefault().registerReceiver(                mMainThread.getApplicationThread(), mBasePackageName,                rd, filter, broadcastPermission);    }  catch (RemoteException e)  {                return null;    }}

Step4:大家注意那个rd对象(IIntentReceiver rd),首先调用成员变量mPackageInfo的成员函数(是LoadedApk的一个对象)getReceiverDispatcher()将广播接收者receiver封装成一个实现了IIntentReceiver接口的Binder的本地对象rd,最后将这个对象发送给AcitivityManagerService。
接着来看看getReceiverDispatcher()这个方法:

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;            //来获得一个实现了IIntentReceiver接口的Binder的本地对象            return rd.getIIntentReceiver();        }    }IIntentReceiver getIIntentReceiver() {            return mIIntentReceiver;        }

Step5:接着来看看给mIIntentReceiver赋值的地方,

static final class ReceiverDispatcher {        final static class InnerReceiver extends IIntentReceiver.Stub {            final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;            final LoadedApk.ReceiverDispatcher mStrongRef; 。。。 。。。}ReceiverDispatcher(BroadcastReceiver receiver, Context context,                Handler activityThread, Instrumentation instrumentation,                boolean registered) {            if (activityThread == null) {                throw new NullPointerException("Handler must not be null");            }        //指向了一个实现IIntentReceiver接口的Binder的本地对象            mIIntentReceiver = new InnerReceiver(this, !registered);            mReceiver = receiver;            mContext = context;            mActivityThread = activityThread;            mInstrumentation = instrumentation;            mRegistered = registered;            mLocation = new IntentReceiverLeaked(null);            mLocation.fillInStackTrace();        }}

Step6:注意:这个InnerReceiver对象内部有一个类型为ReceiverDispatcher的弱引用mDispatcher,它指向一个外部的ReceiverDispatcher对象。
接着就注册到AMS中去了。代码如下:

public Intent registerReceiver(IApplicationThread caller, String callerPackage,            IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {        enforceNotIsolatedCaller("registerReceiver");        int callingUid;        int callingPid;        synchronized(this) {            ProcessRecord callerApp = null;            if (caller != null) {//得到调用者的ProcessRecord                callerApp = getRecordForAppLocked(caller);                if (callerApp == null) {                    throw new SecurityException(                            "Unable to find app for caller " + caller                            + " (pid=" + Binder.getCallingPid()                            + ") when registering receiver " + receiver);                }                if (callerApp.info.uid != Process.SYSTEM_UID &&                        !callerApp.pkgList.containsKey(callerPackage) &&                        !"android".equals(callerPackage)) {                    throw new SecurityException("Given caller package " + callerPackage                            + " is not running in process " + callerApp);                }                callingUid = callerApp.info.uid;                callingPid = callerApp.pid;            } else {                callerPackage = null;                callingUid = Binder.getCallingUid();                callingPid = Binder.getCallingPid();            }            userId = this.handleIncomingUser(callingPid, callingUid, userId,                    true, ALLOW_FULL_ONLY, "registerReceiver", callerPackage);            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,                            UserHandle.USER_ALL);                    allSticky = getStickiesLocked(action, filter, allSticky,                            UserHandle.getUserId(callingUid));                }            } else {                allSticky = getStickiesLocked(null, filter, allSticky,                        UserHandle.USER_ALL);                allSticky = getStickiesLocked(null, filter, allSticky,                        UserHandle.getUserId(callingUid));            }            // The first sticky in the list is returned directly back to            // the client.//判断黏性广播是否为null            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一个                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;                }                //把ReceiverList加入到mRegisteredReceivers                mRegisteredReceivers.put(receiver.asBinder(), rl);            } else if (rl.uid != callingUid) {                throw new IllegalArgumentException(                        "Receiver requested to register for uid " + callingUid                        + " was previously registered for uid " + rl.uid);            } else if (rl.pid != callingPid) {                throw new IllegalArgumentException(                        "Receiver requested to register for pid " + callingPid                        + " was previously registered for pid " + rl.pid);            } else if (rl.userId != userId) {                throw new IllegalArgumentException(                        "Receiver requested to register for user " + userId                        + " was previously registered for user " + rl.userId);            }            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();                }            }            return sticky;        }    }

好了今天就到这里吧,后续再整理。。。

(2)上面说的是动态注册广播的过程,接着我来谈谈静态注册广播的过程。
静态注册广播的信息会在手机启动时,由PackageManagerService(PMS)解析并记录下来,准备好数据。当AMS调用PMS的接口来查询“和intent匹配的组件”时,PMS内部就会去查询当初记录下来的数据,并把结果返回AMS。有的同学认为静态receiver是常驻内存的,这种说法并不准确。因为常驻内存的只是静态receiver的描述性信息,并不是receiver实体本身。
举个栗子:

List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()                        .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user);

具体的queryIntentReceivers的实现就要参考PackageManagerService.java
在这个类中的实现,这里就不阐述这么多了。

  相关解决方案