? ? ? ??一 .基于源碼分析Binder機制:
????? Binder機制是Android系統中實現跨進程通信(IPC)的一種重要機制。可以說,Binder機制在android系統中無處不在,所以,要研究android源碼,學好Binder機制極其重要。
?? 在學習Binder機制之前,我們先試著摸索一下系統中一些相關的涉及到Binder機制的代碼。
?? 首先,先看看SystemServer.java這個文件(基于android4.0源代碼),該文件位于源碼路徑frameworks\base\services\java\com\android\server\SystemServer.java 中,這個文件中有兩個類,一個是SystemServer 類(public),一個是線程類ServerThread。
??SystemServer 類的main函數中會先調用函數init1(),代碼如下:
[java] ?view plaincopy
public ? class ?SystemServer?{?? ??....?? ??public ? static ? void ?main(String[]?args)?{?? ???....?? ???init1(args);?? }?? ??....?? }?? ??init1()是native函數,它的定義為native public static void init1(String[] args); 它的內部會進行一些與Dalvik虛擬機相關的初始化工作,執行完初始化工作后,其內部會調用java端的SystemServer 類的init2()函數。
?? 而SystemServer 類中的init2()函數的實現代碼如下:
[java] ?view plaincopy
public ? static ? final ? void ?init2()?{?? ????Slog.i(TAG,?"Entered?the?Android?system?server!" );?? ????Thread?thr?=?new ?ServerThread();?? ????thr.setName("android.server.ServerThread" );?? ????thr.start();?? }?? ??? 該函數實現創建和啟動ServerThread 線程。
我們再來看看ServerThread 線程 類的run()方法中的部分代碼,如下:
[java] ?view plaincopy
class ?ServerThread? extends ?Thread?{?? ????....?? ????@Override ?? ????public ? void ?run()?{?? ????????....?? ?????????? ????????try ?{?? ??????????????Slog.i(TAG,?"Entropy?Service" );?? ??????????????ServiceManager.addService("entropy" ,? new ?EntropyService());?? ??????????????Slog.i(TAG,?"Power?Manager" );?? ??????????????power?=?new ?PowerManagerService();?? ??????????????ServiceManager.addService(Context.POWER_SERVICE,?power);?? ??????????????....?? ??????????????Slog.i(TAG,?"Telephony?Registry" );?? ??????????????ServiceManager.addService("telephony.registry" ,? new ?TelephonyRegistry(context));?? ??????????????....?? ?????????????? ????????}????? ????}?? }?? 在該線程類的run()函數中,很多的try{}代碼塊里,有如上類似的代碼,它創建一個服務類,然后將初始化的服務類作為參數傳進ServiceManager的addService函數中。也就是說,在frameworks\base\services\java\com\android\server 源碼路徑里的服務類基本上都是在這里啟動的。
??? 而且這些服務類,一般都是繼承于“I服務類名.Stub”(如IVibratorService.Stub,但有些繼承Binder),I服務類名(如IVibratorService)是由aidl文件自動生成的。要想看系統中這些aidl文件生成的類(編譯生成),可以在編譯后的源碼中,out文件目錄下查找。比如,我要找IVibratorService.aidl生成的java文件:進入out目錄,在Linux終端輸入命令:find -name “IVibratorService.java”。這樣就可以找到該類了。
???我們再來看看ServiceManager這個類(源碼所在路徑\frameworks\base\core\java\android\os\ServiceManager.java ):
[java] ?view plaincopy
?? public ? final ? class ?ServiceManager?{?? ????private ? static ? final ?String?TAG?=? "ServiceManager" ;?? ?? ????private ? static ?IServiceManager?sServiceManager;?? ????private ? static ?HashMap<String,?IBinder>?sCache?=? new ?HashMap<String,?IBinder>();?? ?? ????private ? static ?IServiceManager?getIServiceManager()?{?? ????????if ?(sServiceManager?!=? null )?{?? ????????????return ?sServiceManager;?? ????????}?? ?? ?????????? ????????sServiceManager?=?ServiceManagerNative.asInterface(BinderInternal.getContextObject());?? ????????return ?sServiceManager;?? ????}?? ?? ????? ? ? ? ? ?? ????public ? static ?IBinder?getService(String?name)?{?? ????????try ?{?? ????????????IBinder?service?=?sCache.get(name);?? ????????????if ?(service?!=? null )?{?? ????????????????return ?service;?? ????????????}?else ?{?? ????????????????return ?getIServiceManager().getService(name);?? ????????????}?? ????????}?catch ?(RemoteException?e)?{?? ????????????Log.e(TAG,?"error?in?getService" ,?e);?? ????????}?? ????????return ? null ;?? ????}?? ?? ????? ? ? ? ? ? ?? ????public ? static ? void ?addService(String?name,?IBinder?service)?{?? ????????try ?{?? ????????????getIServiceManager().addService(name,?service);?? ????????}?catch ?(RemoteException?e)?{?? ????????????Log.e(TAG,?"error?in?addService" ,?e);?? ????????}?? ????}?? ?????? ????? ? ? ?? ????public ? static ?IBinder?checkService(String?name)?{?? ????????try ?{?? ????????????IBinder?service?=?sCache.get(name);?? ????????????if ?(service?!=? null )?{?? ????????????????return ?service;?? ????????????}?else ?{?? ????????????????return ?getIServiceManager().checkService(name);?? ????????????}?? ????????}?catch ?(RemoteException?e)?{?? ????????????Log.e(TAG,?"error?in?checkService" ,?e);?? ????????????return ? null ;?? ????????}?? ????}?? ?? ????? ? ?? ????public ? static ?String[]?listServices()? throws ?RemoteException?{?? ????????try ?{?? ????????????return ?getIServiceManager().listServices();?? ????????}?catch ?(RemoteException?e)?{?? ????????????Log.e(TAG,?"error?in?listServices" ,?e);?? ????????????return ? null ;?? ????????}?? ????}?? ?? ????? ? ? ? ? ? ? ?? ????public ? static ? void ?initServiceCache(Map<String,?IBinder>?cache)?{?? ????????if ?(sCache.size()?!=? 0 )?{?? ????????????throw ? new ?IllegalStateException( "setServiceCache?may?only?be?called?once" );?? ????????}?? ????????sCache.putAll(cache);?? ????}?? }?? ???該類中提供一個getService(String name) 的靜態函數,參數name對應addService(String name, IBinder service) 函數的name。name參數在SystemServer啟動一個初始化的服務類,然后調用addService函數添加的時候指定(如ServiceManager.addService("entropy", new EntropyService()),name為“entropy”),那么當我們要在另外一個進程里(客戶端)獲取在SystemServer中啟動運行的服務*(服務端),就需要調用ServiceManager類的getService(String name)函數了 (如,我們要在客戶端獲取EntropyService服務對象,那么就需要調用ServiceManager.getService(“entropy”)),而通過getService獲取的是一個IBinder,接著再通過調用對應服務類的aidl文件生成的接口的內部類Stub的asInterface(iBinder)方法,(比如,IAccountManager mRemoteService = IAccountManager.Stub.asasInterface(iBinder)),參數iBinder就是通過getService(String name)獲取得到的對應的IBinder。這樣,客戶端就獲取得到遠程服務對象的代理,并不是服務類對象本身(具體后面會介紹)。
??? 但是,我們發現,ServiceManager這個類是隱藏的(/** @hide */),也就是說在android SDK中不提供該類的接口。如果在開發的第三方應用中需要調用該類,只能通過反射來調用。
?????二.注冊自定義的系統服務(Service類為客戶端服務):
??? 所謂的系統服務指可以使用getSystemService()方法獲取的服務,即Binder服務,由繼承Binder的類來實現。而我們開發第三方應用所常用的Service類服務為客戶端服務。
? ? 當然,如果我們有需求,需要系統中注冊運行一個自定義的系統服務,該服務在手機開機后執行一直運行著的工作(如,保存一些資源在該服務端,需要時,可以時刻獲取)。那么,通過上面的介紹,我們可以在SystemServer中注冊我們自己編寫的系統服務。比如:假如MyService是自己定義的需要注冊在SystemServer中的服務類,那么,我們可以在ServerThread類run函數中,try{}代碼塊添加如下代碼:?ServiceManager.addService("myservice", new MyService());
? ? 而這個我們自定義的MyService,我們該如何去實現它,已到達類似其他系統服務類的效果呢。通過上面的介紹,我們知道,系統服務類一般都繼承由aidl文件生成的一個類的內部類(Stub)。抱著好奇的心態,我們不妨也類試試寫一個IMyService的aidl文件,看看它生成的對應的java文件中的代碼實現。關于aidl文件的相關知識,可以去參考這篇博客: http://www.cnblogs.com/over140/archive/2011/03/08/1976890.html ;
? ? 下面的代碼是在eclipse下的一個android工程項目中,建一個名為IMyService的后綴名aidl文件,然后eclipse會自動在工程的gen目錄中生成的java代碼;
? ? ?IMyService.aidl文件中的定義:
? ? ?? ? ??interface IMyService ? ? ? ? ? { ?????????????String getName();
??????????????void setName(String name); ????????? }
? ? ? android工程gen目錄中生成的IMyService.java文件代碼:
[java] ?view plaincopy
? ? ? ?? ?? ?? ?? public ? interface ?IMyService? extends ?android.os.IInterface?{?? ?????? ?????? ????public ? static ? abstract ? class ?Stub? extends ?android.os.Binder? implements ?? ????????????IMyService?{?? ????????private ? static ? final ?java.lang.String?DESCRIPTOR?=? "IMyService" ;?? ?? ?????????? ????????public ?Stub()?{?? ????????????this .attachInterface( this ,?DESCRIPTOR);?? ????????}?? ?? ????????? ? ? ?? ????????? ? ?? ????????public ? static ?IMyService?asInterface(android.os.IBinder?obj)?{?? ????????????if ?((obj?==? null ))?{?? ????????????????return ? null ;?? ????????????}?? ????????????android.os.IInterface?iin?=?(android.os.IInterface)?obj?? ????????????????????.queryLocalInterface(DESCRIPTOR);?? ?????????????? ????????????if ?(((iin?!=? null )?&&?(iin? instanceof ?IMyService)))?{?? ????????????????return ?((IMyService)?iin);?? ????????????}?? ????????????? ? ?? ????????????return ? new ?IMyService.Stub.Proxy(obj);?? ????????}?? ?? ????????public ?android.os.IBinder?asBinder()?{?? ????????????return ? this ;?? ????????}?? ?? ????????? ? ? ? ? ? ?? ????????@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_getName:?{?? ?????????????????? ????????????????data.enforceInterface(DESCRIPTOR);?? ????????????????? ? ? ?? ????????????????java.lang.String?_result?=?this .getName();?? ????????????????reply.writeNoException();?? ?????????????????? ????????????????reply.writeString(_result);?? ????????????????return ? true ;?? ????????????}?? ????????????case ?TRANSACTION_setName:?{?? ????????????????data.enforceInterface(DESCRIPTOR);?? ????????????????java.lang.String?_arg0;?? ?????????????????? ????????????????_arg0?=?data.readString();?? ?????????????????? ????????????????this .setName(_arg0);?? ????????????????reply.writeNoException();?? ????????????????return ? true ;?? ????????????}?? ????????????}?? ????????????return ? super .onTransact(code,?data,?reply,?flags);?? ????????}?? ?? ?????????? ????????private ? static ? class ?Proxy? implements ?IMyService?{?? ?????????????? ????????????private ?android.os.IBinder?mRemote;?? ?? ????????????Proxy(android.os.IBinder?remote)?{?? ?????????????????? ????????????????mRemote?=?remote;?? ????????????}?? ?? ????????????public ?android.os.IBinder?asBinder()?{?? ????????????????return ?mRemote;?? ????????????}?? ?? ????????????public ?java.lang.String?getInterfaceDescriptor()?{?? ????????????????return ?DESCRIPTOR;?? ????????????}?? ?? ????????????public ?java.lang.String?getName()? throws ?android.os.RemoteException?{?? ?????????????????? ????????????????android.os.Parcel?_data?=?android.os.Parcel.obtain();?? ????????????????android.os.Parcel?_reply?=?android.os.Parcel.obtain();?? ????????????????java.lang.String?_result;?? ????????????????try ?{?? ?????????????????????? ????????????????????_data.writeInterfaceToken(DESCRIPTOR);?? ?????????????????????? ????????????????????mRemote.transact(Stub.TRANSACTION_getName,?_data,?_reply,?0 );?? ????????????????????_reply.readException();?? ?????????????????????? ????????????????????_result?=?_reply.readString();?? ????????????????}?finally ?{?? ????????????????????_reply.recycle();?? ????????????????????_data.recycle();?? ????????????????}?? ????????????????return ?_result;?? ????????????}?? ?? ????????????public ? void ?setName(java.lang.String?name)?? ????????????????????throws ?android.os.RemoteException?{?? ????????????????android.os.Parcel?_data?=?android.os.Parcel.obtain();?? ????????????????android.os.Parcel?_reply?=?android.os.Parcel.obtain();?? ????????????????try ?{?? ????????????????????_data.writeInterfaceToken(DESCRIPTOR);?? ?????????????????????? ????????????????????_data.writeString(name);?? ?????????????????????? ????????????????????mRemote.transact(Stub.TRANSACTION_setName,?_data,?_reply,?0 );?? ????????????????????_reply.readException();?? ????????????????}?finally ?{?? ????????????????????_reply.recycle();?? ????????????????????_data.recycle();?? ????????????????}?? ????????????}?? ????????}?? ?? ????????static ? final ? int ?TRANSACTION_getName?=?(android.os.IBinder.FIRST_CALL_TRANSACTION?+? 0 );?? ????????static ? final ? int ?TRANSACTION_setName?=?(android.os.IBinder.FIRST_CALL_TRANSACTION?+? 1 );?? ????}?? ?? ????public ?java.lang.String?getName()? throws ?android.os.RemoteException;?? ?? ????public ? void ?setName(java.lang.String?name)?? ????????????throws ?android.os.RemoteException;?? }?? ???IMyService.java 文件解析: ?? 1.該接口是由自定義的IMyService.aidl文件 自動生成的,IMyService實現IInterface接口,IInterface提供一個asBinder()的方法聲明,返回值為IBinder。
??? 2.Stub類為IMyService接口的內部類,該內部類(一般稱為樁)繼承Biner,同時實現IMyService接口,也就說覆蓋asBinder()方法。該類主要由服務端來使用。
????3.Stub類中又有一個內部類Proxy(代理),該類就是實現跨進程訪問的重要類。客戶端跨進程獲取的代理對象就是Proxy。
????4.Proxy類中有一個mRemote,該mRemote為遠程服務在Binder對象中對應的引用,通過該引用實現與遠程服務的連接。
? aidl文件編寫完后,接下來就是實現功能代碼塊的系統服務類的編寫了,這里我們將該系統服務實現類命名為MyService,該類的實現代碼如下:
[java] ?view plaincopy
import ?android.os.RemoteException;?? ?? public ? class ?MyService? extends ?IMyService.Stub?? {?? ????private ?String?ServiceName;?? ?? ?????? ????@Override ?? ????public ?String?getName()? throws ?RemoteException??? ????{?? ?????????? ????????return ?ServiceName;?? ????}?? ?? ?????? ????@Override ?? ????public ? void ?setName(String?name)? throws ?RemoteException??? ????{?? ?????????? ????????ServiceName?=?name;?? ????}?? ?? }?? ?? 當然,自定義的系統服務類MyService中的函數,還可以通過調用一些native方法實現調用Android中間層的先關函數(JNI)。ok,系統服務類代碼編寫完后,接下來就是在ServerThread 線程中注冊該系統服務了,如下注冊代碼:
???ServiceManager.addService("myservice", new MyService());
?? 三.實現跨進程訪問自定義的系統服務
???系統服務類的創建和注冊已經完成,那么,該如何進行IPC調用呢。很顯然,通過前面對IMyService.java文件的介紹和解析,我們知道,重點在于IMyService.Stub的asInterfcace函數。比如,我們在另外一個進程中編寫一個MyServiceManager類來實現獲取遠程MyService服務,并實現調用相關的函數。代碼如下:
[java] ?view plaincopy
import ?android.os.IBinder;?? import ?android.os.ServiceManager;?? ?? public ? class ?MyServiceManager??? {?? ?? ????private ? static ?IMyService?mRemoteService;?? ?????? ????public ? static ?IMyService?getService()?? ????{?? ????????if (mRemoteService?==? null )?? ????????{?? ?????????????? ????????????IBinder?iBinder?=?ServiceManager.getService("myservice" );?? ????????????mRemoteService?=?IMyService.Stub.asInterface(iBinder);?? ????????}?? ????????return ?mRemoteService;?? ????}?? ?????? ????public ? static ?String?getName()?? ????{?? ????????getService().getName();?? ????}?? ?????? ????public ? static ?String?setName(String?name)?? ????{?? ????????getService().setName(name);?? ????}?? }?? 這樣,不同進程的客戶端就可以通過該類來實現與系統服務的連接和調用了。
注: 上面的相關類實現都是基于源碼環境開發的,而不是第三方開發。MyService.java,IMyService.java,MyServiceManager.java等文件是存放在源碼路徑frameworks\base\core\java\android\MyProject中,MyProject是自己創建的文件夾,編譯也都是在Linux環境下基于源碼編譯的。
原文地址:?http://blog.csdn.net/stevenhu_223/article/details/8541155
總結
以上是生活随笔 為你收集整理的Android Binder机制----实现自定义的系统服务 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。