理解Android Binder机制(3/3):Java层
本文是Android Binder機(jī)制解析的第三篇,也是最后一篇文章。本文會(huì)講解Binder Framework Java部分的邏輯。
Binder機(jī)制分析的前面兩篇文章,請(qǐng)移步這里:
理解Android Binder機(jī)制(1/3):驅(qū)動(dòng)篇
理解Android Binder機(jī)制(2/3):C++層):驅(qū)動(dòng)篇
下文所講內(nèi)容的相關(guān)源碼,在AOSP源碼樹中的路徑如下:
// Binder Framework JNI /frameworks/base/core/jni/android_util_Binder.h /frameworks/base/core/jni/android_util_Binder.cpp /frameworks/base/core/jni/android_os_Parcel.h /frameworks/base/core/jni/android_os_Parcel.cpp// Binder Framework Java接口 /frameworks/base/core/java/android/os/Binder.java /frameworks/base/core/java/android/os/IBinder.java /frameworks/base/core/java/android/os/IInterface.java /frameworks/base/core/java/android/os/Parcel.java主要結(jié)構(gòu)
Android應(yīng)用程序使用Java語言開發(fā),Binder框架自然也少不了在Java層提供接口。
前文中我們看到,Binder機(jī)制在C++層已經(jīng)有了完整的實(shí)現(xiàn)。因此Java層完全不用重復(fù)實(shí)現(xiàn),而是通過JNI銜接了C++層以復(fù)用其實(shí)現(xiàn)。
下圖描述了Binder Framework Java層到C++層的銜接關(guān)系。
這里對(duì)圖中Java層和JNI層的幾個(gè)類做一下說明( 關(guān)于C++層的講解請(qǐng)看這里?):
| IInterface | interface | 供Java層Binder服務(wù)接口繼承的接口 |
| IBinder | interface | Java層的IBinder類,提供了transact方法來調(diào)用遠(yuǎn)程服務(wù) |
| Binder | class | 實(shí)現(xiàn)了IBinder接口,封裝了JNI的實(shí)現(xiàn)。Java層Binder服務(wù)的基類 |
| BinderProxy | class | 實(shí)現(xiàn)了IBinder接口,封裝了JNI的實(shí)現(xiàn)。提供transact方法調(diào)用遠(yuǎn)程服務(wù) |
| JavaBBinderHolder | class | 內(nèi)部存儲(chǔ)了JavaBBinder |
| JavaBBinder | class | 將C++端的onTransact調(diào)用傳遞到Java端 |
| Parcel | class | Java層的數(shù)據(jù)包裝器,見C++層的Parcel類分析 |
這里的IInterface,IBinder和C++層的兩個(gè)類是同名的。這個(gè)同名并不是巧合:它們不僅僅同名,它們所起的作用,以及其中包含的接口都是幾乎一樣的,區(qū)別僅僅在于一個(gè)是C++層,一個(gè)是Java層而已。
除了IInterface,IBinder之外,這里Binder與BinderProxy類也是與C++的類對(duì)應(yīng)的,下面列出了Java層和C++層類的對(duì)應(yīng)關(guān)系:
| IInterface | IInterface |
| IBinder | IBinder |
| BBinder | Binder |
| BpProxy | BinderProxy |
| Parcel | Parcel |
JNI的銜接
JNI全稱是Java Native Interface,這個(gè)是由Java虛擬機(jī)提供的機(jī)制。這個(gè)機(jī)制使得native代碼可以和Java代碼互相通訊。簡(jiǎn)單來說就是:我們可以在C/C++端調(diào)用Java代碼,也可以在Java端調(diào)用C/C++代碼。
關(guān)于JNI的詳細(xì)說明,可以參見Oracle的官方文檔:Java Native Interface?,這里不多說明。
實(shí)際上,在Android中很多的服務(wù)或者機(jī)制都是在C/C++層實(shí)現(xiàn)的,想要將這些實(shí)現(xiàn)復(fù)用到Java層,就必須通過JNI進(jìn)行銜接。AOSP源碼中,/frameworks/base/core/jni/ 目錄下的源碼就是專門用來對(duì)接Framework層的JNI實(shí)現(xiàn)的。
看一下Binder.java的實(shí)現(xiàn)就會(huì)發(fā)現(xiàn),這里面有不少的方法都是用native關(guān)鍵字修飾的,并且沒有方法實(shí)現(xiàn)體,這些方法其實(shí)都是在C++中實(shí)現(xiàn)的:
public static final native int getCallingPid();public static final native int getCallingUid();public static final native long clearCallingIdentity();public static final native void restoreCallingIdentity(long token);public static final native void setThreadStrictModePolicy(int policyMask);public static final native int getThreadStrictModePolicy();public static final native void flushPendingCommands();public static final native void joinThreadPool();在android_util_Binder.cpp文件中的下面這段代碼,設(shè)定了Java方法與C++方法的對(duì)應(yīng)關(guān)系:
static const JNINativeMethod gBinderMethods[] = {{ "getCallingPid", "()I", (void*)android_os_Binder_getCallingPid },{ "getCallingUid", "()I", (void*)android_os_Binder_getCallingUid },{ "clearCallingIdentity", "()J", (void*)android_os_Binder_clearCallingIdentity },{ "restoreCallingIdentity", "(J)V", (void*)android_os_Binder_restoreCallingIdentity },{ "setThreadStrictModePolicy", "(I)V", (void*)android_os_Binder_setThreadStrictModePolicy },{ "getThreadStrictModePolicy", "()I", (void*)android_os_Binder_getThreadStrictModePolicy },{ "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },{ "init", "()V", (void*)android_os_Binder_init },{ "destroy", "()V", (void*)android_os_Binder_destroy },{ "blockUntilThreadAvailable", "()V", (void*)android_os_Binder_blockUntilThreadAvailable } };這種對(duì)應(yīng)關(guān)系意味著:當(dāng)Binder.java中的getCallingPid方法被調(diào)用的時(shí)候,真正的實(shí)現(xiàn)其實(shí)是android_os_Binder_getCallingPid,當(dāng)getCallingUid方法被調(diào)用的時(shí)候,真正的實(shí)現(xiàn)其實(shí)是android_os_Binder_getCallingUid,其他類同。
然后我們?cè)倏匆幌耡ndroid_os_Binder_getCallingPid方法的實(shí)現(xiàn)就會(huì)發(fā)現(xiàn),這里其實(shí)就是對(duì)接到了libbinder中了:
static jint android_os_Binder_getCallingPid(JNIEnv* env, jobject clazz) {return IPCThreadState::self()->getCallingPid(); }這里看到了Java端的代碼是如何調(diào)用的libbinder中的C++方法的。那么,相反的方向是如何調(diào)用的呢?最關(guān)鍵的,libbinder中的BBinder::onTransact是如何能夠調(diào)用到Java中的Binder::onTransact的呢?
這段邏輯就是android_util_Binder.cpp中JavaBBinder::onTransact中處理的了。JavaBBinder是BBinder子類,其類結(jié)構(gòu)如下:
JavaBBinder::onTransact關(guān)鍵代碼如下:
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) {JNIEnv* env = javavm_to_jnienv(mVM);IPCThreadState* thread_state = IPCThreadState::self();const int32_t strict_policy_before = thread_state->getStrictModePolicy();jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);... }請(qǐng)注意這段代碼中的這一行:
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);這一行代碼其實(shí)是在調(diào)用mObject上offset為mExecTransact的方法。這里的幾個(gè)參數(shù)說明如下:
- mObject 指向了Java端的Binder對(duì)象
- gBinderOffsets.mExecTransact 指向了Binder類的execTransact方法
- data 調(diào)用execTransact方法的參數(shù)
- code, data, reply, flags都是傳遞給調(diào)用方法execTransact的參數(shù)
而JNIEnv.CallBooleanMethod這個(gè)方法是由虛擬機(jī)實(shí)現(xiàn)的。即:虛擬機(jī)會(huì)提供native方法來調(diào)用一個(gè)Java Object上的方法(關(guān)于Android上的Java虛擬機(jī),今后我們會(huì)專門講解)。
這樣,就在C++層的JavaBBinder::onTransact中調(diào)用了Java層Binder::execTransact方法。而在Binder::execTransact方法中,又調(diào)用了自身的onTransact方法,由此保證整個(gè)過程串聯(lián)了起來:
private boolean execTransact(int code, long dataObj, long replyObj,int flags) {Parcel data = Parcel.obtain(dataObj);Parcel reply = Parcel.obtain(replyObj);boolean res;try {res = onTransact(code, data, reply, flags);} catch (RemoteException|RuntimeException e) {if (LOG_RUNTIME_EXCEPTION) {Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);}if ((flags & FLAG_ONEWAY) != 0) {if (e instanceof RemoteException) {Log.w(TAG, "Binder call failed.", e);} else {Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);}} else {reply.setDataPosition(0);reply.writeException(e);}res = true;} catch (OutOfMemoryError e) {RuntimeException re = new RuntimeException("Out of memory", e);reply.setDataPosition(0);reply.writeException(re);res = true;}checkParcel(this, code, reply, "Unreasonably large binder reply buffer");reply.recycle();data.recycle();StrictMode.clearGatheredViolations();return res; }Java Binder服務(wù)舉例
和C++層一樣,這里我們還是通過一個(gè)具體的實(shí)例來看一下Java層的Binder服務(wù)是如何實(shí)現(xiàn)的。
下圖是ActivityManager實(shí)現(xiàn)的類圖:
下面是上圖中幾個(gè)類的說明:
| IActivityManager | Binder服務(wù)的公共接口 |
| ActivityManagerProxy | 供客戶端調(diào)用的遠(yuǎn)程接口 |
| ActivityManagerNative | Binder服務(wù)實(shí)現(xiàn)的基類 |
| ActivityManagerService | Binder服務(wù)的真正實(shí)現(xiàn) |
看過Binder C++層實(shí)現(xiàn)之后,對(duì)于這個(gè)結(jié)構(gòu)應(yīng)該也是很容易理解的,組織結(jié)構(gòu)和C++層服務(wù)的實(shí)現(xiàn)是一模一樣的。
對(duì)于Android應(yīng)用程序的開發(fā)者來說,我們不會(huì)直接接觸到上圖中的幾個(gè)類,而是使用android.app.ActivityManager中的接口。
這里我們就來看一下,android.app.ActivityManager中的接口與上圖的實(shí)現(xiàn)是什么關(guān)系。我們選取其中的一個(gè)方法來看一下:
public void getMemoryInfo(MemoryInfo outInfo) {try {ActivityManagerNative.getDefault().getMemoryInfo(outInfo);} catch (RemoteException e) {throw e.rethrowFromSystemServer();} }這個(gè)方法的實(shí)現(xiàn)調(diào)用了ActivityManagerNative.getDefault()中的方法,因此我們?cè)趤砜匆幌翧ctivityManagerNative.getDefault()返回到到底是什么。
static public IActivityManager getDefault() {return gDefault.get(); }private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {protected IActivityManager create() {IBinder b = ServiceManager.getService("activity");if (false) {Log.v("ActivityManager", "default service binder = " + b);}IActivityManager am = asInterface(b);if (false) {Log.v("ActivityManager", "default service = " + am);}return am;} };這段代碼中我們看到,這里其實(shí)是先通過IBinder b = ServiceManager.getService("activity");?獲取ActivityManager的Binder對(duì)象(“activity”是ActivityManagerService的Binder服務(wù)標(biāo)識(shí)),接著我們?cè)賮砜匆幌耡sInterface(b)的實(shí)現(xiàn):
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); }這里應(yīng)該是比較明白了:首先通過queryLocalInterface確定有沒有本地Binder,如果有的話直接返回,否則創(chuàng)建一個(gè)ActivityManagerProxy對(duì)象。很顯然,假設(shè)在ActivityManagerService所在的進(jìn)程調(diào)用這個(gè)方法,那么queryLocalInterface將直接返回本地Binder,而假設(shè)在其他進(jìn)程中調(diào)用,這個(gè)方法將返回空,由此導(dǎo)致其他調(diào)用獲取到的對(duì)象其實(shí)就是ActivityManagerProxy。而在拿到ActivityManagerProxy對(duì)象之后在調(diào)用其方法所走的路線我想讀者應(yīng)該也能明白了:那就是通過Binder驅(qū)動(dòng)跨進(jìn)程調(diào)用ActivityManagerService中的方法。
這里的asInterface方法的實(shí)現(xiàn)會(huì)讓我們覺得似曾相識(shí)。是的,因?yàn)檫@里的實(shí)現(xiàn)方式和C++層的實(shí)現(xiàn)是一樣的模式。
Java層的ServiceManager
源碼路徑:
frameworks/base/core/java/android/os/IServiceManager.java frameworks/base/core/java/android/os/ServiceManager.java frameworks/base/core/java/android/os/ServiceManagerNative.java frameworks/base/core/java/com/android/internal/os/BinderInternal.java frameworks/base/core/jni/android_util_Binder.cpp有Java端的Binder服務(wù),自然也少不了Java端的ServiceManager。我們先看一下Java端的ServiceManager的結(jié)構(gòu):
通過這個(gè)類圖我們看到,Java層的ServiceManager和C++層的接口是一樣的。
然后我們?cè)龠x取addService方法看一下實(shí)現(xiàn):
public static void addService(String name, IBinder service, boolean allowIsolated) {try {getIServiceManager().addService(name, service, allowIsolated);} catch (RemoteException e) {Log.e(TAG, "error in addService", e);} }private static IServiceManager getIServiceManager() {if (sServiceManager != null) {return sServiceManager;}// Find the service managersServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());return sServiceManager; }很顯然,這段代碼中,最關(guān)鍵就是下面這個(gè)調(diào)用:
ServiceManagerNative.asInterface(BinderInternal.getContextObject());然后我們需要再看一下BinderInternal.getContextObject()和ServiceManagerNative.asInterface兩個(gè)方法。
BinderInternal.getContextObject()是一個(gè)JNI方法,其實(shí)現(xiàn)代碼在android_util_Binder.cpp中:
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz) {sp<IBinder> b = ProcessState::self()->getContextObject(NULL);return javaObjectForIBinder(env, b); }而ServiceManagerNative.asInterface的實(shí)現(xiàn)和其他的Binder服務(wù)是一樣的套路:
static public IServiceManager asInterface(IBinder obj) {if (obj == null) {return null;}IServiceManager in =(IServiceManager)obj.queryLocalInterface(descriptor);if (in != null) {return in;}return new ServiceManagerProxy(obj); }先通過queryLocalInterface查看能不能獲得本地Binder,如果無法獲取,則創(chuàng)建并返回ServiceManagerProxy對(duì)象。
而ServiceManagerProxy自然也是和其他Binder Proxy一樣的實(shí)現(xiàn)套路:
public void addService(String name, IBinder service, boolean allowIsolated)throws RemoteException {Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IServiceManager.descriptor);data.writeString(name);data.writeStrongBinder(service);data.writeInt(allowIsolated ? 1 : 0);mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);reply.recycle();data.recycle(); }有了上文的講解,這段代碼應(yīng)該都是比較容易理解的了。
關(guān)于AIDL
作為Binder機(jī)制的最后一個(gè)部分內(nèi)容,我們來講解一下開發(fā)者經(jīng)常使用的AIDL機(jī)制是怎么回事。
AIDL全稱是Android Interface Definition Language,它是Android SDK提供的一種機(jī)制。借助這個(gè)機(jī)制,應(yīng)用可以提供跨進(jìn)程的服務(wù)供其他應(yīng)用使用。AIDL的詳細(xì)說明可以參見官方開發(fā)文檔:https://developer.android.com/guide/components/aidl.html 。
這里,我們就以官方文檔上的例子看來一下AIDL與Binder框架的關(guān)系。
開發(fā)一個(gè)基于AIDL的Service需要三個(gè)步驟:
aidl文件使用Java語言的語法來定義,每個(gè).aidl文件只能包含一個(gè)interface,并且要包含interface的所有方法聲明。
默認(rèn)情況下,AIDL支持的數(shù)據(jù)類型包括:
- 基本數(shù)據(jù)類型(即int,long,char,boolean等)
- String
- CharSequence
- List(List的元素類型必須是AIDL支持的)
- Map(Map中的元素必須是AIDL支持的)
對(duì)于AIDL中的接口,可以包含0個(gè)或多個(gè)參數(shù),可以返回void或一個(gè)值。所有非基本類型的參數(shù)必須包含一個(gè)描述是數(shù)據(jù)流向的標(biāo)簽,可能的取值是:in,out或者inout。
下面是一個(gè)aidl文件的示例:
// IRemoteService.aidl package com.example.android;// Declare any non-default types here with import statements/** Example service interface */ interface IRemoteService {/** Request the process ID of this service, to do evil things with it. */int getPid();/** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,double aDouble, String aString); }這個(gè)文件中包含了兩個(gè)接口 :
- getPid 一個(gè)無參的接口,返回值類型為int
- basicTypes,包含了幾個(gè)基本類型作為參數(shù)的接口,無返回值
對(duì)于包含.aidl文件的工程,Android IDE(以前是Eclipse,現(xiàn)在是Android Studio)在編譯項(xiàng)目的時(shí)候,會(huì)為aidl文件生成對(duì)應(yīng)的Java文件。
針對(duì)上面這個(gè)aidl文件生成的java文件中包含的結(jié)構(gòu)如下圖所示:
在這個(gè)生成的Java文件中,包括了:
- 一個(gè)名稱為IRemoteService的interface,該interface繼承自android.os.IInterface并且包含了我們?cè)赼idl文件中聲明的接口方法
- IRemoteService中包含了一個(gè)名稱為Stub的靜態(tài)內(nèi)部類,這個(gè)類是一個(gè)抽象類,它繼承自android.os.Binder并且實(shí)現(xiàn)了IRemoteService接口。這個(gè)類中包含了一個(gè)onTransact方法
- Stub內(nèi)部又包含了一個(gè)名稱為Proxy的靜態(tài)內(nèi)部類,Proxy類同樣實(shí)現(xiàn)了IRemoteService接口
仔細(xì)看一下Stub類和Proxy兩個(gè)中包含的方法,是不是覺得很熟悉?是的,這里和前面介紹的服務(wù)實(shí)現(xiàn)是一樣的模式。這里我們列一下各層類的對(duì)應(yīng)關(guān)系:
| BpXXX | XXXProxy | IXXX.Stub.Proxy |
| BnXXX | XXXNative | IXXX.Stub |
為了整個(gè)結(jié)構(gòu)的完整性,最后我們還是來看一下生成的Stub和Proxy類中的實(shí)現(xiàn)邏輯。
Stub是提供給開發(fā)者實(shí)現(xiàn)業(yè)務(wù)的父類,而Proxy的實(shí)現(xiàn)了對(duì)外提供的接口。Stub和Proxy兩個(gè)類都有一個(gè)asBinder的方法。
Stub類中的asBinder實(shí)現(xiàn)就是返回自身對(duì)象:
@Override public android.os.IBinder asBinder() {return this; }而Proxy中asBinder的實(shí)現(xiàn)是返回構(gòu)造函數(shù)中獲取的mRemote對(duì)象,相關(guān)代碼如下:
private android.os.IBinder mRemote;Proxy(android.os.IBinder remote) {mRemote = remote; }@Override public android.os.IBinder asBinder() {return mRemote; }而這里的mRemote對(duì)象其實(shí)就是遠(yuǎn)程服務(wù)在當(dāng)前進(jìn)程的標(biāo)識(shí)。
上文我們說了,Stub類是用來提供給開發(fā)者實(shí)現(xiàn)業(yè)務(wù)邏輯的父類,開發(fā)者者繼承自Stub然后完成自己的業(yè)務(wù)邏輯實(shí)現(xiàn),例如這樣:
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {public int getPid(){return Process.myPid();}public void basicTypes(int anInt, long aLong, boolean aBoolean,float aFloat, double aDouble, String aString) {// Does something} };而這個(gè)Proxy類,就是用來給調(diào)用者使用的對(duì)外接口。我們可以看一下Proxy中的接口到底是如何實(shí)現(xiàn)的:
Proxy中g(shù)etPid方法實(shí)現(xiàn)如下所示:
@Override public int getPid() throws android.os.RemoteException {android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();int _result;try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_getPid, _data, _reply, 0);_reply.readException();_result = _reply.readInt();} finally {_reply.recycle();_data.recycle();}return _result; }這里就是通過Parcel對(duì)象以及transact調(diào)用對(duì)應(yīng)遠(yuǎn)程服務(wù)的接口。而在Stub類中,生成的onTransact方法對(duì)應(yīng)的處理了這里的請(qǐng)求:
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)throws android.os.RemoteException {switch (code) {case INTERFACE_TRANSACTION: {reply.writeString(DESCRIPTOR);return true;}case TRANSACTION_getPid: {data.enforceInterface(DESCRIPTOR);int _result = this.getPid();reply.writeNoException();reply.writeInt(_result);return true;}case TRANSACTION_basicTypes: {data.enforceInterface(DESCRIPTOR);int _arg0;_arg0 = data.readInt();long _arg1;_arg1 = data.readLong();boolean _arg2;_arg2 = (0 != data.readInt());float _arg3;_arg3 = data.readFloat();double _arg4;_arg4 = data.readDouble();java.lang.String _arg5;_arg5 = data.readString();this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);reply.writeNoException();return true;}}return super.onTransact(code, data, reply, flags); }onTransact所要做的就是:
有了前文的講解,對(duì)于這部分內(nèi)容應(yīng)當(dāng)不難理解了。
到這里,我們終于講解完Binder了。
恭喜你,已經(jīng)掌握了Android系統(tǒng)最復(fù)雜的模塊,的其中之一了 :)
– 以上 –
參考資料和推薦讀物
- Android Binder
- Android Interface Definition Language
- Android Bander設(shè)計(jì)與實(shí)現(xiàn) - 設(shè)計(jì)篇
- Binder系列—開篇
- 徹底理解Android Binder通信架構(gòu)
- binder驅(qū)動(dòng)——-之內(nèi)存映射篇
- Android Binder機(jī)制(一) Binder的設(shè)計(jì)和框架
- Android Binder 分析——內(nèi)存管理
原文:?http://qiangbo.space/2017-03-15/AndroidAnatomy_Binder_Java/
總結(jié)
以上是生活随笔為你收集整理的理解Android Binder机制(3/3):Java层的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 理解Android Binder机制(1
- 下一篇: Github 优秀开源项目 Best O