理解 Android Binder 機制(三):Java層
本文是Android Binder機制解析的第三篇,也是最後一篇文章。本文會講解Binder Framework Java部分的邏輯。
Binder機制分析的前面兩篇文章,請移步這裡:
下文所講內容的相關原始碼,在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
主要結構
Android應用程式使用Java語言開發,Binder框架自然也少不了在Java層提供介面。
前文中我們看到,Binder機制在C++層已經有了完整的實現。因此Java層完全不用重複實現,而是通過JNI銜接了C++層以複用其實現。
下圖描述了Binder Framework Java層到C++層的銜接關係。
這裡對圖中Java層和JNI層的幾個類做一下說明( 關於C++層的講解請看這裡 ):
名稱 | 型別 | 說明 |
---|---|---|
IInterface | interface | 供Java層Binder服務介面繼承的介面 |
IBinder | interface | Java層的IBinder類,提供了transact方法來呼叫遠端服務 |
Binder | class | 實現了IBinder介面,封裝了JNI的實現。Java層Binder服務的基類 |
BinderProxy | class | 實現了IBinder介面,封裝了JNI的實現。提供transact方法呼叫遠端服務 |
JavaBBinderHolder | class | 內部儲存了JavaBBinder |
JavaBBinder | class | 將C++端的onTransact呼叫傳遞到Java端 |
Parcel | class | Java層的資料包裝器,見C++層的Parcel類分析 |
這裡的IInterface,IBinder和C++層的兩個類是同名的。這個同名並不是巧合:它們不僅僅同名,它們所起的作用,以及其中包含的介面都是幾乎一樣的,區別僅僅在於一個是C++層,一個是Java層而已。
除了IInterface,IBinder之外,這裡Binder與BinderProxy類也是與C++的類對應的,下面列出了Java層和C++層類的對應關係:
C++ | Java層 |
---|---|
IInterface | IInterface |
IBinder | IBinder |
BBinder | Binder |
BpProxy | BinderProxy |
Parcel | Parcel |
JNI的銜接
JNI全稱是Java Native Interface,這個是由Java虛擬機器提供的機制。這個機制使得native程式碼可以和Java程式碼互相通訊。簡單來說就是:我們可以在C/C++端呼叫Java程式碼,也可以在Java端呼叫C/C++程式碼。
關於JNI的詳細說明,可以參見Oracle的官方文件:Java Native Interface ,這裡不多說明。
實際上,在Android中很多的服務或者機制都是在C/C++層實現的,想要將這些實現複用到Java層,就必須通過JNI進行銜接。AOSP原始碼中,/frameworks/base/core/jni/ 目錄下的原始碼就是專門用來對接Framework層的JNI實現的。
看一下Binder.java的實現就會發現,這裡面有不少的方法都是用native
關鍵字修飾的,並且沒有方法實現體,這些方法其實都是在C++中實現的:
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檔案中的下面這段程式碼,設定了Java方法與C++方法的對應關係:
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 } };
這種對應關係意味著:當Binder.java中的getCallingPid
方法被呼叫的時候,真正的實現其實是android_os_Binder_getCallingPid
,當getCallingUid
方法被呼叫的時候,真正的實現其實是android_os_Binder_getCallingUid
,其他類同。
然後我們再看一下android_os_Binder_getCallingPid
方法的實現就會發現,這裡其實就是對接到了libbinder中了:
static jint android_os_Binder_getCallingPid(JNIEnv* env, jobject clazz) { return IPCThreadState::self()->getCallingPid(); }
這裡看到了Java端的程式碼是如何呼叫的libbinder中的C++方法的。那麼,相反的方向是如何呼叫的呢?最關鍵的,libbinder中的BBinder::onTransact
是如何能夠呼叫到Java中的Binder::onTransact
的呢?
這段邏輯就是android_util_Binder.cpp中JavaBBinder::onTransact
中處理的了。JavaBBinder是BBinder子類,其類結構如下:
JavaBBinder::onTransact
關鍵程式碼如下:
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); ... }
請注意這段程式碼中的這一行:
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact, code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
這一行程式碼其實是在呼叫mObject上offset為mExecTransact的方法。這裡的幾個引數說明如下:
- mObject 指向了Java端的Binder物件
- gBinderOffsets.mExecTransact 指向了Binder類的execTransact方法
- data 呼叫execTransact方法的引數
- code, data, reply, flags都是傳遞給呼叫方法execTransact的引數
而JNIEnv.CallBooleanMethod
這個方法是由虛擬機器實現的。即:虛擬機器會提供native方法來呼叫一個Java Object上的方法(關於Android上的Java虛擬機器,今後我們會專門講解)。
這樣,就在C++層的JavaBBinder::onTransact
中呼叫了Java層Binder::execTransact
方法。而在Binder::execTransact
方法中,又呼叫了自身的onTransact方法,由此保證整個過程串聯了起來:
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服務舉例
和C++層一樣,這裡我們還是通過一個具體的例項來看一下Java層的Binder服務是如何實現的。
下圖是ActivityManager實現的類圖:
下面是上圖中幾個類的說明:
類名 | 說明 |
---|---|
IActivityManager | Binder服務的公共介面 |
ActivityManagerProxy | 供客戶端呼叫的遠端介面 |
ActivityManagerNative | Binder服務實現的基類 |
ActivityManagerService | Binder服務的真正實現 |
看過Binder C++層實現之後,對於這個結構應該也是很容易理解的,組織結構和C++層服務的實現是一模一樣的。
對於Android應用程式的開發者來說,我們不會直接接觸到上圖中的幾個類,而是使用android.app.ActivityManager
中的介面。
這裡我們就來看一下,android.app.ActivityManager
中的介面與上圖的實現是什麼關係。我們選取其中的一個方法來看一下:
public void getMemoryInfo(MemoryInfo outInfo) { try { ActivityManagerNative.getDefault().getMemoryInfo(outInfo); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
這個方法的實現呼叫了ActivityManagerNative.getDefault()
中的方法,因此我們在來看一下ActivityManagerNative.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; } };
這段程式碼中我們看到,這裡其實是先通過IBinder b = ServiceManager.getService("activity");
獲取ActivityManager的Binder物件(“activity”是ActivityManagerService的Binder服務標識),接著我們再來看一下asInterface(b)
的實現:
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); }
這裡應該是比較明白了:首先通過queryLocalInterface
確定有沒有本地Binder,如果有的話直接返回,否則建立一個ActivityManagerProxy
物件。很顯然,假設在ActivityManagerService所在的程式呼叫這個方法,那麼queryLocalInterface
將直接返回本地Binder,而假設在其他程式中呼叫,這個方法將返回空,由此導致其他呼叫獲取到的物件其實就是ActivityManagerProxy
。而在拿到ActivityManagerProxy
物件之後在呼叫其方法所走的路線我想讀者應該也能明白了:那就是通過Binder驅動跨程式呼叫ActivityManagerService中的方法。
這裡的asInterface
方法的實現會讓我們覺得似曾相識。是的,因為這裡的實現方式和C++層的實現是一樣的模式。
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服務,自然也少不了Java端的ServiceManager。我們先看一下Java端的ServiceManager的結構:
通過這個類圖我們看到,Java層的ServiceManager和C++層的介面是一樣的。
然後我們再選取addService
方法看一下實現:
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 manager sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject()); return sServiceManager; }
很顯然,這段程式碼中,最關鍵就是下面這個呼叫:
ServiceManagerNative.asInterface(BinderInternal.getContextObject());
然後我們需要再看一下BinderInternal.getContextObject()和ServiceManagerNative.asInterface兩個方法。
BinderInternal.getContextObject()是一個JNI方法,其實現程式碼在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的實現和其他的Binder服務是一樣的套路:
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,如果無法獲取,則建立並返回ServiceManagerProxy物件。
而ServiceManagerProxy自然也是和其他Binder Proxy一樣的實現套路:
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(); }
有了上文的講解,這段程式碼應該都是比較容易理解的了。
關於AIDL
作為Binder機制的最後一個部分內容,我們來講解一下開發者經常使用的AIDL機制是怎麼回事。
AIDL全稱是Android Interface Definition Language,它是Android SDK提供的一種機制。藉助這個機制,應用可以提供跨程式的服務供其他應用使用。AIDL的詳細說明可以參見官方開發文件:https://developer.android.com/guide/components/aidl.html 。
這裡,我們就以官方文件上的例子看來一下AIDL與Binder框架的關係。
開發一個基於AIDL的Service需要三個步驟:
- 定義一個.aidl檔案
- 實現介面
- 暴露介面給客戶端使用
aidl檔案使用Java語言的語法來定義,每個.aidl檔案只能包含一個interface,並且要包含interface的所有方法宣告。
預設情況下,AIDL支援的資料型別包括:
- 基本資料型別(即int,long,char,boolean等)
- String
- CharSequence
- List(List的元素型別必須是AIDL支援的)
- Map(Map中的元素必須是AIDL支援的)
對於AIDL中的介面,可以包含0個或多個引數,可以返回void或一個值。所有非基本型別的引數必須包含一個描述是資料流向的標籤,可能的取值是:in
,out
或者inout
。
下面是一個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); }
這個檔案中包含了兩個介面 :
- getPid 一個無參的介面,返回值型別為int
- basicTypes,包含了幾個基本型別作為引數的介面,無返回值
對於包含.aidl檔案的工程,Android IDE(以前是Eclipse,現在是Android Studio)在編譯專案的時候,會為aidl檔案生成對應的Java檔案。
針對上面這個aidl檔案生成的java檔案中包含的結構如下圖所示:
在這個生成的Java檔案中,包括了:
- 一個名稱為IRemoteService的interface,該interface繼承自android.os.IInterface並且包含了我們在aidl檔案中宣告的介面方法
- IRemoteService中包含了一個名稱為Stub的靜態內部類,這個類是一個抽象類,它繼承自android.os.Binder並且實現了IRemoteService介面。這個類中包含了一個
onTransact
方法 - Stub內部又包含了一個名稱為Proxy的靜態內部類,Proxy類同樣實現了IRemoteService介面
仔細看一下Stub類和Proxy兩個中包含的方法,是不是覺得很熟悉?是的,這裡和前面介紹的服務實現是一樣的模式。這裡我們列一下各層類的對應關係:
C++ | Java層 | AIDL |
---|---|---|
BpXXX | XXXProxy | IXXX.Stub.Proxy |
BnXXX | XXXNative | IXXX.Stub |
為了整個結構的完整性,最後我們還是來看一下生成的Stub和Proxy類中的實現邏輯。
Stub是提供給開發者實現業務的父類,而Proxy的實現了對外提供的介面。Stub和Proxy兩個類都有一個asBinder
的方法。
Stub類中的asBinder實現就是返回自身物件:
@Override public android.os.IBinder asBinder() { return this; }
而Proxy中asBinder的實現是返回建構函式中獲取的mRemote物件,相關程式碼如下:
private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; }
而這裡的mRemote物件其實就是遠端服務在當前程式的標識。
上文我們說了,Stub類是用來提供給開發者實現業務邏輯的父類,開發者者繼承自Stub然後完成自己的業務邏輯實現,例如這樣:
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 } };
而這個Proxy類,就是用來給呼叫者使用的對外介面。我們可以看一下Proxy中的介面到底是如何實現的:
Proxy中getPid
方法實現如下所示:
@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物件以及transact呼叫對應遠端服務的介面。而在Stub類中,生成的onTransact方法對應的處理了這裡的請求:
@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
所要做的就是:
- 根據code區分請求的是哪個介面
- 通過data來獲取請求的引數
- 呼叫由子類實現的抽象方法
有了前文的講解,對於這部分內容應當不難理解了。
到這裡,我們終於講解完Binder了。
恭喜你,已經掌握了Android系統最複雜的模組,的其中之一了 :)
– 以上 –
參考資料和推薦讀物
- Android Binder
- Android Interface Definition Language
- Android Bander設計與實現 – 設計篇
- Binder系列—開篇
- 徹底理解Android Binder通訊架構
- binder驅動——-之記憶體對映篇
- Android Binder機制(一) Binder的設計和框架
- Android Binder 分析——記憶體管理
相關文章
- 理解 Android Binder 機制(二):C++層AndroidC++
- 理解 Android Binder 機制(一):驅動篇Android
- 藉助 AIDL 理解 Android Binder 機制——Binder 來龍去脈AIAndroid
- Android IPC機制(三):淺談Binder的使用Android
- Android的IPC機制(三)——Binder連線池Android
- Android Binder機制淺析Android
- Android的IPC機制BinderAndroid
- Android外掛化原理解析——Hook機制之Binder HookAndroidHook
- Android進階(六)Binder機制Android
- android Binder機制深入淺出Android
- Android Binder機制文章轉載Android
- Binder機制
- Binder Java層分析Java
- Android 外掛化原理解析(3):Hook 機制之 Binder HookAndroidHook
- 圖解Android中的binder機制圖解Android
- Android系統之Binder通訊機制Android
- Binder學習(二)Binder機制解析
- 藉助 AIDL 理解 Android Binder 機制——AIDL 的使用和原理分析AIAndroid
- Java 底層機制Java
- Binder通訊機制
- Android訊息機制,從Java層到Native層剖析AndroidJava
- 【Android原始碼】Binder機制和AIDL分析Android原始碼AI
- 由淺入深 學習 Android Binder(三)- java binder深究(從java到native)AndroidJava
- Binder機制分析(1)——Binder結構簡介
- Android Handler機制理解Android
- 理解Android安全機制Android
- 3分鐘帶你看懂android的Binder機制Android
- Android 系統原始碼-2:Binder 通訊機制Android原始碼
- Binder機制之AIDLAI
- 理解 Java 垃圾回收機制Java
- 理解 Android 訊息機制Android
- Binder Java層的實現原理分析Java
- Android系統服務編寫例項-Binder(Java層AIDL)AndroidJavaAI
- 全面理解 Android 安全機制(Android Permission)Android
- Android Binder實現示例(C/C++層)AndroidC++
- 理解的Java中SPI機制Java
- Java 中 Varargs 機制的理解Java
- Android 深入理解 Notification 機制Android