Android輸入系統(1)—— 必備Linux知識: inotify epoll socketpair binder_fd

1、inotify 和 epollandroid

1.Android不使用hotplug機制,使用的是inotify機制。inotify監聽的是/dev/input目錄。數組

2.使用inotify來監聽文件的建立與刪除,使用epoll來監聽設備文件句柄的變化,包括inotify的fd。網絡

3.epoll支持管道,FIFO,套接字,POSIX消息隊列,終端,設備等,可是就是不支持普通文件或目錄的fd。
測試驗證,使用fifo測試epoll是能夠的,可是使用普通文件來測試epoll的併發監聽是不行的。併發

3.參考代碼: frameworks\native\services\inputflinger\EventHub.cppsocket

參考文章:《深刻理解Android 卷III》第五章 深刻理解Android輸入系統: http://blog.csdn.net/innost/article/details/47660387ide

4.測試遇到問題:使用O_RDONLY|O_NONBLOCK打開的FIFO讓epoll去監聽,echo一個數據到fifo中後,epoll_wait()一直沒法阻塞住。
tmpFd = open(argv[i], O_RDONLY|O_NONBLOCK);
解答: epoll,fifo : http://stackoverflow.com/questions/15055065/o-rdwr-on-named-pipes-with-poll函數

使用fifo,epoll程序是reader
echo aa > tmp/1 是writer
a.
若是reader以O_RDONLY|O_NONBLOCK打開FIFO文件,
當writer寫入數據時, epoll_wait會馬上返回;
當writer關閉FIFO以後, reader再次調用epoll_wait, 它也會馬上返回(緣由是EPPLLHUP, 描述符被掛斷(這個能夠從epoll_event結構中看到EPPLLHUP碼))
b.
若是reader以O_RDWR打開FIFO文件
當writer寫入數據時, epoll_wait會馬上返回;
當writer關閉FIFO以後, reader再次調用epoll_wait, 它並不會馬上返回, 而是繼續等待有數據oop

5.使用分號隔開能夠實如今命令行中輸入多條語句:eg:# echo 1 > tmp/5; echo 2 > tmp/2測試

6.試驗Demoui

inotify.c

#include <unistd.h> #include <stdio.h> #include <sys/inotify.h> #include <string.h> #include <errno.h>


/* *²Î¿¼: frameworks\native\services\inputflinger\EventHub.cpp */

/*Usage: inotify <dir> */

int read_process_inotify_fd(int fd) { int res; char event_buf[512]; int event_size; int event_pos = 0; struct inotify_event *event; /* block read */ res = read(fd, event_buf, sizeof(event_buf)); if(res < (int)sizeof(*event)) { if(errno == EINTR) return 0; printf("could not get event, %s\n", strerror(errno)); return -1; } /* process * ¶Áµ½µÄÊý¾ÝÊÇ1¸ö»ò¶à¸öinotify_event * ËüÃǵij¤¶È²»Ò»Ñù * Öð¸ö´¦Àí */

    while(res >= (int)sizeof(*event)) { event = (struct inotify_event *)(event_buf + event_pos); //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
        if(event->len) { if(event->mask & IN_CREATE) { printf("create file: %s\n", event->name); } else { printf("delete file: %s\n", event->name); } } event_size = sizeof(*event) + event->len; // buf[0] with no length
        res -= event_size; event_pos += event_size; } return 0; } int main(int argc, char **argv) { int mINotifyFd; int result; if (argc != 2) { printf("Usage: %s <dir>\n", argv[0]); return -1; } /* inotify_init */ mINotifyFd = inotify_init(); /* add watch */ result = inotify_add_watch(mINotifyFd, argv[1], IN_DELETE | IN_CREATE); /* read */
    while (1) { read_process_inotify_fd(mINotifyFd); } return 0; }
View Code

epoll.c

#include <sys/epoll.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h>


#if 0 typedef union epoll_data { // it is a union.
    void        *ptr; int fd; uint32_t u32; uint64_t u64; } epoll_data_t; struct epoll_event { uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */ }; #endif


#define DATA_MAX_LEN 500

/* usage: epoll <file1> [file2] [file3] ... */

int add_to_epoll(int fd, int epollFd) { int result; struct epoll_event eventItem; memset(&eventItem, 0, sizeof(eventItem)); eventItem.events = EPOLLIN; eventItem.data.fd = fd; result = epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &eventItem); return result; } void rm_from_epoll(int fd, int epollFd) { epoll_ctl(epollFd, EPOLL_CTL_DEL, fd, NULL); } int main(int argc, char **argv) { int mEpollFd; int i; char buf[DATA_MAX_LEN]; // Maximum number of signalled FDs to handle at a time.
    static const int EPOLL_MAX_EVENTS = 16; // The array of pending epoll events and the index of the next event to be handled.
    struct epoll_event mPendingEventItems[EPOLL_MAX_EVENTS]; if (argc < 2) { printf("Usage: %s <file1> [file2] [file3] ...\n", argv[0]); return -1; } /* epoll_create */ mEpollFd = epoll_create(8); // man epoll said that 8 not used.

    /* for each file: * open it * add it to epoll: epoll_ctl(...EPOLL_CTL_ADD...) */
    for (i = 1; i < argc; i++) { //int tmpFd = open(argv[i], O_RDONLY|O_NONBLOCK);
        int tmpFd = open(argv[i], O_RDWR); add_to_epoll(tmpFd, mEpollFd); } /* epoll_wait */
    while (1) { int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, -1); for (i = 0; i < pollResult; i++) { printf("Event code is: 0x%x\n", mPendingEventItems[i].events); int len = read(mPendingEventItems[i].data.fd, buf, DATA_MAX_LEN); buf[len] = '\0'; printf("get data: %s\n", buf); //sleep(3);
 } } return 0; }
View Code

inotify_epoll.c

#include <sys/epoll.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <sys/inotify.h> #include <stdlib.h> #include <errno.h>


#define DATA_MAX_LEN 500
#define MAX_FILES 1000

static char *base_dir; static char *epoll_files[MAX_FILES]; #if 0 typedef union epoll_data { void        *ptr; int fd; uint32_t u32; uint64_t u64; } epoll_data_t; #endif



/* usage: epoll <file1> [file2] [file3] ... */

int add_to_epoll(int fd, int epollFd) { int result; struct epoll_event eventItem; memset(&eventItem, 0, sizeof(eventItem)); eventItem.events = EPOLLIN; eventItem.data.fd = fd; result = epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &eventItem); return result; } void rm_from_epoll(int fd, int epollFd) { epoll_ctl(epollFd, EPOLL_CTL_DEL, fd, NULL); } int get_epoll_fd_for_name(char *name) { int i; char name_to_find[500]; sprintf(name_to_find, "%s/%s", base_dir, name); for (i = 0; i < MAX_FILES; i++) { if (!epoll_files[i]) continue; if (!strcmp(epoll_files[i], name_to_find)) return i; } return -1; } /* *²Î¿¼: frameworks\native\services\inputflinger\EventHub.cpp */

/*Usage: inotify <dir> */

int read_process_inotify_fd(int mINotifyFd, int mEpollFd) { int res; char event_buf[512]; int event_size; int event_pos = 0; struct inotify_event *event; /* read */ res = read(mINotifyFd, event_buf, sizeof(event_buf)); if(res < (int)sizeof(*event)) { if(errno == EINTR) return 0; printf("could not get event, %s\n", strerror(errno)); return -1; } /* process * ¶Áµ½µÄÊý¾ÝÊÇ1¸ö»ò¶à¸öinotify_event * ËüÃǵij¤¶È²»Ò»Ñù * Öð¸ö´¦Àí */

    while(res >= (int)sizeof(*event)) { event = (struct inotify_event *)(event_buf + event_pos); //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : "");
        if(event->len) { if(event->mask & IN_CREATE) { printf("create file: %s\n", event->name); char *name = malloc(512); sprintf(name, "%s/%s", base_dir, event->name); int tmpFd = open(name, O_RDWR); printf("add to epoll: %s\n", name); add_to_epoll(tmpFd, mEpollFd); epoll_files[tmpFd] = name; } else { printf("delete file: %s\n", event->name); int tmpFd = get_epoll_fd_for_name(event->name); if (tmpFd >= 0) { printf("remove from epoll: %s/%s\n", base_dir, event->name); rm_from_epoll(tmpFd, mEpollFd); free(epoll_files[tmpFd]); } } } event_size = sizeof(*event) + event->len; res -= event_size; event_pos += event_size; } return 0; } int main(int argc, char **argv) { int mEpollFd; int i; char buf[DATA_MAX_LEN]; int mINotifyFd; int result; // Maximum number of signalled FDs to handle at a time.
    static const int EPOLL_MAX_EVENTS = 16; // The array of pending epoll events and the index of the next event to be handled.
    struct epoll_event mPendingEventItems[EPOLL_MAX_EVENTS]; if (argc != 2) { printf("Usage: %s <tmp>\n", argv[0]); return -1; } base_dir = argv[1]; /* epoll_create */ mEpollFd = epoll_create(8); /* inotify_init */ mINotifyFd = inotify_init(); /* add watch */ result = inotify_add_watch(mINotifyFd, base_dir, IN_DELETE | IN_CREATE); add_to_epoll(mINotifyFd, mEpollFd); /* epoll_wait */
    while (1) { int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, -1); for (i = 0; i < pollResult; i++) { if (mPendingEventItems[i].data.fd == mINotifyFd) { read_process_inotify_fd(mINotifyFd, mEpollFd); } else { printf("Reason: 0x%x\n", mPendingEventItems[i].events); int len = read(mPendingEventItems[i].data.fd, buf, DATA_MAX_LEN); buf[len] = '\0'; printf("get data: %s\n", buf); //sleep(3);
 } } } return 0; }
View Code

 

2、雙向線程間通訊(socketpair)

參考: frameworks/native/libs/input/InputTransport.cpp

1.binder只能單向由Client發起請求,而Service沒法主動傳輸數據,因此單binder是不行的。

2.socketpair能夠實現雙向通訊,可是缺點很是明顯,只能在線程間通訊或有親緣關係的父子進程之間的通訊。

3.socketpair是基於網絡的,fd[0]和fd[1]都關聯了一個接受和發送緩衝區。

4.使用socketpair進行任意兩個進程間通訊的方法
socketpair產生兩個fd,fd[0]和fd[1],fd[1]經過binder與另外一個進程進行通訊。

5.試驗Demo

#include <pthread.h> #include <unistd.h> #include <stdio.h> #include <sys/types.h>          /* See NOTES */ #include <sys/socket.h>

#define SOCKET_BUFFER_SIZE      (32768U)


/* ²Î¿¼: * frameworks\native\libs\input\InputTransport.cpp */

void *function_thread1 (void *arg) { int fd = (int)arg; char buf[500]; int len; int cnt = 0; while (1) { /* Ïò mainÏ̷߳¢³ö: Hello, main thread */ len = sprintf(buf, "Hello, main thread, cnt = %d", cnt++); write(fd, buf, len); /* ¶ÁÈ¡Êý¾Ý(mainÏ̷߳¢»ØµÄÊý¾Ý) */ len = read(fd, buf, 500); buf[len] = '\0'; printf("%s\n", buf); sleep(2); } return NULL; } int main(int argc, char **argv) { int sockets[2]; socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets); int bufferSize = SOCKET_BUFFER_SIZE; setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); /* ´´½¨Ïß³Ì1 */ pthread_t threadID; pthread_create(&threadID, NULL, function_thread1, (void *)sockets[1]); char buf[500]; int len; int cnt = 0; int fd = sockets[0]; while(1) { /* ¶ÁÊý¾Ý: Ïß³Ì1·¢³öµÄÊý¾Ý */ len = read(fd, buf, 500); buf[len] = '\0'; printf("%s\n", buf); /* main threadÏòthread1 ·¢³ö: Hello, thread1 */ len = sprintf(buf, "Hello, thread1, cnt = %d", cnt++); write(fd, buf, len); } }
View Code

 


3、socketpair藉助binder fd實現任意進程之間的雙向通訊

1.參考代碼: frameworks\base\core\jni\android_view_InputChannel.cpp (用binder傳文件句柄)

server端寫fd: android_view_InputChannel_nativeWriteToParcel parcel->writeDupFileDescriptor client端讀fd: android_view_InputChannel_nativeReadFromParcel int rawFd = parcel->readFileDescriptor(); int dupFd = dup(rawFd); frameworks\native\libs\binder\Parcel.cpp

2.進程對fd的管理
struct task_struct中有一個struct files_struct *files成員表示進程打開的文件,files_struct中有一個struct fdtable __rcu *fdt成員,
它表示打開的文件表結構,其內部有一個struct file __rcu **fd,這個fd成員是一個指針數組,進程打開文件得到的句柄就是這個數組的下標,
每個打開的文件使用一個struct file結構表示(也就是說這個struct file實體不是某一個進程的,每一個進程只不過是對其持有一個引用)。

若一個進程想要使用另外一個進程的fd的話,那麼這個進程必需要在本身的file數組上找到一個空閒項,而後指向這個打開的文件。

3.進程的文件描述符fd是per進程的,不能直接傳輸給另外一個進程使用,binder驅動作了處理,見binder驅動BINDER_TYPE_FD

4.ls -l /proc/$(pid)/fd 能夠查看打開進程打開了哪些文件。

5.Parcell.cpp的141行case BINDER_TYPE_FD會去關閉文件句柄,所以須要dup()句柄。

6.調試技巧
(1)如果機率地執行到某處會出問題,能夠在此處以前加while(1)usleep(100);來查看進程的狀態。


7.實現Demo

BnGoodbyeService.cpp

/* 參考: frameworks\av\media\libmedia\IMediaPlayerService.cpp */

#define LOG_TAG "HelloService" #include "IHelloService.h"


namespace android { BnHelloService::BnHelloService() { } BnHelloService::BnHelloService(int fd) { this->fd = fd; } status_t BnHelloService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { /* 解析數據,調用sayhello/sayhello_to */

    switch (code) { case HELLO_SVR_CMD_SAYHELLO: { sayhello(); reply->writeInt32(0);  /* no exception */
            return NO_ERROR; } break; case HELLO_SVR_CMD_SAYHELLO_TO: { /* 從data中取出參數 */ int32_t policy = data.readInt32(); String16 name16_tmp = data.readString16(); /* IHelloService */ String16 name16 = data.readString16(); String8 name8(name16); int cnt = sayhello_to(name8.string()); /* 把返回值寫入reply傳回去 */ reply->writeInt32(0);  /* no exception */ reply->writeInt32(cnt); return NO_ERROR; } break; case HELLO_SVR_CMD_GET_FD: { int fd = this->get_fd(); reply->writeInt32(0);  /* no exception */

            /* 參考: * frameworks\base\core\jni\android_view_InputChannel.cpp * android_view_InputChannel_nativeWriteToParcel */ reply->writeDupFileDescriptor(fd); /*關鍵是這個函數,驅動會作對應的處理*/
            return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } } void BnHelloService::sayhello(void) { static int cnt = 0; ALOGI("say hello : %d\n", ++cnt); } int BnHelloService::sayhello_to(const char *name) { static int cnt = 0; ALOGI("say hello to %s : %d\n", name, ++cnt); return cnt; } int BnHelloService::get_fd(void) { return fd; } }
View Code

BpHelloService.cpp

#include "IHelloService.h"

namespace android { class BpHelloService: public BpInterface<IHelloService> { public: BpHelloService(const sp<IBinder>& impl) : BpInterface<IHelloService>(impl) { } void sayhello(void) { /* 構造/發送數據 */ Parcel data, reply; data.writeInt32(0); data.writeString16(String16("IHelloService")); remote()->transact(HELLO_SVR_CMD_SAYHELLO, data, &reply); } int sayhello_to(const char *name) { /* 構造/發送數據 */ Parcel data, reply; int exception; data.writeInt32(0); data.writeString16(String16("IHelloService")); data.writeString16(String16(name)); remote()->transact(HELLO_SVR_CMD_SAYHELLO_TO, data, &reply); exception = reply.readInt32(); if (exception) return -1; else
            return reply.readInt32(); } int get_fd(void) { /* 構造/發送數據 */ Parcel data, reply; int exception; data.writeInt32(0); data.writeString16(String16("IHelloService")); remote()->transact(HELLO_SVR_CMD_GET_FD, data, &reply); exception = reply.readInt32(); if (exception) return -1; else { /* 參考: * frameworks\base\core\jni\android_view_InputChannel.cpp * android_view_InputChannel_nativeReadFromParcel */
            /* * 也能夠收到這個fd,可是這個fd仍是須要dup()一下, * 由於parcel的析構函數中會釋放它. */
            int rawFd = reply.readFileDescriptor(); return dup(rawFd); } } }; IMPLEMENT_META_INTERFACE(HelloService, "android.media.IHelloService"); }
View Code

IHelloService.h

/* 參考: frameworks\av\include\media\IMediaPlayerService.h */ #ifndef ANDROID_IHELLOERVICE_H #define ANDROID_IHELLOERVICE_H #include <utils/Errors.h>  // for status_t
#include <utils/KeyedVector.h> #include <utils/RefBase.h> #include <utils/String8.h> #include <binder/IInterface.h> #include <binder/Parcel.h>

#define HELLO_SVR_CMD_SAYHELLO     1
#define HELLO_SVR_CMD_SAYHELLO_TO  2
#define HELLO_SVR_CMD_GET_FD       3


namespace android { class IHelloService: public IInterface { public: DECLARE_META_INTERFACE(HelloService); virtual void sayhello(void) = 0; virtual int sayhello_to(const char *name) = 0; virtual int get_fd(void) = 0; }; class BnHelloService: public BnInterface<IHelloService> { private: int fd; public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); virtual void sayhello(void); virtual int sayhello_to(const char *name); virtual int get_fd(void); BnHelloService(); BnHelloService(int fd); }; } #endif
View Code

test_client.cpp

#define LOG_TAG "TestService"
//#define LOG_NDEBUG 0
 #include <fcntl.h> #include <sys/prctl.h> #include <sys/wait.h> #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> #include <binder/IServiceManager.h> #include <cutils/properties.h> #include <utils/Log.h> #include <unistd.h> #include "IHelloService.h" #include "IGoodbyeService.h"

using namespace android; /* ./test_client <hello|goodbye> * ./test_client <readfile> * ./test_client <hello|goodbye> <name> */
int main(int argc, char **argv) { int cnt; if (argc < 2){ ALOGI("Usage:\n"); ALOGI("%s <readfile>\n", argv[0]); ALOGI("%s <hello|goodbye>\n", argv[0]); ALOGI("%s <hello|goodbye> <name>\n", argv[0]); return -1; } /* getService */
    /* 打開驅動, mmap */ sp<ProcessState> proc(ProcessState::self()); /* 得到BpServiceManager */ sp<IServiceManager> sm = defaultServiceManager(); if (strcmp(argv[1], "hello") == 0) { sp<IBinder> binder = sm->getService(String16("hello")); if (binder == 0) { ALOGI("can't get hello service\n"); return -1; } /* service確定是BpHelloServie指針 */ sp<IHelloService> service = interface_cast<IHelloService>(binder); /* 調用Service的函數 */
        if (argc < 3) { service->sayhello(); ALOGI("client call sayhello"); } else { cnt = service->sayhello_to(argv[2]); ALOGI("client call sayhello_to, cnt = %d", cnt); } } else if (strcmp(argv[1], "readfile") == 0) { sp<IBinder> binder = sm->getService(String16("hello")); if (binder == 0) { ALOGI("can't get hello service\n"); return -1; } /* service確定是BpHelloServie指針 */ sp<IHelloService> service = interface_cast<IHelloService>(binder); /* 調用Service的函數 */
        /* * 此時binder驅動已經爲進程處理了task_struct的struct file, 當前進程 * 能夠直接操做這個文件fd了。 */
        int fd = service->get_fd(); ALOGI("client call get_fd = %d", fd); char buf[500]; int len; int cnt = 0; while (1) { /* 向 test_server 進程發出: Hello, test_server */ len = sprintf(buf, "Hello, test_server, cnt = %d", cnt++); /*目前這個write、read就沒有再通過binder了。*/ write(fd, buf, len); /* 讀取數據(test_server進程發回的數據) */ len = read(fd, buf, 500); buf[len] = '\0'; ALOGI("%s\n", buf); sleep(3); } } else { sp<IBinder> binder = sm->getService(String16("goodbye")); if (binder == 0) { ALOGI("can't get goodbye service\n"); return -1; } /* service確定是BpGoodbyeServie指針 */ sp<IGoodbyeService> service = interface_cast<IGoodbyeService>(binder); /* 調用Service的函數 */
        if (argc < 3) { service->saygoodbye(); ALOGI("client call saygoodbye"); } else { cnt = service->saygoodbye_to(argv[2]); ALOGI("client call saygoodbye_to, cnt = %d", cnt); } } return 0; }
View Code

test_server.cpp

/* 參考: frameworks\av\media\mediaserver\Main_mediaserver.cpp */

#define LOG_TAG "TestService"
//#define LOG_NDEBUG 0
 #include <fcntl.h> #include <sys/prctl.h> #include <sys/wait.h> #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> #include <binder/IServiceManager.h> #include <cutils/properties.h> #include <utils/Log.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/socket.h> #include "IHelloService.h" #include "IGoodbyeService.h"

#define SOCKET_BUFFER_SIZE      (32768U)

using namespace android; /* 參考: * http://blog.csdn.net/linan_nwu/article/details/8222349
 */
class MyThread: public Thread { private: int fd; public: MyThread() {} MyThread(int fd) { this->fd = fd; } //若是返回true,循環調用此函數,返回false下一次不會再調用此函數 
    bool threadLoop() { char buf[500]; int len; int cnt = 0; while(1) { /* 讀數據: test_client發出的數據 */ len = read(fd, buf, 500); buf[len] = '\0'; ALOGI("%s\n", buf); /* 向 test_client 發出: Hello, test_client */ len = sprintf(buf, "Hello, test_client, cnt = %d", cnt++); write(fd, buf, len); } return true; } }; /* usage : test_server */
int main(void) { int sockets[2]; socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets); int bufferSize = SOCKET_BUFFER_SIZE; setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); /* 建立一個線程, 用於跟test_client使用socketpiar通訊 */ sp<MyThread> th = new MyThread(sockets[0]); th->run(); /* addService */

    /* while(1){ read data, 解析數據, 調用服務函數 } */

    /* 打開驅動, mmap */ sp<ProcessState> proc(ProcessState::self()); /* 得到BpServiceManager */ sp<IServiceManager> sm = defaultServiceManager(); sm->addService(String16("hello"), new BnHelloService(sockets[1])); /*將sockets[1]傳給遠端進程*/ sm->addService(String16("goodbye"), new BnGoodbyeService());       /*這個是無關的*/

    /* 循環體 */ ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); return 0; }
View Code

IGoodbyeService.h

/* 參考: frameworks\av\include\media\IMediaPlayerService.h */ #ifndef ANDROID_IGOODBYEERVICE_H #define ANDROID_IGOODBYEERVICE_H #include <utils/Errors.h>  // for status_t
#include <utils/KeyedVector.h> #include <utils/RefBase.h> #include <utils/String8.h> #include <binder/IInterface.h> #include <binder/Parcel.h>

#define GOODBYE_SVR_CMD_SAYGOODBYE     1
#define GOODBYE_SVR_CMD_SAYGOODBYE_TO  2


namespace android { class IGoodbyeService: public IInterface { public: DECLARE_META_INTERFACE(GoodbyeService); virtual void saygoodbye(void) = 0; virtual int saygoodbye_to(const char *name) = 0; }; class BnGoodbyeService: public BnInterface<IGoodbyeService> { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); virtual void saygoodbye(void); virtual int saygoodbye_to(const char *name); }; } #endif
View Code

BnGoodbyeService.cpp

/* 參考: frameworks\av\media\libmedia\IMediaPlayerService.cpp */

#define LOG_TAG "GoodbyeService" #include "IGoodbyeService.h"


namespace android { status_t BnGoodbyeService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { /* 解析數據,調用saygoodbye/saygoodbye_to */

    switch (code) { case GOODBYE_SVR_CMD_SAYGOODBYE: { saygoodbye(); reply->writeInt32(0);  /* no exception */
            return NO_ERROR; } break; case GOODBYE_SVR_CMD_SAYGOODBYE_TO: { /* 從data中取出參數 */ int32_t policy = data.readInt32(); String16 name16_tmp = data.readString16(); /* IGoodbyeService */ String16 name16 = data.readString16(); String8 name8(name16); int cnt = saygoodbye_to(name8.string()); /* 把返回值寫入reply傳回去 */ reply->writeInt32(0);  /* no exception */ reply->writeInt32(cnt); return NO_ERROR; } break; default: return BBinder::onTransact(code, data, reply, flags); } } void BnGoodbyeService::saygoodbye(void) { static int cnt = 0; ALOGI("say goodbye : %d\n", ++cnt); } int BnGoodbyeService::saygoodbye_to(const char *name) { static int cnt = 0; ALOGI("say goodbye to %s : %d\n", name, ++cnt); return cnt; } }
View Code

BpGoodbyeService.cpp

/* 參考: frameworks\av\media\libmedia\IMediaPlayerService.cpp */ #include "IGoodbyeService.h"

namespace android { class BpGoodbyeService: public BpInterface<IGoodbyeService> { public: BpGoodbyeService(const sp<IBinder>& impl) : BpInterface<IGoodbyeService>(impl) { } void saygoodbye(void) { /* 構造/發送數據 */ Parcel data, reply; data.writeInt32(0); data.writeString16(String16("IGoodbyeService")); remote()->transact(GOODBYE_SVR_CMD_SAYGOODBYE, data, &reply); } int saygoodbye_to(const char *name) { /* 構造/發送數據 */ Parcel data, reply; int exception; data.writeInt32(0); data.writeString16(String16("IGoodbyeService")); data.writeString16(String16(name)); remote()->transact(GOODBYE_SVR_CMD_SAYGOODBYE_TO, data, &reply); exception = reply.readInt32(); if (exception) return -1; else
            return reply.readInt32(); } }; IMPLEMENT_META_INTERFACE(GoodbyeService, "android.media.IGoodbyeService"); }
View Code
相關文章
相關標籤/搜索