当前位置:网站首页>大厂底层必修:“应用程序与 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 架构师之路还很漫长,与君共勉
边栏推荐
- Anaconda报错:An unexpected error has occurred. Conda has prepared the above report 解决办法
- CTF之xxe
- The CTF introduction of PHP file contains
- Syncthing文件同步方案完全攻略(亲测有效)
- CTF introductory notes ping
- uniapp | Problems with the use of the official map component
- 英语每日打卡
- 链动2+1模式开发系统
- CSRF(跨站请求伪造)
- 链动2+1无限循环系统,2022年起盘成功率超高的模式
猜你喜欢

财产清查概述、 全面清查的情况、局部清查的情况、财产清查的方法、财产清查结果的处理
![[Hello World教程] 使用HBuilder和Uni-app 生成一个简单的微信小程序DEMO](/img/98/7ad7fcee0deaaa92446098d1d99dc3.png)
[Hello World教程] 使用HBuilder和Uni-app 生成一个简单的微信小程序DEMO

Praying: 1 vulnhub walkthrough

c语言用栈实现计算中缀表达式

The first time to tear the code by hand, how to solve the problem of full arrangement
![WeChat applet development video loading: [Rendering layer network layer error] Failed to load media](/img/24/e12a1312aee28a43428b2ae0bfbe00.png)
WeChat applet development video loading: [Rendering layer network layer error] Failed to load media

CTF-网鼎杯往届题目

C language uses stack to calculate infix expressions

file contains vulnerabilities

Debian 12 Bookworm 尝鲜记
随机推荐
重点考:金融资产概述、交易性金融资产的概念、交易性金融资产的账务处理(取得、持有。出售)、
Eric target penetration test complete tutorial
机器学习1
SATA M2 SSD 无法安装系统的解决方法
(1) the print () function, escape character, binary and character encoding, variables, data type, the input () function, operator
超级云APP,陪伴您一起成长的软件
强化学习笔记:DDPG
php中魔术方法详解
英语每日打卡
CTF入门笔记之ping
【泰山众筹】模式为什么一直都这么火热?是有原因的
Laravel打印执行的SQL语句
Alfa: 1 vulnhub walkthrough
Solve the problem that the 5+APP real machine test cannot access the background (same local area network)
Shuriken: 1 vulnhub walkthrough
uniapp | Compilation error after updating with npm update
命令执行漏洞
SQL注入(6)
How to calculate the distance between two points on the earth (with formula derivation)
web安全之目录遍历