热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

一.概述        Android中有一个重要的系统进程(system_s
一. 概述

        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.Stubimplements 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 mViewAncestor;private final IWindowSession mWindowSession;W(ViewRootImpl viewAncestor) {mViewAncestor = new WeakReference(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.Stubimplements 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);}@UnsupportedAppUsageprivate 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() 方法

@Overridepublic 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) {....//1attachApplicationLocked(thread, callingPid, callingUid, startSeq);....
}

此时,AMS会反转角色,即系统进程作为客户端,通过IApplicationThread接口向应用进程发起调用。

@GuardedBy("this")private boolean attachApplicationLocked(@NonNull IApplicationThread thread,int pid, int callingUid, long startSeq) {// 2thread.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 providers, ComponentName instrumentationName,ProfilerInfo profilerInfo, Bundle instrumentationArgs,
.......
.......data.contentCaptureOptions = contentCaptureOptions;//3sendMessage(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;//4handleBindApplication(data);Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);//processLinkTurboMonitor();break;

调用handleBindApplication方法:

private void handleBindApplication(AppBindData data) {.....try {//5mInstrumentation.callApplicationOnCreate(app);}

最终会走到 Application的 onCreate()方法中去

//Instrumentation.java中public void callApplicationOnCreate(Application app) {app.onCreate();}//Application.javapublic void onCreate() {}

        ApplicationThread作为IApplicationThread接口的服务端实现,运行在应用进程中, 然后ApplicationThread.bindApplication()会被执行,完成一些简单的数据封装(AppBindData)后,通过Handler抛出BIND_APPLICATION消息。这一抛,就抛到了主线程上,

ActivityThread.handleBindApplication()会被执行,接着就到了各位观众较为熟悉的Application.onCreate()函数。历经应用进程和系统进程之间的一个完整来回,总算是创建了一个应用程序。

















推荐阅读
  • 掌握Android UI设计:利用ZoomControls实现图片缩放功能
    本文介绍了如何在Android应用中通过使用ZoomControls组件来实现图片的缩放功能。ZoomControls提供了一种简单且直观的方式,让用户可以通过点击放大和缩小按钮来调整图片的显示大小。文章详细讲解了ZoomControls的基本用法、布局设置以及与ImageView的结合使用方法,适合初学者快速掌握Android UI设计中的这一重要功能。 ... [详细]
  • 设计实战 | 10个Kotlin项目深度解析:首页模块开发详解
    设计实战 | 10个Kotlin项目深度解析:首页模块开发详解 ... [详细]
  • C++ 异步编程中获取线程执行结果的方法与技巧及其在前端开发中的应用探讨
    本文探讨了C++异步编程中获取线程执行结果的方法与技巧,并深入分析了这些技术在前端开发中的应用。通过对比不同的异步编程模型,本文详细介绍了如何高效地处理多线程任务,确保程序的稳定性和性能。同时,文章还结合实际案例,展示了这些方法在前端异步编程中的具体实现和优化策略。 ... [详细]
  • 在处理 XML 数据时,如果需要解析 `` 标签的内容,可以采用 Pull 解析方法。Pull 解析是一种高效的 XML 解析方式,适用于流式数据处理。具体实现中,可以通过 Java 的 `XmlPullParser` 或其他类似的库来逐步读取和解析 XML 文档中的 `` 元素。这样不仅能够提高解析效率,还能减少内存占用。本文将详细介绍如何使用 Pull 解析方法来提取 `` 标签的内容,并提供一个示例代码,帮助开发者快速解决问题。 ... [详细]
  • 本文探讨了资源访问的学习路径与方法,旨在帮助学习者更高效地获取和利用各类资源。通过分析不同资源的特点和应用场景,提出了多种实用的学习策略和技术手段,为学习者提供了系统的指导和建议。 ... [详细]
  • 技术分享:深入解析GestureDetector手势识别机制
    技术分享:深入解析GestureDetector手势识别机制 ... [详细]
  • 本文探讨了在Android应用中实现动态滚动文本显示控件的优化方法。通过详细分析焦点管理机制,特别是通过设置返回值为`true`来确保焦点不会被其他控件抢占,从而提升滚动文本的流畅性和用户体验。具体实现中,对`MarqueeText.java`进行了代码层面的优化,增强了控件的稳定性和兼容性。 ... [详细]
  • IOS Run loop详解
    为什么80%的码农都做不了架构师?转自http:blog.csdn.netztp800201articledetails9240913感谢作者分享Objecti ... [详细]
  • 在尝试对 QQmlPropertyMap 类进行测试驱动开发时,发现其派生类中无法正常调用槽函数或 Q_INVOKABLE 方法。这可能是由于 QQmlPropertyMap 的内部实现机制导致的,需要进一步研究以找到解决方案。 ... [详细]
  • 本文详细解析了使用C++实现的键盘输入记录程序的源代码,该程序在Windows应用程序开发中具有很高的实用价值。键盘记录功能不仅在远程控制软件中广泛应用,还为开发者提供了强大的调试和监控工具。通过具体实例,本文深入探讨了C++键盘记录程序的设计与实现,适合需要相关技术的开发者参考。 ... [详细]
  • 本文介绍了一种自定义的Android圆形进度条视图,支持在进度条上显示数字,并在圆心位置展示文字内容。通过自定义绘图和组件组合的方式实现,详细展示了自定义View的开发流程和关键技术点。示例代码和效果展示将在文章末尾提供。 ... [详细]
  • 本文探讨了如何利用Java代码获取当前本地操作系统中正在运行的进程列表及其详细信息。通过引入必要的包和类,开发者可以轻松地实现这一功能,为系统监控和管理提供有力支持。示例代码展示了具体实现方法,适用于需要了解系统进程状态的开发人员。 ... [详细]
  • 本文探讨了如何利用 jQuery 的 JSONP 技术实现跨域调用外部 Web 服务。通过详细解析 JSONP 的工作原理及其在 jQuery 中的应用,本文提供了实用的代码示例和最佳实践,帮助开发者解决跨域请求中的常见问题。 ... [详细]
  • Node.js 教程第五讲:深入解析 EventEmitter(事件监听与发射机制)
    本文将深入探讨 Node.js 中的 EventEmitter 模块,详细介绍其在事件监听与发射机制中的应用。内容涵盖事件驱动的基本概念、如何在 Node.js 中注册和触发自定义事件,以及 EventEmitter 的核心 API 和使用方法。通过本教程,读者将能够全面理解并熟练运用 EventEmitter 进行高效的事件处理。 ... [详细]
  • Android 图像色彩处理技术详解
    本文详细探讨了 Android 平台上的图像色彩处理技术,重点介绍了如何通过模仿美图秀秀的交互方式,利用 SeekBar 实现对图片颜色的精细调整。文章展示了具体的布局设计和代码实现,帮助开发者更好地理解和应用图像处理技术。 ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有