一、Ashmem驱动程序
~/Android/kernel/goldfish
----include
----linux
----ashmem.h
----mm
----ashmem.c
驱动程序详解请看《Android系统源代码情景分析》,作者罗升阳。
二、运行时库cutils的匿名共享内存访问接口
~/Android/system/core
----libcutils
----ashmem-dev.c
详解请看《Android系统源代码情景分析》,作者罗升阳。
三、MemoryHeapBase
1、Server端实现
我们只分析下面3个类
IMemoryHeap--->IMemory.h,IMemory.cpp
BnMemoryHeap--->IMemory.h,IMemory.cpp
MemoryHeapBase--->MemoryHeapBase.h,MemoryHeapBase.cpp
详解请看《Android系统源代码情景分析》,作者罗升阳,这里只列出代码。
IMemoryHeap(IMemory.h)
class IMemoryHeap : public IInterface
{
public:
DECLARE_META_INTERFACE(MemoryHeap);
// flags returned by getFlags()
enum {
READ_ONLY = 0x00000001
};
virtual int getHeapID() const = 0;
virtual void* getBase() const = 0;
virtual size_t getSize() const = 0;
virtual uint32_t getFlags() const = 0;
// these are there just for backward source compatibility
int32_t heapID() const { return getHeapID(); }
void* base() const { return getBase(); }
size_t virtualSize() const { return getSize(); }
};
BnMemoryHeap(IMemory.cpp)
status_t BnMemoryHeap::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case HEAP_ID: {
CHECK_INTERFACE(IMemoryHeap, data, reply);
reply->writeFileDescriptor(getHeapID());
reply->writeInt32(getSize());
reply->writeInt32(getFlags());
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
MemoryHeapBase(MemoryHeapBase.cpp)
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));
int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size);
LOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
if (fd >= 0) {
if (mapfd(fd, size) == NO_ERROR) {
if (flags & READ_ONLY) {
ashmem_set_prot_region(fd, PROT_READ);
}
}
}
}
......
status_t MemoryHeapBase::mapfd(int fd, size_t size, uint32_t offset)
{
.....
if ((mFlags & DONT_MAP_LOCALLY) == 0) {
void* base = (uint8_t*)mmap(0, size,
PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
......
mBase = base;
mNeedUnmap = true;
} else {
.....
}
mFD = fd;
mSize = size;
return NO_ERROR;
}
.........
int MemoryHeapBase::getHeapID() const {
return mFD;
}
void* MemoryHeapBase::getBase() const {
return mBase;
}
size_t MemoryHeapBase::getSize() const {
return mSize;
}
uint32_t MemoryHeapBase::getFlags() const {
return mFlags;
}
2、Client端实现
我们只分析下面2个类
IMemoryHeap--->IMemory.h,IMemory.cpp
BpMemoryHeap--->IMemory.cpp
详解请看《Android系统源代码情景分析》,作者罗升阳。
BpMemoryHeap(IMemory.cpp)
BpMemoryHeap::BpMemoryHeap(const sp& impl)
: BpInterface(impl),
mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mRealHeap(false)
{
}
.......
void BpMemoryHeap::assertMapped() const
{
if (mHeapId == -1) {
sp binder(const_cast(this)->asBinder());
sp heap(static_cast(find_heap(binder).get()));
heap->assertReallyMapped();
if (heap->mBase != MAP_FAILED) {
Mutex::Autolock _l(mLock);
if (mHeapId == -1) {
mBase = heap->mBase;
mSize = heap->mSize;
android_atomic_write( dup( heap->mHeapId ), &mHeapId );
}
} else {
// something went wrong
free_heap(binder);
}
}
}
void BpMemoryHeap::assertReallyMapped() const
{
if (mHeapId == -1) {
// remote call without mLock held, worse case scenario, we end up
// calling transact() from multiple threads, but that's not a problem,
// only mmap below must be in the critical section.
Parcel data, reply;
data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());
status_t err = remote()->transact(HEAP_ID, data, &reply);
int parcel_fd = reply.readFileDescriptor();
ssize_t size = reply.readInt32();
uint32_t flags = reply.readInt32();
.........
int fd = dup( parcel_fd );
........
int access = PROT_READ;
if (!(flags & READ_ONLY)) {
access |= PROT_WRITE;
}
Mutex::Autolock _l(mLock);
if (mHeapId == -1) {
mRealHeap = true;
mBase = mmap(0, size, access, MAP_SHARED, fd, 0);
if (mBase == MAP_FAILED) {
LOGE("cannot map BpMemoryHeap (binder=%p), size=%ld, fd=%d (%s)",
asBinder().get(), size, fd, strerror(errno));
close(fd);
} else {
mSize = size;
mFlags = flags;
android_atomic_write(fd, &mHeapId);
}
}
}
}
int BpMemoryHeap::getHeapID() const {
assertMapped();
return mHeapId;
}
void* BpMemoryHeap::getBase() const {
assertMapped();
return mBase;
}
size_t BpMemoryHeap::getSize() const {
assertMapped();
return mSize;
}
uint32_t BpMemoryHeap::getFlags() const {
assertMapped();
return mFlags;
}
四、MemoryBase
1、Server端实现
我们只分析下面3个类
IMemory--->IMemory.h,IMemory.cpp
BnMemory--->IMemory.h,IMemory.cpp
MemoryBase--->MemoryBase.h,MemoryBase.cpp
详解请看《Android系统源代码情景分析》,作者罗升阳。
IMemory(IMemory.h)
class IMemory : public IInterface
{
public:
DECLARE_META_INTERFACE(Memory);
virtual sp getMemory(ssize_t* offset=0, size_t* size=0) const = 0;
// helpers
void* fastPointer(const sp& heap, ssize_t offset) const;
void* pointer() const;
size_t size() const;
ssize_t offset() const;
};
IMemory(IMemory.cpp)
void* IMemory::pointer() const {
ssize_t offset;
sp heap = getMemory(&offset);
void* const base = heap!=0 ? heap->base() : MAP_FAILED;
if (base == MAP_FAILED)
return 0;
return static_cast(base) + offset;
}
size_t IMemory::size() const {
size_t size;
getMemory(NULL, &size);
return size;
}
ssize_t IMemory::offset() const {
ssize_t offset;
getMemory(&offset);
return offset;
}
status_t BnMemory::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case GET_MEMORY: {
CHECK_INTERFACE(IMemory, data, reply);
ssize_t offset;
size_t size;
reply->writeStrongBinder( getMemory(&offset, &size)->asBinder() );
reply->writeInt32(offset);
reply->writeInt32(size);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
MemoryBase::MemoryBase(const sp& heap,
ssize_t offset, size_t size)
: mSize(size), mOffset(offset), mHeap(heap)
{
}
sp MemoryBase::getMemory(ssize_t* offset, size_t* size) const
{
if (offset) *offset = mOffset;
if (size) *size = mSize;
return mHeap;
}
2、Client端实现
我们只分析下面2个类
IMemory--->IMemory.h,IMemory.cpp
BpMemory--->IMemory.cpp
详解请看《Android系统源代码情景分析》,作者罗升阳。
BpMemory(IMemory.cpp)
sp BpMemory::getMemory(ssize_t* offset, size_t* size) const
{
if (mHeap == 0) {
Parcel data, reply;
data.writeInterfaceToken(IMemory::getInterfaceDescriptor());
if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) {
sp heap = reply.readStrongBinder();
ssize_t o = reply.readInt32();
size_t s = reply.readInt32();
if (heap != 0) {
mHeap = interface_cast(heap);//mHeap
if (mHeap != 0) {
mOffset = o;//mOffset
mSize = s;//mSize
}
}
}
}
if (offset) *offset = mOffset;
if (size) *size = mSize;
return mHeap;
}
五、应用实例
~/Android/external/ashmem
----common
----ISharedBuffer.h
----ISharedBuffer.cpp
----server
----SharedBufferServer.cpp
----Android.mk
----client
----SharedBufferClient.cpp
----Android.mk
1、Server端实现
想象上面的图。
我们只分析下面3个类
ISharedBuffer--->ISharedBuffer.h,ISharedBuffer.cpp
BnSharedBuffer--->ISharedBuffer.h,ISharedBuffer.cpp
SharedBufferService--->SharedBufferServer.cpp
详解请看《Android系统源代码情景分析》,作者罗升阳。
ISharedBuffer(ISharedBuffer.h)
class ISharedBuffer: public IInterface
{
public:
DECLARE_META_INTERFACE(SharedBuffer);
virtual sp getBuffer() = 0;
};
BnSharedBuffer(ISharedBuffer.cpp)
status_t BnSharedBuffer::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code)
{
case GET_BUFFER:
{
CHECK_INTERFACE(ISharedBuffer, data, reply);
sp buffer = getBuffer();
if(buffer != NULL)
{
reply->writeStrongBinder(buffer->asBinder());
}
return NO_ERROR;
}
default:
{
return BBinder::onTransact(code, data, reply, flags);
}
}
}
class SharedBufferService : public BnSharedBuffer
{
public:
SharedBufferService()
{
sp heap = new MemoryHeapBase(SHARED_BUFFER_SIZE, 0, "SharedBuffer");
if(heap != NULL)
{
mMemory = new MemoryBase(heap, 0, SHARED_BUFFER_SIZE);
int32_t* data = (int32_t*)mMemory->pointer();
if(data != NULL)
{
*data = 0;
}
}
}
virtual ~SharedBufferService()
{
mMemory = NULL;
}
public:
static void instantiate()
{
defaultServiceManager()->addService(String16(SHARED_BUFFER_SERVICE), new SharedBufferService());
}
virtual sp getBuffer()
{
return mMemory;
}
private:
sp mMemory;
};
2、Client端实现
想象上面的图。我们只分析下面2个类
ISharedBuffer--->ISharedBuffer.h,ISharedBuffer.cpp
BpSharedBuffer--->ISharedBuffer.cpp
详解请看《Android系统源代码情景分析》,作者罗升阳。
BpSharedBuffer(ISharedBuffer.cpp)
class BpSharedBuffer: public BpInterface
{
public:
BpSharedBuffer(const sp& impl)
: BpInterface(impl)
{
}
public:
sp getBuffer()
{
Parcel data;
data.writeInterfaceToken(ISharedBuffer::getInterfaceDescriptor());
Parcel reply;
remote()->transact(GET_BUFFER, data, &reply);
sp buffer = interface_cast(reply.readStrongBinder());
return buffer;
}
};
六、执行代码
SharedBufferServer.cpp
........
int main(int argc, char** argv)
{
SharedBufferService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return 0;
}
int main()
{
sp binder = defaultServiceManager()->getService(String16(SHARED_BUFFER_SERVICE));
if(binder == NULL)
{
printf("Failed to get service: %s.\n", SHARED_BUFFER_SERVICE);
return -1;
}
sp service = ISharedBuffer::asInterface(binder);
if(service == NULL)
{
return -2;
}
sp buffer = service->getBuffer();
if(buffer == NULL)
{
return -3;
}
int32_t* data = (int32_t*)buffer->pointer();
if(data == NULL)
{
return -4;
}
printf("The value of the shared buffer is %d.\n", *data);
*data = *data + 1;
printf("Add value 1 to the shared buffer.\n");
return 0;
}
我们从service->getBuffer()开始分析,下面的执行流程如下图:
由于第5步reply->writeStrongBinder(buffer->asBinder());//SharedBufferServer的本地对象,writeStrongBinder请参考http://blog.csdn.net/jltxgcy/article/details/26059215。
在第6步和第7步之间,经历的过程是下面:
static void
binder_transaction(struct binder_proc *proc, struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
struct binder_transaction *t;
struct binder_work *tcomplete;
size_t *offp, *off_end;
struct binder_proc *target_proc;
struct binder_thread *target_thread = NULL;
struct binder_node *target_node = NULL;
struct list_head *target_list;
wait_queue_head_t *target_wait;
struct binder_transaction *in_reply_to = NULL;
struct binder_transaction_log_entry *e;
uint32_t return_error;
......
offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));
......
off_end = (void *)offp + tr->offsets_size;
for (; offp < off_end; offp++) {
struct flat_binder_object *fp;
......
fp = (struct flat_binder_object *)(t->buffer->data + *offp);
switch (fp->type) {
......
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
struct binder_ref *ref;
struct binder_node *node = binder_get_node(proc, fp->binder);
if (node == NULL) {
node = binder_new_node(proc, fp->binder, fp->cookie);
if (node == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_new_node_failed;
}
node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
}
if (fp->cookie != node->cookie) {
binder_user_error("binder: %d:%d sending u%p "
"node %d, cookie mismatch %p != %p\n",
proc->pid, thread->pid,
fp->binder, node->debug_id,
fp->cookie, node->cookie);
goto err_binder_get_ref_for_node_failed;
}
ref = binder_get_ref_for_node(target_proc, node);
if (ref == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_for_node_failed;
}
if (fp->type == BINDER_TYPE_BINDER)
fp->type = BINDER_TYPE_HANDLE;
else
fp->type = BINDER_TYPE_WEAK_HANDLE;
fp->handle = ref->desc;
binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, &thread->todo);
if (binder_debug_mask & BINDER_DEBUG_TRANSACTION)
printk(KERN_INFO " node %d u%p -> ref %d desc %d\n",
node->debug_id, node->ptr, ref->debug_id, ref->desc);
} break;
......
}
}
......
}
形成了SharedBufferServer的实体对象和SharedBufferClient引用对象,传递给Client。
接下来执行:
sp buffer = interface_cast(reply.readStrongBinder());
又形成了SharedBufferClient代理对象。readStrongBinder请参考http://blog.csdn.net/jltxgcy/article/details/26370733。
interface_cast
接下来执行:
int32_t* data = (int32_t*)buffer->pointer();
调用IMemory的pointer,然后调用BpMemory的getMemory函数,
又执行了一遍上图的流程,只是把BpSharedBuffer变成BpMemory,把BnSharedBuffer变成BnMemory。
然后接着执行:
void* const base = heap!=0 ? heap->base() : MAP_FAILED;
调用IMemoryHeap的base函数,最终调用到BpMemoryHeap的getBase函数,又调用到BpMemoryHeap的assertReallyMapped函数,
又执行了一遍上图的流程,只是把BpSharedBuffer变成BpMemoryHeap,把BnSharedBuffer变成BnMemoryHeap。此时有一点不同,就是第6步到第7步执行过程如下:
static void
binder_transaction(struct binder_proc *proc, struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
struct binder_transaction *t;
struct binder_work *tcomplete;
size_t *offp, *off_end;
struct binder_proc *target_proc;
struct binder_thread *target_thread = NULL;
struct binder_node *target_node = NULL;
struct list_head *target_list;
wait_queue_head_t *target_wait;
struct binder_transaction *in_reply_to = NULL;
struct binder_transaction_log_entry *e;
uint32_t return_error;
......
offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));
......
off_end = (void *)offp + tr->offsets_size;
for (; offp < off_end; offp++) {
struct flat_binder_object *fp;
......
fp = (struct flat_binder_object *)(t->buffer->data + *offp);
switch (fp->type) {
......
case BINDER_TYPE_FD: {
int target_fd;
struct file *file;
if (reply) {
if (!(in_reply_to->flags & TF_ACCEPT_FDS)) {
binder_user_error("binder: %d:%d got reply with fd, %ld, but target does not allow fds\n",
proc->pid, thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_fd_not_allowed;
}
} else if (!target_node->accept_fds) {
binder_user_error("binder: %d:%d got transaction with fd, %ld, but target does not allow fds\n",
proc->pid, thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_fd_not_allowed;
}
file = fget(fp->handle);
if (file == NULL) {
binder_user_error("binder: %d:%d got transaction with invalid fd, %ld\n",
proc->pid, thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_fget_failed;
}
target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
if (target_fd < 0) {
fput(file);
return_error = BR_FAILED_REPLY;
goto err_get_unused_fd_failed;
}
task_fd_install(target_proc, target_fd, file);
if (binder_debug_mask & BINDER_DEBUG_TRANSACTION)
printk(KERN_INFO " fd %ld -> %d\n", fp->handle, target_fd);
/* TODO: fput? */
fp->handle = target_fd;
} break;
......
}
}
......
}
status_t Parcel::writeFileDescriptor(int fd)
{
flat_binder_object obj;
obj.type = BINDER_TYPE_FD;
obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
obj.handle = fd;
obj.cookie = (void*)0;
return writeObject(obj, true);
}
int Parcel::readFileDescriptor() const
{
const flat_binder_object* flat = readObject(true);
if (flat) {
switch (flat->type) {
case BINDER_TYPE_FD:
//LOGI("Returning file descriptor %ld from parcel %p\n", flat->handle, this);
return flat->handle;
}
}
return BAD_TYPE;
}
接下来的分析,请看Android系统匿名共享内存Ashmem(Anonymous Shared Memory)在进程间共享的原理分析http://blog.csdn.net/luoshengyang/article/details/6666491。
注意上文中的这句话, 这里, 我们需要关注的便是虚线框部分了,它在Binder驱动程序中实现了在两个进程中共享同一个打开文件的方法。我们知道,在Linux系统中,文件描述符其实就是一个整数。每一个进程在内核空间都有一个打开文件的数组,这个文件描述符的整数值就是用来索引这个数组的,而且,这个文件描述符只是在本进程内有效,也就是说,在不同的进程中,相同的文件描述符的值,代表的可能是不同的打开文件。因此,在进程间传输文件描述符时,不能简要地把一个文件描述符从一个进程传给另外一个进程,中间必须做一过转换,使得这个文件描述在目标进程中是有效的,并且它和源进程的文件描述符所对应的打开文件是一致的,这样才能保证共享。
也就是根据fd,得到的file结构,在两个进程是一样的,即使两个进程的fd不一样。
也就是在Server端的文件描述符,不能在Client端直接使用,而需要经过上面的转换,这时候得到文件描述符,再调用mmap映射到Client进程地址空间,就与Server共享一个匿名共享内存了。
接着:
printf("The value of the shared buffer is %d.\n", *data);
*data = *data + 1;
printf("Add value 1 to the shared buffer.\n");
和
sp heap = new MemoryHeapBase(SHARED_BUFFER_SIZE, 0, "SharedBuffer");
if(heap != NULL)
{
mMemory = new MemoryBase(heap, 0, SHARED_BUFFER_SIZE);
int32_t* data = (int32_t*)mMemory->pointer();
if(data != NULL)
{
*data = 0;
}
}
它们两个操作的是同一个内存。
最后附上一张,整体的流程图: