Tech & IT/프로그래밍

Android Franwork Binder(Server, Client) c부터 cpp까지

해피콧 2012. 3. 20. 16:45
'); }
'); }
############
//myserver0.c
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <errno.h>
  4 #include <unistd.h>
  5 #include <fcntl.h>
  6 #include <sys/mman.h>
  7 #include "binder.h"
  8
  9 // myserver0.c
 10 //
 11 struct binder_state
 12 {
 13     int fd;
 14     void* mapped;
 15     unsigned mapsize;
 16 };
 17
 18 unsigned token;
 19
 20 //do something to do because It is server
 21 int Add(int a, int b)
 22 {
 23     printf("Add(%d, %d)\n", a, b);
 24     return a + b;
 25 }
 26
 27 int my_handler(struct binder_state* bs,
 28         struct binder_txn* txn,
 29         struct binder_io* msg,
 30         struct binder_io* reply)
 31 {
 32     int ret, a, b;
 33     switch(txn->code)
 34     {
 35         case 1:
 36             a = bio_get_uint32(msg);
 37             b = bio_get_uint32(msg);
 38             ret = Add(a, b);
 39             bio_put_uint32(reply, ret);
 40             return 0;
 41     }
 42     return 0;
 43 }
 44
 45
 46 int main()
 47 {
 48     int mapsize = 1024 * 128;
 49     struct binder_state* bs;
 50
 51     unsigned int status;
 52     char iodata[512];
 53     struct binder_io msg;
 54     struct binder_io reply;
 55
 56     // --------------------------------------------------------------
 57     // 1. binder driver open
 58     //bs = malloc(sizeof(struct binder_state));
 59     //bs->fd = open("/dev/binder", O_RDWR);
 60     //bs->mapsize = mapsize;
 61     //bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
 62     bs = binder_open(mapsize);
 63
 64
 65     // --------------------------------------------------------------
 66     // 2. add service
 67     bio_init(&msg, iodata, sizeof(iodata), 4);
 68
 69     //
 70     bio_put_string16_x(&msg, SVC_MGR_NAME);
 71     bio_put_string16_x(&msg, "myserver0");
 72     bio_put_obj(&msg, &token);
 73
 74     if(binder_call(bs, &msg, &reply, BINDER_SERVICE_MANAGER, SVC_MGR_ADD_SERVICE))
 75     {
 76         printf("error register service\n");
 77         return -1;
 78     }
 79     status = bio_get_uint32(&reply);
 80
 81     binder_done(bs, &msg, &reply);
 82     //3. binder loop
 83     binder_loop(bs, my_handler);
 84
 85
 86
 87
 88     return 0;
 89 }
 



//myclient0.c
   1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <errno.h>
  4 #include <unistd.h>
  5 #include <fcntl.h>
  6 #include <sys/mman.h>
  7 #include "binder.h"
  8
  9 int main(int argc, char** argv)
 10 {
 11     void* ptr;    //var that get service no on server
 12     struct binder_state* bs;
 13     struct binder_io msg, reply;
 14     char iodata[512/4];
 15     int ret;
 16
 17     //1. driver open and make receive ber
 18     bs = binder_open(128*1024); // 128k receive buffer
 19
 20     //2. make packet that will send service manager
 21     // work on binder_io but eventually send to driver as binder_write_read
 22     bio_init(&msg, iodata, sizeof(iodata), 4);
 23     bio_put_string16_x(&msg, SVC_MGR_NAME); // "android.os.IServiceManager"
 24     bio_put_string16_x(&msg, argv[1]);
 25
 26     if(binder_call(bs, &msg, &reply, BINDER_SERVICE_MANAGER, SVC_MGR_CHECK_SERVICE))
 27     {
 28         printf("can't find service : %s\n", argv[1]);
 29         return -1;
 30     }
 31     ptr = bio_get_ref(&reply);
 32
 33     printf("find service handle : %d\n", ptr);
 34
 35     //3. request add function
 36     memset(&msg, 0, sizeof(msg));
 37     memset(&iodata, 0, sizeof(iodata));
 38     memset(&reply, 0, sizeof(reply));
 39
 40     bio_init(&msg, iodata, sizeof(iodata), 4);
 41     bio_put_uint32(&msg, 3);
 42     bio_put_uint32(&msg, 4);
 43
 44     if(binder_call(bs, &msg, &reply, ptr, 1))
 45     {
 46         printf("can't request : %s\n", argv[1]);
 47         return -1;
 48     }
 49     ret = bio_get_uint32(&reply);
 50     printf("result = %d\n", ret);
 51
 52     //-----------------------------------------
 53     binder_done(bs, &msg, &reply);
 54
 55     return 0;
 56 }
 57
 58


==============================================================================================================
cpp로

//myserver1.cpp
      서버의 기본 흐름
       1. 반드시 BBinder 클래스의 자식클래스로 만들어야 합니다.
       2.  
  3 #include <sys/types.h>
  4 #include <unistd.h>
  5 #include <grp.h>
  6 #include <binder/IPCThreadState.h>
  7 #include <binder/ProcessState.h>
  8 #include <binder/IServiceManager.h>
  9 #include <utils/Log.h>
 10 using namespace android;
 11
 12 enum {
 13     ADD = IBinder::FIRST_CALL_TRANSACTION,
 14     SUB,
 15 };
 16
 12 class Calc : public BBinder
 13 {
 14     public:
 15         int Add(int a, int b)
 16         {
 17             printf("Calc.Add(%d, %d)\n", a, b);
 18             return a + b;
 19         }
 15         int Sub(int a, int b)
 16         {
 17             printf("Calc.Sub(%d, %d)\n", a, b);
 18             return a - b;
 19         }
 21         virtual status_t onTransact(uint32_t code, // service code
 22                                     const Parcel& data, // data that client sent
 23                                     Parcel* reply,      // place that will send return value
 24                                     uint32_t flags = 0)
 25         {
 26             int ret;
 27             int a = data.readInt32();
 28             int b = data.readInt32();
 29
 30             switch(code)
 31             {
 32                 case ADD: ret = Add(a, b);
 33                         reply->writeInt32(ret);
 34                         break;
 32                 case SUB: ret = Sub(a, b);
 33                         reply->writeInt32(ret);
 34                         break; 
 35             }
 36             return 0;
 37         }
 38 };
 39
 40 int main(int argc, char** argv)
 41 {
 42     sp<ProcessState> proc(ProcessState::self()); // code that we learn yesterday.
 43     sp<IServiceManager> sm = defaultServiceManager();
 44     sm->addService(String16("myserver1"), new Calc); //Calc 객체가 token대신 들어가게 됩니다.
 45     IPCThreadState::self()->joinThreadPool(); // 이 순간 enter the loop
 46
 47     return 0;
 48 }
 49




//myclient1.cpp
  1 #include <sys/types.h>
  2 #include <unistd.h>
  3 #include <grp.h>
  4 #include <binder/IPCThreadState.h>
  5 #include <binder/ProcessState.h>
  6 #include <binder/IServiceManager.h>
  7 #include <utils/Log.h>
  8
  9 using namespace android;
 12 enum {
 13     ADD = IBinder::FIRST_CALL_TRANSACTION,
 14     SUB,
 15 };
 
 11 int main(int argc, char** argv)
 12 {
 13     sp<ProcessState> proc(ProcessState::self());    //드라이버 오픈 // 수신버퍼 생성 // IPCThreadState와는 Friend관계
         // 서비스 매니저를 래핑하는 클래스가 IServiceManager입니다.
 14     sp<IServiceManager> sm = defaultServiceManager();   //이순간 서비스 매니저를 만들고..
    

         // myserver1을 핸들을 알아냅니다.
         // 핸들(번호)를 알아낸 후 해당 번호를 관리하는 BpBinder객체를 만들어 줍니다.
         // BpBinder는 내부적으로 transact()함수가 있는데
         // 이 함수가 IPCThreadState를 사용해서 ioctl()함수로 드라이버와 통신합니다.
 16     sp<IBinder> svc = sm->getService(String16("myserver1")); // 결국 내부적으로 뭘할까요?
 17
 18     // now call the server func
 19     Parcel data, reply;
 20
 21     data.writeInt32(3);
 22     data.writeInt32(5);
 23     svc->transact(SUB, data, &reply);
 24     printf("result : %d\n", reply.readInt32());
 25     return 0;
 26

==============================================================
2번째꺼는 transact로 Add, Sub를 호출한다. Add, Sub를 호출하는 것처럼 보이지 않고
client를 만드는 사람은 SUB, ADD라는 코드를 이용해서 실행하는 모양새임

그래서 3번재꺼는 Add, Sub라는 걸 마치 server에서 사용하는 것처럼 할것임
이걸 프락시라고 말하는 것임

다른 서버의 함수를 호출하도록 만듬 Remote Process Call(RPC)를 짠 것임
 

//myclient2.cpp
#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>

using namespace android;

 
enum {
    ADD = IBinder::FIRST_CALL_TRANSACTION,
    SUB,
};

class BpCalc : public RefBase
{
    sp<IBinder> mRemote;
public:
    BpCalc(sp<IBinder>& p) : mRemote(p) {}
    sp<IBinder> remote() const {return mRemote; }

    int Add(int a, int b) {
        Parcel data, reply;
        data.writeInt32(a);
        data.writeInt32(b);
        int ret = mRemote->transact(ADD, data, &reply);
        return reply.readInt32();
    }
    int Sub(int a, int b) {
        Parcel data, reply;
        data.writeInt32(a);
        data.writeInt32(b);
        int ret = mRemote->transact(SUB, data, &reply);
        return reply.readInt32();
    }

    //모든 Proxy안에는 바인더를 인자로 받아서 객체를 만드는 static멤버를 만들기로 약속하자.
    static sp<BpCalc> asInterface(const sp<IBinder>& binder)
    {
         return new BpCalc(binder);
    }
};


template<typename T> sp<T> my_interface_cast(const sp<IBinder>& binder)
{
    return T::asInterface(binder);  //binder를 가지고 proxy를 얻을 수 있음
    //return new T(binder); // If Constructor is private? No way~
}


int main()
{
    sp<ProcessState> proc( ProcessState::self());
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> svc = sm->getService(String16("myserver1"));

    //바인더를 객체로 변경하는 코드입니다.
    //sp<BpCalc> pCalc = new BpCalc(svc);

    //숙제는 : 바인더로부터 Proxy객체를 만드는 캐스팅
    sp<BpCalc> pCalc = my_interface_cast<BpCalc>(svc);
    //윗 코드 binder를 proxy로 캐스팅하는 것처럼 보이지만 실제로는 객체를 생성한 것임

    int ret = pCalc->Add(1,2);
    printf("result : %d\n", ret);

    return 0;
}