一、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输入系统:
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;
/* 参考:
*
*/
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