private void attach(boolean system) { ... if (!system) { ... try { mgr.attachApplication(mAppThread); } catch (RemoteException ex) { // Ignore } ... } public static void main(String[] args) { ... Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } ... Looper.loop(); }
# ActivityThread.java private void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges, boolean dontReport) { ActivityClientRecord r = mActivities.get(token); if (r != null) { //Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r); // 如果离开,像点击 home 键,就会调用这里 if (userLeaving) { performUserLeavingActivity(r); } r.activity.mConfigChangeFlags |= configChanges; // 这里最终会调用 Client Activity 的 onPause() 方法 performPauseActivity(token, finished, r.isPreHoneycomb()); // Make sure any pending writes are now committed. // 等待前面的工作完成 if (r.isPreHoneycomb()) { QueuedWork.waitToFinish(); } // Tell the activity manager we have paused. if (!dontReport) { try { // 发送一个已经进入中止状态的进程间通信 ActivityManagerNative.getDefault().activityPaused(token); } catch (RemoteException ex) { } } mSomeActivitiesChanged = true; } }从上面的 handlePauseActivity 方法中可以看到会先把当前 Activity 进行 pause 完成,让后再发送一个进入中止状态的进程间通信,让子 Activity 启动。所以,不要在 onPause 中做一些耗时的操作,否则会使子 Activity 等待启动的时间过久.
(1). Client 向 AMS 发送一个启动 Service 的进程间通信请求;
(2). AMS 发现用来运行 Service 的应用程序进程不存在,因此,它会首先将 Service 的组件信息保存下来, 接着再创建一个新的应用程序进程;
(3).新的应用程序进程启动完成之后,就会向 AMS 发送一个启动完成的进程间通行请求,以便 AMS 可以继续执行启动 Service 的操作;
(4). AMS 将第 2 步保存下来的 Service 组件信息发送到第 2 步 创建的应用程序进程,以便它可以将 Service 启动。
I. 启动时,如果版本大于 LOLLIPOP 及其以上版本, Intent 必须是显示,否则会抛出异常
// ContextImpl.java 中
private void validateServiceIntent(Intent service) { if (service.getComponent() == null && service.getPackage() == null) { if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) { IllegalArgumentException ex = new IllegalArgumentException( "Service Intent must be explicit: " + service); throw ex; } else { Log.w(TAG, "Implicit intents with startService are not safe: " + service + " " + Debug.getCallers(2, 3)); } } }
(1). Activity 想 AMS 发送一个绑定 Service 组件的进程间通信请求;
(2). AMS 发现用来运行 Service 组件的应用程序进程,即 Activity 组件所运行在的应用程序进程已经存在。因此,它直接通知应用程序将 Service 启动;
(3).Service 启动后,AMS 就会请求它返回一个 Binder 本地对象,以便 Activity 可以通过这个 Binder 本地对象和 Service 建立连接;
(4). AMS 将前面从 Service 组件中获得一个 Binder 本地对象发个 Activity 组件;
(5). Activity 组件获得 AMS 给它发送的 Binder 本地对象之后,就可以通过它来获得 Service 组件的一个访问接口. Activity 组件以后可以通过这个访问接口来使用 Service 所提供的服务,这相当于将这个 Service 组件绑定在 Activity 内部。
ActivityThread.java
I.如果没有绑定过,则绑定,如果已经绑定过了,从新绑定
private void handleBindService(BindServiceData data) { Service s = mServices.get(data.token); ... if (s != null) { try { data.intent.setExtrasClassLoader(s.getClassLoader()); data.intent.prepareToEnterProcess(); try { if (!data.rebind) { IBinder binder = s.onBind(data.intent); ActivityManagerNative.getDefault().publishService( data.token, data.intent, binder); } else { s.onRebind(data.intent); ActivityManagerNative.getDefault().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); } ensureJitEnabled(); } catch (RemoteException ex) { } } catch (Exception e) { ... } } }
广播机制是在 Binder 进程间通信机制的基础上实现的; 广播机制是一种基于消息发布和订阅的事件驱动模型,即广播发送者负责发布消息,而广播接收者需要先订阅消息,然后才能接收消息。
Activity 组件注册一个广播接受者是,并不是真的将这个广播接收者注册到 ActivityManagerService 中, 而是将与它关联的 InnerReceiver 对象注册到 AMS 中。
.在 AMS 的 broadcastIntentLocked 方法的开始添加了
// By default broadcasts do not go to stopped apps.
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
这表示在 Android 5.0 中,默认情况下,广播不会发送给已经停止的应用
Intent 的标记位
FLAG_INCLUDE_STOPPED_PACKAGES
表示包含已经停止的应用,这个时候广播会发送给已经停止的应用;
FLAG_EXCLUDE_STOPPED_PACKAGES
表示不包含已经停止的应用,这个时候广播不会发送给已经停止的应用;
从 Android 3.1 开始,系统为所有广播默认条件了 FLAG_EXCLUDE_STOPPED_PACKAGES 标志。如果确实需要调去未启动的应用,添加
FLAG_INCLUDE_STOPPED_PACKAGES 标记位即可。 两者共存时,以 FLAG_INCLUDE_STOPPED_PACKAGES 为准。
这里应用处于停止状态分两种情况: 第一种是应用安装后未运行,第二种是应用被手动或者其他应用强停了。
从 Android 3.1 开始,处于停止状态的应用无法接收到开机广播,而 3.1 之前,处于停止状态的应用是可以收到开机广播的。