zoukankan      html  css  js  c++  java
  • Android输入系统(1)—— 必备Linux知识: inotify epoll socketpair binder_fd

    一、inotify 和 epoll

    1.Android不使用hotplug机制,使用的是inotify机制。inotify监听的是/dev/input目录。

    2.使用inotify来监听文件的创建与删除,使用epoll来监听设备文件句柄的变化,包括inotify的fd。

    3.epoll支持管道,FIFO,套接字,POSIX消息队列,终端,设备等,但是就是不支持普通文件或目录的fd。
    测试验证,使用fifo测试epoll是可以的,但是使用普通文件来测试epoll的并发监听是不行的。

    3.参考代码: frameworks ativeservicesinputflingerEventHub.cpp

    参考文章:《深入理解Android 卷III》第五章 深入理解Android输入系统: http://blog.csdn.net/innost/article/details/47660387

    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, 它并不会立刻返回, 而是继续等待有数据

    5.使用分号隔开可以实现在命令行中输入多条语句:eg:# echo 1 > tmp/5; echo 2 > tmp/2

    6.试验Demo

    inotify.c

    #include <unistd.h>
    #include <stdio.h>
    #include <sys/inotify.h>
    #include <string.h>
    #include <errno.h>
    
    
    /*
     *²Î¿¼: frameworks
    ativeservicesinputflingerEventHub.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
    ", 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"
    ", event->wd, event->mask, event->len ? event->name : "");
            if(event->len) {
                if(event->mask & IN_CREATE) {
                    printf("create file: %s
    ", event->name);
                } else {
                    printf("delete file: %s
    ", 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>
    ", 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] ...
    ", 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
    ", mPendingEventItems[i].events);
                int len = read(mPendingEventItems[i].data.fd, buf, DATA_MAX_LEN);
                buf[len] = '';
                printf("get data: %s
    ", 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
    ativeservicesinputflingerEventHub.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
    ", 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"
    ", event->wd, event->mask, event->len ? event->name : "");
            if(event->len) {
                if(event->mask & IN_CREATE) {
                    printf("create file: %s
    ", 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
    ", name);
                    add_to_epoll(tmpFd, mEpollFd);
    
                    epoll_files[tmpFd] = name;
                        
                } else {
                    printf("delete file: %s
    ", event->name);
                    int tmpFd = get_epoll_fd_for_name(event->name);
                    if (tmpFd >= 0)
                    {
                        printf("remove from epoll: %s/%s
    ", 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>
    ", 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
    ", mPendingEventItems[i].events);
                    int len = read(mPendingEventItems[i].data.fd, buf, DATA_MAX_LEN);
                    buf[len] = '';
                    printf("get data: %s
    ", buf);
                    //sleep(3);
                }
            }
            
        }
        
        return 0;
    }
    View Code

    二、双向线程间通信(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
    ativelibsinputInputTransport.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] = '';
            printf("%s
    ", 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] = '';
            printf("%s
    ", buf);
            
            /* main threadÏòthread1 ·¢³ö: Hello, thread1 */
            len = sprintf(buf, "Hello, thread1, cnt = %d", cnt++);
            write(fd, buf, len);
        }
    }
    View Code


    三、socketpair借助binder fd实现任意进程之间的双向通信

    1.参考代码: frameworksasecorejniandroid_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
    ativelibsinderParcel.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

    /* 参考: frameworksavmedialibmediaIMediaPlayerService.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 */
    
                /* 参考:
                 * frameworksasecorejniandroid_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
    ", ++cnt);
    
    }
    
    int BnHelloService::sayhello_to(const char *name)
    {
        static int cnt = 0;
        ALOGI("say hello to %s : %d
    ", 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
            {
    
                /* 参考:
                 * frameworksasecorejniandroid_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

    /* 参考: frameworksavincludemediaIMediaPlayerService.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:
    ");
            ALOGI("%s <readfile>
    ", argv[0]);
            ALOGI("%s <hello|goodbye>
    ", argv[0]);
            ALOGI("%s <hello|goodbye> <name>
    ", 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
    ");
                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
    ");
                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] = '';
                ALOGI("%s
    ", buf);
            
                sleep(3);
            }
        }
        else
        {
    
            sp<IBinder> binder = sm->getService(String16("goodbye"));
            if (binder == 0)
            {
                ALOGI("can't get goodbye service
    ");
                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

    /* 参考: frameworksavmediamediaserverMain_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] = '';
                ALOGI("%s
    ", 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

    /* 参考: frameworksavincludemediaIMediaPlayerService.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

    /* 参考: frameworksavmedialibmediaIMediaPlayerService.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
    ", ++cnt);
    
    }
    
    int BnGoodbyeService::saygoodbye_to(const char *name)
    {
        static int cnt = 0;
        ALOGI("say goodbye to %s : %d
    ", name, ++cnt);
        return cnt;
    }
    
    }
    View Code

    BpGoodbyeService.cpp

    /* 参考: frameworksavmedialibmediaIMediaPlayerService.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
  • 相关阅读:
    编译
    Package vim is not available, but is referred to by another package.
    Http 请求处理流程 Asp.Net 编程 TraceFact.Net
    JavaScript中两个感叹号的作用
    IE6 链接失效 <a>失效 不能点击
    父元素绝对定位 子元素在IE6 不能点击
    ie6 ie7 绝对定位 相对定位 层被遮住
    HTTP深入浅出http请求
    主流的js template引擎 前端模板
    第3章:基本概念(一)
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/10855163.html
Copyright © 2011-2022 走看看