Android输入系统(1)—— 必备Linux知识: inotify epoll socketpair binder_fd 双向binder通信

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

 

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

 


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

 

posted on 2019-05-13 10:16  Hello-World3  阅读(894)  评论(0编辑  收藏  举报

导航