当前位置:网站首页>大厂底层必修:“应用程序与 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 架构师之路还很漫长,与君共勉
边栏推荐
猜你喜欢

文件上传漏洞

Eric target penetration test complete tutorial

The roll call system and array elements find maximum and minimum values for sorting of objects

云安全笔记:云原生全链路加密

(5) Modules and packages, encoding formats, file operations, directory operations

hackmyvm-bunny预排

【一句话攻略】彻底理解JS中的回调(Callback)函数

(4) Function, Bug, Class and Object, Encapsulation, Inheritance, Polymorphism, Copy

ES6 iterator explanation example

How to determine the direction based on two coordinate points on the map
随机推荐
Google Hacking
Masashi: 1 vulnhub walkthrough
一个网络安全小白鼠的学习之路—nmap高级用法之脚本使用
file contains vulnerabilities
清理c盘爆满告急,C盘清理
GreenOptic: 1 vulnhub walkthrough
会计账簿、会计账簿概述、会计账簿的启用与登记要求、会计账簿的格式和登记方法
敏感信息泄露
Warzone: 3 (Exogen) vulnhub walkthrough
c语言用栈实现计算中缀表达式
Phonebook
CSRF (Cross Site Request Forgery)
How to determine the direction based on two coordinate points on the map
OPENSSL基本实验以及OPENSSL详解
重点考:金融资产概述、交易性金融资产的概念、交易性金融资产的账务处理(取得、持有。出售)、
CTF-Neting Cup Past Topics
uniapp | Problems with the use of the official map component
The shooting range that web penetration must play - DVWA shooting range 1 (centos8.2+phpstudy installation environment)
xxe of CTF
mysql 原生语句点滴学习记录