Skip to main content
 首页 » 编程设计

Android输入系统(1)—— 必备Linux知识: inotify epoll socketpair binder_fd

2022年07月19日27yyy_WW

一、inotify 和 epoll

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.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\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; 
}

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; 
}

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; 
}

二、双向线程间通信(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); 
    } 
}


三、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; 
} 
 
 
}

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"); 
 
}

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

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; 
}

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; 
}

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

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; 
} 
 
}

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"); 
 
}

本文参考链接:https://www.cnblogs.com/hellokitty2/p/10855163.html