Android中设计的Ashmem使用起来非常方便,但是很多封装使用,却让其看起来复杂了。
下面通过一个例子来查看其使用
服务端创建共享内存fd,并通过binder通信把fd提供给客户端
#define LOG_TAG "bindertest"
#include <stdio.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <binder/IBinder.h>
#include <binder/Binder.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <iostream>
#include <iomanip>
#include <unistd.h>
//for ALOGD
#include <log/log.h>
using namespace android;
using namespace std;
//
int32_t* pdata = NULL;
int fd = -1;
class myBinder : public BBinder
{
public:
status_t dump(int fd2, const Vector<String16>& args)
{
write(fd2, "myBinder dump called ", 22);
return NO_ERROR;
}
status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch (code)
{
case 1: {
printf("onTransact called, case 1\n");
int in_data = data.readInt32();
reply->writeInt32(in_data * 2);
return NO_ERROR;
}
case 2:{
printf("onTransact called, case 2\n");
return NO_ERROR;
}
case 3:{
printf("onTransact called, case 3\n");
reply->writeFileDescriptor(fd);
return NO_ERROR;
}
}
return BBinder::onTransact(code, data, reply, flags);
}
};
int main(int argc, char** argv)
{
sp < ProcessState > proc(ProcessState::self());
sp < IServiceManager > sm = defaultServiceManager();
sm->addService(String16("atest"), new myBinder());
//test ashmem
//ashmem_create_region and mmap is called in the init of MemoryHeapBase
sp<MemoryHeapBase> heap = new MemoryHeapBase(32, 0, "testmem");
if (heap != NULL)
{
pdata = (int32_t*)heap->getBase();
if (pdata != NULL)
{
//*pdata = 1;
pdata[0] = 1;
pdata[1] = 2;
pdata[2] = 3;
pdata[3] = 4;
int* pos = pdata;
int* p0 = pdata;
for (int i = 0; i < 4; i++)
{
cout << "data[" << i << "] = " << *(p0 + i) << endl;
}
}
fd = heap->getHeapID();
}
printf("add myService\n");
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return 0;
}
服务端创建了共享内存,并且向里面写入了数据
再来测试下客户端使用这个共享内存
#include <stdio.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <binder/IBinder.h>
#include <binder/Binder.h>
#include <binder/ProcessState.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <iostream>
#include <iomanip>
#include <unistd.h>
//for lseek
#include <sys/types.h>
//for mmap
#include <sys/mman.h>
using namespace android;
using namespace std;
class Observer : public IBinder::DeathRecipient
{
public:
//
void binderDied(const wp<IBinder>& who)
{
printf("binderDied !\n");
}
};
int main(int argc, char* const argv[])
{
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> service = sm->checkService(String16("atest"));//test
Parcel data;
Parcel reply;
int fd = -1;
int err = service->transact(3, data, &reply, 0);
if (err == NO_ERROR)
{
fd = reply.readFileDescriptor();
printf("\n get reply, result is %d \n", fd);
//mmap
int32_t* base = (int32_t*)mmap(0, 64, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
cout << "base[0] = " << *base << " ,base[1] = " << base[1] << endl;
int data = 0;
//read 4 byte from fd to data
read(fd, (void*)&data, 4);
cout << "data is " << data << endl;
}
else
{
printf("error \n");
}
return 0;
}
客户端对接收到的fd进行mmap操作后,获取到了映射的内存地址,就可以进行读写操作了,
客户端也可以使用read(fd)的方式去读取数据,但是需要注意的是,这会导致文件偏移,一般还是使用内存操作比较方便
相应的mk文件
LOCAL_PATH := $(call my-dir)
#for service
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
service.cpp
LOCAL_SHARED_LIBRARIES := \
libbase \
libutils \
liblog \
libbinder
ifeq ($(TARGET_OS),linux)
LOCAL_CFLAGS += -DXP_UNIX
#LOCAL_SHARED_LIBRARIES += librt
endif
LOCAL_MODULE:= binderServer
include $(BUILD_EXECUTABLE)
#for client
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
client.cpp
LOCAL_SHARED_LIBRARIES := \
libbase \
libutils \
liblog \
libbinder
ifeq ($(TARGET_OS),linux)
LOCAL_CFLAGS += -DXP_UNIX
#LOCAL_SHARED_LIBRARIES += librt
endif
LOCAL_MODULE:= binderClient
include $(BUILD_EXECUTABLE)