Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析

一、Ashmem驱动程序

      ~/Android/kernel/goldfish

      ----include

              ----linux

                       ----ashmem.h

      ----mm

              ----ashmem.c

      驱动程序详解请看《Android系统源代码情景分析》,作者罗升阳。


二、运行时库cutils的匿名共享内存访问接口

      ~/Android/system/core

      ----libcutils

               ----ashmem-dev.c

       详解请看《Android系统源代码情景分析》,作者罗升阳。


三、MemoryHeapBase

1、Server端实现

Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析_第1张图片


        我们只分析下面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端实现

Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析_第2张图片

        我们只分析下面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端实现

Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析_第3张图片

        我们只分析下面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;
}

      BnMemory(IMemory.cpp)

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.cpp)

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端实现

Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析_第4张图片

        我们只分析下面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);
		}
	}
}

        SharedBufferService(SharedBufferServer.cpp)

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

        SharedBufferClient.cpp

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()开始分析,下面的执行流程如下图:

Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析_第5张图片


       由于第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(  )的实现请参考,http://blog.csdn.net/jltxgcy/article/details/25953361。

      

      接下来执行:

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

      它们两个操作的是同一个内存。

       最后附上一张,整体的流程图:

Android系统匿名共享内存(Anonymous Shared Memory)C++调用接口分析_第6张图片

你可能感兴趣的:(Android源码分析)