應用程式與 AMS 的通訊實現——ActivityManager函式
“我報名參加金石計劃1期挑戰——瓜分10萬獎池,這是我的第2篇文章,點選檢視活動詳情”
1、前言
咱們在許多和Framework
解析相關的文章中,都會看到ActivityManagerService
這個類,可是在上層的應用開發中,卻不多直接會使用到他
那麼咱們為何要學習它的呢,一個最直接的好處就是它是咱們理解應用程式啟動過程的基礎,只有把和ActivityManagerService
以及和它相關的類的關係都理解透了,咱們才能理清應用程式啟動的過程
今天這篇文章,咱們就來對ActivityManagerService
與應用程序之間的通訊方式作一個簡單的總結,這裡咱們根據程序之間的通訊方向,分為兩個部分來討論:
-
從應用程式程序到管理者程序ide
(a) IActivityManager (b) ActivityManagerNative (c) ActivityManagerProxy (d) ActivityManagerService函式
-
從管理者程序到應用程式程序學習
(a) IApplicationThread (b) ApplicationThreadNative (c) 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)
方法中進行訊息的處理,從而實現了程序之間的通訊
好了,以上就是今天要分享的內容,大家覺得有用的話,可以點贊分享一下;如果文章中有什麼問題歡迎大家指正;歡迎在評論區或後臺討論哈~