3C科技 娛樂遊戲 美食旅遊 時尚美妝 親子育兒 生活休閒 金融理財 健康運動 寰宇綜合

Zi 字媒體

2017-07-25T20:27:27+00:00
加入好友
主要結構Android應用程序使用Java語言開發,Binder框架自然也少不了在Java層提供介面。前文中我們看到,Binder機制在C++層已經有了完整的實現。因此Java層完全不用重複實現,而是通過JNI銜接了C++層以復用其實現。下圖描述了Binder Framework Java層到C++層的銜接關係。這裡對圖中Java層和JNI層的幾個類做一下說明( 關於C++層的講解請看這裡 ): 這裡的IInterface,IBinder和C++層的兩個類是同名的。這個同名並不是巧合:它們不僅僅同名,它們所起的作用,以及其中包含的介面都是幾乎一樣的,區別僅僅在於一個是C++層,一個是Java層而已。除了IInterface,IBinder之外,這裡Binder與BinderProxy類也是與C++的類對應的,下面列出了Java層和C++層類的對應關係: 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,(&data), reinterpret_cast 請注意這段代碼中的這一行:jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact, 這一行代碼其實是在調用mObject上offset為mExecTransact的方法。這裡的幾個參數說明如下:1.mObject 指向了Java端的Binder對象 2.gBinderOffsets.mExecTransact 指向了Binder類的execTransact方法 3.data 調用execTransact方法的參數 4.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 { } } else { reply.setDataPosition(0); reply.writeException(e); } res = true; } catch (OutOfMemoryError e) { RuntimeException re = new RuntimeException("Out of memory", e); 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實現的類圖:下面是上圖中幾個類的說明: 看過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 SingletongDefault = new Singleton{ 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.javaframeworks/base/core/java/android/os/ServiceManager.javaframeworks/base/core/java/android/os/ServiceManagerNative.javaframeworks/base/core/java/com/android/internal/os/BinderInternal.javaframeworks/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); } 很顯然,這段代碼中,最關鍵就是下面這個調用:ServiceManagerNative.asInterface(BinderInternal.getContextObject); 然後我們需要再看一下BinderInternal.getContextObject和ServiceManagerNative.asInterface兩個方法。BinderInternal.getContextObject是一個JNI方法,其實現代碼在android_util_Binder.cpp中: 而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需要三個步驟:1.定義一個.aidl文件 2.實現介面 3.暴露介面給客戶端使用 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.aidlpackage 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兩個中包含的方法,是不是覺得很熟悉?是的,這裡和前面介紹的服務實現是一樣的模式。這裡我們列一下各層類的對應關係: 為了整個結構的完整性,最後我們還是來看一下生成的Stub和Proxy類中的實現邏輯。Stub是提供給開發者實現業務的父類,而Proxy的實現了對外提供的介面。Stub和Proxy兩個類都有一個asBinder的方法。 而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方法實現如下所示:@Overridepublic 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方法對應的處理了這裡的請求:@Overridepublic 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: { 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); return true; } } return super.onTransact(code, data, reply, flags);} onTransact所要做的就是:1.根據code區分請求的是哪個介面 2.通過data來獲取請求的參數 3.調用由子類實現的抽象方法

本文由yidianzixun提供 原文連結

寫了 5860316篇文章,獲得 23313次喜歡
精彩推薦