ashmme的典型用法是先打开设备文件,然后做mmap映射。
第一步通过调用ashmem_create_region函数,这个函数完成这几件事:
1)fd = open("/dev/ashmem", O_RDWR);
2)ioctl(fd, ASHMEM_SET_NAME, region_name); // 这一步可选
3)ioctl(fd, ASHMEM_SET_SIZE, region_size);
第二步,应用程序一般会调用mmap来把ashmem分配的空间映射到进程空间:
mapAddr = mmap(NULL, pHdr->mapLength, PROT_READ |PROT_WRITE, MAP_PRIVATE, fd, 0);
应用程序还可以通过ioctl来pin和unpin某一段映射的空间,以提示内核的pagecache算法可以把哪些页面回收,这是一般mmap做不到的。
可以说ashmem以较小的代价(用户需进行额外的ioctl调用来设置名字,大小,pin和unpin),获得了一些内存使用的智能性。
ashmem本身实现也很小巧,只有不到700行。原因是借助了内核已经有的工具,例如shmem_file_setup(支撑文件),cache_shrinker(slab分配算法的页面回收的回调函数)等。
如果ashmem不使用内核驱动实现,则pin/unpin的语义比较难以实现,或者即使实现,效率也不会很高。但查询android源码,使用pin/unpin很少,看来ashmem还是没有很好地用起来。
如果不使用ashmem驱动,并且舍弃pin/unpin语义,那么模拟ashmem的语义还是很简单的。首先,ashmem_create_region可以为进程创建一个唯一的文件(如进程名+时戳),打开,然后返回这个文件的fd;接着应用程序可以进性一般的mmap操作了。如果不使用ashmem_create_region接口函数,那么使用anonymous的mmap就可以了,但这种方式属于正在被丢弃的方式,而且并不是所有的系统都支持,比如Macos就不支持。
几个与内存相关的类的头文件如下所示:
IMemory.h:定义内存相关类的接口,表示堆内存的类IMemoryHeap和BnMemoryHeap,表示一般内存的类IMemory和BnMemory。
MemoryHeapBase.h:定义类MemoryHeapBase,继承并实现BnMemoryHeap
MemoryBase.h:定义类MemoryBase,继承并实现BnMemory
在一般的使用过程中,通常是以使用MemoryHeapBase类分配一块堆内存(类似malloc),而MemoryBase表示从一块分配好堆内存中的一部分内存。
class AudioTrackJniStorage {
public:
sp<MemoryHeapBase>mMemHeap;//这两个Memory很重要
sp<MemoryBase>mMemBase;
audiotrack_callback_cookie mCallbackData;
intmStreamType;
bool allocSharedMem(int sizeInBytes) {
mMemHeap = new MemoryHeapBase(sizeInBytes, 0, "AudioTrack Heap Base");
mMemBase = new MemoryBase(mMemHeap, 0, sizeInBytes);
//注意用法,先弄一个HeapBase,再把HeapBase传入到MemoryBase中去。
return true;
}
};
2 MemoryHeapBase
MemroyHeapBase也是Android搞的一套基于Binder机制的对内存操作的类。既然是Binder机制,那么肯定有一个服务端(Bnxxx),一个代理端Bpxxx。看看MemoryHeapBase定义:
class MemoryHeapBase : public virtual BnMemoryHeap
{
果然,从BnMemoryHeap派生,那就是Bn端。这样就和Binder挂上钩了
//Bp端调用的函数最终都会调到Bn这来
对Binder机制不了解的,可以参考:
http://blog.csdn.net/Innost/archive/2011/01/08/6124685.aspx
有好几个构造函数,我们看看我们使用的:
MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
: mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
mDevice(0), mNeedUnmap(false)
{
const size_t pagesize = getpagesize();
size = ((size + pagesize-1) & ~(pagesize-1));
//创建共享内存,ashmem_create_region这个是系统提供的,可以不管它
//设备上打开的是/dev/ashmem设备,而Host上打开的是一个tmp文件
int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size);
mapfd(fd, size);//把刚才那个fd通过mmap方式得到一块内存
//不明白得去man mmap看看
mapfd完了后,mBase变量指向内存的起始位置, mSize是分配的内存大小,mFd是
ashmem_create_region返回的文件描述符
}
MemoryHeapBase提供了一下几个函数,可以获取共享内存的大小和位置。
getBaseID()--->返回mFd,如果为负数,表明刚才创建共享内存失败了
getBase()->返回mBase,内存位置
getSize()->返回mSize,内存大小
有了MemoryHeapBase,又搞了一个MemoryBase,这又是一个和Binder机制挂钩的类。
唉,这个估计是一个在MemoryHeapBase上的方便类吧?因为我看见了offset
那么估计这个类就是一个能返回当前Buffer中写位置(就是offset)的方便类
这样就不用用户到处去计算读写位置了。
ashmem主要 用于两个进程 的内存共享.
使用步骤:
1、server端调用ashmem_create_region创建一个共享内存,调用mmap进行内存映射,并把这个fd通过binder返回给client端面
2、client使用从server端拿到的句柄fd,调用mmap进行内存映射,这样client和server端 就映射到了同一块内存区域,从而实现共享。
相关代码实现
首先看一下binder基类
- #ifndef ANDROID_ITESTBINDERSERVICE_H_
- #define ANDROID_ITESTBINDERSERVICE_H_
- #include <utils/RefBase.h>
- #include <binder/IInterface.h>
- #include <binder/Parcel.h>
- namespace android {
- class Parcel;
- class ITestBinderService: public IInterface {
- public:
- DECLARE_META_INTERFACE(TestBinderService);
- virtual int allocbuf(int pipe_fd, const char* name, int bs) = 0;
- };
- class BnTestBinderService: public BnInterface<ITestBinderService> {
- public:
- virtual status_t onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags = 0);
- };
- }
- #endif /* ANDROID_ITESTBINDERSERVICE_H_ */
定义一个ITestBinderService的基类,还有一个BnTestBinderService实现binder的Bn服务端,这里定义了一个方法allocbuf,传入一个管道的一端面,还有共享内存的名字,长度。
现来看一下Bp的实现
- #include <utils/Log.h>
- #include "../TestBinderServer_new/ITestBinderService.h"
- namespace android {
- enum {
- TEST_ALLOCBUF = IBinder::FIRST_CALL_TRANSACTION,
- };
- class BpTestBinderService: public BpInterface<ITestBinderService> {
- public:
- BpTestBinderService(const sp<IBinder>& impl) :
- BpInterface<ITestBinderService> (impl) {
- }
- int allocbuf(int pipe_fd, const char* name, int bs) {
- Parcel data, reply;
- LOGI("Enter BpTestBinderService allocbuf,pipe_fd = %d , bs = %d", pipe_fd, bs);
- data.writeInterfaceToken(ITestBinderService::getInterfaceDescriptor());
- data.writeFileDescriptor(pipe_fd);
- data.writeCString(name);
- data.writeInt32(bs);
- remote()->transact(TEST_ALLOCBUF, data, &reply);
- int fd = reply.readFileDescriptor();
- LOGI("BpTestBinderService fd = %d", fd);
- int fd2 = dup(fd);
- LOGI("fd2 = %d", fd2);
- perror("3dup: ");
- return fd2;
- }
- };
- IMPLEMENT_META_INTERFACE(TestBinderService, "android.test.ITestBinderService");
- // ----------------------------------------------------------------------
- status_t BnTestBinderService::onTransact(uint32_t code, const Parcel& data,
- Parcel* reply, uint32_t flags) {
- switch (code) {
- case TEST_ALLOCBUF: {
- CHECK_INTERFACE(ITestBinderService, data, reply);
- int pipe_fd = data.readFileDescriptor();
- const char *name = data.readCString();
- int bs = data.readInt32();
- LOGI("Enter BnTestBinderService add,pipe_fd = %d , bs = %d", pipe_fd, bs);
- int sum = 0;
- int fd = allocbuf(pipe_fd, name, bs);
- LOGI("2BnTestBinderService fd = %d", fd);
- reply->writeFileDescriptor(fd);
- int fd2= dup(fd);
- LOGI("fd2 = %d", fd2);
- perror("2dup: ");
- return sum;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
- }
BnTestBinderService则恰好相反,读到相关参数,调用allocbuf函数,再把结果返回给Client端
再来看一下TestBinderService,主要是实现了BnTestBinderService
- #include <utils/KeyedVector.h>
- #include "ITestBinderService.h"
- namespace android {
- class TestBinderService: public BnTestBinderService {
- public:
- static void instantiate();
- int add(int a,int b);
- int allocbuf(int pipe_fd, const char* name, int bs);
- static void* test_proc(void*a);
- private:
- TestBinderService();
- virtual ~TestBinderService();
- };
- }
- #include <utils/Log.h>
- #include <pthread.h>
- #include <unistd.h>
- #include <sys/mman.h>
- #include <cutils/ashmem.h>
- #include <binder/IServiceManager.h>
- #include <binder/IPCThreadState.h>
- #include "binderservice.h"
- #include "TestBinderService.h"
- static int m_fd ;
- static int m_pipe_fd;
- char *m_buf;
- namespace android {
- void TestBinderService::instantiate() {
- LOGI("Enter TestBinderService::instantiate");
- status_t st = defaultServiceManager()->addService(
- String16("my.test.binder"), new TestBinderService());
- LOGD("ServiceManager addService ret=%d", st);
- LOGD("instantiate> end");
- }
- TestBinderService::TestBinderService() {
- m_fd = -1;
- m_buf = NULL;
- m_pipe_fd = -1;
- LOGD(" TestBinderServicet");
- }
- TestBinderService::~TestBinderService() {
- LOGD("TestBinderService destroyed,never destroy normally");
- }
- void* TestBinderService::test_proc(void*a) {
- char buf[100];
- int len = 100;
- int read_len = -1;
- int write_len = -1;
- while(1)
- {
- read_len = read(m_pipe_fd, buf, 12);
- LOGI("TestBinderService::read_len = %d.buf = %s",read_len, buf);
- sleep(1);
- if(read_len > 0)
- {
- //write_len = write(m_fd, "from server", 12);
- strncpy(m_buf, "from server", 12);
- }
- LOGI("TestBinderService::write_len = %d.",write_len);
- }
- return NULL;
- }
- int TestBinderService::allocbuf(int pipe_fd, const char* name, int bs) {
- int result = -1;
- pthread_t th;
- LOGI("TestBinderService::allocbuf pipe_fd = %d, bs = %d.", pipe_fd , bs);
- m_pipe_fd = dup(pipe_fd);
- LOGI("m_pipe_fd = %d", m_pipe_fd);
- m_fd = ashmem_create_region(name, bs);
- if(m_fd > 0)
- {
- m_buf = (char *)mmap(0, bs, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd , 0);
- if(m_buf == (void*)-1)
- LOGI("TestBinderService mmap fail");
- }
- LOGI("TestBinderService::m_fd = %d. m_buf = 0x%x",m_fd, m_buf);
- int fd2 = dup(m_fd);
- LOGI("fd2 = %d", fd2);
- perror("1dup: ");
- pthread_create(&th, NULL, test_proc, NULL);
- return m_fd;
- }
- }
这里调用ashmem_create_region 创建匿名共享内存,然后调用mmap进行内存映射,创建一个线程,从管道读数据,并拷贝数据到共享内存
接下来就要启动这个Service
- #include <binder/IPCThreadState.h>
- #include <binder/ProcessState.h>
- #include <binder/IServiceManager.h>
- #include <utils/Log.h>
- #include "TestBinderService.h"
- using namespace android;
- int main(int argc, char** argv)
- {
- sp<ProcessState> proc(ProcessState::self());
- sp<IServiceManager> sm = defaultServiceManager();
- LOGI("TestBinderService before");
- TestBinderService::instantiate();
- LOGI("TestBinderService End");
- ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
- return 0;
- }
再就是测试case
- #include <binder/IServiceManager.h>
- #include "../TestBinderServer_new/ITestBinderService.h"
- //#include "testBinder.h"
- #include "TestBinderService.h"
- using namespace android;
- int write_pipe_fd = -1;
- int m_fd = -1;
- char *m_buf = NULL;
- static void* test_proc(void*a) {
- char buf[100];
- int len = 100;
- int read_len = -1;
- int write_len = -1;
- while(1)
- {
- write_len = write(write_pipe_fd, "from client", 12);
- LOGI("TestBinderClient::write_len = %d.",write_len);
- sleep(1);
- if(write_len > 0)
- {
- }
- if(m_buf != (void*)-1)
- LOGI("TestBinderClient::read_len = %d.m_buf = %s",read_len, m_buf);
- }
- return NULL;
- }
- int main()
- {
- int sum = 0;
- pthread_t th;
- sp<ITestBinderService> mTestBinserService;
- if (mTestBinserService.get() == 0) {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder;
- do {
- binder = sm->getService(String16("my.test.binder"));
- if (binder != 0)
- break;
- LOGI("getService fail");
- usleep(500000); // 0.5 s
- } while (true);
- mTestBinserService = interface_cast<ITestBinderService> (binder);
- LOGE_IF(mTestBinserService == 0, "no ITestBinserService!?");
- }
- sum = mTestBinserService->add(3, 4);
- int pipe_fd[2];
- pipe(pipe_fd);
- write_pipe_fd = pipe_fd[1];
- LOGI("pipe_fd[0] = %d, pipe_fd[1] = %d", pipe_fd[0], pipe_fd[1]);
- m_fd = mTestBinserService->allocbuf(pipe_fd[0], "test", 1024);
- close(pipe_fd[0]);
- LOGI("m_fd = %d", m_fd);
- m_fd = dup(m_fd);
- perror("dup: ");
- LOGI("m_fd = %d", m_fd);
- m_buf = (char *)mmap(0, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd , 0);
- if(m_buf == (void*)-1){
- LOGI("TestBinderService mmap fail");
- perror("mmap: ");}
- LOGI("m_fd = %d m_buf = 0x%x", m_fd, m_buf);
- pthread_create(&th, NULL, test_proc, NULL);
- close(pipe_fd[0]);
- while(1)
- sleep(1);
- return 0;
- }
首先获取Service,然后调用allocbuf把管道的读端传过去,返回一个共享内在的句柄后,调用mmap进行内存映射,同样也是新建一个进程,不断的往管道里面写数据,然后把映射的共享内存的值打印出来,这个值是Service端写进去的。
相应log:
- I/ ( 1433): TestBinderService before
- I/TestBinderService( 1433): Enter TestBinderService::instantiate
- D/TestBinderService( 1433): TestBinderServicet
- D/TestBinderService( 1433): ServiceManager addService ret=0
- D/TestBinderService( 1433): instantiate> end
- I/ ( 1433): TestBinderService End
- D/KeyguardUpdateMonitor( 1058): received broadcast android.intent.action.TIME_TICK
- D/KeyguardUpdateMonitor( 1058): handleTimeUpdate
- I/ ( 1436): int the main function
- I/ITeeveePlayerService( 1436): Enter BpTestBinderService add,a = 3 , b = 4
- I/ITeeveePlayerService( 1433): Enter BnTestBinderService add,a = 3 , b = 4
- I/TestBinderService( 1433): TestBinderService::add a = 3, b = 4.
- D/ ( 1433): sum2 a = 3, b = 4
- I/TestBinderService( 1433): TestBinderService::result = 7.
- I/ITeeveePlayerService( 1433): BnTestBinderService sum = 7
- I/ITeeveePlayerService( 1436): BpTestBinderService sum = 7
- I/TestBinserService( 1436): pipe_fd[0] = 28, pipe_fd[1] = 29
- I/ITeeveePlayerService( 1436): Enter BpTestBinderService allocbuf,pipe_fd = 28 , bs = 1024
- I/ITeeveePlayerService( 1433): Enter BnTestBinderService add,pipe_fd = 28 , bs = 1024
- I/TestBinderService( 1433): TestBinderService::allocbuf pipe_fd = 28, bs = 1024.
- I/TestBinderService( 1433): m_pipe_fd = 29
- I/TestBinderService( 1433): TestBinderService::m_fd = 30. m_buf = 0x40107000
- I/TestBinderService( 1433): fd2 = 31
- I/ITeeveePlayerService( 1433): 2BnTestBinderService fd = 30
- I/ITeeveePlayerService( 1433): fd2 = 32
- I/ITeeveePlayerService( 1436): BpTestBinderService fd = 30
- I/ITeeveePlayerService( 1436): fd2 = 31
- I/TestBinserService( 1436): m_fd = 31
- I/TestBinserService( 1436): m_fd = 28
- I/TestBinserService( 1436): m_fd = 28 m_buf = 0x40107000
- I/TestBinserService( 1436): TestBinderClient::write_len = 12.
- I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
- I/TestBinderService( 1433): TestBinderService::write_len = -1.
- I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
- I/TestBinserService( 1436): TestBinderClient::write_len = 12.
- I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
- I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
- I/TestBinserService( 1436): TestBinderClient::write_len = 12.
- I/TestBinderService( 1433): TestBinderService::write_len = -1.
- I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
- I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
- I/TestBinserService( 1436): TestBinderClient::write_len = 12.
- I/TestBinderService( 1433): TestBinderService::write_len = -1.
- I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
- I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
- I/TestBinserService( 1436): TestBinderClient::write_len = 12.
- I/TestBinderService( 1433): TestBinderService::write_len = -1.
- I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
- I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
- I/TestBinserService( 1436): TestBinderClient::write_len = 12.
- I/TestBinderService( 1433): TestBinderService::write_len = -1.
- I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
- I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
- I/TestBinserService( 1436): TestBinderClient::write_len = 12.
- I/TestBinderService( 1433): TestBinderService::write_len = -1.
- I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
- I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
- I/TestBinserService( 1436): TestBinderClient::write_len = 12.
- I/TestBinderService( 1433): TestBinderService::write_len = -1.
- I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
- I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
- I/TestBinserService( 1436): TestBinderClient::write_len = 12.
- I/TestBinderService( 1433): TestBinderService::write_len = -1.
- I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
- I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
- I/TestBinserService( 1436): TestBinderClient::write_len = 12.
- I/TestBinderService( 1433): TestBinderService::write_len = -1.
- I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
- I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
- I/TestBinserService( 1436): TestBinderClient::write_len = 12.
- I/TestBinderService( 1433): TestBinderService::write_len = -1.
- I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
- I/TestBinserService( 1436): TestBinderClient::read_len = -1.m_buf = from server
- I/TestBinserService( 1436): TestBinderClient::write_len = 12.
- I/TestBinderService( 1433): TestBinderService::write_len = -1.
- I/TestBinderService( 1433): TestBinderService::read_len = 12.buf = from client
- init: untracked pid 1436 exited
- I/TestBinderService( 1433): TestBinderService::write_len = -1.
- I/TestBinderService( 1433): TestBinderService::read_len = 0.buf = from client
- init: untracked pid 1433 exited
- I/ServiceManager( 766): service 'my.test.binder' died
http://download.csdn.NET/download/new_abc/4744981