Android : 跟我學Binder --- (3) C程序示例



目錄:

 

 

一、Binder框架分析

  1、IPC、LPC和RPC的概念:

    IPC:  (Inter Process Communication )跨進程通信,泛指進程之間任何形式的通信行為,它不僅包括各種形式的消息傳遞,還可以指共享資源,以及同步對象;

    LPC: Local Procedure Call 本地過程調用,用在多任務操作系統中,使得同時運行的任務能互相會話。這些任務共享內存空間使任務同步和互相發送信息;(IPC的封裝)

    RPC:(Reomote Procedure Call )遠程過程調用,類似於LPC,只是在網上工作。RPC開始是出現在Sun微系統公司和HP公司的運行UNIX操作系統的計算機中;

 

  2、通信架構:

    Client/Server <---> service manager 交互流程:

      server ---------addservice-------> service manager

      client  ---------getservice--------> service manager

 注:ServiceManager首先向binder驅動注冊為服務管理者,handle為0;

 

  3、簡析示例代碼(非完整流程)

①android_5.0.2_32\frameworks\native\cmds\servicemanager\service_manager.c  //管理server注冊的服務(進程)

    a. binder_open  //打開驅動
    b. binder_become_context_manager //告訴驅動注冊為service manager
    c. binder_loop(bs, svcmgr_handler);
       c.1 res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);  //讀數據
       c.2 binder_parse // 解析數據
    
          /*處理數據  : svcmgr_handler*/
                     SVC_MGR_GET_SERVICE/SVC_MGR_CHECK_SERVICE : 獲取服務
                     SVC_MGR_ADD_SERVICE : 注冊服務
          /*有必要則回復數據*/  
             .......

 

android_5.0.2_32\frameworks\native\cmds\servicemanager\bctest.c  //client測試代碼

   注冊服務的過程:
    a. binder_open  //打開驅動
    b. svcmgr_publish  //構造數據   
    c. binder_call(bs, &msg, &reply, 0, SVC_MGR_ADD_SERVICE)
                       // 含有服務的名字
                             // 它會含有servicemanager回復的數據
                                     // 0表示servicemanager
                                        // code: 表示要調用servicemanager中的"addservice函數"

  獲取服務的過程:
    a. binder_open //打開驅動
    
b. svcmgr_lookup //構造數據
    
c. binder_call(bs,
&msg, &reply, 0, SVC_MGR_CHECK_SERVICE)      // 含有服務的名字     // 它會含有servicemanager回復的數據, 表示提供服務的進程     // 0表示servicemanager      // code: 表示要調用servicemanager中的"getservice函數

 

android_5.0.2_32\frameworks\native\cmds\servicemanager\binder.c  //封裝好的C函數

(1)構造參數:放在一個buffer用binder_io來描述;

   unsigned iodata[512/4]; //用binder_io來管理這個緩沖區
    struct binder_io msg, reply;
...
    bio_init(&msg, iodata, sizeof(iodata), 4); //初始化binder_io對象

  /*可以放入各類型參數,反之通過get方法獲取*/
    bio_put_uint32(&msg, 0);  // strict mode header
    bio_put_string16_x(&msg, SVC_MGR_NAME); 
    bio_put_string16_x(&msg, name);
    bio_put_obj(&msg, ptr);
...

/*調用binder_call(struct binder_state *bs,
          struct binder_io *msg/*提供參數*/, 
          struct binder_io *reply/*獲得回復*/,
          uint32_t target/*發送對象*/,
          uint32_t code/*調用函數*/)*/

    if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE))
        return -1;

 

(2)根據 binder_io、targetcode 構造writebuf:

    struct binder_write_read bwr;
    struct {
        uint32_t cmd;
        struct binder_transaction_data txn;
    } __attribute__((packed)) writebuf;
    unsigned readbuf[32];
....

    writebuf.cmd = BC_TRANSACTION;
    writebuf.txn.target.handle = target;
    writebuf.txn.code = code;
    writebuf.txn.flags = 0;
    writebuf.txn.data_size = msg->data - msg->data0;
    writebuf.txn.offsets_size = ((char*) msg->offs) - ((char*) msg->offs0);
    writebuf.txn.data.ptr.buffer = (uintptr_t)msg->data0;
    writebuf.txn.data.ptr.offsets = (uintptr_t)msg->offs0;

    bwr.write_size = sizeof(writebuf);
    bwr.write_consumed = 0;
    bwr.write_buffer = (uintptr_t) &writebuf;

  其中binder_write_read 結構體在內核代碼中的定義:

struct binder_write_read { signed long write_size; /* bytes to write */ signed long write_consumed; /* bytes consumed by driver */ unsigned long write_buffer; signed long read_size; /* bytes to read */ signed long read_consumed; /* bytes consumed by driver */ unsigned long read_buffer; };

  其中binder_transaction_data結構體在內核代碼中的定義:

struct binder_transaction_data {
    /* The first two are only used for bcTRANSACTION and brTRANSACTION,
     * identifying the target and contents of the transaction.
     */
    union {
        size_t    handle;    /* target descriptor of command transaction */
        void    *ptr;    /* target descriptor of return transaction */
    } target;
    void        *cookie;    /* target object cookie */
    unsigned int    code;        /* transaction command */

    /* General information about the transaction. */
    unsigned int    flags;
    pid_t        sender_pid;
    uid_t        sender_euid;
    size_t        data_size;    /* number of bytes of data */
    size_t        offsets_size;    /* number of bytes of offsets */

    /* If this transaction is inline, the data immediately
     * follows here; otherwise, it ends with a pointer to
     * the data buffer.
     */
    union {
        struct {
            /* transaction data */
            const void    *buffer;
            /* offsets from buffer to flat_binder_object structs */
            const void    *offsets;
        } ptr;
        uint8_t    buf[8];
    } data;
};

 

(3)通過ioctl發送數據:

    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;

        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

        if (res < 0) {
            fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno));
            goto fail;
        }

        res = binder_parse(bs, reply, (uintptr_t) readbuf, bwr.read_consumed, 0); //解析返回的數據
        if (res == 0) return 0;
        if (res < 0) goto fail;
    }

 

框架流程總結:

  client端: binder_open ---> 獲得服務handle ---> 構造參數binder_io ---> 調用binder_call ---> 解析返回的binder_io;

  server端:binder_open ---> 注冊服務 ---> ioctl讀取數據(binder_write_read )---> 解析數據(binder_transaction_data ) ---> 獲得binder_io並根據code調用對應函數 ---> 把返回值發送給client;

 

 

二、編寫程序

  1.參考service_manager.c編寫test_server.c添加服務:

/* Copyright 2008 The Android Open Source Project
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <linux/types.h>
#include<stdbool.h>
#include <string.h>

#include <private/android_filesystem_config.h>

#include "binder.h"
#include "test_server.h"

int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr)
{
    int status;
    unsigned iodata[512/4];
    struct binder_io msg, reply;

    bio_init(&msg, iodata, sizeof(iodata), 4);
    bio_put_uint32(&msg, 0);  // strict mode header
    bio_put_string16_x(&msg, SVC_MGR_NAME);
    bio_put_string16_x(&msg, name);
    bio_put_obj(&msg, ptr);

    if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE))
        return -1;

    status = bio_get_uint32(&reply);

    binder_done(bs, &msg, &reply);

    return status;
}

void sayhello(void)
{
    static int cnt = 0;
    fprintf(stderr, "say hello : %d\n", ++cnt);
}


int sayhello_to(char *name)
{
    static int cnt = 0;
    fprintf(stderr, "say hello to %s : %d\n", name, ++cnt);
    return cnt;
}

void saygoodbye(void)
{
    static int cnt = 0;
    fprintf(stderr, "say goodbye : %d\n", ++cnt);
}


int saygoodbye_to(char *name)
{
    static int cnt = 0;
    fprintf(stderr, "say goodbye to %s : %d\n", name, ++cnt);
    return cnt;
}


int hello_service_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    /* 根據txn->code知道要調用哪一個函數
     * 如果需要參數, 可以從msg取出
     * 如果要返回結果, 可以把結果放入reply
     */

    /* sayhello
     * sayhello_to
     */
    
    uint16_t *s;
    char name[512];
    size_t len;
    uint32_t handle;
    uint32_t strict_policy;
    int i;


    // Equivalent to Parcel::enforceInterface(), reading the RPC
    // header with the strict mode policy mask and the interface name.
    // Note that we ignore the strict_policy and don't propagate it
    // further (since we do no outbound RPCs anyway).
    strict_policy = bio_get_uint32(msg); // 取出0,后面才是傳過來的所需數據


    switch(txn->code) {
    case HELLO_SVR_CMD_SAYHELLO:
        sayhello();
        bio_put_uint32(reply, 0); /* no exception */
        return 0;

    case HELLO_SVR_CMD_SAYHELLO_TO:
        /* 從msg里取出字符串(16位轉8位) */
        s = bio_get_string16(msg, &len);  //"IHelloService"
        s = bio_get_string16(msg, &len);  // name
        if (s == NULL) {
            return -1;
        }
        for (i = 0; i < len; i++)
            name[i] = s[i];
        name[i] = '\0';

        /* 處理 */
        i = sayhello_to(name);

        /* 把結果放入reply */
        bio_put_uint32(reply, 0); /* no exception */
        bio_put_uint32(reply, i);
        
        break;

    default:
        fprintf(stderr, "unknown code %d\n", txn->code);
        return -1;
    }

    return 0;
}



int goodbye_service_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    /* 根據txn->code知道要調用哪一個函數
     * 如果需要參數, 可以從msg取出
     * 如果要返回結果, 可以把結果放入reply
     */

    /* sayhello
     * sayhello_to
     */
    
    uint16_t *s;
    char name[512];
    size_t len;
    uint32_t handle;
    uint32_t strict_policy;
    int i;


    // Equivalent to Parcel::enforceInterface(), reading the RPC
    // header with the strict mode policy mask and the interface name.
    // Note that we ignore the strict_policy and don't propagate it
    // further (since we do no outbound RPCs anyway).
    strict_policy = bio_get_uint32(msg);


    switch(txn->code) {
    case GOODBYE_SVR_CMD_SAYGOODBYE:
        saygoodbye();
        bio_put_uint32(reply, 0); /* no exception */
        return 0;

    case GOODBYE_SVR_CMD_SAYGOODBYE_TO:
        /* 從msg里取出字符串(16位轉8位) */
        s = bio_get_string16(msg, &len);  //"IGoodbyeService"
        s = bio_get_string16(msg, &len);  // name
        if (s == NULL) {
            return -1;
        }
        for (i = 0; i < len; i++)
            name[i] = s[i];
        name[i] = '\0';

        /* 處理 */
        i = saygoodbye_to(name);

        /* 把結果放入reply */
        bio_put_uint32(reply, 0); /* no exception */
        bio_put_uint32(reply, i);
        
        break;

    default:
        fprintf(stderr, "unknown code %d\n", txn->code);
        return -1;
    }

    return 0;
}


int test_server_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    int (*handler)(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply);

    handler = (int (*)(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply))txn->target.ptr;
    
    return handler(bs, txn, msg, reply);
}

int main(int argc, char **argv)
{
    int fd;
    struct binder_state *bs;
    uint32_t svcmgr = BINDER_SERVICE_MANAGER;
    uint32_t handle;
    int ret;

    bs = binder_open(128*1024);
    if (!bs) {
        fprintf(stderr, "failed to open binder driver\n");
        return -1;
    }

    /* add service */
    ret = svcmgr_publish(bs, svcmgr, "hello", hello_service_handler); //第三個參數值需要唯一,obj->binder = (uintptr_t)ptr;
    if (ret) {
        fprintf(stderr, "failed to publish hello service\n");
        return -1;
    }
    ret = svcmgr_publish(bs, svcmgr, "goodbye", goodbye_service_handler);
    if (ret) {
        fprintf(stderr, "failed to publish goodbye service\n");
    }

    binder_set_maxthreads(bs, 10);
    
    /* //binder_loop已封裝如下步驟:
    while (1)
    {
        /* read data */
        /* parse data, and process */
        /* reply */
    }
    */
    binder_loop(bs, test_server_handler); //通過函數test_server_handler處理消息

    return 0;
}

test_server.h :

#ifndef _TEST_SERVER_H
#define _TEST_SERVER_H

#define HELLO_SVR_CMD_SAYHELLO     1
#define HELLO_SVR_CMD_SAYHELLO_TO  2

#define GOODBYE_SVR_CMD_SAYGOODBYE     1
#define GOODBYE_SVR_CMD_SAYGOODBYE_TO  2

#endif // _TEST_SERVER_H

 

    2.編寫test_client.c獲得/使用服務:

/* Copyright 2008 The Android Open Source Project
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <linux/types.h>
#include<stdbool.h>
#include <string.h>

#include <private/android_filesystem_config.h>

#include "binder.h"
#include "test_server.h"



uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name)
{
    uint32_t handle;
    unsigned iodata[512/4];
    struct binder_io msg, reply;

    bio_init(&msg, iodata, sizeof(iodata), 4);
    bio_put_uint32(&msg, 0);  // strict mode header
    bio_put_string16_x(&msg, SVC_MGR_NAME);
    bio_put_string16_x(&msg, name);

    if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE))
        return 0;

    handle = bio_get_ref(&reply);

    if (handle)
        binder_acquire(bs, handle);

    binder_done(bs, &msg, &reply);

    return handle;
}


struct binder_state *g_bs;
uint32_t g_hello_handle;
uint32_t g_goodbye_handle;

void sayhello(void)
{
    unsigned iodata[512/4];
    struct binder_io msg, reply;

    /* 構造binder_io */
    bio_init(&msg, iodata, sizeof(iodata), 4);
    bio_put_uint32(&msg, 0);  // strict mode header ,傳入0
    bio_put_string16_x(&msg, "IHelloService");

    /* 放入參數 */

    /* 調用binder_call */
    if (binder_call(g_bs, &msg, &reply, g_hello_handle, HELLO_SVR_CMD_SAYHELLO))
        return ;
    
    /* 從reply中解析出返回值 */

    binder_done(g_bs, &msg, &reply);
    
}

/*
*帶參數
*/
int sayhello_to(char *name)
{
    unsigned iodata[512/4];
    struct binder_io msg, reply;
    int ret;
    int exception;

    /* 構造binder_io */
    bio_init(&msg, iodata, sizeof(iodata), 4);
    bio_put_uint32(&msg, 0);  // strict mode header
    bio_put_string16_x(&msg, "IHelloService");

    /* 放入參數 */
    bio_put_string16_x(&msg, name);

    /* 調用binder_call */
    if (binder_call(g_bs, &msg, &reply, g_hello_handle, HELLO_SVR_CMD_SAYHELLO_TO))
        return 0;
    
    /* 從reply中解析出返回值 */
    exception = bio_get_uint32(&reply);
    if (exception)
        ret = -1;
    else
        ret = bio_get_uint32(&reply);

    binder_done(g_bs, &msg, &reply);

    return ret;
    
}


void saygoodbye(void)
{
    unsigned iodata[512/4];
    struct binder_io msg, reply;

    /* 構造binder_io */
    bio_init(&msg, iodata, sizeof(iodata), 4);
    bio_put_uint32(&msg, 0);  // strict mode header
    bio_put_string16_x(&msg, "IGoodbyeService");

    /* 放入參數 */

    /* 調用binder_call */
    if (binder_call(g_bs, &msg, &reply, g_goodbye_handle, GOODBYE_SVR_CMD_SAYGOODBYE))
        return ;
    
    /* 從reply中解析出返回值 */

    binder_done(g_bs, &msg, &reply);
    
}

int saygoodbye_to(char *name)
{
    unsigned iodata[512/4];
    struct binder_io msg, reply;
    int ret;
    int exception;

    /* 構造binder_io */
    bio_init(&msg, iodata, sizeof(iodata), 4);
    bio_put_uint32(&msg, 0);  // strict mode header
    bio_put_string16_x(&msg, "IGoodbyeService");

    /* 放入參數 */
    bio_put_string16_x(&msg, name);

    /* 調用binder_call */
    if (binder_call(g_bs, &msg, &reply, g_goodbye_handle, GOODBYE_SVR_CMD_SAYGOODBYE_TO))
        return 0;
    
    /* 從reply中解析出返回值 */
    exception = bio_get_uint32(&reply);
    if (exception)
        ret = -1;
    else
        ret = bio_get_uint32(&reply);

    binder_done(g_bs, &msg, &reply);

    return ret;
    
}



/* ./test_client hello
 * ./test_client hello <name>
 */

int main(int argc, char **argv)
{
    int fd;
    struct binder_state *bs;
    uint32_t svcmgr = BINDER_SERVICE_MANAGER;
    uint32_t handle;
    int ret;

    if (argc < 2){
        fprintf(stderr, "Usage:\n");
        fprintf(stderr, "%s <hello|goodbye>\n", argv[0]);
        fprintf(stderr, "%s <hello|goodbye> <name>\n", argv[0]);
        return -1;
    }

    bs = binder_open(128*1024);
    if (!bs) {
        fprintf(stderr, "failed to open binder driver\n");
        return -1;
    }
    g_bs = bs;


    /* get service */
    handle = svcmgr_lookup(bs, svcmgr, "goodbye");
    if (!handle) {
        fprintf(stderr, "failed to get goodbye service\n");
        return -1;
    }
    g_goodbye_handle = handle;
    fprintf(stderr, "Handle for goodbye service = %d\n", g_goodbye_handle);

    handle = svcmgr_lookup(bs, svcmgr, "hello");
    if (!handle) {
        fprintf(stderr, "failed to get hello service\n");
        return -1;
    }
    g_hello_handle = handle;
    fprintf(stderr, "Handle for hello service = %d\n", g_hello_handle);

    /* send data to server */
    if (!strcmp(argv[1], "hello"))
    {
        if (argc == 2) {
            sayhello();
        } else if (argc == 3) {
            ret = sayhello_to(argv[2]);
            fprintf(stderr, "get ret of sayhello_to = %d\n", ret);        
        }
    } else if (!strcmp(argv[1], "goodbye"))
    {
        if (argc == 2) {
            saygoodbye();
        } else if (argc == 3) {
            ret = saygoodbye_to(argv[2]);
            fprintf(stderr, "get ret of sayhello_to = %d\n", ret);        
        }
    }

    binder_release(bs, handle);

    return 0;
}

  3.編譯腳本:

  (1)Makefile

APPS = service_manager test_client test_server

all : $(APPS)

service_manager : service_manager.o binder.o
    arm-linux-gcc -o $@ $^ -lpthread

test_client : test_client.o binder.o
    arm-linux-gcc -o $@ $^ -lpthread

test_server : test_server.o binder.o
    arm-linux-gcc -o $@ $^ -lpthread

%.o : %.c 
    arm-linux-gcc -DBINDER_IPC_32BIT=1 -I include -c -o $@ $<
            
clean:
    rm $(APPS) -f; rm -f *.o

  (2)Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1
 
LOCAL_SRC_FILES:= service_manager.c binder.c

LOCAL_C_INCLUDES += system/core/include/cutils

LOCAL_MODULE:= service_manager_my

include $(BUILD_EXECUTABLE)

include $(CLEAR_VARS)

LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1

LOCAL_SRC_FILES:= test_server.c binder.c

LOCAL_C_INCLUDES += system/core/include/cutils

LOCAL_MODULE:= test_server

include $(BUILD_EXECUTABLE)

include $(CLEAR_VARS)

LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1

LOCAL_SRC_FILES:= test_client.c binder.c

LOCAL_C_INCLUDES += system/core/include/cutils

LOCAL_MODULE:= test_client

include $(BUILD_EXECUTABLE)

 

-end-


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM