Android的IPC機制Binder

yangxi_001發表於2013-11-20
 第一部分Binder的組成 
1.1 
驅動 
程式部分驅動程式的部分在以下的檔案 夾中: 
kernel /include/linux /binder.h 
kernel/drivers/android /binder.c 

    binder
 驅動程式是一個miscdevice,主裝置號為10,此裝置號使用動態獲得(MISC_DYNAMIC_MINOR),其裝置的節點為:
/dev/binder 
    binder 驅動程式會在proc檔案系統 中建立自己的資訊,其資料夾為 /proc/binde ,其中包含如下內容: 
proc 目錄:呼叫Binder各個程式 的內容
state 檔案:使用函式binder_read _proc_state
stats 檔案:使用函式binder_read_proc_stats
transactions 檔案:使用函式binder_read_proc_transactions
transaction_log 檔案:使用函式binder_read_proc_transaction_log,其引數為binder_transaction_log (型別為struct binder_transaction_log)
failed_transaction_log 檔案:使用函式binder_read_proc_transaction_log 其引數為
binder_transaction_log_failed (型別為struct binder_transaction_log)

    在binder檔案被開啟後,其私有資料 (private_data)的型別:
struct binder_proc 
    在這個資料結構中,主要包含了當前程式、程式ID、
記憶體 
對映資訊、Binder的統計資訊和執行緒資訊等。
    在使用者空間對Binder驅動程式進行控制主要使用的介面是mmap、poll和ioctl,ioctl主要使用的ID為: 
#define BINDER_WRITE_READ        _IOWR('b', 1, struct binder_write_read)
#define BINDER_SET_IDLE_TIMEOUT  _IOW('b', 3, int64_t)
#define BINDER_SET_MAX_THREADS   _IOW('b', 5, size_t)
#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, int)
#define BINDER_SET_CONTEXT_MGR   _IOW('b', 7, int)
#define BINDER_THREAD_EXIT       _IOW('b', 8, int)
#define BINDER_VERSION           _IOWR('b', 9, struct binder_version)
 
    BR_XXX等巨集為BinderDriverReturnProtocol,表示Binder驅動返回協議。
    BC_XXX等巨集為BinderDriverCommandProtocol,表示Binder驅動命令 協議。
    binder_thread是Binder驅動程式中使用的另外一個重要的資料結構,資料結構的定義如下所示:
struct binder_thread {
      struct binder_proc *proc;
     struct rb_node rb_node;
     int pid;
     int looper;
     struct binder_transaction *transaction_stack;
     struct list_head todo;
     uint32_t return_error ;
     uint32_t return_error2;
     wait_queue_head_t wait;
     struct binder_stats stats;
};
 
    binder_thread 的各個成員資訊是從rb_node中得出。
    BINDER_WRITE_READ是最重要的ioctl,它使用一個資料結構binder_write_read定義讀寫的資料。
struct binder_write_read {
     signed long write_size; 
     signed long write_consumed; 
     unsigned long write_buffer;
     signed long read_size; 
     signed long read_consumed; 
     unsigned long read_buffer;
};
 

  1.3 binder的庫的部分
    binder 相關的檔案作為Android的uitls庫的一部分,這個庫編譯 後的名稱為libutils.so,是Android系統中的一個公共庫。
    主要檔案的路徑如下所示: 
frameworks/base/include/utils/* 
frameworks/base/libs/utils/* 
    
    主要的類為: 
  RefBase.h : 
    引用計數,定義類 RefBase。
  Parcel.h : 
    為在 IPC中傳輸的資料定義容器,定義類Parcel 
  IBinder.h 
    Binder物件的抽象介面, 定義類IBinder
  Binder.h 
    Binder物件的基本功能, 定義類Binder和BpRefBase
  BpBinder.h  
  BpBinder 的功能,定義類BpBinder
  IInterface.h 
  為抽象經過 Binder的介面定義通用類,
    定義類 IInterface,類别範本BnInterface,類别範本BpInterface
  ProcessState.h 
    表示程式狀態的類,定義類 ProcessState
  IPCThreadState.h 
    表示 IPC執行緒的狀態,定義類IPCThreadState 
各個類之間的關係如下所示: 



        1.2 servicemanager部分        servicemanager 是一個守護程式,用於這個程式的和/dev/binder通訊,從而達到管理系統中各個服務的作用。
         可執行程式的路徑:
         /system/bin/ servicemanager          
開源版本 檔案的路徑:
frameworks/base/cmds/servicemanager/binder.h
frameworks/base/cmds/servicemanager/binder.c
frameworks/base/cmds/servicemanager/service_manager.c
 

       程式執行的流程:

open ()
 :開啟binder驅動

mmap()
 :對映一個128*1024位元組的記憶體

ioctl(BINDER_SET_CONTEXT_MGR)
 :設定上下文為mgr
       進入主迴圈binder_loop()
             ioctl(BINDER_WRITE_READ)
 ,讀取
                       binder_parse() 進入binder處理過程迴圈處理
         binder_parse() 的處理,呼叫返回值:
         當處理BR_TRANSACTION的時候,呼叫svcmgr_handler()處理增加服務、檢查服務等工作。各種服務存放在一個連結串列(svclist)中。其中呼叫binder_等開頭的函式,又會呼叫ioctl的各種命令。 
         處理BR_REPLY的時候,填充binder_io型別的資料結
  第二部分 Binder的運作 
  2.1 Binder的工作機制 
      Service Manager是一個守護程式,它負責啟動各個程式之間的服務,對於相關的兩個需要通訊的程式,它們通過呼叫libutil.so庫實現通訊,而真正通訊的機制,是核心 空間中的一塊共享
記憶體 

       

  2.2 從應  用程式的角度看Binder

   從應用程式的角度看Binder一共有三個方面:
  Native 本地:例如BnABC,這是一個需要被繼承和實現的類。
  Proxy 代理:例如BpABC,這是一個在介面框架中被實現,但是在介面中沒有體現的類。
  客戶端:例如客戶端得到一個介面ABC,在呼叫的時候實際上被呼叫的是BpABC

本地功能(Bn)部分做的:
    實現 BnABC:: BnTransact() 
    註冊服務: IServiceManager::AddService
代理部分( Bp)做的:
    實現幾個功能函式,呼叫 BpABC::remote()->transact() 
客戶端做的: 
    獲得 ABC介面,然後呼叫介面(實際上呼叫了BpABC ,繼而通過IPC 呼叫了BnABC ,然後呼叫了具體的功能)

       在程式的實現過程中BnABC 和BpABC 是雙繼承了介面ABC 。一般來說BpABC 是一個實現類,這個實現類不需要在介面中體現,它實際上負責的只是通訊功能,不執行具體的功能;BnABC 則是一個介面類,需要一個真正工作的類來繼承、實現它,這個類才是真正執行具體功能的類。
       在客戶端中,從ISeriviceManager 中獲得一個ABC 的介面,客戶端呼叫這個介面,實際上是在呼叫BpABC,而BpABC 又通過Binder 的IPC 機制和BnABC 通訊,BnABC 的實現類在後面執行。
  事實上,
伺服器 
的具體實現和客戶端是兩個不同的程式,如果不考慮程式間通訊的過程,從呼叫者的角度,似乎客戶端在直接呼叫另外一個程式間的函式——當然這個函式必須是介面ABC 中定義的。
  2.3 ISericeManager的作用
      ISericeManager涉及的兩個檔案是ISericeManager.h和ISericeManager.cpp。這兩個檔案基本上是 ISericeManager。ISericeManager是系統最先被啟動的服務。非常值得注意的是:ISericeManager本地功能並沒有使 現,它實際上由ServiceManager守護程式執行,而使用者程式通過呼叫BpServiceManager來獲得其他的服務。
      在ISericeManager.h中定義了一個介面,用於得到預設的ISericeManager:
        sp defaultServiceManager(); 
     這時得到的ISericeManager實際上是一個全域性的ISericeManager
  第三部分 程式中Binder的具體實現 
  3.1 一個利用介面的具體實現
    PermissionController也是libutils中定義的一個有關許可權控制的介面,它一共包含兩個檔案:IPermissionController.h和IPermissionController.cpp這個結構在所有類的實現中都是類似的。
     標頭檔案IPermissionController.h的主要內容是定義IPermissionController介面和類BnPermissionController:
class IPermissionController : public IInterface
{
public:
    DECLARE_META_INTERFACE(PermissionController);
    virtual bool   checkPermission(const String16& permission,int32_t pid, int32_t uid) = 0;
    enum {
        CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
    };
};
class BnPermissionController : public BnInterface
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
};
 
    IPermissionController是一個介面類,只有checkPermission()一個純虛擬函式。
    BnPermissionController繼承了以BnPermissionController例項化模版類BnInterface。因 此,BnPermissionController,事實上BnPermissionController雙繼承了BBinder和 IPermissionController。
    實現檔案IPermissionController.cpp中,首先實現了一個BpPermissionController。
class BpPermissionController : public BpInterface
{
public:
    BpPermissionController(const sp& impl)
        : BpInterface(impl)
    {
    }
    virtual bool checkPermission(const String16& permission, int32_t pid, int32_t uid)
    {
        Parcel data, reply;
        data.writeInterfaceToken(IPermissionController::
                                       getInterfaceDescriptor());
        data.writeString16(permission);
        data.writeInt32(pid);
        data.writeInt32(uid);
        remote()->transact(CHECK_PERMISSION_TRANSACTION, data, &reply);
        if (reply.readInt32() != 0) return 0;
        return reply.readInt32() != 0;
    }
};
IMPLEMENT_META_INTERFACE(PermissionController, "android.os.IPermissionController");

    BpPermissionController繼承了BpInterface,它本身是一個已經實現的類,而且並沒有在介面中體現。這個類按照格式寫就可 以,在實現checkPermission()函式的過程中,使用Parcel作為傳輸資料的容器,傳輸中時候transact()函式,其引數需要包含 列舉值CHECK_PERMISSION_TRANSACTION。 IMPLEMENT_META_INTERFACE用於扶助生成。
    BnPermissionController中實現的onTransact()函式如下所示:
status_t BnPermissionController:: BnTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
        case CHECK_PERMISSION_TRANSACTION: {
            CHECK_INTERFACE(IPermissionController, data, reply);
            String16 permission = data.readString16();
            int32_t pid = data.readInt32();
            int32_t uid = data.readInt32();
            bool res = checkPermission(permission, pid, uid);
            reply->writeInt32(0);
            reply->writeInt32(res ? 1 : 0);
            return NO_ERROR;
        } break;
        default:
            return BBinder:: BnTransact(code, data, reply, flags);
    }
}
 
       在onTransact()函式中根據列舉值判斷資料使用的方式。注意,由於BnPermissionController也是繼承了類 IPermissionController,但是純虛擬函式checkPermission()依然沒有實現。因此這個 BnPermissionController類並不能例項化,它其實也還是一個介面,需要一個實現類來繼承它,那才是實現具體功能的類。
  3.2 BnABC的實現
    本地服務啟動後將形成一個守護程式,具體的本地服務是由一個實現類繼承BnABC來實現的,這個服務的名稱通常叫做ABC。
    在其中,通常包含了一個instantiate()函式,這個函式一般按照如下的方式實現:
void ABC::instantiate() {
    defaultServiceManager()->addService(
            String16("XXX.ABC"), new ABC ());
}
 
    按照這種方式,通過呼叫defaultServiceManager()函式,將增加一個名為"XXX.ABC"的服務。
    在這個defaultServiceManager()函式中呼叫了:
ProcessState::self()->getContextObject(NULL));
    IPCThreadState* ipc = IPCThreadState::self();
   IPCThreadState::talkWithDriver()
 
在ProcessState 類建立的過程中呼叫open_driver()開啟
驅動 
程式,在talkWithDriver()的執行過程中。
  3.3 BpABC呼叫的實現 
    BpABC呼叫的過程主要通過mRemote()->transact() 來傳輸資料,mRemote()是BpRefBase的成員,它是一個IBinder。這個呼叫過程如下所示:
    mRemote()->transact() 
    Process::self() 
    IPCThreadState::self()->transact()
    writeTransactionData()
    waitForResponse()
    talkWithDriver()
    ioctl(fd, BINDER_WRITE_READ, &bwr)
 
    在IPCThreadState::executeCommand()函式中,實現傳輸操作

相關文章