Android系统的Ashmem匿名共享内存子系统分析(3)- Ashmem子系统的 C/C++访问接口

声明

  • 其实对于Android系统的Ashmem匿名共享内存系统早就有分析的想法,记得2019年6、7月份Mr.Deng离职期间约定一起对其进行研究的,但因为我个人问题没能实施这个计划,留下些许遗憾…
  • 文中参考了很多书籍及博客内容,可能涉及的比较多先不具体列出来了;
  • 本文使用的代码是LineageOS的cm-14.1,对应Android 7.1.2,可以参考我的另一篇博客:cm-14.1 Android系统启动过程分析(1)-如何下载Nexus5的LineageOS14.1(cm-14.1)系统源码并编译、刷机
  • 若对 Binder 不熟悉,可参考专栏:Android系统中的Binder通信机制分析

1 Ashmem的架构

  Android 系统实现的 Ashmem 匿名共享内存子系统,用来在应用程序之间共享数据。Ashmem 与传统的Linux系统实现的共享内存一样,都是基于内核提供的临时文件系统tmpfs实现的,但是 Ashmem 对内存块进行了更为精细化的管理。应用程序可以动态地将一块匿名共享内存划分为若干个小块,当这些小块内存不再需要使用时,它们就可以被内存管理系统回收。通过这种动态的、分而治之的内存管理方式,Android系统就能够有效地使用系统内存,适应内存较小的移动设备环境。

  匿名共享内存系统是以Ashmem驱动程序为基础的,系统中所有的匿名共享内存都由Ashmem驱动程序负责分配和管理。Android系统在 Native 层提供了 C/C++ 调用接口和 Framework 层提供了 Java 调用接口。

  • 在Framework 层中,提供了两个C++类 MemoryBase 和 MemoryHeapBase,以及一个 Java 类 MemoryFile 来使用匿名共享内存。
  • 在运行时库 cutils 中,主要提供了三个C函数 ashmem_create_region、ashmem_pin_region 和 ashmem_unpin_region 来访问 Ashmem 驱动程序。

  Ashmem驱动程序在启动时,会创建一个 /dev/ashmem 设备文件,这样,运行时库 cutils 中的匿名共享内存接口就可以通过文件操作函数 open 和 ioctl 等来访问 Ashmem 驱动程序。
Android系统的Ashmem匿名共享内存子系统分析(3)- Ashmem子系统的 C/C++访问接口_第1张图片

  传统的 Linux 系统使用一个整数来标志一块共享内存,而 Android 系统则使用一个文件描述符来标志一块匿名共享内存。使用文件描述符来描述一块匿名共享内存有两个好处:

  1. 可以方便地将它映射到进程的地址空间,从而可以直接访问它的内容;
  2. 可以使用 Binder 进程间通信机制来传输这个文件描述符,从而实现在不同的应用程序之间共享一块匿名内存。

  Binder 进程间通信机制使用一个类型为 BINDER_TYPE_FD 的 Binder 对象来描述一个文件描述符,当 Binder 驱动程序发现进程间通信数据中包含有这种 Binder 对象时,就会将对应的文件描述符复制到目标进程中,从而实现在两个进程中共享同一个文件。

2 Ashmem子系统 C/C++ 访问接口分析

在 Android 进程之间共享一个完整的匿名共享内存块,可以通过调用接口 MemoryHeapBase 来实现;在进程之间共享匿名共享内存块中的一部分时,可以通过调用接口 MemoryBase 来实现。

2.1 接口MemoryHeapBase

接口 MemoryBase 以接口 MemoryHeapBase 为基础,这两个接口都可以作为一个 Binder 对象在进程之间进行传输。因为接口 MemoryHeapBase 是一个 Binder 对象,所以拥有 Server 端对象(必须实现一个BnInterface 接口)和 Client 端引用(必须要实现一个 BpInterface 接口)的概念。

2.1.1 在Server端的实现

在 Server 端的实现过程中,接口 MemoryHeapBase 可以将所有涉及到的类分为以下3种类型:

  1. 业务相关类:即跟匿名共享内存操作相关的类,包括 MemoryHeapBase、BnMemoryHeap 和 IMemoryHeap;
  2. Binder 进程通信类:即和 Binder 进程通信机制相关的类,包括 IInterface、BnInterface、IBinder、BBinder、ProcessState 和IPCThreadState;
  3. 智能指针类:RefBase;

在上述3种类型中,Binder 进程通信类和智能指针类可参考专栏:Android系统中的Binder通信机制分析。在接口 IMemoryHeap 中定义了和操作匿名共享内存的几个方法,此接口源码:frameworks/native/include/binder/IMemory.h 中定义

class IMemoryHeap : public IInterface
{
public:
    DECLARE_META_INTERFACE(MemoryHeap);

    // flags returned by getFlags()
    enum {
        READ_ONLY   = 0x00000001,
#ifdef USE_MEMORY_HEAP_ION
        USE_ION_FD  = 0x00008000
#endif
    };

    virtual int         getHeapID() const = 0;
    virtual void*       getBase() const = 0;
    virtual size_t      getSize() const = 0;
    virtual uint32_t    getFlags() const = 0;
    virtual uint32_t    getOffset() 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(); }
};

class BnMemoryHeap : public BnInterface<IMemoryHeap>
{
public:
    virtual status_t onTransact(
            uint32_t code,
            const Parcel& data,
            Parcel* reply,
            uint32_t flags = 0);

    BnMemoryHeap();
protected:
    virtual ~BnMemoryHeap();
};

在上述定义代码中,有如下3 个重要的成员函数:

  • getHeapID:功能是获得匿名共享内存块的打开文件描述符;
  • getBase:功能是获得匿名共享内存块的基地址,通过这个地址可以在程序中直接访问这块共享内存;
  • getSize:功能是获得匿名共享内存块的大小;

类 BnMemoryHeap 是一个本地对象类,当 Client 端引用请求 Server 端对象执行命令时,Binder 系统就会调用类 BnMemoryHeap 的成员函数 onTransact 执行具体的命令。函数 onTransact 在源码:frameworks/native/libs/binder/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( IInterface::asBinder(getMemory(&offset, &size)) );
            reply->writeInt32(offset);
            reply->writeInt32(size);
            return NO_ERROR;
        } break;
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
}

类 MemoryHeapBase 继承了类 BnMemoryHeap,作为 Binder 机制中的 Server 角色需要实现 IMemoryBase 接口,主要功能是实现类 IMemoryBase 中列出的成员函数,描述了一块匿名共享内存服务。MemoryHeapBase 类在源码:frameworks/native/include/binder/MemoryHeapBase.h 中定义。

class MemoryHeapBase : public virtual BnMemoryHeap
{
public:
    enum {
        READ_ONLY = IMemoryHeap::READ_ONLY,
        // memory won't be mapped locally, but will be mapped in the remote
        // process.
        DONT_MAP_LOCALLY = 0x00000100,
        NO_CACHING = 0x00000200
    };

    /*
     * maps the memory referenced by fd. but DOESN'T take ownership
     * of the filedescriptor (it makes a copy with dup()
     */
    MemoryHeapBase(int fd, size_t size, uint32_t flags = 0, uint32_t offset = 0);

    /*
     * maps memory from the given device
     */
    MemoryHeapBase(const char* device, size_t size = 0, uint32_t flags = 0);

    /*
     * maps memory from ashmem, with the given name for debugging
     */
    MemoryHeapBase(size_t size, uint32_t flags = 0, char const* name = NULL);

    virtual ~MemoryHeapBase();

    /* implement IMemoryHeap interface */
    virtual int         getHeapID() const;

    /* virtual address of the heap. returns MAP_FAILED in case of error */
    virtual void*       getBase() const;

    virtual size_t      getSize() const;
    virtual uint32_t    getFlags() const;
    virtual uint32_t    getOffset() const;

    const char*         getDevice() const;

    /* this closes this heap -- use carefully */
    void dispose();

    /* this is only needed as a workaround, use only if you know
     * what you are doing */
    status_t setDevice(const char* device) {
        if (mDevice == 0)
            mDevice = device;
        return mDevice ? NO_ERROR : ALREADY_EXISTS;
    }

protected:
            MemoryHeapBase();
    // init() takes ownership of fd
    status_t init(int fd, void *base, int size,
            int flags = 0, const char* device = NULL);

private:
    status_t mapfd(int fd, size_t size, uint32_t offset = 0);

    int         mFD;				//一个文件描述符,是在打开设备文件/dev/ashmem后得到的,能够描述一个匿名共享内存块
    size_t      mSize;				//内存块的大小
    void*       mBase;				//内存块的映射地址
    uint32_t    mFlags;				//内存块的访问保护位
    const char* mDevice;
    bool        mNeedUnmap;
    uint32_t    mOffset;
};

类MemoryHeapBase 在源码:frameworks/native/libs/binder/MemoryHeapBase.cpp 中实现,其核心功能是包含了一块匿名共享内存。

MemoryHeapBase::MemoryHeapBase()
    : mFD(-1), mSize(0), mBase(MAP_FAILED),
      mDevice(NULL), mNeedUnmap(false), mOffset(0)
{
}

/*
	size:  表示要创建的匿名共享内存的大小。
	flags: 设置这块匿名共享内存的属性,例如可读写、只读等。
	name:  此参数只是作为调试信息使用的,用于标识匿名共享内存的名字,可以是空值
*/
MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
    : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
      mDevice(0), mNeedUnmap(false), mOffset(0)
{
    const size_t pagesize = getpagesize();
    size = ((size + pagesize-1) & ~(pagesize-1));
    int fd = ashmem_create_region(name == NULL ? "MemoryHeapBase" : name, size);
    ALOGE_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);
            }
        }
    }
}

MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
    : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
      mDevice(0), mNeedUnmap(false), mOffset(0)
{
    int open_flags = O_RDWR;
    if (flags & NO_CACHING)
        open_flags |= O_SYNC;

    int fd = open(device, open_flags);
    ALOGE_IF(fd<0, "error opening %s: %s", device, strerror(errno));
    if (fd >= 0) {
        const size_t pagesize = getpagesize();
        size = ((size + pagesize-1) & ~(pagesize-1));
        if (mapfd(fd, size) == NO_ERROR) {
            mDevice = device;
        }
    }
}

MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, uint32_t offset)
    : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
      mDevice(0), mNeedUnmap(false), mOffset(0)
{
    const size_t pagesize = getpagesize();
    size = ((size + pagesize-1) & ~(pagesize-1));
    mapfd(dup(fd), size, offset);
}

status_t MemoryHeapBase::init(int fd, void *base, int size, int flags, const char* device)
{
    if (mFD != -1) {
        return INVALID_OPERATION;
    }
    mFD = fd;
    mBase = base;
    mSize = size;
    mFlags = flags;
    mDevice = device;
    return NO_ERROR;
}

/*
	其功能是将得到的匿名共享内存的文件描述符映射到进程地址空间。
	在调用函数 mapfd 后,会进入到内核空间的 ashmem 驱动程序模块中执行函数 ashmem_map。
*/
status_t MemoryHeapBase::mapfd(int fd, size_t size, uint32_t offset)
{
    if (size == 0) {
        // try to figure out the size automatically
        struct stat sb;
        if (fstat(fd, &sb) == 0)
            size = sb.st_size;
        // if it didn't work, let mmap() fail.
    }

    if ((mFlags & DONT_MAP_LOCALLY) == 0) {		//条件为true 时执行系统调用mmap来执行内存映射的操作
        void* base = (uint8_t*)mmap(0, //表示由内核来决定这个匿名共享内存文件在进程地址空间的起始位置
        							size, //表示要映射的匿名共享内文件的大小
                					PROT_READ|PROT_WRITE, //表示这个匿名共享内存是可读写的
                					MAP_SHARED, 
                					fd, //指定要映射的匿名共享内存的文件描述符
                					offset //表示要从这个文件的哪个偏移位置开始映射
                					);
        if (base == MAP_FAILED) {
            ALOGE("mmap(fd=%d, size=%u) failed (%s)",
                    fd, uint32_t(size), strerror(errno));
            close(fd);
            return -errno;
        }
        //ALOGD("mmap(fd=%d, base=%p, size=%lu)", fd, base, size);
        mBase = base;
        mNeedUnmap = true;
    } else  {
        mBase = 0; // not MAP_FAILED
        mNeedUnmap = false;
    }
    mFD = fd;
    mSize = size;
    mOffset = offset;
    return NO_ERROR;
}

MemoryHeapBase::~MemoryHeapBase()
{
    dispose();
}

void MemoryHeapBase::dispose()
{
    int fd = android_atomic_or(-1, &mFD);
    if (fd >= 0) {
        if (mNeedUnmap) {
            //ALOGD("munmap(fd=%d, base=%p, size=%lu)", fd, mBase, mSize);
            munmap(mBase, mSize);
        }
        mBase = 0;
        mSize = 0;
        close(fd);
    }
}

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

const char* MemoryHeapBase::getDevice() const {
    return mDevice;
}

uint32_t MemoryHeapBase::getOffset() const {
    return mOffset;
}

2.1.2 在Client端的实现

在客户端的实现过程中接口 MemoryHeapBase 可以将所有涉及到的类分为以下3种类型:

  1. 业务相关类:即跟匿名共享内存操作相关的类,包括 BpMemoryHeap、IMemoryHeap;
  2. Binder 进程通信类:即和 Binder 进程通信机制相关的类,包括 IInterface、BnInterface、IBinder、BBinder、ProcessState 和IPCThreadState;
  • 智能指针类:RefBase;

  类 BpMemoryHeap 是类 MemoryHeapBase 在 Client 端进程的远接接口类,当 Client 端进程从 servicemanager 获得了一个 MemoryHeapBase 对象的引用后,会在本地创建一个 BpMemoryHeap 对象来表示这个引用。类 BpMemoryHeap 是从 RefBase 类继承下来的,也要实现 IMemoryHeap 接口,可以和智能指针来结合使用。类 BpMemoryHeap 在源码 frameworks/native/libs/binder/IMemory.cpp 中定义。

class BpMemoryHeap : public BpInterface<IMemoryHeap>
{
public:
    BpMemoryHeap(const sp<IBinder>& impl);
    virtual ~BpMemoryHeap();

    virtual int getHeapID() const;
    virtual void* getBase() const;
    virtual size_t getSize() const;
    virtual uint32_t getFlags() const;
    virtual uint32_t getOffset() const;

private:
    friend class IMemory;
    friend class HeapCache;

    // for debugging in this module
    static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) {
        return gHeapCache->find_heap(binder);
    }
    static inline void free_heap(const sp<IBinder>& binder) {
        gHeapCache->free_heap(binder);
    }
    static inline sp<IMemoryHeap> get_heap(const sp<IBinder>& binder) {
        return gHeapCache->get_heap(binder);
    }
    static inline void dump_heaps() {
        gHeapCache->dump_heaps();
    }

    void assertMapped() const;
    void assertReallyMapped() const;

    mutable volatile int32_t mHeapId;
    mutable void*       mBase;
    mutable size_t      mSize;
    mutable uint32_t    mFlags;
    mutable uint32_t    mOffset;
    mutable bool        mRealHeap;
    mutable Mutex       mLock;
};

类 BpMemoryHeap 对应的构造函数为:

BpMemoryHeap::BpMemoryHeap(const sp<IBinder>& impl)
    : BpInterface<IMemoryHeap>(impl),
        mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mOffset(0), mRealHeap(false)
{
}

成员函数 getHeapID、getBase、getSize、getFlags、getOffset 的实现代码如下所示:

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

uint32_t BpMemoryHeap::getOffset() const {
    assertMapped();
    return mOffset;
}

  在使用上述成员函数之前,通过调用函数 assertMapped 来确保在 Client 端已经准备好了匿名共享内存。函数 assertMapped 在源码 frameworks/native/libs/binder/IMemory.cpp 中定义。

void BpMemoryHeap::assertMapped() const
{
    if (mHeapId == -1) {
        sp<IBinder> binder(IInterface::asBinder(const_cast<BpMemoryHeap*>(this)));
        sp<BpMemoryHeap> heap(static_cast<BpMemoryHeap*>(find_heap(binder).get()));
        heap->assertReallyMapped();
        if (heap->mBase != MAP_FAILED) {
            Mutex::Autolock _l(mLock);
            if (mHeapId == -1) {
                mBase   = heap->mBase;
                mSize   = heap->mSize;
                mOffset = heap->mOffset;
                android_atomic_write( dup( heap->mHeapId ), &mHeapId );
            }
        } else {
            // something went wrong
            free_heap(binder);
        }
    }
}

类 HeapCache 的定义:

class HeapCache : public IBinder::DeathRecipient
{
public:
    HeapCache();
    virtual ~HeapCache();

    virtual void binderDied(const wp<IBinder>& who);

    sp<IMemoryHeap> find_heap(const sp<IBinder>& binder);
    void free_heap(const sp<IBinder>& binder);
    sp<IMemoryHeap> get_heap(const sp<IBinder>& binder);
    void dump_heaps();

private:
    // For IMemory.cpp
    struct heap_info_t {
        sp<IMemoryHeap> heap;
        int32_t         count;
    };

    void free_heap(const wp<IBinder>& binder);

    Mutex mHeapCacheLock;
    KeyedVector< wp<IBinder>, heap_info_t > mHeapCache;
};

  在上述代码中定义了成员变量 mHeapCache,功能是维护进程内的所有 BpMemoryHeap 对象。另外还提供了函数 find_heap 和函数 get_heap 来查内部所维护的 BpMemoryHeap 对象,这两个函数的具体说明如下所示:

  • 函数 find_heap:如果在 mHeapCache 找不到相应的 BpMemoryHeap 对象,则把 BpMemoryHeap 对象加入到 mHeapCache 中。
  • 函数 get_heap:不会自动把 BpMemoryHeap 对象加入到 mHeapCache 中。

  接下来看函数 find_heap,首先以传进来的参数 binder 作为关键字在 mHeapCache 中查找,查找是否存在对应的 heap_info 对象 info。

  • 如果有:增加引用计数 info.count 的值,表示此 BpBinder 对象多了一个使用者。
  • 如果没有:创建一个放到 mHeapCache 中的 heap_info 对象 info。

函数 find_heap 在源码 frameworks/native/libs/binder/IMemory.cpp 中定义。

sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder)
{
    Mutex::Autolock _l(mHeapCacheLock);
    ssize_t i = mHeapCache.indexOfKey(binder);
    if (i>=0) {
        heap_info_t& info = mHeapCache.editValueAt(i);
        ALOGD_IF(VERBOSE,
                "found binder=%p, heap=%p, size=%zu, fd=%d, count=%d",
                binder.get(), info.heap.get(),
                static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
                static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
                info.count);
        android_atomic_inc(&info.count);
        return info.heap;
    } else {
        heap_info_t info;
        info.heap = interface_cast<IMemoryHeap>(binder);
        info.count = 1;
        //ALOGD("adding binder=%p, heap=%p, count=%d",
        //      binder.get(), info.heap.get(), info.count);
        mHeapCache.add(binder, info);
        return info.heap;
    }
}

在类 BpMemoryHeap 的定义中有一个成员函数 find_heap,能够调用全局变量 gHeapCache 执行查找的操作。

class BpMemoryHeap : public BpInterface<IMemoryHeap>
{
......
private:
    ......
    // for debugging in this module
    static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) {
        return gHeapCache->find_heap(binder);
    }
}

  通过调用函数 find_heap 得到 BpMemoryHeap 对象中的函数 assertReallyMapped,这样可以确认它内部的匿名共享内存是否已经映射到进程空间。

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();
        uint32_t offset = reply.readInt32();

        ALOGE_IF(err, "binder=%p transaction failed fd=%d, size=%zd, err=%d (%s)",
                IInterface::asBinder(this).get(),
                parcel_fd, size, err, strerror(-err));

#ifdef USE_MEMORY_HEAP_ION
        ion_client ion_client_num = -1;
        if (flags & USE_ION_FD) {
            ion_client_num = ion_client_create();
            ALOGE_IF(ion_client_num < 0, "BpMemoryHeap : ion client creation error");
        }
#endif
        Mutex::Autolock _l(mLock);
        if (mHeapId == -1) {
            int fd = dup( parcel_fd );
            ALOGE_IF(fd==-1, "cannot dup fd=%d, size=%zd, err=%d (%s)",
                    parcel_fd, size, err, strerror(errno));

            int access = PROT_READ;
            if (!(flags & READ_ONLY)) {
                access |= PROT_WRITE;
            }

            mRealHeap = true;

#ifdef USE_MEMORY_HEAP_ION
        if (flags & USE_ION_FD) {
            if (ion_client_num < 0)
                mBase = MAP_FAILED;
            else
                mBase = ion_map(fd, size, offset);
            } else
#endif
            mBase = mmap(0, size, access, MAP_SHARED, fd, offset);
            if (mBase == MAP_FAILED) {
                ALOGE("cannot map BpMemoryHeap (binder=%p), size=%zd, fd=%d (%s)",
                        IInterface::asBinder(this).get(), size, fd, strerror(errno));
                close(fd);
            } else {
                mSize = size;
                mFlags = flags;
                mOffset = offset;
                android_atomic_write(fd, &mHeapId);
            }
        }
#ifdef USE_MEMORY_HEAP_ION
        if (ion_client_num < 0)
            ion_client_num = -1;
        else
            ion_client_destroy(ion_client_num);
#endif
    }
}

2.2 接口 MemoryBase

  接口 MemoryBase 是建立在接口 MemoryHeapBase 基础上的,两者都可以作为一个 Binder 对象在进程之间实现数据共享。

2.2.1 在Server端的实现

  首先分析类 MemoryBase 在 Server 端的实现,MemoryBase 在 Server 端只是简单地封装了 MemoryHeapBase 的实现。类 MemoryBase 在 Server 端的实现跟类 MemoryHeapBase 在 Server端的实现类似,只需在整个类图结构中实现如下转换即可:

  • 把类 IMemory 换成类 ImemoryHeap;
  • 把类 BnMemory 换成类 BnMemoryHeap;
  • 把类 MemoryBase 换成类 MemoryHeapBase;

  类 IMemory 在源码:frameworks/native/include/binder/IMemory.h 中实现,功能是定义类 MemoryBase 所需要的实现接口。

class IMemory : public IInterface
{
public:
    DECLARE_META_INTERFACE(Memory);

    virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const = 0;

    // helpers
    void* fastPointer(const sp<IBinder>& heap, ssize_t offset) const;
    void* pointer() const;
    size_t size() const;
    ssize_t offset() const;
};

在类 IMemory 中定义了如下所示的成员函数:

  • getMemory:功能是获取内部 MemoryHeapBase 对象的 IMemoryHeap 接口;
  • pointer():功能是获取内部所维护的匿名共享内存的基地址;
  • size():功能是获取内部所维护的匿名共享内存的大小;
  • offset():功能是获取内部所维护的匿名共享内存在整个匿名共享内存中的偏移量。

  类 IMemory 在本身定义过程中实现了3个成员函数:pointer、size 和 offset,其子类 MemoryBase 只需实现成员函数 getMemory 即可。类 IMemory 的具体实现在源码 frameworks/native/libs/binder/IMemory.cpp 中定义。

void* IMemory::pointer() const {
    ssize_t offset;
    sp<IMemoryHeap> heap = getMemory(&offset);
    void* const base = heap!=0 ? heap->base() : MAP_FAILED;
    if (base == MAP_FAILED)
        return 0;
    return static_cast<char*>(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;
}

  类 MemoryBase 是一个本地 Binder 对象类在源码 frameworks/native/include/binder/MemoryBase.h 中声明,具体实现代码如下所示:

namespace android {

// ---------------------------------------------------------------------------

class MemoryBase : public BnMemory
{
public:
    MemoryBase(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
    virtual ~MemoryBase();
    virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;

protected:
    size_t getSize() const { return mSize; }
    ssize_t getOffset() const { return mOffset; }
    const sp<IMemoryHeap>& getHeap() const { return mHeap; }

private:
    size_t          mSize;
    ssize_t         mOffset;
    sp<IMemoryHeap> mHeap;
};

// ---------------------------------------------------------------------------
}; // namespace android

类 MemoryBase 的具体实现在源码 frameworks/native/libs/binder/IMemory.cpp 中定义。

namespace android {

MemoryBase::MemoryBase(const sp<IMemoryHeap>& heap, //指向 MemoryHeapBase 对象,真正的匿名共享内存就是由它来维护的
        ssize_t offset, size_t size) //表示这个MemoryBase 对象所要维护的这部分匿名共享内存在整个匿名共享内存块中的起始位置
    : mSize(size), mOffset(offset), mHeap(heap) //表示这个MemoryBase 对象所要维护的这部分匿名共享内存的大小
{
}

/*
	功能是返回内部的 MemoryHeapBase 对象的 IMemoryHeap 接口
	如果传进来的参数offset 和 size 不为 NULL
	会把其内部维护的这部分匿名共享内存,在整个匿名共享内存块中的偏移位置
	以及这部分匿名共享内存的大小返回给调用者
*/
sp<IMemoryHeap> MemoryBase::getMemory(ssize_t* offset, size_t* size) const
{
    if (offset) *offset = mOffset;
    if (size)   *size = mSize;
    return mHeap;
}

MemoryBase::~MemoryBase()
{
}

}; // namespace android

2.2.2 在Client端的实现

  MemoryBase 类在 Client 端的实现,类 MemoryBase 在 Client 端的实现与类 MemoryHeapBase 在 Client 端的实现类似,只需要进行如下所示的类转换即可成为 MemoryHeapBase 在 Client端的实现。

  • 把类 IMemory 换成类 ImemoryHeap;
  • 把类 BpMemory 换成类 BpMemoryHeap;

  类 BpMemory 用于描述类 MemoryBase 服务的代理对象,在源码 frameworks/native/libs/binder/IMemory.cpp 中定义。

class BpMemory : public BpInterface<IMemory>
{
public:
    BpMemory(const sp<IBinder>& impl);
    virtual ~BpMemory();
    virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const;

private:
    mutable sp<IMemoryHeap> mHeap;
    mutable ssize_t mOffset;
    mutable size_t mSize;
};

类 BpMemory 中的成员函数 getMemory 在源码 frameworks/native/libs/binder/IMemory.cpp 中定义。

sp<IMemoryHeap> 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<IBinder> heap = reply.readStrongBinder();
            ssize_t o = reply.readInt32();
            size_t s = reply.readInt32();
            if (heap != 0) {
                mHeap = interface_cast<IMemoryHeap>(heap);
                if (mHeap != 0) {
                    size_t heapSize = mHeap->getSize();
                    if (s <= heapSize
                            && o >= 0
                            && (static_cast<size_t>(o) <= heapSize - s)) {
                        mOffset = o;
                        mSize = s;
                    } else {
                        // Hm.
                        android_errorWriteWithInfoLog(0x534e4554,
                            "26877992", -1, NULL, 0);
                        mOffset = 0;
                        mSize = 0;
                    }
                }
            }
        }
    }
    if (offset) *offset = mOffset;
    if (size) *size = mSize;
    return (mSize > 0) ? mHeap : 0;
}

  如果成员变量 mHeap 的值为 NULL,表示此 BpMemory 对象还没有建立好名共享内存,此时会调用一个 Binder 进程去 Server 端请求匿名共享内存信息。通过引用信息中的 Server 端的 MemoryHeapBase 对象的引用 heap,可以在 Client 端进程中创建一个 BpMemoryHeap 远程接口,最后将这个 BpMemoryHeap 远程接口保存在成员变量 mHeap 中,同时从 Server 端获得的信息还包括这块匿名共享内存在整个匿名共享内存中的偏移位置以及大小。

你可能感兴趣的:(#,android,Ashmem,C/C++)