当前位置:网站首页>大厂底层必修:“应用程序与 AMS 的通讯实现”
大厂底层必修:“应用程序与 AMS 的通讯实现”
2022-08-02 03:27:00 【Android技术栈】
1、前言
咱们在许多和Framework
解析相关的文章中,都会看到ActivityManagerService
这个类,可是在上层的应用开发中,却不多直接会使用到他
那么咱们为何要学习它的呢,一个最直接的好处就是它是咱们理解应用程序启动过程的基础,只有把和ActivityManagerService
以及和它相关的类的关系都理解透了,咱们才能理清应用程序启动的过程。app
今天这篇文章,咱们就来对ActivityManagerService
与应用进程之间的通讯方式作一个简单的总结,这里咱们根据进程之间的通讯方向,分为两个部分来讨论:
从应用程序进程到管理者进程ide
(a) IActivityManager(b) ActivityManagerNative ActivityManagerProxy(d) ActivityManagerService函数
从管理者进程到应用程序进程学习
(a) IApplicationThread(b) ApplicationThreadNative ApplicationThreadProxy(d) ApplicationThreadui
2、从应用程序进程到管理者进程
在这一方向上的通讯,应用程序进程做为客户端,而管理者进程则做为服务端。举一个最简单的例子,当咱们启动一个Activity
,就须要通知全局的管理者,让它去负责启动,这个全局的管理者就运行在另一个进程,这里就涉及到了从应用程序进程到管理者进程的通讯
这一个方向上通讯过程所涉及到的类包括:
2.1 应用程序进程向管理者进程发送消息
当咱们想要启动一个Activity
,会首先调用到Activity
的:代理
@Override
public void startActivityForResult(
String who, Intent intent, int requestCode, @Nullable Bundle options) {
//...
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, who,
intent, requestCode, options);
//...
}
以后调用到Instrumentation
的:
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
//....
int result = ActivityManagerNative.getDefault()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
//...
}
这里咱们看到了上面UML
图中ActivityManagerNative
,它的getDefault()
方法返回的是一个IActivityManager
的实现类:
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
//1.获得一个代理对象
IBinder b = ServiceManager.getService("activity");
//2.将这个代理对象再通过一层封装
IActivityManager am = asInterface(b);
return am;
}
};
static public IActivityManager getDefault() {
return gDefault.get();
}
这里,对于gDefault
变量有两点说明:
- 这是一个
static
类型的变量,所以在程序中的任何地方调用getDefault()
方法访问的是内存中的同一个对象 - 这里采用了
Singleton
模式,也就是懒汉模式的单例,只有第一次调用get()
方法时,才会经过create()
方法来建立一个对象
create()
作了两件事:
- 经过
ServieManager
获得IBinder
,这个IBinder
是管理进程在应用程序进程的代理对象,经过IBinder
的transact
方法,咱们就能够向管理进程发送消息:
public boolean transact(int code, Parcel data, Parcel reply, int flags)
- 将
IBinder
传入asInterface(IBinder b)
构建一个IActivityManager
的实现类,能够看到,这里返回的是一个ActivityManagerProxy
对象:
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
//这一步先忽略....
IActivityManager in = (IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ActivityManagerProxy(obj);
}
下面,咱们在来看一下这个ActivityManagerProxy
,它实现了IActivityManager
接口,咱们能够看到它所实现的IActivityManager
接口方法都是经过构造这个对象时所传入的IBinder.transact(xxxx)
来调用的,这些方法之间的区别就在于消息的类型以及参数。
class ActivityManagerProxy implements IActivityManager {
public ActivityManagerProxy(IBinder remote) {
mRemote = remote;
}
public IBinder asBinder() {
return mRemote;
}
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
//这个也很重要,咱们以后分析..
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
//发送消息到管理者进程...
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
}
通过上面的分析,咱们用一句话总结:
应用程序进程经过
ActivityManagerProxy
内部的IBinder.transact(...)
向管理者进程发送消息,这个IBinder
是管理者进程在应用程序进程的一个代理对象,它是经过ServieManager
得到的。
2.2 管理者进程处理消息
下面,咱们看一下管理者进程对于消息的处理,在管理者进程中,最终是经过ActivityManagerService
对各个应用程序进行管理的。
它继承了ActivityManagerNative
类,并重写了Binder
类的onTransact(...)
方法,咱们前面经过ActivityManagerProxy
的IBinder
对象发送的消息最终会调用到管理者进程中的这个函数当中,ActivityManagerNative
对该方法进行了重写:
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case START_ACTIVITY_TRANSACTION:
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
String callingPackage = data.readString();
Intent intent = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
IBinder resultTo = data.readStrongBinder();
String resultWho = data.readString();
int requestCode = data.readInt();
int startFlags = data.readInt();
ProfilerInfo profilerInfo = data.readInt() != 0
? ProfilerInfo.CREATOR.createFromParcel(data) : null;
Bundle options = data.readInt() != 0
? Bundle.CREATOR.createFromParcel(data) : null;
//这里在管理者进程进行处理操做....
int result = startActivity(app, callingPackage, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
reply.writeNoException();
reply.writeInt(result);
return true;
//...
}
在onTransact(xxx)
方法中,会根据收到的消息类型,调用IActivityManager
接口中所定义的不一样接口,而ActivityManagerNative
是没有实现这些接口的,真正的处理在ActivityManagerService
中,ActivityManagerService
开始进行一系列复杂的操做,这里以后咱们介绍应用程序启动过程的时候再详细分析。
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
一样的,咱们也用一句话总结:
管理者进程经过
onTransact(xxxx)
处理应用程序发送过来的消息
3、从管理者进程到应用程序进程
接着,咱们考虑另外一个方向上的通讯方式,从管理者进程到应用程序进程,这一方向上的通讯过程涉及到下面的类:
ApplicationThread
的整个框架和上面很相似,只不过在这一个方向上,管理者进程做为客户端,而应用程序进行则做为服务端。
3.1 管理者进程向应用程序进程发送消息
前面咱们分析的时候,应用程序进程向管理者进程发送消息的时候,是经过IBinder
这个管理者进程在应用程序进程中的代理对象来实现的,而这个IBinder
则是经过ServiceManager
获取的:
IBinder b = ServiceManager.getService("activity");
同理,若是管理者进程但愿向应用程序进程发送消息,那么它也必须设法获得一个应用程序进程在它这边的代理对象。
咱们回忆一下,在第二节的分析中,应用者进程向管理者进程发送消息的同时,经过writeStringBinder
,放入了下面这个对象:
public int startActivity(IApplicationThread caller, ...) {
//...
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
//...
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
}
这个caller
是在最开始调用startActivityForResult
时传入的:
ActivityThread mMainThread;
@Override
public void startActivityForResult(
String who, Intent intent, int requestCode, @Nullable Bundle options) {
//...
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, who,
intent, requestCode, options);
//...
}
经过查看ActivityThread
的代码,咱们能够看到它实际上是一个定义在ApplicationThread
中的ApplicationThread
对象,它的asBinder
实现是在ApplicationThreadNative
当中:
public IBinder asBinder() {
return this;
}
在管理者进程接收消息的时候,就能够经过readStrongBinder
得到这个ApplicationThread
对象在管理者进程的代理对象IBinder
:
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case START_ACTIVITY_TRANSACTION:
//取出传入的ApplicationThread对象,以后调用asInterface方法..
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
//...
int result = startActivity(app, callingPackage, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
return true;
}
}
接着,它再经过asInterface(IBinder xx)
方法把传入的代理对象经过ApplicationThreadProxy
进行了一层封装:
static public IApplicationThread asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IApplicationThread in = (IApplicationThread) obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ApplicationThreadProxy(obj);
}
以后,管理者进程就能够经过这个代理对象的transact(xxxx)
方法向应用程序进程发送消息了:
class ApplicationThreadProxy implements IApplicationThread {
private final IBinder mRemote;
public ApplicationThreadProxy(IBinder remote) {
mRemote = remote;
}
public final IBinder asBinder() {
return mRemote;
}
public final void schedulePauseActivity(IBinder token, boolean finished,
boolean userLeaving, int configChanges, boolean dontReport) throws RemoteException {
//....
mRemote.transact(SCHEDULE_PAUSE_ACTIVITY_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
//...
}
这一个过程能够总结为:
管理者进程经过
ApplicationThreadProxy
内部的IBinder
向应用程序进程发送消息,这个IBinder
是应用程序进程在管理者进程的代理对象,它是在管理者进程接收应用程序进程发送过来的消息中得到的。
3.2 用户进程接收消息
在用户程序进程中,ApplicationThread
的onTransact(....)
就能够收到管理者进程发送的消息,以后再调用ApplicationThread
所实现的IApplicationThread
的接口方法进行消息的处理:
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case SCHEDULE_PAUSE_ACTIVITY_TRANSACTION:
data.enforceInterface(IApplicationThread.descriptor);
IBinder b = data.readStrongBinder();
boolean finished = data.readInt() != 0;
boolean userLeaving = data.readInt() != 0;
int configChanges = data.readInt();
boolean dontReport = data.readInt() != 0;
schedulePauseActivity(b, finished, userLeaving, configChanges, dontReport);
return true;
}
4、结语
以上就是应用程序进程和管理者进程之间的通讯方式,究其根本,都是经过获取对方进程的代理对象的transact(xxxx)
方法发送消息,而对方进程则在onTransact(xxxx)
方法中进行消息的处理,从而实现了进程之间的通讯
有需要学习更多Android进阶技术的同学;我自荐一套《完整的Android的资料,以及一些视频课讲解》现在私信发送 “进阶” 或 “笔记” 即可免费获取
最后我想说:
对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们
技术是无止境的,你需要对自己提交的每一行代码、使用的每一个工具负责,不断挖掘其底层原理,才能使自己的技术升华到更高的层面
Android 架构师之路还很漫长,与君共勉
边栏推荐
- 最简单的FRP内网穿透教程
- Smart Tips for Frida Scripting in Kali Environment
- 清理c盘爆满告急,C盘清理
- 元宇宙是一个炒作的科幻概念,还是互联网发展的下半场?
- Shuriken: 1 vulnhub walkthrough
- PALISADE:CKKS的使用
- How to calculate the distance between two points on the earth (with formula derivation)
- 2021-09-04 最简单的Golang定时器应用以及最简单的协程入门儿
- CTF-Neting Cup Past Topics
- 成本会计的概念、产品成本核算的要求、产品成本核算的对象与成本项目、产品成本的归集和分配(可能考判断)、产品成本计算方法 (三种:产品的品种(品种法),批次(分批法),步骤(分步法))
猜你喜欢
Microsoft Office安装全过程记录
链动2+1模式开发系统
CTF entry md5
hackmyvm: again walkthrough
快速搭建一个网关服务,动态路由、鉴权的流程,看完秒会(含流程图)
元宇宙是一个炒作的科幻概念,还是互联网发展的下半场?
什么是广告电商商业模式?这几个门派告诉你
File upload vulnerability
(1) the print () function, escape character, binary and character encoding, variables, data type, the input () function, operator
强化学习笔记:DDPG
随机推荐
命令执行漏洞
Shuriken: 1 vulnhub walkthrough
php函数漏洞总结
Scrapy crawler encounters redirection 301/302 problem solution
The roll call system and array elements find maximum and minimum values for sorting of objects
CTF之xxe
Win10 解决AMD平台下SVM无法开启的问题
Eric target penetration test complete tutorial
Solve the problem that the 5+APP real machine test cannot access the background (same local area network)
php中魔术方法详解
A network security guinea pig's learning path - scripting of advanced usage of nmap
重点考:从债劵的角度来看交易性金融资产
Microsoft Office安装全过程记录
(7) superficial "crawlers" process (concept + practice)
Laravel 登录,中间件和路由分组
CTF入门之md5
快速搭建一个网关服务,动态路由、鉴权的流程,看完秒会(含流程图)
元宇宙是一个炒作的科幻概念,还是互联网发展的下半场?
真·杂项:资本论阅读笔记(随缘更新)
最简单的FRP内网穿透教程