Android 进程间通信机制(三) 系统进程与应用进程通信

一. 概述

        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()函数。历经应用进程和系统进程之间的一个完整来回,总算是创建了一个应用程序。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值