您的位置:首页 > 数据 >
天天百事通!在Android系统中为什么需要广播机制?
来源:CSDN 2023-01-09 09:15:35

在Android系统中,广播(Broadcast)是在组件之间传播数据(Intent)的一种机制;这些组件甚至是可以位于不同的进程中,这样它就像Binder机制一样,起到进程间通信的作用。

在Android系统中,为什么需要广播机制呢?如果是两个组件位于不同的进程当中,那么可以用Binder机制来实现,如果两个组件是在同一个进程中,那么它们之间可以用来通信的方式就更多了,这样看来,广播机制似乎是多余的。

然而,广播机制却是不可替代的,它和Binder机制不一样的地方在于,广播的发送者和接收者事先是不需要知道对方的存在的,这样带来的好处便是,系统的各个组件可以松耦合地组织在一起,这样系统就具有高度的可扩展性,容易与其它系统进行集成。


(资料图片)

使用广播的两个步骤: 1、广播的接收者需要通过调用registerReceiver函数告诉系统,它对什么样的广播有兴趣,即指定IntentFilter,并且向系统注册广播接收器,即指定BroadcastReceiver:

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

这里,指定感兴趣的广播就是CounterService.BROADCAST_COUNTER_ACTION了,而指定的广播接收器就是counterActonReceiver,它是一个BroadcastReceiver类型的实例。

2、广播的发送者通过调用sendBroadcast函数来发送一个指定的广播,并且可以指定广播的相关参数:

Intent intent = new Intent(BROADCAST_COUNTER_ACTION);  intent.putExtra(COUNTER_VALUE, counter);  sendBroadcast(intent)

这里,指定的广播为CounterService.BROADCAST_COUNTER_ACTION,并且附带的带参数当前的计数器值counter。调用了sendBroadcast函数之后,所有注册了CounterService.BROADCAST_COUNTER_ACTION广播的接收者便可以收到这个广播了。

在第1步中,广播的接收者把广播接收器注册到ActivityManagerService中;在第2步中,广播的发送者同样是把广播发送到ActivityManagerService中,由ActivityManagerService去查找注册了这个广播的接收者,然后把广播分发给它们。

在第2步的分发的过程,其实就是把这个广播转换成一个消息,然后放入到接收器所在的线程消息队列中去,最后就可以在消息循环中调用接收器的onReceive函数了。这里有一个要非常注意的地方是,由于ActivityManagerService把这个广播放进接收器所在的线程消息队列后,就返回了,它不关心这个消息什么时候会被处理,因此,对广播的处理是异步的,即调用sendBroadcast时,这个函数不会等待这个广播被处理完后才返回。

虚线上面Step 1到Step 4步是注册广播接收器的过程,其中Step 2通过LoadedApk.getReceiverDispatcher在LoadedApk内部创建了一个IIntentReceiver接口,并且传递给ActivityManagerService;

虚线下面的Step 5到Step 11是发送广播的过程,在Step 8中,ActivityManagerService利用上面得到的IIntentReceiver远程接口,调用LoadedApk.performReceiver接口,LoadedApk.performReceiver接口通过ActivityThread.H接口的post函数将这个广播消息放入到ActivityThread的消息队列中去,最后这个消息在LoadedApk的Args.run函数中处理,LoadedApk.Args.run函数接着调用MainActivity.BroadcastReceiver的onReceive函数来最终处理这个广播。

注册广播接收器(registerReceiver)

在Android的广播机制中,ActivityManagerService扮演着广播中心的角色,负责系统中所有广播的注册和发布操作,因此,Android应用程序注册广播接收器的过程就把是广播接收器注册到ActivityManagerService的过程。Android应用程序是通过调用ContextWrapper类的registerReceiver函数来把广播接收器BroadcastReceiver注册到ActivityManagerService中去的,而ContextWrapper类本身又借助ContextImpl类来注册广播接收器。

在Android应用程序框架中,Activity和Service类都继承了ContextWrapper类,因此,我们可以在Activity或者Service的子类中调用registerReceiver函数来注册广播接收器。

我们先来看一下MainActivity是如何调用registerReceiver函数来注册广播接收器的:

public class MainActivity extends Activity implements OnClickListener {......        @Override         public void onResume() {super.onResume();              IntentFilter counterActionFilter = new IntentFilter(CounterService.BROADCAST_COUNTER_ACTION);            registerReceiver(counterActionReceiver, counterActionFilter);        }         ......    }

Step 1. ContextWrapper.registerReceiver

public class ContextWrapper extends Context {Context mBase;      ......        @Override      public Intent registerReceiver(          BroadcastReceiver receiver, IntentFilter filter) {return mBase.registerReceiver(receiver, filter);      }        ......    }

这里的成员变量mBase是一个ContextImpl实例。

Step 2. ContextImpl.registerReceiver

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 {......              }          }          try {return ActivityManagerNative.getDefault().registerReceiver(                      mMainThread.getApplicationThread(),                      rd, filter, broadcastPermission);          } catch (RemoteException e) {return null;          }      }        ......    }

通过两个函数的中转,最终就进入到ContextImpl.registerReceiverInternal这个函数来了。这里的成员变量mPackageInfo是一个LoadedApk实例,它是用来负责处理广播的接收的。

参数broadcastPermission和scheduler都为null,而参数context是上面的函数通过调用函数getOuterContext得到的,这里它就是指向MainActivity了,因为MainActivity是继承于Context类的,因此,这里用Context类型来引用。

由于条件mPackageInfo != null和context != null都成立,而且条件scheduler == null也成立,于是就调用mMainThread.getHandler来获得一个Handler了,这个Hanlder是后面用来分发ActivityManagerService发送过的广播用的。这里的成员变量mMainThread是一个ActivityThread实例。

Step 3. ActivityThread.getHandler

public final class ActivityThread {......        final H mH = new H();        private final class H extends Handler {......            public void handleMessage(Message msg) {......                switch (msg.what) {......              }                ......          }            ......        }        ......        final Handler getHandler() {return mH;      }        ......    }

有了这个Handler之后,就可以分发消息给应用程序处理了。

再回到上一步的ContextImpl.registerReceiverInternal函数中,它通过mPackageInfo.getReceiverDispatcher函数获得一个IIntentReceiver接口对象rd,这是一个Binder对象,接下来会把它传给ActivityManagerService,ActivityManagerService在收到相应的广播时,就是通过这个Binder对象来通知MainActivity来接收的。

Step 4. LoadedApk.getReceiverDispatcher

final class LoadedApk {......        public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,              Context context, Handler handler,              Instrumentation instrumentation, boolean registered) {synchronized (mReceivers) {LoadedApk.ReceiverDispatcher rd = null;              HashMapmap = 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();                          mReceivers.put(context, map);                      }                      map.put(r, rd);                  }              } else {rd.validate(context, handler);              }              return rd.getIIntentReceiver();          }      }        ......        static final class ReceiverDispatcher {final static class InnerReceiver extends IIntentReceiver.Stub {final WeakReferencemDispatcher;              ......                InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {mDispatcher = new WeakReference(rd);                  ......              }                ......          }            ......            final IIntentReceiver.Stub mIIntentReceiver;          final Handler mActivityThread;            ......            ReceiverDispatcher(BroadcastReceiver receiver, Context context,                  Handler activityThread, Instrumentation instrumentation,                  boolean registered) {......                mIIntentReceiver = new InnerReceiver(this, !registered);              mActivityThread = activityThread;                            ......          }            ......            IIntentReceiver getIIntentReceiver() {return mIIntentReceiver;          }        }        ......    }

在LoadedApk.getReceiverDispatcher函数中,首先看一下参数r是不是已经有相应的ReceiverDispatcher存在了,如果有,就直接返回了,否则就新建一个ReceiverDispatcher,并且以r为Key值保在一个HashMap中,而这个HashMap以Context,这里即为MainActivity为Key值保存在LoadedApk的成员变量mReceivers中,这样,只要给定一个Activity和BroadcastReceiver,就可以查看LoadedApk里面是否已经存在相应的广播接收发布器ReceiverDispatcher了。

在新建广播接收发布器ReceiverDispatcher时,会在构造函数里面创建一个InnerReceiver实例,这是一个Binder对象,实现了IIntentReceiver接口,可以通过ReceiverDispatcher.getIIntentReceiver函数来获得,获得后就会把它传给ActivityManagerService,以便接收广播。

在ReceiverDispatcher类的构造函数中,还会把传进来的Handle类型的参数activityThread保存下来,以便后面在分发广播的时候使用。

现在,再回到ContextImpl.registerReceiverInternal函数,在获得了IIntentReceiver类型的Binder对象后,就开始要把它注册到ActivityManagerService中去了。

Step 5. ActivityManagerProxy.registerReceiver

class ActivityManagerProxy implements IActivityManager  {......        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驱动程序就进入到ActivityManagerService中的registerReceiver函数中去了。

Step 6. ActivityManagerService.registerReceiver

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) {......                  }              }                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 {......              }                // The first sticky in the list is returned directly back to              // the client.              Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;                ......                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 {......                  }                  mRegisteredReceivers.put(receiver.asBinder(), rl);              }                BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);              rl.add(bf);              ......              mReceiverResolver.addFilter(bf);                // Enqueue broadcasts for all existing stickies that match              // this filter.              if (allSticky != null) {......              }                return sticky;          }      }        ......    }

函数首先是获得调用registerReceiver函数的应用程序进程记录块:

ProcessRecord callerApp = null;     if (caller != null) {callerApp = getRecordForAppLocked(caller);  if (callerApp == null) {......         }     }

这里得到的便是应用程序Broadcast的进程记录块了,MainActivity就是在里面启动起来的。

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 {......     }       // The first sticky in the list is returned directly back to     // the client.     Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;

这里传进来的filter只有一个action,就是前面描述的CounterService.BROADCAST_COUNTER_ACTION了,这里先通过getStickiesLocked函数查找一下有没有对应的sticky intent列表存在。什么是Sticky Intent呢?我们在最后一次调用sendStickyBroadcast函数来发送某个Action类型的广播时,系统会把代表这个广播的Intent保存下来,这样,后来调用registerReceiver来注册相同Action类型的广播接收器,就会得到这个最后发出的广播。这就是为什么叫做Sticky Intent了,这个最后发出的广播虽然被处理完了,但是仍然被粘住在ActivityManagerService中,以便下一个注册相应Action类型的广播接收器还能继承处理。

这里,假设我们不使用sendStickyBroadcast来发送CounterService.BROADCAST_COUNTER_ACTION类型的广播,于是,这里得到的allSticky和sticky都为null了。

继续往下看,这里传进来的receiver不为null,于是,继续往下执行:

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 {......  }  mRegisteredReceivers.put(receiver.asBinder(), rl);     }

这里其实就是把广播接收器receiver保存一个ReceiverList列表中,这个列表的宿主进程是rl.app,这里就是MainActivity所在的进程了,在ActivityManagerService中,用一个进程记录块来表示这个应用程序进程,它里面有一个列表receivers,专门用来保存这个进程注册的广播接收器。接着,又把这个ReceiverList列表以receiver为Key值保存在ActivityManagerService的成员变量mRegisteredReceivers中,这些都是为了方便在收到广播时,快速找到对应的广播接收器的。

再往下看:

BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);  rl.add(bf);  ......  mReceiverResolver.addFilter(bf);

上面只是把广播接收器receiver保存起来了,但是还没有把它和filter关联起来,这里就创建一个BroadcastFilter来把广播接收器列表rl和filter关联起来,然后保存在ActivityManagerService中的成员变量mReceiverResolver中去。

发送广播(sendBroadcast)的过程分析

前面我们分析了Android应用程序注册广播接收器的过程,这个过程只完成了万里长征的第一步,接下来它还要等待ActivityManagerService将广播分发过来。

广播的发送过程比广播接收器的注册过程要复杂得多了,不过这个过程仍然是以ActivityManagerService为中心。广播的发送者将广播发送到ActivityManagerService,ActivityManagerService接收到这个广播以后,就会在自己的注册中心查看有哪些广播接收器订阅了该广播,然后把这个广播逐一发送到这些广播接收器中,但是ActivityManagerService并不等待广播接收器处理这些广播就返回了,因此,广播的发送和处理是异步的。

在分析广播的发送过程前,我们先来看一下广播发送过程的序列图,然后按照这个序图中的步骤来一步一步分析整个过程。

Step 1. ContextWrapper.sendBroadcast

public class ContextWrapper extends Context {Context mBase;        ......        @Override      public void sendBroadcast(Intent intent) {mBase.sendBroadcast(intent);      }        ......    }

Step 2. ContextImpl.sendBroadcast

class ContextImpl extends Context {......        @Override      public void sendBroadcast(Intent intent) {String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());          try {ActivityManagerNative.getDefault().broadcastIntent(                  mMainThread.getApplicationThread(), intent, resolvedType, null,                  Activity.RESULT_OK, null, null, null, false, false);          } catch (RemoteException e) {}      }        ......    }

这里的resolvedType表示这个Intent的MIME类型,我们没有设置这个Intent的MIME类型,因此,这里的resolvedType为null。接下来就调用ActivityManagerService的远程接口ActivityManagerProxy把这个广播发送给ActivityManagerService了。

Step 3. ActivityManagerProxy.broadcastIntent

class ActivityManagerProxy implements IActivityManager  {......        public int broadcastIntent(IApplicationThread caller,          Intent intent, String resolvedType,  IIntentReceiver resultTo,          int resultCode, String resultData, Bundle map,          String requiredPermission, boolean serialized,          boolean sticky) 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.writeString(requiredPermission);          data.writeInt(serialized ? 1 : 0);          data.writeInt(sticky ? 1 : 0);          mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);          reply.readException();          int res = reply.readInt();          reply.recycle();          data.recycle();          return res;      }        ......    }

Step 4. ActivityManagerService.broadcastIntent

public final class ActivityManagerService extends ActivityManagerNative          implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {......        public final int broadcastIntent(IApplicationThread caller,              Intent intent, String resolvedType, IIntentReceiver resultTo,              int resultCode, String resultData, Bundle map,              String requiredPermission, boolean serialized, boolean sticky) {synchronized(this) {intent = verifyBroadcastLocked(intent);                final ProcessRecord callerApp = getRecordForAppLocked(caller);              final int callingPid = Binder.getCallingPid();              final int callingUid = Binder.getCallingUid();              final long origId = Binder.clearCallingIdentity();              int res = broadcastIntentLocked(callerApp,                  callerApp != null ? callerApp.info.packageName : null,                  intent, resolvedType, resultTo,                  resultCode, resultData, map, requiredPermission, serialized,                  sticky, callingPid, callingUid);              Binder.restoreCallingIdentity(origId);              return res;          }      }        ......  }

这里调用broadcastIntentLocked函数来进一步处理。

Step 5. ActivityManagerService.broadcastIntentLocked

public final class ActivityManagerService extends ActivityManagerNative          implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {......        private final int broadcastIntentLocked(ProcessRecord callerApp,              String callerPackage, Intent intent, String resolvedType,              IIntentReceiver resultTo, int resultCode, String resultData,              Bundle map, String requiredPermission,              boolean ordered, boolean sticky, int callingPid, int callingUid) {intent = new Intent(intent);            ......            // Figure out who all will receive this broadcast.          List receivers = null;          ListregisteredReceivers = null;          try {if (intent.getComponent() != null) {......              } else {......                  registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);              }          } catch (RemoteException ex) {......          }            final boolean replacePending =              (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;            int NR = registeredReceivers != null ? registeredReceivers.size() : 0;          if (!ordered && NR > 0) {// If we are not serializing this broadcast, then send the              // registered receivers separately so they don"t wait for the              // components to be launched.              BroadcastRecord r = new BroadcastRecord(intent, callerApp,                  callerPackage, callingPid, callingUid, requiredPermission,                  registeredReceivers, resultTo, resultCode, resultData, map,                  ordered, sticky, false);              ......              boolean replaced = false;              if (replacePending) {for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {......                          mParallelBroadcasts.set(i, r);                          replaced = true;                          break;                      }                  }              }                if (!replaced) {mParallelBroadcasts.add(r);                    scheduleBroadcastsLocked();              }                registeredReceivers = null;              NR = 0;          }            ......        }        ......  }

这个函数首先是根据intent找出相应的广播接收器:

// Figure out who all will receive this broadcast.     List receivers = null;     ListregisteredReceivers = null;     try {if (intent.getComponent() != null) {......  } else {......      registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);  }     } catch (RemoteException ex) {......     }

回忆一下前面过程分析中的Step 6(ActivityManagerService.registerReceiver)中,我们将一个filter类型为BROADCAST_COUNTER_ACTION类型的BroadcastFilter实例保存在了ActivityManagerService的成员变量mReceiverResolver中,这个BroadcastFilter实例包含了我们所注册的广播接收器,这里就通过mReceiverResolver.queryIntent函数将这个BroadcastFilter实例取回来。由于注册一个广播类型的接收器可能有多个,所以这里把所有符合条件的的BroadcastFilter实例放在一个List中,然后返回来。在我们这个场景中,这个List就只有一个BroadcastFilter实例了,就是MainActivity注册的那个广播接收器。

继续往下看:

final boolean replacePending =  (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;

这里是查看一下这个intent的Intent.FLAG_RECEIVER_REPLACE_PENDING位有没有设置,如果设置了的话,ActivityManagerService就会在当前的系统中查看有没有相同的intent还未被处理,如果有的话,就有当前这个新的intent来替换旧的intent。这里,我们没有设置intent的Intent.FLAG_RECEIVER_REPLACE_PENDING位,因此,这里的replacePending变量为false。

再接着往下看:

int NR = registeredReceivers != null ? registeredReceivers.size() : 0;    if (!ordered && NR > 0) {// If we are not serializing this broadcast, then send the  // registered receivers separately so they don"t wait for the  // components to be launched.  BroadcastRecord r = new BroadcastRecord(intent, callerApp,      callerPackage, callingPid, callingUid, requiredPermission,      registeredReceivers, resultTo, resultCode, resultData, map,      ordered, sticky, false);  ......  boolean replaced = false;  if (replacePending) {for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {......              mParallelBroadcasts.set(i, r);              replaced = true;              break;          }      }  }    if (!replaced) {mParallelBroadcasts.add(r);        scheduleBroadcastsLocked();  }    registeredReceivers = null;  NR = 0;     }

前面我们说到,这里得到的列表registeredReceivers的大小为1,且传进来的参数ordered为false,表示要将这个广播发送给所有注册了BROADCAST_COUNTER_ACTION类型广播的接收器,因此,会执行下面的if语句。这个if语句首先创建一个广播记录块BroadcastRecord,里面记录了这个广播是由谁发出的以及要发给谁等相关信息。由于前面得到的replacePending变量为false,因此,不会执行接下来的if语句,即不会检查系统中是否有相同类型的未处理的广播。

这样,这里得到的replaced变量的值也为false,于是,就会把这个广播记录块r放在ActivityManagerService的成员变量mParcelBroadcasts中,等待进一步处理;进一步处理的操作由函数scheduleBroadcastsLocked进行。

Step 6. ActivityManagerService.scheduleBroadcastsLocked

public final class ActivityManagerService extends ActivityManagerNative          implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {......        private final void scheduleBroadcastsLocked() {......            if (mBroadcastsScheduled) {return;          }            mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);          mBroadcastsScheduled = true;      }        ......  }

这里的mBroadcastsScheduled表示ActivityManagerService当前是不是正在处理其它广播,如果是的话,这里就先不处理直接返回了,保证所有广播串行处理。

注意这里处理广播的方式,它是通过消息循环来处理,每当ActivityManagerService接收到一个广播时,它就把这个广播放进自己的消息队列去就完事了,根本不管这个广播后续是处理的,因此,这里我们可以看出广播的发送和处理是异步的。

这里的成员变量mHandler是一个在ActivityManagerService内部定义的Handler类变量,通过它的sendEmptyMessage函数把一个类型为BROADCAST_INTENT_MSG的空消息放进ActivityManagerService的消息队列中去。这里的空消息是指这个消息除了有类型信息之外,没有任何其它额外的信息,因为前面已经把要处理的广播信息都保存在mParcelBroadcasts中了,等处理这个消息时,从mParcelBroadcasts就可以读回相关的广播信息了,因此,这里不需要把广播信息再放在消息内容中。

Step 7. Handler.sendEmptyMessage

这个自定义的Handler类实现在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中,它是ActivityManagerService的内部类,调用了它的sendEmptyMessage函数来把一个消息放到消息队列后,一会就会调用它的handleMessage函数来真正处理这个消息:

public final class ActivityManagerService extends ActivityManagerNative          implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {......        final Handler mHandler = new Handler() {public void handleMessage(Message msg) {switch (msg.what) {......              case BROADCAST_INTENT_MSG: {......                  processNextBroadcast(true);              } break;              ......              }          }      }        ......  }

这里又调用了ActivityManagerService的processNextBroadcast函数来处理下一个未处理的广播。

Step 8. ActivityManagerService.processNextBroadcast

public final class ActivityManagerService extends ActivityManagerNative          implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {......        private final void processNextBroadcast(boolean fromMsg) {synchronized(this) {BroadcastRecord r;                ......                if (fromMsg) {mBroadcastsScheduled = false;              }                // First, deliver any non-serialized broadcasts right away.              while (mParallelBroadcasts.size() > 0) {r = mParallelBroadcasts.remove(0);                  ......                  final int N = r.receivers.size();                  ......                  for (int i=0; i<N; i++)="" {Object target = r.receivers.get(i);                      ......                        deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);                  }                  addBroadcastToHistoryLocked(r);                  ......              }                ......            }      }        ......  }这里传进来的参数fromMsg为true,于是把mBroadcastScheduled重新设为false,这样,下一个广播就能进入到消息队列中进行处理了。前面我们在Step 5中,把一个广播记录块BroadcastRecord放在了mParallelBroadcasts中,因此,这里就把它取出来进行处理了。广播记录块BroadcastRecord的receivers列表中包含了要接收这个广播的目标列表,即前面我们注册的广播接收器,用BroadcastFilter来表示,这里while循环中的for循环就是把这个广播发送给每一个订阅了该广播的接收器了,通过deliverToRegisteredReceiverLocked函数执行。Step 9. ActivityManagerService.deliverToRegisteredReceiverLockedpublic final class ActivityManagerService extends ActivityManagerNative          implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {......        private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,              BroadcastFilter filter, boolean ordered) {boolean skip = false;          if (filter.requiredPermission != null) {......          }          if (r.requiredPermission != null) {......          }            if (!skip) {// If this is not being sent as an ordered broadcast, then we              // don"t want to touch the fields that keep track of the current              // state of ordered broadcasts.              if (ordered) {......              }                try {......                  performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,                      new Intent(r.intent), r.resultCode,                      r.resultData, r.resultExtras, r.ordered, r.initialSticky);                  ......              } catch (RemoteException e) {......              }          }        }        ......  }

函数首先是检查一下广播发送和接收的权限,在我们分析的这个场景中,没有设置权限,因此,这个权限检查就跳过了,这里得到的skip为false,于是进入下面的if语句中。由于上面传时来的ordered参数为false,因此,直接就调用performReceiveLocked函数来进一步执行广播发送的操作了。

Step 10. ActivityManagerService.performReceiveLocked

public final class ActivityManagerService extends ActivityManagerNative          implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {......        static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,              Intent intent, int resultCode, String data, Bundle extras,              boolean ordered, boolean sticky) throws RemoteException {// Send the intent to the receiver asynchronously using one-way binder calls.          if (app != null && app.thread != null) {// If we have an app thread, do the call through that so it is              // correctly ordered with other one-way calls.              app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,                      data, extras, ordered, sticky);          } else {......          }      }        ......  }

注意,这里传进来的参数app是注册广播接收器的Activity所在的进程记录块,在我们分析的这个场景中,由于是MainActivity调用registerReceiver函数来注册这个广播接收器的,因此,参数app所代表的ProcessRecord就是MainActivity所在的进程记录块了;

而参数receiver也是注册广播接收器时传给ActivityManagerService的一个Binder对象,它的类型是IIntentReceiver。

MainActivity在注册广播接收器时,已经把自己的ProcessRecord记录下来了,所以这里的参数app和app.thread均不为null,于是,ActivityManagerService就调用app.thread.scheduleRegisteredReceiver函数来把这个广播分发给MainActivity了。这里的app.thread是一个Binder远程对象,它的类型是ApplicationThreadProxy。

Step 11. ApplicationThreadProxy.scheduleRegisteredReceiver

class ApplicationThreadProxy implements IApplicationThread {......        public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,              int resultCode, String dataStr, Bundle extras, boolean ordered, boolean sticky)              throws RemoteException {Parcel data = Parcel.obtain();          data.writeInterfaceToken(IApplicationThread.descriptor);          data.writeStrongBinder(receiver.asBinder());          intent.writeToParcel(data, 0);          data.writeInt(resultCode);          data.writeString(dataStr);          data.writeBundle(extras);          data.writeInt(ordered ? 1 : 0);          data.writeInt(sticky ? 1 : 0);          mRemote.transact(SCHEDULE_REGISTERED_RECEIVER_TRANSACTION, data, null,              IBinder.FLAG_ONEWAY);          data.recycle();      }        ......  }

这里通过Binder驱动程序就进入到ApplicationThread.scheduleRegisteredReceiver函数去了。

Step 12. ApplicaitonThread.scheduleRegisteredReceiver

public final class ActivityThread {......        private final class ApplicationThread extends ApplicationThreadNative {......            // This function exists to make sure all receiver dispatching is          // correctly ordered, since these are one-way calls and the binder driver          // applies transaction ordering per object for such calls.          public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,                  int resultCode, String dataStr, Bundle extras, boolean ordered,                  boolean sticky) throws RemoteException {receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky);          }            ......      }        ......    }

这里的receiver是在前面过程分析中的Step 4中创建的,它的具体类型是LoadedApk.ReceiverDispatcher.InnerReceiver,即定义在LoadedApk类的内部类ReceiverDispatcher里面的一个内部类InnerReceiver,这里调用它的performReceive函数。

Step 13. InnerReceiver.performReceive

final class LoadedApk {......         static final class ReceiverDispatcher {final static class InnerReceiver extends IIntentReceiver.Stub {......                public void performReceive(Intent intent, int resultCode,                      String data, Bundle extras, boolean ordered, boolean sticky) {LoadedApk.ReceiverDispatcher rd = mDispatcher.get();                  ......                  if (rd != null) {rd.performReceive(intent, resultCode, data, extras,                              ordered, sticky);                  } else {......                  }              }          }            ......      }        ......  }

这里,它只是简单地调用ReceiverDispatcher的performReceive函数来进一步处理,这里的ReceiverDispatcher类是LoadedApk类里面的一个内部类。

Step 14. ReceiverDispatcher.performReceive

final class LoadedApk {......         static final class ReceiverDispatcher {......            public void performReceive(Intent intent, int resultCode,                  String data, Bundle extras, boolean ordered, boolean sticky) {......                Args args = new Args();              args.mCurIntent = intent;              args.mCurCode = resultCode;              args.mCurData = data;              args.mCurMap = extras;              args.mCurOrdered = ordered;              args.mCurSticky = sticky;              if (!mActivityThread.post(args)) {......              }           }            ......      }        ......  }

这里mActivityThread成员变量的类型为Handler,它是前面MainActivity注册广播接收器时,从ActivityThread取得的。

这里ReceiverDispatcher借助这个Handler,把这个广播以消息的形式放到MainActivity所在的这个ActivityThread的消息队列中去,因此,ReceiverDispatcher不等这个广播被MainActivity处理就返回了,这里也体现了广播的发送和处理是异步进行的。

注意这里处理消息的方式是通过Handler.post函数进行的,post函数的参数是Runnable类型的,这个消息最终会调用这个这个参数的run成员函数来处理。这里的Args类是LoadedApk类的内部类ReceiverDispatcher的一个内部类,它继承于Runnable类,因此,可以作为mActivityThread.post的参数传进去,代表这个广播的intent也保存在这个Args实例中。

Step 15. Hanlder.post

这个函数定义在frameworks/base/core/java/android/os/Handler.java文件中,它的作用就是把消息放在消息队列中,然后就返回了,这个消息最终会在传进来的Runnable类型的参数的run成员函数中进行处理。

Step 16. Args.run

final class LoadedApk {......         static final class ReceiverDispatcher {......            final class Args implements Runnable {......                public void run() {BroadcastReceiver receiver = mReceiver;                    ......                    Intent intent = mCurIntent;                                    ......                    try {ClassLoader cl =  mReceiver.getClass().getClassLoader();                      intent.setExtrasClassLoader(cl);                      if (mCurMap != null) {mCurMap.setClassLoader(cl);                      }                      receiver.setOrderedHint(true);                      receiver.setResult(mCurCode, mCurData, mCurMap);                      receiver.clearAbortBroadcast();                      receiver.setOrderedHint(mCurOrdered);                      receiver.setInitialStickyHint(mCurSticky);                      receiver.onReceive(mContext, intent);                  } catch (Exception e) {......                  }                    ......              }                ......          }            ......      }        ......  }

这里的mReceiver是ReceiverDispatcher类的成员变量,它的类型是BroadcastReceiver,这里它就是MainActivity注册广播接收器时创建的BroadcastReceiver实例了。

有了这个ReceiverDispatcher实例之后,就可以调用它的onReceive函数把这个广播分发给它处理了。

Step 17. BroadcastReceiver.onReceive

public class MainActivity extends Activity implements OnClickListener {......          private BroadcastReceiver counterActionReceiver = new BroadcastReceiver(){public void onReceive(Context context, Intent intent) {int counter = intent.getIntExtra(CounterService.COUNTER_VALUE, 0);                String text = String.valueOf(counter);                counterText.setText(text);                  Log.i(LOG_TAG, "Receive counter event");            }          }        ......      }

这样,MainActivity里面的定义的BroadcastReceiver实例counterActionReceiver就收到这个广播并进行处理了。

至此,Android应用程序发送广播的过程就分析完成了。

最后,我们总结一下这个Android应用程序发送广播的过程:

Step 1 - Step 7,计数器服务CounterService通过sendBroadcast把一个广播通过Binder进程间通信机制发送给ActivityManagerService,ActivityManagerService根据这个广播的Action类型找到相应的广播接收器,然后把这个广播放进自己的消息队列中去,就完成第一阶段对这个广播的异步分发了;Step 8 - Step 15,ActivityManagerService在消息循环中处理这个广播,并通过Binder进程间通信机制把这个广播分发给注册的广播接收分发器ReceiverDispatcher,ReceiverDispatcher把这个广播放进MainActivity所在的线程的消息队列中去,就完成第二阶段对这个广播的异步分发了;Step 16 - Step 17, ReceiverDispatcher的内部类Args在MainActivity所在的线程消息循环中处理这个广播,最终是将这个广播分发给所注册的BroadcastReceiver实例的onReceive函数进行处理。

关键词:
相关文章
国家能源局再核准新疆两个煤矿项目 产能合计270万吨/年

国家能源局再核准新疆两个煤矿项目 产能合计270

  4日,从新疆维吾尔自治区发改委获悉,在国家能源局核准新疆地区三个煤矿项目后,又新增两个煤矿项目,产能合计270万吨年,涉及产能总计870更多

2023-01-06 09:59:54
12月第三周山西煤炭价格环比上涨1.8% 全球热闻

12月第三周山西煤炭价格环比上涨1.8% 全球热闻

  据山西省商务厅生产资料市场监测数据显示:(12月19日-25日)山西省煤炭均价13028元吨,环比上涨18%。其中,动力煤发热量5000-5500大卡均更多

2023-01-06 09:53:51
天天消息!12月第四周内蒙古煤炭价格环比下降1.1%

天天消息!12月第四周内蒙古煤炭价格环比下降1.1%

  据内蒙古自治区商务厅生产资料市场监测系统数据显示:本周(12月24日-30日)从监测品种样本数据来看煤炭平均价格为92897元吨,与前一周比更多

2023-01-06 10:17:10
新年伊始进口煤市场稳中偏弱运行 全球热闻

新年伊始进口煤市场稳中偏弱运行 全球热闻

  上周国外正值圣诞和新年假期,贸易商基本处于休假状态,市场表现较为冷清。  节后,进口煤市场延续节前的稳中偏弱运行态势。当前国内多更多

2023-01-06 09:59:35
2022年浩吉铁路运煤总量9024.2万吨 增长55.6%

2022年浩吉铁路运煤总量9024.2万吨 增长55.6%

  截至2022年12月29日,世界最长运煤专线浩吉铁路累计完成运量90242万吨,较上年同期增加32551万吨,增长554%。  据悉,浩吉铁路自2019年9更多

2023-01-06 08:58:04
焦点速讯:截至2022年底山东有生产建设煤矿93处 产能12651万吨/年

焦点速讯:截至2022年底山东有生产建设煤矿93处

  山东省能源局发布的公告显示,截至2022年12月31日,山东省有依法生产建设煤矿93处,产能规模12651万吨年;其中,建设煤矿2处,建设规模225更多

2023-01-06 09:09:13
世界热消息:国家能源局:2023年电煤中长协供应量提升到26亿吨

世界热消息:国家能源局:2023年电煤中长协供应量

  国家能源局在全国能源工作会议上介绍,2022年国内煤炭总产量约445亿吨,同比增长8%,全年实现增产煤炭32亿吨。预计全年电煤中长期合同实际更多

2023-01-06 08:54:27
山西拟确认17 座煤矿为二级安全生产标准化管理体系煤矿 观速讯

山西拟确认17 座煤矿为二级安全生产标准化管理体

  山西省应急管理厅1月3日消息,按照国家煤矿安监局《煤矿安全生产标准化管理体系考核定级办法(试行)》和《煤矿安全生产标准化管理体系基更多

2023-01-05 10:10:12
世界观察:统计局:12月下旬全国煤炭价格各有涨跌

世界观察:统计局:12月下旬全国煤炭价格各有涨跌

  国家统计局1月4日公布的数据显示,12月下旬全国煤炭价格各有涨跌。各煤种具体价格变化情况如下:  无烟煤(洗中块,挥发份&le;8%)价格2更多

2023-01-05 10:12:50
国家能源局核准新疆三个煤矿项目 产能合计600万吨/年

国家能源局核准新疆三个煤矿项目 产能合计600万

  近日,国家能源局核准新疆地区三个煤矿项目。  一是阿艾矿区北山中部150万吨年煤矿,项目建设单位为开滦库车高科能源有限公司,建设地点更多

2023-01-05 09:54:26