一. 概述
Android中有一个重要的系统进程(system_server),运行着系统中非常重要服务(AMS, PMS, WMS等), 针对Activity而言,系统进程需要不断地调度Activity执行,管理Activity的状态; 每一个APK都需要运行在一个应用进程中,有自己独立的内存空间, 针对Activity而言,应用进程需要执行Activity生命周期函数(onCreate, onStart, …onDestroy)的具体逻辑。
应用进程需要频繁与系统进程通信,譬如Activity生命周期的各个方法都是需要经过系统进程调度的,只是在应用进程进行回调,这就需要从系统到应用的跨进程调用; 应用进程有需要将当前Activity的状态告诉系统进程,以便系统将Activity驱动到下一个状态,这就需要从应用到系统的跨进程调用。
应用进程与系统进程相互通信的手段,就是利用前面文章介绍的Binder机制, 本文要分析的不是Binder机制的内在原理,而是应用进程与系统进程建立在Binder之上通信的业务逻辑,Android为此设计了两个Binder接口:
IApplicationThread: 作为系统进程请求应用进程的接口
IActivityManager: 作为应用进程请求系统进程的接口。
本文内容基于Android10的源码分析总结.
示例图:
左侧为系统进程 右侧为应用进程
二 . AMS是什么?
比如在你的应用中(进程A)中启动一个Activity界面,肯定会调用startActivity这个方法, 然后跨进程和AMS通信, 接着AMS会管理这个Activity的生命周期方法, 先来说一说AMS是什么的?
1. 从java角度来看,AMS就是一个java对象
它实现了Ibinder接口,所以它是一个用于进程间通信的接口,这个对象初始化是在systemServer.java 的run()方法里面.
public Lifecycle(Context context) {
super(context);
mService = new ActivityManagerService(context);
}
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
2. AMS是一个服务
ActivityManagerService从名字就可以看出,它是一个服务,用来管理Activity,而且是一个系统服务,就是包管理服务,电池管理服务,震动管理服务等。
3. AMS是一个Binder
AMS实现了Ibinder接口,所以它是一个Binder,这意味着他不但可以用于进程间通信,还是一个线程,因为一个Binder就是一个线程。
如果我们运行一个Hello world的安卓应用程序, 这个进程至少要启动4个线程
1. main线程,只是程序的主线程,也是日常用到的最多的线程,也叫UI线程,因为android的组
件是非线程安全的,所以只允许UI/MAIN线程来操作。
2. GC线程,java有垃圾回收机制,每个java程序都有一个专门负责垃圾回收的线程.
3. Binder1 就是我们的ApplicationThread,这个类实现了Ibinder接口,用于进程之间通信,具体
来说,就是我们程序和AMS通信的工具.
4. Binder2 就是我们的ViewRoot.W对象,他也是实现了IBinder接口,就是用于我们的应用程序和
wms通信的工具。
static class W extends IWindow.Stub {
private final WeakReference<ViewRootImpl> mViewAncestor;
private final IWindowSession mWindowSession;
W(ViewRootImpl viewAncestor) {
mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor);
mWindowSession = viewAncestor.mWindowSession;
}
.....
.....
}
WMS就是WindowManagerServicer ,和AMS差不多的概念,不过他是管理窗口的系统服务。
三. 两个接口
既然 IApplicationThread 和 IActivityManager 是两个接口, 我们来看看哪些类实现它们
3.1 IApplicationThread接口
只要继承了android.os.IInterface 则说明它是一个Binder对象, 是用于进程间通信的接口.
public interface IApplicationThread extends android.os.IInterface{
}
1. 先看IApplicationThread , 在 AS中 ctrl + T 快捷键(Eclipse风格)
实现这个接口的类为: ApplicationThread 它是 ActivityThread.java的内部类
private class ApplicationThread extends IApplicationThread.Stub {
......
......
}
上图中,例外的 (Defaut in IApplicationThread) (Proxy in stub in IApplicationThread) (Stub in IApplicationThread) 是 系统编译 IApplicationThread.aidl 文件后自动生成的代码文件, 里面的核心内容就是 1. 静态抽象类 Stub; 2. Stub的静态内部类Proxy ;
在看看 IApplicationThread.aidl 的写法, 接口文件前修饰关键字为oneway
/**
* System private API for communicating with the application. This is given to
* the activity manager by an application when it starts up, for the activity
* manager to tell the application about things it needs to do.
系统进程与应用进程通信的系统专用API
*
* {@hide}
*/
oneway interface IApplicationThread {
.....
}
oneway 表示在远程调用时(是异步调用,即客户端不会被阻塞), 它只是发送事务数据并立即返回.
oneway修饰了的方法不可以有返回值,也不可以有带out或inout的参数。可以去看看 IApplicationThread.aidl文件中,定义的方法, 都是void类型, 没有返回值.
这也对应 AMS 给应用进程发送消息后, 肯定继续做自己的事情, 不会被阻塞, 因为AMS是四大组件的管理者,同一时刻好多事情等着做了, 要是和普通的[(in out inout), 他们是同步调用, 调用方执行 mRemote.transact 时, 会挂起, 然后等待服务端reply值] 一样的话, 那么系统AMS这么重要的服务岂不是卡的要死. 系统运行也不流畅.
google设计它的使命是什么呢?
IApplicationThread接口的具体业务实现类是ApplicationThread, 它是ActivityThread的一个内部类,ApplicationThread负责响应系统进程发起的请求,这些请求大部分都是需要调度在应用进程的主线程执行,而ActivityThread是应用进程的主线程,通过Handle往主线程发送消息,ApplicationThread就轻松将具体执行任务的工作转交给了主线程。
3.2 IActivityManager接口
同样使用ctrl + T 查看实现类
实现这个接口的类为: ActivityManagerService.java , AMSEx.java 为 AMS的继承类
public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
.....
}
public static abstract class Stub extends android.os.Binder implements android.app.IActivityManager
{
.....
}
根据上面"AMS是什么"介绍, 其实你也可以把AMS理解成运行在 system_server进程中的一个线程.
当然 WMS PMS 也可以理解成运行在system_server进程中的线程.
Binder 在进程间通信传递的数据限制大小为 1M - 8K
根据以前的文章(Android 进程间通信机制(二) mmap 原理)查看dev/binder分配内存的命令:
cat proc/进程号/maps | grep dev/binder
我们可以查看 system_server进程 dev/binder 驱动文件分配的内存空间也是为 1M - 8K
Android 系统底层基于 Linux Kernel, 当 Kernel 启动过程会创建 init 进程, 该进 程是所有用户空间的鼻祖, init 进程会启动 servicemanager(binder 服务管家), Zygote 进程(Java 进程的鼻祖). Zygote 进程会创建 system_server 进程以及各 种 app 进程,下图是这几个系统重量级进程之间的层级关系。
用自己的手机查看进程号:
[号外]: servicemanager 进程分配dev/binder的内存空间为 128K , 结论支撑代码为
frameworks/native/cmds/servicemanager/service_manager.c
int main(int argc, char** argv)
{
struct binder_state *bs;
union selinux_callback cb;
char *driver;
if (argc > 1) {
driver = argv[1];
} else {
driver = "/dev/binder";
}
bs = binder_open(driver, 128*1024);
google设计128k的理由, 推测是和servicemanager进程通信的业务包括
请求服务(如 ServiceManager.getService(Context.USAGE_STATS_SERVICE)) 和
添加服务等轻量级的工作
ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
ServiceManager.addService("meminfo", new MemBinder(this), /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_HIGH);
ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
ServiceManager.addService("dbinfo", new DbBinder(this));
if (MONITOR_CPU_USAGE) {
ServiceManager.addService("cpuinfo", new CpuBinder(this),
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
}
ServiceManager.addService("permission", new PermissionController(this));
ServiceManager.addService("processinfo", new ProcessInfoService(this));
所以在binder分配的空间上只需要128K就可以满足.
四. 握手通信全流程
4.1 从应用进程到系统进程
在ActivityThread创建的时候,会将自己的ApplicationThread绑定到AMS中, 源码流程如下:
1. 首先在 ActivityThread.java 的main方法中
public static void main(String[] args) {
ActivityThread thread = new ActivityThread();
.....
//步骤一
thread.attach(false, startSeq);
}
@UnsupportedAppUsage
private void attach(boolean system, long startSeq) {
final IActivityManager mgr = ActivityManager.getService();
//步骤二 通过 IActivityManager接口跨进程通信, 把 mAppThread(ApplicationThread对象)传递到AMS中
mgr.attachApplication(mAppThread, startSeq);
}
应用进程作为客户端,通过IAcitivtyManager接口发起了跨进程调用, 跨进程传递的参数mAppThread就是IApplicationThread的实例, 执行流程从应用进程进入到系统进程
2 接下来就到AMS中去了,调用 AMS.attachApplication() 方法
@Override
public void attachApplication(IApplicationThread thread, long startSeq) {
if (thread == null) {
throw new SecurityException("Invalid application interface");
}
synchronized (this) {
int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
Binder.restoreCallingIdentity(origId);
}
}
AMS作为IActivityManager接口的服务端实现,会响应客户端的请求,最终AMS.attachApplication()函数会被执行, 该函数接收跨进程传递过来的IApplicationThread实例,将其绑定到系统进程。 具体的绑定操作细节此处不表,我们只需要知道AMS中维护了所有进程运行时的信息(ProcessRecord),一旦发生了应用进程的绑定请求, ProcessRecord.thread就被赋值成应用进程的IApplicationThread实例,这样一来,在AMS中就能通过该实例发起向应用进程的调用。
4.2 从系统进程到应用进程
在AMS.attachApplication()的过程中,会有一些信息要传递给应用进程,以便应用进程的初始化.
public void attachApplication(IApplicationThread thread, long startSeq) {
....
//1
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
....
}
此时,AMS会反转角色,即系统进程作为客户端,通过IApplicationThread接口向应用进程发起调用。
@GuardedBy("this")
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
// 2
thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions);
}
2中的 thread就是 实现了IApplicationThread的接口对象,通过它跨进程通信,就跳转到ActivityThread.bindApplication 方法中去了
public final void bindApplication(String processName, ApplicationInfo appInfo,
List<ProviderInfo> providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
.......
.......
data.contentCaptureOptions = contentCaptureOptions;
//3
sendMessage(H.BIND_APPLICATION, data);
}
接下来会到消息处理的地方
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
//4
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//processLinkTurboMonitor();
break;
调用handleBindApplication方法:
private void handleBindApplication(AppBindData data) {
.....
try {
//5
mInstrumentation.callApplicationOnCreate(app);
}
最终会走到 Application的 onCreate()方法中去
//Instrumentation.java中
public void callApplicationOnCreate(Application app) {
app.onCreate();
}
//Application.java
public void onCreate() {
}
ApplicationThread作为IApplicationThread接口的服务端实现,运行在应用进程中, 然后ApplicationThread.bindApplication()会被执行,完成一些简单的数据封装(AppBindData)后,通过Handler抛出BIND_APPLICATION消息。这一抛,就抛到了主线程上,
ActivityThread.handleBindApplication()会被执行,接着就到了各位观众较为熟悉的Application.onCreate()函数。历经应用进程和系统进程之间的一个完整来回,总算是创建了一个应用程序。