編輯:關於Android編程
這篇博客不是為了分析Binder機制,只是我個人學習了Binder之後的總結.
Binder分為Binder驅動程序,server,client,servermanger4個模塊,這裡的server其實就是對應java中的Client端,client對應java中的Service端.
每一個server或者client都是運行在各自的進程中,都要經歷打開(open)設備文件,映射(mmap)設備文件的內存地址到進程空間,為進程分配內核空間.然後在通過iotic函數與binder交互.servermanger是系統定義好的一個特殊的類,它其實也是由server和client組成,通過servermanger可以管理我們自己定義的Service.
一.servermanger的創建過程
1. servermanger啟動成為守護進程 servermanger是由init進程啟動的,而init進程是由系統啟動時啟動的,因此,servermanger也是在系統啟動的時候啟動的. servermanger的啟動main函數主要做3件事情.第一步是調用函數binder_open打開設備文件/dev/binder以及將它映射到本進程的地址空間.第二步是調用函數binder_become_context_manager將自己注冊為binder進程間通信的上下文管理者.第三部是調用函數binder_loop來循環等待和處理Client進程的通信請求. 2. servermanger代理對象的獲取過程. servermanger是一個特殊的server,它的代理對象的獲取和普通的server的獲取不同.對於一般的service組建來說,Client進程在獲取代理對象時,首先要通過binder驅動程序來獲得它注冊時的一個句柄值,然後才可以根據這個句柄值創建一個binder代理對象,最後將這個binder代理對象轉化為一個特定的接口的代理對象.由於servermanger的句柄值是固定的0,所以就省去與binder驅動程序交互的過程.系統在Binder庫中提供了一個函數defaultServiceManager來獲得一個servermanger代理對象. 3. 普通Service(client)組件的啟動過程 Service組件是在Server進程中運行的(在c++中就是一個.cpp文件,就是一個可執行文件,可運行的程序).所以我們一般是創建一個Server.cpp文件,然後運行就可以將Server啟動了,在Server裡面就能啟動Service組件.一般的server.cpp就是包括instantiate函數創建一個Service組件,並且將它注冊到ServieManager中.然後調用ProcessState::self()->startThreadPool()啟動一個Binder線程池;最後調用joinThreadPool()將主線程也加入到Binder線程池中去等待和處理Client的通信請求. 在instanitiate函數創建Service的過程如下: 首先獲取到ServiceManager的代理對象,然後通過代理對象的addService方法就可以將該Service注冊到servermanger中. 4. 在普通Client進程(c++中就是一個.cpp文件)獲取普通Service組件的代理對象 通過servermanger的成員函數getService函數就可以獲取到對應的service.
二.普通Client進程和Service進程的一次進程通信過程分為如下5個步驟:
1.Client進程將進程空間通信數據封裝成一個Parcel對象,以便可以將進程間通信數據傳遞給Binder驅動程序.
2.Client進程向Bindder驅動程序發送一個BC_TRANSACTIOIN命令協議.Binder驅動程序根據協議內容找到目錄Server進程之後,就會向Client進程發送一個BR_TRANSACTION_COMPLETE返回協議,表示它的進程間通信請求已經被接受了.Client進程接收到Binder驅動程序發送給它的BR_TRANSACTIOIN_COMPLETE返回協議.並且對他進程處理之後,就會再次進入到Binder驅動程序中去等待目標Service進程返回進程間通信結果.
3.Binder驅動程序在向Client進程發送BR_TRANSACTION_COMPLETE返回協議的同時,也會向目標Server進程發送一個BT_TRANSACTIONF返回協議,請求目標Server進程處理該進程間通信請求.
4.Server進程接收到Binder驅動程序發來的BR_TRANSACTION返回協議,並且對他處理之後,就會向Binder驅動程序發送一個BC_REPLY命令.Binder驅動程序根據協議內容找到目標Client之後,就會向Server進程發送一個BR_TA.._COMPLETE協議,表示他返回的進程間通信結果已經收到了.Server進程接收到Binder驅動程序發送給它的返回協議,並且處理之後,一次進程間通信過程就結束了.接著它會再次進入到Binder驅動程序中去等待下一個進程間通信請求.
5.Binder驅動程序向Server進程發送BR_TRANSACTION_COMPLETE返回協議的同時,也會向目標Client發送一個BR_REPLY返回協議,表示Server進程已經處理完成他的進程間通信請求了,並且將進程間通信結果返回給它.
三.Binderbinder在應用框架層的java接口分析
上面說的都是在library層用c/c++編寫的程序,但是我們android程序都是用java語言寫的,其實系統在應用框架層定義的各種Service比如packageService都是用的Binder機制,因為應用框架層是在systemserver進程中啟動的,而我們的應用是在我們自己的進程中,如果在我們自己的應用中使用應用框架層的各種服務其實就是屬於跨進程通信.下面我總結一下系統的Service在應用框架層是如何定義好的.主要分為以下4個過程:1.IService接口的定義,並且定義Service;2. Service的啟動過程;3. Client獲取Service的Java遠程接口的過程;4. Client通過Service的Java遠程接口來使用Service提供的服務的過程。
1.Iservice接口的定義,一般是定義在一個aidl文件中,然後定義Service,但是這個Service要繼承Iservcie.Stub這個類比如:
1. 2. package android.os; 3. public interface IHelloService extends android.os.IInterface 4. { 5. /** Local-side IPC implementation stub class. */ 6. public static abstract class Stub extends android.os.Binder implements android.os.IHelloService 7. { 8. private static final java.lang.String DESCRIPTOR = "android.os.IHelloService"; 9. /** Construct the stub at attach it to the interface. */ 10. public Stub() 11. { 12. this.attachInterface(this, DESCRIPTOR); 13. } 14. 15. /** 16. * Cast an IBinder object into an android.os.IHelloService interface, 17. * generating a proxy if needed. 18. */ 19. public static android.os.IHelloService asInterface(android.os.IBinder obj) 20. { 21. if ((obj==null)) { 22. return null; 23. } 24. android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR); 25. if (((iin!=null)&&(iin instanceof android.os.IHelloService))) { 26. return ((android.os.IHelloService)iin); 27. } 28. return new android.os.IHelloService.Stub.Proxy(obj); 29. } 30. 31. public android.os.IBinder asBinder() 32. { 33. return this; 34. } 35. 36. @Override 37. public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException 38. { 39. switch (code) 40. { 41. case INTERFACE_TRANSACTION: 42. { 43. reply.writeString(DESCRIPTOR); 44. return true; 45. } 46. case TRANSACTION_setVal: 47. { 48. data.enforceInterface(DESCRIPTOR); 49. int _arg0; 50. _arg0 = data.readInt(); 51. this.setVal(_arg0); 52. reply.writeNoException(); 53. return true; 54. } 55. case TRANSACTION_getVal: 56. { 57. data.enforceInterface(DESCRIPTOR); 58. int _result = this.getVal(); 59. reply.writeNoException(); 60. reply.writeInt(_result); 61. return true; 62. } 63. } 64. return super.onTransact(code, data, reply, flags); 65. } 66. 67. private static class Proxy implements android.os.IHelloService 68. { 69. private android.os.IBinder mRemote; 70. 71. Proxy(android.os.IBinder remote) 72. { 73. mRemote = remote; 74. } 75. 76. public android.os.IBinder asBinder() 77. { 78. return mRemote; 79. } 80. 81. public java.lang.String getInterfaceDescriptor() 82. { 83. return DESCRIPTOR; 84. } 85. 86. public void setVal(int val) throws android.os.RemoteException 87. { 88. android.os.Parcel _data = android.os.Parcel.obtain(); 89. android.os.Parcel _reply = android.os.Parcel.obtain(); 90. try { 91. _data.writeInterfaceToken(DESCRIPTOR); 92. _data.writeInt(val); 93. mRemote.transact(Stub.TRANSACTION_setVal, _data, _reply, 0); 94. _reply.readException(); 95. } 96. finally { 97. _reply.recycle(); 98. _data.recycle(); 99. } 100. } 101. 102. public int getVal() throws android.os.RemoteException 103. { 104. android.os.Parcel _data = android.os.Parcel.obtain(); 105. android.os.Parcel _reply = android.os.Parcel.obtain(); 106. int _result; 107. try { 108. _data.writeInterfaceToken(DESCRIPTOR); 109. mRemote.transact(Stub.TRANSACTION_getVal, _data, _reply, 0); 110. _reply.readException(); 111. _result = _reply.readInt(); 112. } 113. finally { 114. _reply.recycle(); 115. _data.recycle(); 116. } 117. return _result; 118. } 119. } 120. 121. static final int TRANSACTION_setVal = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); 122. static final int TRANSACTION_getVal = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); 123. } 124. 125. public void setVal(int val) throws android.os.RemoteException; 126. public int getVal() throws android.os.RemoteException; 127. }
這裡我們可以看到IHelloService.aidl這個文件編譯後的真面目,原來就是根據IHelloService接口的定義生成相應的Stub和Proxy類,這個就是我們熟悉的Binder機制的內容了,即實現這個HelloService的Server必須繼承於這裡的IHelloService.Stub類.在Client調用stub.asinterface會轉換為IHelloService接口,而這個HelloService的遠程接口就是這裡的IHelloService.Stub.Proxy對象獲得的IHelloService接口.
2.有了HelloService這個Server類後,下一步就是考慮怎麼樣把它啟動起來了。在frameworks/base/services/java/com/android/server/SystemServer.java文件中,定義了SystemServer類。SystemServer對象是在系統啟動的時候創建的,它被創建的時候會啟動一個線程來創建HelloService,並且把它添加到Service Manager中去
1. class ServerThread extends Thread { 2. ...... 3. 4. @Override 5. public void run() { 6. 7. ...... 8. 9. Looper.prepare(); 10. 11. ...... 12. 13. try { 14. Slog.i(TAG, "Hello Service"); 15. ServiceManager.addService("hello", new HelloService()); 16. } catch (Throwable e) { 17. Slog.e(TAG, "Failure starting Hello Service", e); 18. } 19. 20. ...... 21. 22. Looper.loop(); 23. 24. ...... 25. } 26. }通過調用ServiceManager.addService把一個HelloService實例添加到Service Manager中去。
public static void addService(String name, IBinder service) { 1. try { 2. getIServiceManager().addService(name, service); 3. } catch (RemoteException e) { 4. Log.e(TAG, "error in addService", e); 5. } 6. }
通過這個addService的參數我們可以知道,實際上利用servermanger添加的是一個IBinder接口的子類,所以我們定義的Service要繼承.stub這個類.
3.在Client就是通過servermanger.getservie來獲取到對應的Service
4.就是通過Service來調用定義好的方法完成功能了.
顯示進度對話框 我們常常有這樣的經歷:執行某一應用程序時,需要等待一會,這時會顯示一個進度(Please Wait)對話框,讓用戶知道操作正在進行。 我們繼續在上一
微信公眾號開發者中心提供了使用代碼開發微信微應用的功能,使用代碼開發微應用需要用到服務器,以存放編寫的代碼,因此我們需要一個服務器。那麼在微信那裡設置服務器呢?在微信公眾
1.第一種方法package com.example.jer824;import android.os.Handler;import android.os.Message
在一些復雜布局中,經常會遇到事件沖突,事件失效等問題,這就需要我們深入理解Android事件的分發傳遞機制。最好的方法是自己寫一個demo,打印事件相關的日志查看其運行流