前面分析了 binder 中用来打包、传递数据的 Parcel,一般用来传递 IPC 中的小型参数和返回值。binder 目前每个进程 mmap 接收数据的内存是 1M,所以就算你不考虑效率问题用 Parcel 来传,也无法传过去。只要超过 1M 就会报错(binder 无法分配接收空间)。所以 android 里面有一个专门用来在 IPC 中传递大型数据的东西—— Ashmem(Anonymous Shared Memroy)。照例把相关代码的位置说一下(4.4):

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                            
                                                            # MemroyFile 是 ashmem java 层接口                                                                                        frameworks/base/core/java/os/Parcel.java                                                                                        frameworks/base/core/java/os/Parcelable.java                                                                                        frameworks/base/core/java/os/ParcelFileDescriptor.java                                                                                        frameworks/base/core/java/os/MemoryFile.java                                                                                        # jni 相关                                                                                        frameworks/base/core/jni/android_os_Parcel.h                                                                                        frameworks/base/core/jni/android_os_MemoryFile.cpp                                                                                        frameworks/base/core/jni/android_os_Parcel.cpp                                                                                        libnativehelper/JNIHelp.cpp                                                                                        # 封装了 ashmem 驱动的 c 接口                                                                                        system/core/include/cutils/ashmem.h                                                                                        system/core/libcutils/ashmem-dev.c                                                                                        # MemoryXx 是 ashmem 的 native 接口                                                                                        frameworks/native/include/binder/Parcel.h                                                                                        frameworks/native/include/binder/IMemory.h                                                                                        frameworks/native/include/binder/MemoryHeapBase.h                                                                                        frameworks/native/include/binder/MemoryBase.h                                                                                        frameworks/native/libs/binder/Parcel.cpp                                                                                        frameworks/native/libs/binder/Memory.cpp                                                                                        frameworks/native/libs/binder/MemoryHeapBase.cpp                                                                                        frameworks/native/libs/binder/MemoryBase.cpp                                                                                        # kernel binder 驱动                                                                                        kernel/drivers/staging/android/binder.h                                                                                        kernel/drivers/staging/android/binder.c                                                                                        # kernel ashmem 驱动                                                                                        kernel/include/linux/ashmem.h                                                                                        kernel/mm/ashmem.c                            

(这和 Parcel 篇的基本一样么 -_-||)

原理概述

ashmem 并像 binder 是 android 重新自己搞的一套东西,而是利用了 linux 的 tmpfs 文件系统。关于 tmpfs 我目前还不算很了解,可以先看下这里的2篇,有个基本的了解:

Linux tmpfs
linux共享内存的设计

那么大致能够知道,tmpfs 是一种可以基于 ram 或是 swap 的高速文件系统,然后可以拿它来实现不同进程间的内存共享。

然后大致思路和流程是:

  • Proc A 通过 tmpfs 创建一块共享区域,得到这块区域的 fd(文件描述符)
  • Proc A 在 fd 上 mmap 一片内存区域到本进程用于共享数据
  • Proc A 通过某种方法把 fd 倒腾给 Proc B
  • Proc B 在接到的 fd 上同样 mmap 相同的区域到本进程
  • 然后 A、B 在 mmap 到本进程中的内存中读、写,对方都能看到了

其实核心点就是创建一块共享区域,然后2个进程同时把这片区域 mmap 到本进程,然后读写就像本进程的内存一样。这里要解释下第3步,为什么要倒腾 fd,因为在 linux 中 fd 只是对本进程是唯一的,在 Proc A 中打开一个文件得到一个 fd,但是把这个打开的 fd 直接放到 Proc B 中,Proc B 是无法直接使用的。但是文件是唯一的,就是说一个文件(file)可以被打开多次,每打开一次就有一个 fd(文件描述符),所以对于同一个文件来说,需要某种转化,把 Proc A 中的 fd 转化成 Proc B 中的 fd。这样 Proc B 才能通过 fd mmap 同样的共享内存文件(额,其实这里相关知识我也还没了解,瞎扯一下)。

java 层接口

java 层的接口要拿 2.3 的来说,因为从 4.1(具体哪个版本我不好说,反正我手上只有 4.1 之后的)之后 java 层的 MemroyFile 应该就无法正常使用了,搜索代码发现,除了 test 有 MemroyFile 其它地方就去掉了。具体原因后面分析代码就知道了。

咋先来点感性的认识(MemroyFile.java):

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                            
                                                            private FileDescriptor mFD;                                        // ashmem file descriptor                                                                                        private                                 int mAddress;                                   // address of ashmem memory                                                                                        private                                 int mLength;                                    // total length of our ashmem region                                                                                        private                                 boolean mAllowPurging =                                 false;                                  // true if our ashmem region is unpinned                                                                                        private                                 final                                 boolean mOwnsRegion;                                  // false if this is a ref to an existing ashmem region                                                                                        /*                                                                                         * Allocates a new ashmem region. The region is initially not purgable.                                                                                         *                                                                                         * @param name optional name for the file (can be null).                                                                                         * @param length of the memory file in bytes.                                                                                         * @throws IOException if the memory file could not be created.                                                                                         */                                                                                        public                                 MemoryFile(String name,                                 int length)                                 throws IOException {                                                                                            mLength = length;                                                                                            mFD = native_open(name, length);                                                                                            mAddress = native_mmap(mFD, length, PROT_READ | PROT_WRITE);                                                                                            mOwnsRegion =                                 true;                                                                                        }                            

MemroyFile 还是比较简单的,成员变量也比较少,上面基本上就是所有的变量了。FileDescriptor 这个是 java 本身的对象,应该是 natvie fd 的封装吧。后面的地址、长度不说了。后面2个 boolean, mAllowPurging 表示这块 ashmem 是否允许被回收。 ashmem 在驱动那向 kernel 注册了一个内存回收算法,当 kernel 进行内存扫描的时候会调用这个回收算法,当标记了可以回收的时候,会把标记的内存给回收掉。这个设计的目的估计是想更高效的使用内存(能够标记一段共享内存不用了),但是后面你会发现这个东西目前还是个摆设。mOwnsRegion 表示只有创建者才能标记这块共享内存被回收。

MemroyFile 的使用方法,就只有构造函数一个。而且默认 mAllowPurging 是 false。这个构造函数是创建共享内存的,所以 mOwnsRegion 是 true。回想下前面原理,说的 Proc A 首先要创建一块共享内存,然后再 mmap 到本进程。这里正好2个 jni:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                            
                                                            static jobject android_os_MemoryFile_open(JNIEnv* env, jobject clazz, jstring name, jint length)                                                                                        {                                                                                            const                                 char* namestr = (name ? env->GetStringUTFChars(name, NULL) : NULL);                                                                                            int result = ashmem_create_region(namestr, length);                                                                                            if (name)                                                                                                env->ReleaseStringUTFChars(name, namestr);                                                                                            if (result <                                 0) {                                                                                                jniThrowException(env,                                 "java/io/IOException",                                 "ashmem_create_region failed");                                                                                                return NULL;                                                                                            }                                                                                            return jniCreateFileDescriptor(env, result);                                                                                        }                            

这个 jni 很简单了,前面的 MemroyFile 传了要创建的共享内存的名字以及大小。这里主要是调用 libcutils 里面的 ashmem-dev.c 的接口去创建共享内存:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                            
                                                            #define ASHMEM_DEVICE   "/dev/ashmem"                                                                                        /*                                                                                         * ashmem_create_region - creates a new ashmem region and returns the file                                                                                         * descriptor, or <0 on error                                                                                         *                                                                                         * `name' is an optional label to give the region (visible in /proc/pid/maps)                                                                                         * `size' is the size of the region, in page-aligned bytes                                                                                         */                                                                                        int ashmem_create_region(                                const                                 char *name, size_t size)                                                                                        {                                                                                            int fd, ret;                                                                                            fd = open(ASHMEM_DEVICE, O_RDWR);                                                                                            if (fd <                                 0)                                                                                                return fd;                                                                                            if (name) {                                                                                                char buf[ASHMEM_NAME_LEN];                                                                                                strlcpy(buf, name,                                 sizeof(buf));                                                                                                ret = ioctl(fd, ASHMEM_SET_NAME, buf);                                                                                                if (ret <                                 0)                                                                                                    goto error;                                                                                            }                                                                                            ret = ioctl(fd, ASHMEM_SET_SIZE, size);                                                                                            if (ret <                                 0)                                                                                                goto error;                                                                                            return fd;                                                                                        error:                                                                                            close(fd);                                                                                            return ret;                                                                                        }                            

熟悉 linux 环境编程的也没啥要说的, open 打开设备。/dev/ashmem 在前面有篇文章说到,在 init.rc 里面和 /dev/binder 是系统 init 进程创建好的设备节点(虚拟机设备)。然后 ioctl 去设置名字和大小。这里就要走到 kernel 的驱动里面去了,这些后面再说。然后返回 fd。然后回到 jni 里面,通过 fd 构造出 java 的 FileDescriptor(JNIHelp.cpp):

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                            
                                                            jobject jniCreateFileDescriptor(C_JNIEnv* env,                                 int fd) {                                                                                            JNIEnv* e =                                 reinterpret_cast(env);                                                                                            static jmethodID ctor = e->GetMethodID(JniConstants::fileDescriptorClass,                                 "",                                 "()V");                                                                                            jobject fileDescriptor = (*env)->NewObject(e, JniConstants::fileDescriptorClass, ctor);                                                                                            jniSetFileDescriptorOfFD(env, fileDescriptor, fd);                                                                                            return fileDescriptor;                                                                                        }                                                                                        int jniGetFDFromFileDescriptor(C_JNIEnv* env, jobject fileDescriptor) {                                                                                            JNIEnv* e =                                 reinterpret_cast(env);                                                                                            static jfieldID fid = e->GetFieldID(JniConstants::fileDescriptorClass,                                 "descriptor",                                 "I");                                                                                            return (*env)->GetIntField(e, fileDescriptor, fid);                                                                                        }                                                                                        void jniSetFileDescriptorOfFD(C_JNIEnv* env, jobject fileDescriptor,                                 int value) {                                                                                            JNIEnv* e =                                 reinterpret_cast(env);                                                                                            static jfieldID fid = e->GetFieldID(JniConstants::fileDescriptorClass,                                 "descriptor",                                 "I");                                                                                            (*env)->SetIntField(e, fileDescriptor, fid, value);                                                                                        }                            

这里就能看得出,FileDescriptor 就是把 fd 封装了一下,核心还是这个 int 值啊(通过反射,用 fd 设置了一下 FileDescriptor 的 fileDescriptor 这个变量)。然后看下 mmap:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                            
                                                            static jint android_os_MemoryFile_mmap(JNIEnv* env, jobject clazz, jobject fileDescriptor,                                                                                                jint length, jint prot)                                                                                        {                                                                                            int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);                                                                                            jint result = (jint)mmap(NULL, length, prot, MAP_SHARED, fd,                                 0);                                                                                            if (!result)                                                                                                jniThrowException(env,                                 "java/io/IOException",                                 "mmap failed");                                                                                            return result;                                                                                        }                            

这个更简单,通过 FileDescriptor 得到 fd,直接系统 mmap 。这里 mmap 也是要进到 kernel 的驱动里面的。稍微注意下, port 是 PORT_READ | PORT_WRITE 读写, flag 是 MAP_SHARED,就说明这是专为共享设置的。

Proc A 算是把共享内存创建好了也 mmap 到本进程,现在就要把 fd 倒腾给 Proc B。现在我们假设 Proc A 是 Bn 端,Proc B 是 Bp 端。然后来看看 MemroyFile 的一个接口:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                            
                                                            /*                                                                                         * Gets a ParcelFileDescriptor for the memory file. See {@link #getFileDescriptor()}                                                                                         * for caveats. This must be here to allow classes outside android.os                                                                                         * make ParcelFileDescriptors from MemoryFiles, as                                                                                         * {@link ParcelFileDescriptor#ParcelFileDescriptor(FileDescriptor)} is package private.                                                                                         *                                                                                          *                                                                                          * @return The file descriptor owned by this memory file object.                                                                                         *         The file descriptor is not duplicated.                                                                                         * @throws IOException If the memory file has been closed.                                                                                         *                                                                                          * @hide                                                                                         */                                                                                        public ParcelFileDescriptor                                 getParcelFileDescriptor()                                 throws IOException {                                                                                            FileDescriptor fd = getFileDescriptor();                                                                                            return fd !=                                 null ?                                 new ParcelFileDescriptor(fd) :                                 null;                                                                                        }                            

ParcelFileDescriptor,看名字你是不是明白了什么咧,能够 Parcelable 的 fd,这个就是让你拿来用 binder 传给 Proc B 的啊。

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                            
                                                            /*package */ParcelFileDescriptor(FileDescriptor descriptor) {                                                                                            super();                                                                                            if (descriptor ==                                 null) {                                                                                                throw                                 new NullPointerException(                                "descriptor must not be null");                                                                                            }                                                                                            mFileDescriptor = descriptor;                                                                                            mParcelDescriptor =                                 null;                                                                                        }                                                                                        /*                                                                                         * {@inheritDoc}                                                                                         * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags,                                                                                         * the file descriptor will be closed after a copy is written to the Parcel.                                                                                         */                                                                                        public                                 void                                 writeToParcel(Parcel out,                                 int flags) {                                                                                            out.writeFileDescriptor(mFileDescriptor);                                                                                            if ((flags&PARCELABLE_WRITE_RETURN_VALUE) !=                                 0 && !mClosed) {                                                                                                try {                                                                                                    close();                                                                                                }                                 catch (IOException e) {                                                                                                    // Empty                                                                                                }                                                                                            }                                                                                        }                                                                                        public                                 static                                 final Parcelable.Creator CREATOR                                                                                                =                                 new Parcelable.Creator() {                                                                                            public ParcelFileDescriptor                                 createFromParcel(Parcel in) {                                                                                                return in.readFileDescriptor();                                                                                            }                                                                                            public ParcelFileDescriptor[]                                 newArray(                                int size) {                                                                                                return                                 new ParcelFileDescriptor[size];                                                                                            }                                                                                        };                            

ParcelFileDescriptor 其实挺简单,主要是看它的 Paracelable 接口。又是调用 Parcel 的对应接口(java jni native 放一起了,麻烦,而且下面是 2.3 的代码,4.4 的不一样了,基本上好像太能配合 MemroyFile 使用了)。

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                                                                                        44                                                                                        45                                                                                        46                                                                                        47                                                                                        48                                                                                        49                                                                                        50                                                                                        51                                                                                        52                                                                                        53                                                                                        54                                                                                        55                                                                                        56                                                                                        57                                                                                        58                                                                                        59                                                                                        60                                                                                        61                                                                                        62                                                                                        63                                                                                        64                                                                                        65                                                                                        66                                                                                        67                                                                                        68                                                                                        69                                                                                        70                                                                                        71                                                                                        72                                                                                        73                                                                                        74                                                                                        75                                                                                        76                                                                                        77                                                                                        78                                                                                        79                                                                                        80                                                                                        81                            
                                                            // java ================================                                                                                            /**                                                                                             * Write a FileDescriptor into the parcel at the current dataPosition(),                                                                                             * growing dataCapacity() if needed.                                                                                             *                                                                                              * 

The file descriptor will not be closed, which may * result in file descriptor leaks when objects are returned from Binder * calls. Use {@link ParcelFileDescriptor#writeToParcel} instead, which * accepts contextual flags and will close the original file descriptor * if {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set.

*/ public final native void writeFileDescriptor(FileDescriptor val); /** * Read a FileDescriptor from the parcel at the current dataPosition(). */ public final ParcelFileDescriptor readFileDescriptor() { FileDescriptor fd = internalReadFileDescriptor(); return fd != null ? new ParcelFileDescriptor(fd) : null; } // jni ================================ static void android_os_Parcel_writeFileDescriptor(JNIEnv* env, jobject clazz, jobject object) { Parcel* parcel = parcelForJavaObject(env, clazz); if (parcel != NULL) { const status_t err = parcel->writeDupFileDescriptor( env->GetIntField(object, gFileDescriptorOffsets.mDescriptor)); if (err != NO_ERROR) { jniThrowException(env, "java/lang/OutOfMemoryError", NULL); } } } // 这个在 jni 注册那里是叫 internalReadFileDescriptor -_-|| static jobject android_os_Parcel_readFileDescriptor(JNIEnv* env, jobject clazz) { Parcel* parcel = parcelForJavaObject(env, clazz); if (parcel != NULL) { int fd = parcel->readFileDescriptor(); if (fd < 0) return NULL; fd = dup(fd); if (fd < 0) return NULL; jobject object = env->NewObject( gFileDescriptorOffsets.mClass, gFileDescriptorOffsets.mConstructor); if (object != NULL) { //LOGI("Created new FileDescriptor %p with fd %d\n", object, fd); env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, fd); } return object; } return NULL; } // native ================================ status_t Parcel::writeDupFileDescriptor( int fd) { flat_binder_object obj; obj.type = BINDER_TYPE_FD; obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; obj.handle = dup(fd); obj.cookie = ( void*) 1; 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; }

最后,是到 Parcel ,通过 flat_binder_object 来传递的。回想下前面几篇的内容,Parcel 传递 flat_binder_object 到 binder 驱动的时候,有好几种类型,当时是不是有一种 BINDER_TYPE_FD 类型被选择性的无视了,现在知道这个 FD 是专门拿来倒腾 fd 用的了吧。这里 writeDupFileDescriptor 用 dup 复制了一个 fd 封装在 flat_binder_object 里面,然后 kernel 那里倒腾后面再说。反正 binder 传到 Proc B 那边,通过 Parcelable 的 CREATEOR 调用到 readFileDescriptor 会把 flat_binder_object 读出来,然后这里的 fd 就是经过倒腾的,是 Proc B 进程能够用的了。

Proc B 拿到 fd 后就可以 mmap Proc A 创建的共享内存了(还是创建 MemroyFile):

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                            
                                                            /*                                                                                         * Creates a reference to an existing memory file. Changes to the original file                                                                                         * will be available through this reference.                                                                                         * Calls to {@link #allowPurging(boolean)} on the returned MemoryFile will fail.                                                                                         *                                                                                          * @param fd File descriptor for an existing memory file, as returned by                                                                                         *        {@link #getFileDescriptor()}. This file descriptor will be closed                                                                                         *        by {@link #close()}.                                                                                         * @param length Length of the memory file in bytes.                                                                                         * @param mode File mode. Currently only "r" for read-only access is supported.                                                                                         * @throws NullPointerException if fd is null.                                                                                         * @throws IOException If fd does not refer to an existing memory file,                                                                                         *         or if the file mode of the existing memory file is more restrictive                                                                                         *         than mode.                                                                                         *                                                                                          * @hide                                                                                         */                                                                                        public                                 MemoryFile(FileDescriptor fd,                                 int length, String mode)                                 throws IOException {                                                                                            if (fd ==                                 null) {                                                                                                throw                                 new NullPointerException(                                "File descriptor is null.");                                                                                            }                                                                                            if (!isMemoryFile(fd)) {                                                                                                       throw                                 new IllegalArgumentException(                                "Not a memory file.");                                                                                            }                                                                                            mLength = length;                                                                                            mFD = fd;                                                                                            mAddress = native_mmap(mFD, length, modeToProt(mode));                                                                                            mOwnsRegion =                                 false;                                                                                        }                            

这个就是 Proc A 那里省去了 open 的操作(当然,因为有现成的 fd 了)。Proc B 也把共享内存文件 mmap 到本进程后,A、B 就可以通过 MemroyFile 的 read、write 接口读写了:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                                                                                        44                                                                                        45                                                                                        46                                                                                        47                                                                                        48                                                                                        49                                                                                        50                                                                                        51                                                                                        52                                                                                        53                                                                                        54                                                                                        55                                                                                        56                                                                                        57                                                                                        58                                                                                        59                                                                                        60                                                                                        61                                                                                        62                                                                                        63                                                                                        64                                                                                        65                                                                                        66                                                                                        67                                                                                        68                                                                                        69                                                                                        70                                                                                        71                                                                                        72                                                                                        73                                                                                        74                                                                                        75                                                                                        76                                                                                        77                                                                                        78                                                                                        79                                                                                        80                                                                                        81                                                                                        82                                                                                        83                                                                                        84                                                                                        85                                                                                        86                                                                                        87                                                                                        88                                                                                        89                                                                                        90                                                                                        91                            
                                                            // java ================================                                                                                            /**                                                                                             * Reads bytes from the memory file.                                                                                             * Will throw an IOException if the file has been purged.                                                                                             *                                                                                             * @param buffer byte array to read bytes into.                                                                                             * @param srcOffset offset into the memory file to read from.                                                                                             * @param destOffset offset into the byte array buffer to read into.                                                                                             * @param count number of bytes to read.                                                                                             * @return number of bytes read.                                                                                             * @throws IOException if the memory file has been purged or deactivated.                                                                                             */                                                                                            public                                 int readBytes(byte[] buffer,                                 int srcOffset,                                 int destOffset,                                 int count)                                                                                                     throws IOException {                                                                                                           if (isDeactivated()) {                                                                                                    throw                                 new IOException(                                "Can't read from deactivated memory file.");                                                                                                }                                                                                                if (destOffset <                                 0 || destOffset > buffer.length || count <                                 0                                                                                                        || count > buffer.length - destOffset                                                                                                        || srcOffset <                                 0 || srcOffset > mLength                                                                                                        || count > mLength - srcOffset) {                                                                                                     throw                                 new IndexOutOfBoundsException();                                                                                                }                                                                                                return native_read(mFD, mAddress, buffer, srcOffset, destOffset, count, mAllowPurging);                                                                                            }                                                                                            /**                                                                                             * Write bytes to the memory file.                                                                                             * Will throw an IOException if the file has been purged.                                                                                             *                                                                                              * @param buffer byte array to write bytes from.                                                                                             * @param srcOffset offset into the byte array buffer to write from.                                                                                             * @param destOffset offset  into the memory file to write to.                                                                                             * @param count number of bytes to write.                                                                                             * @throws IOException if the memory file has been purged or deactivated.                                                                                             */                                                                                            public                                 void writeBytes(byte[] buffer,                                 int srcOffset,                                 int destOffset,                                 int count)                                                                                                    throws IOException {                                                                                                           if (isDeactivated()) {                                                                                                    throw                                 new IOException(                                "Can't write to deactivated memory file.");                                                                                                }                                                                                                if (srcOffset <                                 0 || srcOffset > buffer.length || count <                                 0                                                                                                        || count > buffer.length - srcOffset                                                                                                        || destOffset <                                 0 || destOffset > mLength                                                                                                        || count > mLength - destOffset) {                                                                                                    throw                                 new IndexOutOfBoundsException();                                                                                                }                                                                                                native_write(mFD, mAddress, buffer, srcOffset, destOffset, count, mAllowPurging);                                                                                            }                                                                                        // jni ================================                                                                                        static jint android_os_MemoryFile_read(JNIEnv* env, jobject clazz,                                                                                                jobject fileDescriptor, jint address, jbyteArray buffer, jint srcOffset, jint destOffset,                                                                                                jint count, jboolean unpinned)                                                                                        {                                                                                            int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);                                                                                            if (unpinned && ashmem_pin_region(fd,                                 0,                                 0) == ASHMEM_WAS_PURGED) {                                                                                                ashmem_unpin_region(fd,                                 0,                                 0);                                                                                                jniThrowException(env,                                 "java/io/IOException",                                 "ashmem region was purged");                                                                                                return -                                1;                                                                                            }                                                                                            env->SetByteArrayRegion(buffer, destOffset, count, (                                const jbyte *)address + srcOffset);                                                                                            if (unpinned) {                                                                                                ashmem_unpin_region(fd,                                 0,                                 0);                                                                                            }                                                                                            return count;                                                                                        }                                                                                        static jint android_os_MemoryFile_write(JNIEnv* env, jobject clazz,                                                                                                jobject fileDescriptor, jint address, jbyteArray buffer, jint srcOffset, jint destOffset,                                                                                                jint count, jboolean unpinned)                                                                                        {                                                                                            int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);                                                                                            if (unpinned && ashmem_pin_region(fd,                                 0,                                 0) == ASHMEM_WAS_PURGED) {                                                                                                ashmem_unpin_region(fd,                                 0,                                 0);                                                                                                jniThrowException(env,                                 "java/io/IOException",                                 "ashmem region was purged");                                                                                                return -                                1;                                                                                            }                                                                                            env->GetByteArrayRegion(buffer, srcOffset, count, (jbyte *)address + destOffset);                                                                                            if (unpinned) {                                                                                                ashmem_unpin_region(fd,                                 0,                                 0);                                                                                            }                                                                                            return count;                                                                                        }                            

jni 里面,除去那个 unpinned 不看(mAllowPurging 默认是 false),read 和 write 很简单,就是单纯的从 mAddress(mmap 到本进程的地址)读或写数据(数据都是二进制的,至于怎么用,那是上层业务的事情了)。就算手动设置了 mAllowPurging(2.3 的源码系统里面也没主动设置的地方),ashmem_pin_region 的范围都是 0,在 kernel 驱动中, 0 代表整块区域,所以就算设置了,也暂时没起到分块使用的作用。所以这些就忽略这些东西(主要是我也不太懂 -_-||)。

是用完之后就可以调用 close 接口,先 munmap 内存映射,然后再关掉共享内存文件:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                                                                                        44                                                                                        45                                                                                        46                                                                                        47                                                                                        48                                                                                        49                                                                                        50                                                                                        51                                                                                        52                                                                                        53                                                                                        54                                                                                        55                                                                                        56                                                                                        57                                                                                        58                                                                                        59                                                                                        60                                                                                        61                                                                                        62                                                                                        63                                                                                        64                                                                                        65                                                                                        66                                                                                        67                                                                                        68                                                                                        69                                                                                        70                                                                                        71                                                                                        72                                                                                        73                            
                                                            // java ================================                                                                                            /**                                                                                             * Closes the memory file. If there are no other open references to the memory                                                                                             * file, it will be deleted.                                                                                             */                                                                                            public                                 void close() {                                                                                                deactivate();                                                                                                if (!isClosed()) {                                                                                                    native_close(mFD);                                                                                                }                                                                                            }                                                                                            /**                                                                                             * Unmaps the memory file from the process's memory space, but does not close it.                                                                                             * After this method has been called, read and write operations through this object                                                                                             * will fail, but {@link #getFileDescriptor()} will still return a valid file descriptor.                                                                                             *                                                                                             * @hide                                                                                             */                                                                                            public                                 void deactivate() {                                                                                                if (!isDeactivated()) {                                                                                                            try {                                                                                                        native_munmap(mAddress, mLength);                                                                                                        mAddress =                                 0;                                                                                                    }                                 catch (IOException ex) {                                                                                                             Log.e(TAG, ex.toString());                                                                                                         }                                                                                                }                                                                                            }                                                                                            /**                                                                                             * Checks whether the memory file has been deactivated.                                                                                             */                                                                                            private boolean isDeactivated() {                                                                                                return mAddress ==                                 0;                                                                                            }                                                                                            /**                                                                                             * Checks whether the memory file has been closed.                                                                                             */                                                                                            private boolean isClosed() {                                                                                                return !mFD.valid();                                                                                            }                                                                                        // jni ================================                                                                                        static jint android_os_MemoryFile_mmap(JNIEnv* env, jobject clazz, jobject fileDescriptor,                                                                                                jint length, jint prot)                                                                                        {                                                                                            int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);                                                                                            jint result = (jint)mmap(NULL, length, prot, MAP_SHARED, fd,                                 0);                                                                                            if (!result)                                                                                                jniThrowException(env,                                 "java/io/IOException",                                 "mmap failed");                                                                                            return result;                                                                                        }                                                                                                                                                    static                                 void android_os_MemoryFile_munmap(JNIEnv* env, jobject clazz, jint addr, jint length)                                                                                        {                                                                                            int result = munmap((                                void *)addr, length);                                                                                            if (result <                                 0)                                                                                                jniThrowException(env,                                 "java/io/IOException",                                 "munmap failed");                                                                                        }                                                                                                                                                            static                                 void android_os_MemoryFile_close(JNIEnv* env, jobject clazz, jobject fileDescriptor)                                                                                        {                                                                                            int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);                                                                                            if (fd >=                                 0) {                                                                                                jniSetFileDescriptorOfFD(env, fileDescriptor, -                                1);                                                                                                close(fd);                                                                                            }                                                                                        }                            

jni 里面直接就是系统调用了。open 了就要 close,mmap 了就要 munmap, 没啥好说的。前面说为什么 4.1 之后 java 的 MemroyFile 应该就没法用了呢。仔细看下上面,我贴的几个接口,是 hide 的有:

public MemoryFile(FileDescriptor fd, int length, String mode) public ParcelFileDescriptor getParcelFileDescriptor()

这普通应用正常情况下,根本就没办法用 MemroyFile。所以后面直接把这几个 hide 接口给干掉了。所以我感觉 android 在 java 上不想普通应用直接使用 ashmem,因为很多东西是系统帮你使用了 ashmem,例如传递稍微大一点的 Bitmap。可能 android 觉得在该使用 ashmem 的地方,系统帮你弄好了,你就不要瞎操心了。

native 层接口

java 层的 MemroyFile 基本是残废的,但是 native 层的接口可是齐全的。native 层的 android 搞了2个:

  • MemroyHeapBase: 这个类代表一块共享内存区域。
  • MemroyBase: 这个是上面一块共享内存区域中的一段,就是说 native 层中是支持一段、一段的使用的(不过大多时候是把上面一块就当成一块用 -_-||)。
  • IMemory: binder 接口。

流程也是和原理一样的,先是 Proc A 创建一块共享内存区域(创建一个 MemroyHeapBase 对象):

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                            
                                                            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();                                                                                            // 页面字节对齐,native 层的就是讲究效率                                                                                            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);                                                                                                    }                                                                                                }                                                                                            }                                                                                        }                            

底层的接口和 jni 的的一样的,创建也是调用 libcutils 的 ashmem-dev.c 相关接口。然后 mapfd 是 mmap 内存到本进程:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                            
                                                            status_t MemoryHeapBase::mapfd(                                int fd, size_t size, uint32_t offset)                                                                                        {                                                                                            // 如果不指定大小,则尝试自动分配,不过一般使用者都会指定大小的                                                                                            if (size ==                                 0) {                                                                                                // try to figure out the size automatically                                                                                        #ifdef HAVE_ANDROID_OS                                                                                                // first try the PMEM ioctl                                                                                                    pmem_region reg;                                                                                                int err = ioctl(fd, PMEM_GET_TOTAL_SIZE, ®);                                                                                                if (err ==                                 0)                                                                                                    size = reg.len;                                                                                        #endif                                                                                                if (size ==                                 0) {                                 // try fstat                                                                                                      struct stat sb;                                                                                                    if (fstat(fd, &sb) ==                                 0)                                                                                                               size = sb.st_size;                                                                                                             }                                                                                                // if it didn't work, let mmap() fail.                                                                                            }                                                                                            // 一般也不会指定 DONT_MAP_LOCALLY 这个标志,这个标志就不会 mmap 内存了                                                                                            if ((mFlags & DONT_MAP_LOCALLY) ==                                 0) {                                                                                                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;                                                                                        }                            

这个函数正常情况下,排除那几个特殊标志,就是调用了系统接口 mmap,然后把 fd,映射得到的地址,大小,偏移保存了一下。这下 Proc A 的共享内存区域就创建好了。不过前面说了, native 层的接口,真正使用的是 MemroyBase,这个可以从 MemroyHeapBase 中指定一段区域来使用,这里我们考虑把 MemroyHeapBase 当成一整块来使用。MemroyXx 都实现了 binder 相关的接口(忘记了的,回去看第一篇原理,其实封装搞多了我也是醉了):

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                                                                                        44                                                                                        45                                                                                        46                                                                                        47                                                                                        48                                                                                        49                                                                                        50                            
                                                            // 我把相关代码贴全点,帮大家回想起 binder 相关的接口                                                                                        // IMemroy ================================                                                                                        class BnMemoryHeap :                                 public BnInterface                                                                                        {                                                                                        public:                                                                                            virtual status_t onTransact(                                                                                                     uint32_t code,                                                                                                    const Parcel& data,                                                                                                    Parcel* reply,                                                                                                    uint32_t flags =                                 0);                                                                                                                                                             BnMemoryHeap();                                                                                        protected:                                                                                            virtual ~BnMemoryHeap();                                                                                        };                                                                                        // MemroyHeapBase =========================                                                                                        class MemoryHeapBase :                                 public                                 virtual BnMemoryHeap                                                                                        {                                                                                        ... ...                                                                                        }                                                                                        // MemroyBase =============================                                                                                        class MemoryBase :                                 public BnMemory                                                                                         {                                                                                        public:                                                                                            MemoryBase(                                const sp& heap, ssize_t offset, size_t size);                                                                                            virtual ~MemoryBase();                                                                                            virtual sp getMemory(ssize_t* offset, size_t* size)                                 const;                                                                                        protected:                                                                                            size_t getSize()                                 const {                                 return mSize; }                                                                                            ssize_t getOffset()                                 const {                                 return mOffset; }                                                                                            const sp& getHeap()                                 const {                                 return mHeap; }                                                                                        private:                                                                                            size_t          mSize;                                                                                            ssize_t         mOffset;                                                                                            sp mHeap;                                                                                        };                                                                                        MemoryBase::MemoryBase(                                const sp& heap,                                                                                                ssize_t offset, size_t size)                                                                                            : mSize(size), mOffset(offset), mHeap(heap)                                                                                        {                                                                                        }                            

所以说,举个例子说,Proc A 中创建了一个 2048 byte 的 MemroyHeapBase,要整块一起使用,应该是下面这样写:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                            
                                                            class ProcA :                                 public BinderService,                                                                                                             public BnProcA                                                                                        {                                                                                        public:                                                                                            static                                 char                                 const* getServiceName() {                                                                                                return                                 "ProcA";                                                                                            }                                                                                            ProcA();                                                                                            ~ProcA();                                                                                        private:                                                                                            virtual status_t onTransact(uint32_t code,                                 const Parcel& data,                                                                                                Parcel* reply, uint32_t flags);                                                                                            virtual sp getMemory();                                                                                            sp mMemory;                                                                                        };                                                                                        ProcA::K7Service()                                                                                            :   BnK7() {                                                                                            sp heap =                                 new MemoryHeapBase(                                2048,                                 0,                                 "K7Service");                                                                                            mMemory =                                 new MemoryBase(heap,                                 0,                                 2048);                                                                                        }                            

那么接下来 Proc A 只要把 fd 倒腾给 Proc B 就行了。不过这里 fd 是封装在 MemroyHeapBase 里面的,真正使用的又是 MemroyBase,而且又实现了 binder 接口,当然得一层层转。首先得把 MemroyBase 传给 Proc B,MemroyBase 的 binder 接口是 IMemroy(IBinder),把这个通过 binder 扔给 Proc B 先。我们假设在 Proc A 的 binder 接口中有一个教 getMemroy 的接口:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                            
                                                            // IProcA =================================                                                                                        class BpProcA :                                 public BpInterface                                                                                        {                                                                                        public:                                                                                            virtual sp getMemory() {                                                                                                Parcel data, reply;                                                                                                data.writeInterfaceToken(IProcA::getInterfaceDescriptor());                                                                                                remote()->transact(BnProcA::GET_MEMORY, data, &reply);                                                                                                sp memory = interface_cast(reply.readStrongBinder());                                                                                                return memory;                                                                                            }                                                                                        }                                                                                        status_t BnProcA::onTransact(                                                                                            uint32_t code,                                 const Parcel& data, Parcel* reply, uint32_t flags)                                                                                        {                                                                                            switch(code) {                                                                                                case GET_MEMORY: {                                                                                                    CHECK_INTERFACE(IProcA, data, reply);                                                                                                    sp memory = getMemory();                                                                                                    reply->writeStrongBinder(memory->asBinder());                                                                                                }                                 break;                                                                                                default:                                                                                                    return BBinder::onTransact(code, data, reply, flags);                                                                                            }                                                                                            return NO_ERROR;                                                                                        }                                                                                        // ProcA ==================================                                                                                        sp K7Service::getMemory() {                                                                                             return mMemory;                                                                                        }                            

Parcel 的 readStrongBinder 和 writeStrongBinder 前面说过了,Parcel 的 flat_binder_object 专门用来传递 binder 对象的。IMemroy 传到 Proc B 后,来看看 IMemroy 有哪些接口:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                                                                                        44                                                                                        45                                                                                        46                                                                                        47                                                                                        48                                                                                        49                                                                                        50                                                                                        51                                                                                        52                                                                                        53                            
                                                            // IMemroy.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;                                                                                        };                                                                                        class BnMemory :                                 public BnInterface                                                                                        {                                                                                        public:                                                                                            virtual status_t onTransact(                                                                                                    uint32_t code,                                                                                                    const Parcel& data,                                                                                                                Parcel* reply,                                                                                                    uint32_t flags =                                 0);                                                                                            BnMemory();                                                                                        protected:                                                                                            virtual ~BnMemory();                                                                                        };                                                                                        // IMemroy.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<                                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;                                                                                        }                            

基本上可以看得出, pointer() 是返回共享内存的地址,这个地址是已经映射到 Proc B 中了的,就是可以直接读、写了的。然后 size() 和 offset() 分别是返回大小和偏移(例子中是 2048 和 0)。

然后,它们都调用了一个比较关键的函数叫 getMemroy:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                                                                                        44                                                                                        45                                                                                        46                                                                                        47                                                                                        48                                                                                        49                                                                                        50                                                                                        51                                                                                        52                            
                                                            // MemroyBase ===============================                                                                                        sp MemoryBase::getMemory(ssize_t* offset, size_t* size)                                 const                                                                                        {                                                                                            if (offset) *offset = mOffset;                                                                                            if (size)   *size = mSize;                                                                                            return mHeap;                                                                                        }                                                                                        // IMemroy ==================================                                                                                        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);                                                                                                        if (mHeap !=                                 0) {                                                                                                                          mOffset = o;                                                                                                                               mSize = s;                                                                                                        }                                                                                                    }                                                                                                }                                                                                            }                                                                                            if (offset) *offset = mOffset;                                                                                             if (size) *size = mSize;                                                                                            return mHeap;                                                                                        }                                                                                        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);                                                                                            }                                                                                        }                            

这个叫 getMemroy 的最后其实是把 MemoryBase 用的 MemoryHeapBase 的 binder 接口(IMemroyHeap)传了过来(前面说了要一层层转的吧)。然后我们就得来看看 IMemroyHeap 的接口了:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                                                                                        44                                                                                        45                                                                                        46                                                                                        47                                                                                        48                                                                                        49                                                                                        50                                                                                        51                                                                                        52                                                                                        53                                                                                        54                                                                                        55                                                                                        56                                                                                        57                                                                                        58                                                                                        59                                                                                        60                                                                                        61                                                                                        62                                                                                        63                                                                                        64                                                                                        65                                                                                        66                                                                                        67                                                                                        68                                                                                        69                                                                                        70                                                                                        71                                                                                        72                                                                                        73                                                                                        74                                                                                        75                                                                                        76                                                                                        77                                                                                        78                                                                                        79                                                                                        80                                                                                        81                                                                                        82                                                                                        83                                                                                        84                                                                                        85                                                                                        86                                                                                        87                                                                                        88                            
                                                            // MemroyHeapBase ============================                                                                                        int MemoryHeapBase::getHeapID()                                 const {                                                                                            return mFD;                                                                                        }                                                                                        // IMemroy.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;                                                                                            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                                                                                        {                                                                                        public:                                                                                            virtual status_t onTransact(                                                                                                    uint32_t code,                                                                                                    const Parcel& data,                                                                                                                Parcel* reply,                                                                                                    uint32_t flags =                                 0);                                                                                                                                                                   BnMemoryHeap();                                                                                        protected:                                                                                            virtual ~BnMemoryHeap();                                                                                        };                                                                                        // IMemroy.cpp ==================================                                                                                        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;                                                                                        }                                                                                        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());                                                                                                     reply->writeInt32(getOffset());                                                                                                    return NO_ERROR;                                                                                                  }                                 break;                                                                                                default:                                                                                                    return BBinder::onTransact(code, data, reply, flags);                                                                                            }                                                                                        }                            

上面 IMemory 那里获取到 IMemroyHeap 后,调用的是 base(), 这个最后是调用 getBaes() 的。但是这几个 Bp 端的接口实现,无一例外,全都调用了另一个关键的函数(又是关键的 -_-||):

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                                                                                        44                                                                                        45                                                                                        46                                                                                        47                                                                                        48                                                                                        49                                                                                        50                                                                                        51                                                                                        52                                                                                        53                                                                                        54                                                                                        55                                                                                        56                                                                                        57                                                                                        58                                                                                        59                                                                                        60                                                                                        61                                                                                        62                                                                                        63                                                                                        64                                                                                        65                                                                                        66                                                                                        67                                                                                        68                                                                                        69                            
                                                            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;                                                                                                                 mOffset = heap->mOffset;                                                                                                               android_atomic_write( dup( heap->mHeapId ), &mHeapId );                                                                                                    }                                                                                                }                                 else {                                                                                                    // something went wrong                                                                                                            free_heap(binder);                                                                                                }                                                                                            }                                                                                        }                                                                                        void BpMemoryHeap::assertReallyMapped()                                 const                                                                                        {                                                                                            if (mHeapId == -                                1) {                                                                                                // 注释好像是说为了性能,不在 transact 远程调用加锁,只在后面 mmap 那里加锁                                                                                                // 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=%ld, err=%d (%s)",                                                                                                        asBinder().get(), parcel_fd, size, err, strerror(-err));                                                                                                int fd = dup( parcel_fd );                                                                                                ALOGE_IF(fd==-                                1,                                 "cannot dup fd=%d, size=%ld, err=%d (%s)",                                                                                                        parcel_fd, size, err, strerror(errno));                                                                                                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, offset);                                                                                                    if (mBase == MAP_FAILED) {                                                                                                        ALOGE(                                "cannot map BpMemoryHeap (binder=%p), size=%ld, fd=%d (%s)",                                                                                                                asBinder().get(), size, fd, strerror(errno));                                                                                                        close(fd);                                                                                                    }                                 else {                                                                                                        mSize = size;                                                                                                        mFlags = flags;                                                                                                        mOffset = offset;                                                                                                        // mHeapId 就是 fd 啊                                                                                                        android_atomic_write(fd, &mHeapId);                                                                                                    }                                                                                                }                                                                                            }                                                                                        }                            

这里 Proc B 是要用到共享内存才会去 mmap 的。assertMapped()、assertReallyMapped() 这2个名字还真直白。 mHeapId 就是 Proc A 倒腾给 Proc B 的 fd,如果为 -1 表示 Proc B 还没 mmap 过,所以进入 assert(Really)Mapped() 进行 mmap 。assertMapped() 那里有个 find_heap 的东西,看起来挺多余的,直接调用自己的函数有那么费劲么,后面看了下注释好像是拿来调试用的,那就不用管它了。然后 assertReallyMapped 就和 java 层的差不多了,先是发一个 HEAP_ID 给 MemoryHeapBase 的 Bn 让它把 Proc A 那边的 fd 通过 Parcel 的 writeFileDescriptor 倒腾
过来。注意这里调用的是 native Parcel 的 writeFileDescriptor,而上面 java 的是 writeDupFileDescriptor,所以 Proc B Bp 这边接到后,要自己手动 dup(fd) 一次 -_-||。然后就 mmap 了,报得到的地址、大小、偏移保存一下,Proc B 就能读写了。

native 层的接口返回的直接是地址,读写比 java 层的灵活很多。然后 native 的 close、munmap 都是在析够函数中进行的,可以说配合 android 的智能指针(其实我挺讨厌这玩意),可以说使用无脑(用 sp,初始化的时候 new 出来,在析构函数里置为 NULL 就行了)。

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                                                                                        44                                                                                        45                                                                                        46                                                                                        47                                                                                        48                                                                                        49                                                                                        50                                                                                        51                                                                                        52                            
                                                            // 因为主要 open、mmap 都是 MemoryHeapBase 做的,MemoryBase 只是把地址、偏移设置了下,                                                                                        // 所以 close、munmap 都只要 MemoryHeapBase 来做就行了,MemoryBase 不用做什么清理的。                                                                                        // Bn 端(Proc A)的关闭                                                                                        // MemroyHeapBase ==================================                                                                                        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);                                                                                            }                                                                                        }                                                                                        // Bp 端(Proc B)的关闭                                                                                         // IMemroy ==================================                                                                                        BpMemoryHeap::~BpMemoryHeap() {                                                                                            if (mHeapId != -                                1) {                                                                                                close(mHeapId);                                                                                                if (mRealHeap) {                                                                                                    // by construction we're the last one                                                                                                    if (mBase != MAP_FAILED) {                                                                                                        sp binder =                                 const_cast(                                this)->asBinder();                                                                                                                                                                    if (VERBOSE) {                                                                                                            ALOGD(                                "UNMAPPING binder=%p, heap=%p, size=%d, fd=%d",                                                                                                                    binder.get(),                                 this, mSize, mHeapId);                                                                                                            CallStack                                 stack(LOG_TAG);                                                                                                        }                                                                                                                                                                    munmap(mBase, mSize);                                                                                                    }                                                                                                }                                 else {                                                                                                    // remove from list only if it was mapped before                                                                                                    sp binder =                                 const_cast(                                this)->asBinder();                                                                                                    free_heap(binder);                                                                                                }                                                                                            }                                                                                        }                            

又是 MemoryHeapBase、MemoryBase、IMemoryBase、IMemory 是不是有点头晕咧,主要是 android 在 native 层搞了2个东西,加那一堆 binder 接口,这还没 java 层简洁(虽然 java 层的被废掉了 -_-||)。最后来张图吧:

kernel 驱动

上面把应用层的接口说往了,下面就要讲 kernel 里面的驱动了。最开始的时候说了, ashmem 是基于 linux 的 tmpfs 实现的,所以最好要有点这方面的知识,不过目前我还是不太清楚 tmpfs 相关的接口用法 -_-||,等以后找点书来看补补吧。

前面那些接口最后面就是调用到 libcutils 的 ashmem-dev.c 中的那些接口,那些接口最后都是 open 或是 ioctl 的系统调用,这些最后都是进入到 kernel 的 ashmem 驱动当中。

我们先来看下 ashmem 驱动加载初始化的时候:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                                                                                        44                                                                                        45                                                                                        46                                                                                        47                                                                                        48                                                                                        49                                                                                        50                                                                                        51                                                                                        52                                                                                        53                                                                                        54                                                                                        55                                                                                        56                                                                                        57                                                                                        58                                                                                        59                                                                                        60                                                                                        61                                                                                        62                                                                                        63                                                                                        64                                                                                        65                                                                                        66                                                                                        67                                                                                        68                                                                                        69                                                                                        70                                                                                        71                                                                                        72                                                                                        73                                                                                        74                            
                                                            /*                                                                                         * ashmem_area - anonymous shared memory area                                                                                         * Lifecycle: From our parent file's open() until its release()                                                                                         * Locking: Protected by `ashmem_mutex'                                                                                         * Big Note: Mappings do NOT pin this structure; it dies on close()                                                                                         */                                                                                        struct ashmem_area {                                                                                            char name[ASHMEM_FULL_NAME_LEN];                                /* optional name for /proc/pid/maps */                                                                                            struct list_head unpinned_list;                                 /* list of all ashmem areas */                                                                                             struct file *file;                                      /* the shmem-based backing file */                                                                                            size_t size;                                            /* size of the mapping, in bytes */                                                                                            unsigned                                 long prot_mask;                                    /* allowed prot bits, as vm_flags */                                                                                        };                                                                                        static                                 struct kmem_cache *ashmem_area_cachep __read_mostly;                                                                                        static                                 struct kmem_cache *ashmem_range_cachep __read_mostly;                                                                                        static                                 int __init ashmem_init(                                void)                                                                                        {                                                                                            int ret;                                                                                            // 为 ashmem 驱动的数据结构创建一块后备高速缓存                                                                                            ashmem_area_cachep = kmem_cache_create(                                "ashmem_area_cache",                                                                                                              sizeof(                                struct ashmem_area),                                                                                                              0,                                 0, NULL);                                                                                            if (unlikely(!ashmem_area_cachep)) {                                                                                                printk(KERN_ERR                                 "ashmem: failed to create slab cache\n");                                                                                                return -ENOMEM;                                                                                            }                                                                                            // 这块数据结构是 pin/unpin 相关的,无视 ... ...                                                                                            ashmem_range_cachep = kmem_cache_create(                                "ashmem_range_cache",                                                                                                              sizeof(                                struct ashmem_range),                                                                                                              0,                                 0, NULL);                                                                                            if (unlikely(!ashmem_range_cachep)) {                                                                                                printk(KERN_ERR                                 "ashmem: failed to create slab cache\n");                                                                                                return -ENOMEM;                                                                                            }                                                                                            // 注册驱动操作相关函数                                                                                            ret = misc_register(&ashmem_misc);                                                                                            if (unlikely(ret)) {                                                                                                printk(KERN_ERR                                 "ashmem: failed to register misc device!\n");                                                                                                return ret;                                                                                            }                                                                                            // 注册内存回收扫描算法,继续无视 ... ...                                                                                            register_shrinker(&ashmem_shrinker);                                                                                            printk(KERN_INFO                                 "ashmem: initialized\n");                                                                                            return                                 0;                                                                                        }                                                                                        // exit 函数很多对应上面 init 的注销、销毁操作                                                                                        static                                 void __exit ashmem_exit(                                void)                                                                                        {                                                                                            int ret;                                                                                            unregister_shrinker(&ashmem_shrinker);                                                                                            ret = misc_deregister(&ashmem_misc);                                                                                            if (unlikely(ret))                                                                                                printk(KERN_ERR                                 "ashmem: failed to unregister misc device!\n");                                                                                            kmem_cache_destroy(ashmem_range_cachep);                                                                                            kmem_cache_destroy(ashmem_area_cachep);                                                                                            printk(KERN_INFO                                 "ashmem: unloaded\n");                                                                                        }                                                                                        module_init(ashmem_init);                                                                                        module_exit(ashmem_exit);                            

init 和 exit 函数是 kernel 第一次加载 ashmem 模块的时候调用的,一般做一些驱动初始化或是申请资源相关的操作。这里首先在 kernel 的后备高速缓存区开辟的一段空间,用来申请 struct ashmem_area 这个驱动相关的结构体的存储空间。这个后备高速缓存据说是应用于反复的多次分配的情况,因为 ashmem 本身就是出于性能考虑设计的,所以选择使用这个吧,能够加快分配内存的速度(注意这里只是分配驱动保存一些状态的数据结构,不是共享内存本身)。这个后备高速缓存好像又叫 slab 分配器,好像是 kernel 里面挺快的一个东西 -_-|| 。

然后后面那个和 pin/unpin 还有内存回收算法相关的,我现在不打算去分析,因为第一,这个东西前面说过了,现在基本上没用;第二,最主要的是我也不是很清楚这些玩意 -_-||。再后注册驱动操作相关函数:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                            
                                                            static                                 struct file_operations ashmem_fops = {                                                                                            .owner = THIS_MODULE,                                                                                            .open = ashmem_open,                                                                                            .release = ashmem_release,                                                                                                .read = ashmem_read,                                                                                                  .llseek = ashmem_llseek,                                                                                                   .mmap = ashmem_mmap,                                                                                            .unlocked_ioctl = ashmem_ioctl,                                                                                            .compat_ioctl = ashmem_ioctl,                                                                                        };                                                                                        static                                 struct miscdevice ashmem_misc = {                                                                                            .minor = MISC_DYNAMIC_MINOR,                                                                                            .name =                                 "ashmem",                                                                                            .fops = &ashmem_fops,                                                                                        };                            

稍微接触过点 linux 驱动的都应该知道,这个 file_operations 就是 linux 文件设备驱动(linux 上所有设置都是文件)的操作函数。例如说上层应用对本设备调用 open 对应的驱动函数就是 .open 对应的,然后依此类推:

mmap  --> .mmap(ashmem_mapp)ioctl --> .unlocked_ioctl(ashmem_ioctl)          .compat_ioctl(ashmem_ioctl)close --> .release(ashmem_release)read  --> .read(ashmem_read)seek  --> llseek(ashmem_llseek)

file_operations 的操作函数不止这几个,没实现的就不支持对应的操作,上层调用接口,会返回错误值。以前 2.3 的 ashmem 不支持 read 和 seek 的,4.x 的开始支持啦,不过这里只关注另外几个重要的。

首先是 Proc A 调用 open 创建共享内存:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                            
                                                            static                                 int ashmem_open(                                struct inode *inode,                                 struct file *file)                                                                                        {                                                                                            struct ashmem_area *asma;                                                                                            int ret;                                                                                            // 调用系统方法打开文件                                                                                            ret = generic_file_open(inode, file);                                                                                            if (unlikely(ret))                                                                                                return ret;                                                                                            // 在 init 创建的高速缓存区,申请 struct ashmem_area 变量                                                                                            asma = kmem_cache_zalloc(ashmem_area_cachep, GFP_KERNEL);                                                                                            if (unlikely(!asma))                                                                                                return -ENOMEM;                                                                                            INIT_LIST_HEAD(&asma->unpinned_list);                                                                                            // 保持打开的文件的名字                                                                                            memcpy(asma->name, ASHMEM_NAME_PREFIX, ASHMEM_NAME_PREFIX_LEN);                                                                                            asma->prot_mask = PROT_MASK;                                                                                            // 保持驱动私有变量                                                                                            file->private_data = asma;                                                                                            return                                 0;                                                                                        }                            

这个函数 kernel 传递过来2个参数,第一个 inode 是文件设备节点,前面说了一个真实的文件只有一个设备节点。后面那个是文件指针,但是一个文件可以打开多次,每打开一次就有一个文件指针对应。那个 generic_file_open kernel 的接口,具体目前我也不是很清楚,反正就理解为调用 kernel 接口打开指定的文件设备吧 -_-||。然后利用 init 中开辟的高速缓存创建驱动的私有驱动数据,看上面, ashmem 的私有结构挺简单的,基本上就是名字、大小、打开的文件指针和端口标志(那个 unpin 的 list 咱们无视)。然后这里强制把名字的前缀设置为:

#define ASHMEM_NAME_PREFIX "dev/ashmem/"

注意这里只是设置前缀而已,后面有 set_name 的 ioctl 接口的,这个接口是把用户设置的名字加在后面而已,基本上名字就是: “dev/shmem/xx”,这个名字感觉除了在 cat /proc/pid/maps 的时候显示一下以外就没啥别的用处了(而且好多应用还不设置)。

然后就是把在高速缓存区创建的 ashmem_area 保持在 file->private_data 这个字段中。这是很多驱动的通用做法,把私有的数据结构保持在这个字段,在后面的 ioctl 里面能取出来用。

然后 Proc A 就该调用 mmap 了:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                                                                                        44                                                                                        45                                                                                        46                                                                                        47                                                                                        48                                                                                        49                                                                                        50                                                                                        51                                                                                        52                                                                                        53                                                                                        54                                                                                        55                                                                                        56                                                                                        57                                                                                        58                                                                                        59                                                                                        60                                                                                        61                                                                                        62                                                                                        63                                                                                        64                                                                                        65                                                                                        66                                                                                        67                                                                                        68                                                                                        69                                                                                        70                                                                                        71                                                                                        72                                                                                        73                                                                                        74                                                                                        75                                                                                        76                                                                                        77                                                                                        78                                                                                        79                                                                                        80                                                                                        81                                                                                        82                                                                                        83                                                                                        84                                                                                        85                                                                                        86                                                                                        87                                                                                        88                                                                                        89                                                                                        90                                                                                        91                                                                                        92                                                                                        93                                                                                        94                                                                                        95                                                                                        96                                                                                        97                                                                                        98                                                                                        99                                                                                        100                                                                                        101                                                                                        102                                                                                        103                                                                                        104                                                                                        105                            
                                                            static                                 int ashmem_mmap(                                struct file *file,                                 struct vm_area_struct *vma)                                                                                        {                                                                                            struct ashmem_area *asma = file->private_data;                                                                                            int ret =                                 0;                                                                                            mutex_lock(&ashmem_mutex);                                                                                            // 在调用 mmap 之前必须调用 ioctl SET_SIZE -_-||                                                                                            /* user needs to SET_SIZE before mapping */                                                                                            if (unlikely(!asma->size)) {                                                                                                ret = -EINVAL;                                                                                                        goto out;                                                                                            }                                                                                            /* requested protection bits must match our allowed protection mask */                                                                                            if (unlikely((vma->vm_flags & ~calc_vm_prot_bits(asma->prot_mask)) &                                                                                                                calc_vm_prot_bits(PROT_MASK))) {                                                                                                ret = -EPERM;                                                                                                         goto out;                                                                                                         }                                                                                            vma->vm_flags &= ~calc_vm_may_flags(~asma->prot_mask);                                                                                            // 还没创建共享内存文件,则创建                                                                                            if (!asma->file) {                                                                                                char *name = ASHMEM_NAME_DEF;                                                                                                  struct file *vmfile;                                                                                                  if (asma->name[ASHMEM_NAME_PREFIX_LEN] !=                                 '\0')                                                                                                    name = asma->name;                                                                                                // 在 tmpfs 文件系统上创建共享内存文件                                                                                                /* ... and allocate the backing shmem file */                                                                                                vmfile = shmem_file_setup(name, asma->size, vma->vm_flags);                                                                                                if (unlikely(IS_ERR(vmfile))) {                                                                                                    ret = PTR_ERR(vmfile);                                                                                                    goto out;                                                                                                }                                                                                                asma->file = vmfile;                                                                                            }                                                                                            get_file(asma->file);                                                                                            if (vma->vm_flags & VM_SHARED)                                                                                                shmem_set_file(vma, asma->file);                                                                                            else {                                                                                                if (vma->vm_file)                                                                                                    fput(vma->vm_file);                                                                                                vma->vm_file = asma->file;                                                                                            }                                                                                            vma->vm_flags |= VM_CAN_NONLINEAR;                                                                                        out:                                                                                            mutex_unlock(&ashmem_mutex);                                                                                            return ret;                                                                                        }                                                                                        static                                 long ashmem_ioctl(                                struct file *file,                                 unsigned                                 int cmd,                                 unsigned                                 long arg)                                                                                        {                                                                                            struct ashmem_area *asma = file->private_data;                                                                                            long ret = -ENOTTY;                                                                                            switch (cmd) {                                                                                            case ASHMEM_SET_NAME:                                                                                                ret = set_name(asma, (                                void __user *) arg);                                                                                                break;                                                                                            case ASHMEM_GET_NAME:                                                                                                ret = get_name(asma, (                                void __user *) arg);                                                                                                break;                                                                                            case ASHMEM_SET_SIZE:                                                                                                ret = -EINVAL;                                                                                                if (!asma->file) {                                                                                                    ret =                                 0;                                                                                                    asma->size = (size_t) arg;                                                                                                     }                                                                                                break;                                                                                            case ASHMEM_GET_SIZE:                                                                                                ret = asma->size;                                                                                                break;                                                                                            case ASHMEM_SET_PROT_MASK:                                                                                                ret = set_prot_mask(asma, arg);                                                                                                break;                                                                                            case ASHMEM_GET_PROT_MASK:                                                                                                ret = asma->prot_mask;                                                                                                break;                                                                                            case ASHMEM_PIN:                                                                                            case ASHMEM_UNPIN:                                                                                            case ASHMEM_GET_PIN_STATUS:                                                                                                ret = ashmem_pin_unpin(asma, cmd, (                                void __user *) arg);                                                                                                break;                                                                                            case ASHMEM_PURGE_ALL_CACHES:                                                                                                ret = -EPERM;                                                                                                if (capable(CAP_SYS_ADMIN)) {                                                                                                    struct shrink_control sc = {                                                                                                        .gfp_mask = GFP_KERNEL,                                                                                                        .nr_to_scan =                                 0,                                                                                                    };                                                                                                    ret = ashmem_shrink(&ashmem_shrinker, &sc);                                                                                                    sc.nr_to_scan = ret;                                                                                                    ashmem_shrink(&ashmem_shrinker, &sc);                                                                                                }                                                                                                break;                                                                                            }                                                                                            return ret;                                                                                        }                            

mmap 一开始要在调用前需要调用 ioctl SET_SIZE 设置这片共享内存区域的大小。回去前面看下 ashmem_create_region 是不是在 open 之后,调用了 ioctl 去设置大小。所以我把 ioctl 那部分也贴出来了,SET_SIZE 其实很简单,就是把 asm->size 设置了一下。但是我觉得有点奇怪,上层调用 mmap 的时候也传了 size 了(size 和 调用 ioctl 的一样),那为什么不像 binder 的那样使用 vma 中的 size 。这点我就暂时无法理解了(对 kernel 相关的知识不太了解)。

然后后面的就能更难理解了,调用 shmem_file_setup 据说好像是 kernel 的 tmpfs 的接口,然后从参数看,姑且就认为在 tmpfs 上创建了一个名字为 name,大小为 asm->size 的文件,用于共享内存。后面那个 get_file 也不知道用处是什么(主要是没百度到)。然后 flags,前面 mmap 的时候,都设置了 MAP_SHARED,这里 shmem_set_file 就说是 android 在 kernel 中自己加的接口,我就更不知道是干啥用的了。不过看名字,加上参数,好像是激活刚刚创建的文件吧。然后就完了 -_-||。

其实 ashmem 的 kernel 驱动,这里就只能大致讲个原理,具体的因为不太懂 kernel 文件系统、I/O 相关的东西,没办法继续分析下去了,等以后再说吧。

然后就应该到 Proc A 把 fd 倒腾给 Proc B 了,这里倒腾要借助 binder 的驱动。还记得 Parcel 的 flat_binder_object 么,binder 的驱动专门处理这个东西的,那么就要去看 Parcel 的 flat_binder_object 在 binder 里面怎么倒腾的了。前面说 BINDER_TYPE_FD 这个类型就是专门到来倒腾 fd 的,这个在 binder_transaction 中(忘记流程了的,回去复习下前面几篇):

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                                                                                        44                                                                                        45                                                                                        46                                                                                        47                                                                                        48                                                                                        49                                                                                        50                                                                                        51                                                                                        52                                                                                        53                                                                                        54                                                                                        55                                                                                        56                                                                                        57                                                                                        58                                                                                        59                                                                                        60                                                                                        61                                                                                        62                                                                                        63                                                                                        64                                                                                        65                                                                                        66                                                                                        67                                                                                        68                                                                                        69                                                                                        70                                                                                        71                                                                                        72                                                                                        73                                                                                        74                                                                                        75                                                                                        76                                                                                        77                                                                                        78                                                                                        79                                                                                        80                                                                                        81                                                                                        82                                                                                        83                                                                                        84                                                                                        85                                                                                        86                                                                                        87                                                                                        88                                                                                        89                                                                                        90                                                                                        91                                                                                        92                                                                                        93                                                                                        94                                                                                        95                                                                                        96                                                                                        97                                                                                        98                                                                                        99                                                                                        100                                                                                        101                                                                                        102                                                                                        103                                                                                        104                                                                                        105                                                                                        106                                                                                        107                                                                                        108                                                                                        109                                                                                        110                                                                                        111                                                                                        112                            
                                                            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 *)));                                                                                            if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {                                                                                                binder_user_error(                                "binder: %d:%d got transaction with invalid "                                                                                                    "data ptr\n", proc->pid, thread->pid);                                                                                                return_error = BR_FAILED_REPLY;                                                                                                goto err_copy_data_failed;                                                                                            }                                                                                            if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {                                                                                                binder_user_error(                                "binder: %d:%d got transaction with invalid "                                                                                                    "offsets ptr\n", proc->pid, thread->pid);                                                                                                return_error = BR_FAILED_REPLY;                                                                                                goto err_copy_data_failed;                                                                                            }                                                                                            if (!IS_ALIGNED(tr->offsets_size,                                 sizeof(size_t))) {                                                                                                binder_user_error(                                "binder: %d:%d got transaction with "                                                                                                    "invalid offsets size, %zd\n",                                                                                                    proc->pid, thread->pid, tr->offsets_size);                                                                                                return_error = BR_FAILED_REPLY;                                                                                                goto err_bad_offset;                                                                                            }                                                                                            off_end = (                                void *)offp + tr->offsets_size;                                                                                            for (; offp < off_end; offp++) {                                                                                                struct flat_binder_object *fp;                                                                                                if (*offp > t->buffer->data_size -                                 sizeof(*fp) ||                                                                                                    t->buffer->data_size <                                 sizeof(*fp) ||                                                                                                    !IS_ALIGNED(*offp,                                 sizeof(                                void *))) {                                                                                                    binder_user_error(                                "binder: %d:%d got transaction with "                                                                                                        "invalid offset, %zd\n",                                                                                                        proc->pid, thread->pid, *offp);                                                                                                    return_error = BR_FAILED_REPLY;                                                                                                    goto err_bad_offset;                                                                                                }                                                                                                fp = (                                struct flat_binder_object *)(t->buffer->data + *offp);                                                                                                switch (fp->type) {                                                                                                ... ...                                                                                                case BINDER_TYPE_FD: {                                                                                                    int target_fd;                                                                                                    struct file *file;                                                                                                    if (reply) {                                                                                                        // 如果目标对象不接受 fd 的话则报错,前面 Parcel 调用那个相关接口的时候设置了这个标志的                                                                                                        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;                                                                                                    }                                                                                                    // 这个 fp->handle 就是前面的 fd                                                                                                    // 通过 fd 取得 file 文件指针                                                                                                    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_proc: Proc B)中空闲的 fd                                                                                                    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;                                                                                                    }                                                                                                    // 在目标进程空闲的 fd 中安装 file 文件指针                                                                                                    task_fd_install(target_proc, target_fd, file);                                                                                                    binder_debug(BINDER_DEBUG_TRANSACTION,                                                                                                             "        fd %ld -> %d\n", fp->handle, target_fd);                                                                                                    // 把转化好的目标进程的 fd 设回 flat_binder_object 传递给上层应用                                                                                                    /* TODO: fput? */                                                                                                    fp->handle = target_fd;                                                                                                }                                 break;                                                                                                default:                                                                                                    binder_user_error(                                "binder: %d:%d got transactio"                                                                                                        "n with invalid object type, %lx\n",                                                                                                        proc->pid, thread->pid, fp->type);                                                                                                    return_error = BR_FAILED_REPLY;                                                                                                    goto err_bad_object_type;                                                                                                }                                                                                            }                                                                                            ... ...                                                                                        }                            

这里倒腾的主要是另外2个函数:

task_get_unused_fd_flags: 在目标进程中找到空闲的 fd
task_fd_install: 在目标进程空闲的 fd 中安装 Proc A 中打开的文件指针

我看来看下这2个函数:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                                                                                        44                                                                                        45                                                                                        46                                                                                        47                                                                                        48                                                                                        49                                                                                        50                                                                                        51                                                                                        52                                                                                        53                                                                                        54                                                                                        55                                                                                        56                                                                                        57                                                                                        58                                                                                        59                                                                                        60                                                                                        61                                                                                        62                                                                                        63                                                                                        64                                                                                        65                                                                                        66                                                                                        67                                                                                        68                                                                                        69                                                                                        70                                                                                        71                                                                                        72                                                                                        73                                                                                        74                                                                                        75                                                                                        76                                                                                        77                                                                                        78                                                                                        79                                                                                        80                                                                                        81                                                                                        82                                                                                        83                                                                                        84                                                                                        85                                                                                        86                                                                                        87                            
                                                            /*                                                                                         * copied from get_unused_fd_flags                                                                                         */                                                                                        int task_get_unused_fd_flags(                                struct binder_proc *proc,                                 int flags)                                                                                        {                                                                                            struct files_struct *files = proc->files;                                                                                            int fd, error;                                                                                            struct fdtable *fdt;                                                                                            unsigned                                 long rlim_cur;                                                                                            unsigned                                 long irqs;                                                                                            if (files == NULL)                                                                                                return -ESRCH;                                                                                            error = -EMFILE;                                                                                            spin_lock(&files->file_lock);                                                                                        repeat:                                                                                            fdt = files_fdtable(files);                                                                                            fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds,                                                                                                        files->next_fd);                                                                                            /*                                                                                             * N.B. For clone tasks sharing a files structure, this test                                                                                             * will limit the total number of files that can be opened.                                                                                             */                                                                                            rlim_cur =                                 0;                                                                                            if (lock_task_sighand(proc->tsk, &irqs)) {                                                                                                rlim_cur = proc->tsk->signal->rlim[RLIMIT_NOFILE].rlim_cur;                                                                                                unlock_task_sighand(proc->tsk, &irqs);                                                                                            }                                                                                            if (fd >= rlim_cur)                                                                                                goto out;                                                                                            /* Do we need to expand the fd array or fd set?  */                                                                                            error = expand_files(files, fd);                                                                                            if (error <                                 0)                                                                                                goto out;                                                                                            if (error) {                                                                                                /*                                                                                                 * If we needed to expand the fs array we                                                                                                 * might have blocked - try again.                                                                                                 */                                                                                                error = -EMFILE;                                                                                                goto repeat;                                                                                            }                                                                                            FD_SET(fd, fdt->open_fds);                                                                                            if (flags & O_CLOEXEC)                                                                                                FD_SET(fd, fdt->close_on_exec);                                                                                            else                                                                                                FD_CLR(fd, fdt->close_on_exec);                                                                                            files->next_fd = fd +                                 1;                                                                                        #if 1                                                                                            /* Sanity check */                                                                                            if (fdt->fd[fd] != NULL) {                                                                                                printk(KERN_WARNING                                 "get_unused_fd: slot %d not NULL!\n", fd);                                                                                                fdt->fd[fd] = NULL;                                                                                            }                                                                                        #endif                                                                                            error = fd;                                                                                        out:                                                                                            spin_unlock(&files->file_lock);                                                                                            return error;                                                                                        }                                                                                        /*                                                                                         * copied from fd_install                                                                                         */                                                                                        static                                 void task_fd_install(                                                                                            struct binder_proc *proc,                                 unsigned                                 int fd,                                 struct file *file)                                                                                        {                                                                                            struct files_struct *files = proc->files;                                                                                            struct fdtable *fdt;                                                                                            if (files == NULL)                                                                                                return;                                                                                            spin_lock(&files->file_lock);                                                                                            fdt = files_fdtable(files);                                                                                            BUG_ON(fdt->fd[fd] != NULL);                                                                                            rcu_assign_pointer(fdt->fd[fd], file);                                                                                            spin_unlock(&files->file_lock);                                                                                        }                            

这2个函数现在的我完全无法解释啥,看注释好像是从 kernel 的文件 I/O 中抄过来的,我又醉了 -_-|| 。反正就知道经过这2个函数的倒腾后,Proc A 的 fd 就能扔给 Proc B 用了。然后 Proc B 就能那这个 fd 去 mmap Proc A 在 tmpfs 上创建的共享内存文件了。然后 mmap 到地址后,就能读、写了。

呃,最后看看 close 的操作吧(这个相对能理解点):

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                            
                                                            static                                 int ashmem_release(                                struct inode *ignored,                                 struct file *file)                                                                                        {                                                                                            struct ashmem_area *asma = file->private_data;                                                                                            struct ashmem_range *range, *next;                                                                                            mutex_lock(&ashmem_mutex);                                                                                            list_for_each_entry_safe(range, next, &asma->unpinned_list, unpinned)                                                                                                range_del(range);                                                                                            mutex_unlock(&ashmem_mutex);                                                                                            if (asma->file)                                                                                                fput(asma->file);                                                                                            kmem_cache_free(ashmem_area_cachep, asma);                                                                                            return                                 0;                                                                                        }                            

抛去 pin/unping 的不看,这里就是把 open 里面从高速缓存中申请的 ashmem_area 给释放掉了。

例子

上面说了那么多,咋来点例子来看下 framework 中是怎么使用 ashmem 的。前面说 java 层 android 不希望开发者自己倒腾 ashmem,这里我们拿用 Parcel 传递 Bitmap 为例子。图片算是比较大型的资源了,大的图片也很占内存,当你使用 Parcel 传递 Bitmap android 自动帮我们使用 ashmem 了,因为 Bitmap 是 Parcelable 的:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                            
                                                            public                                 static                                 final Parcelable.Creator CREATOR                                                                                                =                                 new Parcelable.Creator() {                                                                                            /**                                                                                               * Rebuilds a bitmap previously stored with writeToParcel().                                                                                             *                                                                                             * @param p    Parcel object to read the bitmap from                                                                                             * @return a new bitmap created from the data in the parcel                                                                                             */                                                                                            public Bitmap                                 createFromParcel(Parcel p) {                                                                                                 Bitmap bm = nativeCreateFromParcel(p);                                                                                                if (bm ==                                 null) {                                                                                                    throw                                 new RuntimeException(                                "Failed to unparcel Bitmap");                                                                                                }                                                                                                    return bm;                                                                                            }                                                                                                public Bitmap[]                                 newArray(                                int size) {                                                                                                return                                 new Bitmap[size];                                                                                            }                                                                                            };                                                                                        /*                                                                                         * No special parcel contents.                                                                                         */                                                                                        public                                 int                                 describeContents() {                                                                                            return                                 0;                                                                                        }                                                                                        /*                                                                                         * Write the bitmap and its pixels to the parcel. The bitmap can be                                                                                         * rebuilt from the parcel by calling CREATOR.createFromParcel().                                                                                         * @param p    Parcel object to write the bitmap data into                                                                                         */                                                                                        public                                 void                                 writeToParcel(Parcel p,                                 int flags) {                                                                                            checkRecycled(                                "Can't parcel a recycled bitmap");                                                                                            if (!nativeWriteToParcel(mNativeBitmap, mIsMutable, mDensity, p)) {                                                                                                throw                                 new RuntimeException(                                "native writeToParcel failed");                                                                                            }                                                                                            }                            

挂 jni 的马甲咧:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                                                                                        44                                                                                        45                                                                                        46                                                                                        47                                                                                        48                                                                                        49                                                                                        50                                                                                        51                                                                                        52                                                                                        53                                                                                        54                                                                                        55                                                                                        56                                                                                        57                                                                                        58                                                                                        59                                                                                        60                                                                                        61                                                                                        62                            
                                                            static jboolean Bitmap_writeToParcel(JNIEnv* env, jobject,                                                                                                                             const SkBitmap* bitmap,                                                                                                                             jboolean isMutable, jint density,                                                                                                                             jobject parcel) {                                                                                            if (parcel == NULL) {                                                                                                SkDebugf(                                "------- writeToParcel null parcel\n");                                                                                                return                                 false;                                                                                            }                                                                                                                                                        // 通过 java 的 Parcel 对象获取 native 层的 parcel 对象                                                                                            android::Parcel* p = android::parcelForJavaObject(env, parcel);                                                                                            // 把 bitmap 的一些配置信息写进去                                                                                            p->writeInt32(isMutable);                                                                                            p->writeInt32(bitmap->config());                                                                                            p->writeInt32(bitmap->width());                                                                                            p->writeInt32(bitmap->height());                                                                                            p->writeInt32(bitmap->rowBytes());                                                                                            p->writeInt32(density);                                                                                            // 如果是 index 格式,不使用 ashmem,直接拿 Parcel 申请普通内存传递                                                                                            // 颜色索引格式的图片占用资源一般都不大                                                                                            if (bitmap->getConfig() == SkBitmap::kIndex8_Config) {                                                                                                SkColorTable* ctable = bitmap->getColorTable();                                                                                                if (ctable != NULL) {                                                                                                    int count = ctable->count();                                                                                                    p->writeInt32(count);                                                                                                    memcpy(p->writeInplace(count *                                 sizeof(SkPMColor)),                                                                                                           ctable->lockColors(), count *                                 sizeof(SkPMColor));                                                                                                    ctable->unlockColors(                                false);                                                                                                }                                 else {                                                                                                    p->writeInt32(                                0);                                   // indicate no ctable                                                                                                }                                                                                            }                                                                                            size_t size = bitmap->getSize();                                                                                            // 其它格式(最常见的 ARGB)是用 ashmem                                                                                            // 这个 Blob 是 Parcel 的一个简单的封装类                                                                                            android::Parcel::WritableBlob blob;                                                                                            // writeBlob 就是创建 size 大小的 ashmem                                                                                            android::status_t status = p->writeBlob(size, &blob);                                                                                            if (status) {                                                                                                doThrowRE(env,                                 "Could not write bitmap to parcel blob.");                                                                                                return                                 false;                                                                                            }                                                                                            bitmap->lockPixels();                                                                                            const                                 void* pSrc =  bitmap->getPixels();                                                                                            if (pSrc == NULL) {                                                                                                memset(blob.data(),                                 0, size);                                                                                            }                                 else {                                                                                                // memcpy, 这里需要 copy 一次                                                                                                memcpy(blob.data(), pSrc, size);                                                                                            }                                                                                            bitmap->unlockPixels();                                                                                            // 图片 pixels 复制完了可以 munmap 了                                                                                            blob.release();                                                                                            return                                 true;                                                                                        }                            

这个函数主要是调用 Parcel 的 writeBlob 创建 ashmem,并初始化 Blob。然后把 bitmap 的 pixels 数据 copy 到 ashmem 中,注意 copy 完之后 Proc A 就不再需要对 ashmem 进行操作了,所以后面就 munmap(下面 Blob 的代码可以看到 release 只是 munmap 而已,没 close,这里还不能 close 要等 Proc B 读完才能 close)。
然后我们看下 Parcel 的 Blob 类:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                                                                                        44                                                                                        45                                                                                        46                                                                                        47                                                                                        48                                                                                        49                                                                                        50                                                                                        51                            
                                                            // Parcel.h ==================================                                                                                            class Blob {                                                                                            public:                                                                                                Blob();                                                                                                ~Blob();                                                                                                void release();                                                                                                inline size_t size()                                 const {                                 return mSize; }                                                                                             protected:                                                                                                void init(                                bool mapped,                                 void* data, size_t size);                                                                                                void clear();                                                                                                // true 表示 mmap 过,release 的时候需要 munmap                                                                                                bool mMapped;                                                                                                // mmap 的内存地址                                                                                                void* mData;                                                                                                    // mmap 的内存大小                                                                                                      size_t mSize;                                                                                            };                                                                                        // Parcel.cpp ==================================                                                                                        Parcel::Blob::Blob() :                                                                                                mMapped(                                false), mData(NULL), mSize(                                0) {                                                                                        }                                                                                        Parcel::Blob::~Blob() {                                                                                            release();                                                                                        }                                                                                        void Parcel::Blob::release() {                                                                                            if (mMapped && mData) {                                                                                                ::munmap(mData, mSize);                                                                                                    }                                                                                            clear();                                                                                        }                                                                                        void Parcel::Blob::init(                                bool mapped,                                 void* data, size_t size) {                                                                                            mMapped = mapped;                                                                                            mData = data;                                                                                            mSize = size;                                                                                        }                                                                                        void Parcel::Blob::clear() {                                                                                            mMapped =                                 false;                                                                                            mData = NULL;                                                                                            mSize =                                 0;                                                                                        }                            

十分简单,然后再来看 Parcel Blob 相关操作:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                                                                                        44                                                                                        45                                                                                        46                                                                                        47                                                                                        48                                                                                        49                                                                                        50                                                                                        51                                                                                        52                                                                                        53                                                                                        54                                                                                        55                                                                                        56                                                                                        57                                                                                        58                            
                                                            status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob)                                                                                        {                                                                                            status_t status;                                                                                            // 这里判断下,如果禁用 ashmem 或是要创建的 ashmem 不够大,不让使用                                                                                            // 直接用普通内存代替,果然前面 bitmap 判断小空间不用是正确的                                                                                            if (!mAllowFds || len <= IN_PLACE_BLOB_LIMIT) {                                                                                                ALOGV(                                "writeBlob: write in place");                                                                                                status = writeInt32(                                0);                                                                                                        if (status)                                 return status;                                                                                                     void* ptr = writeInplace(len);                                                                                                 if (!ptr)                                 return NO_MEMORY;                                                                                                    outBlob->init(                                false                                 /*mapped*/, ptr, len);                                                                                                return NO_ERROR;                                                                                            }                                                                                            // 调用 libcutils 的接口创建 ashmem                                                                                            ALOGV(                                "writeBlob: write to ashmem");                                                                                            int fd = ashmem_create_region(                                "Parcel Blob", len);                                                                                            if (fd <                                 0)                                 return NO_MEMORY;                                                                                            // 设置下 ashmem 的读、写权限                                                                                            int result = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE);                                                                                            if (result <                                 0) {                                                                                                status = result;                                                                                            }                                 else {                                                                                                // 记起我们的例子:创建完之后,Proc A mmap 内存到本进程空间                                                                                                void* ptr = ::mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd,                                 0);                                                                                                if (ptr == MAP_FAILED) {                                                                                                           status = -errno;                                                                                                }                                 else {                                                                                                    // 这里这么又把端口设成只读的啦??                                                                                                    result = ashmem_set_prot_region(fd, PROT_READ);                                                                                                    if (result <                                 0) {                                                                                                        status = result;                                                                                                    }                                 else {                                                                                                        // 1 标志是用 ashmem 的                                                                                                        status = writeInt32(                                1);                                                                                                        if (!status) {                                                                                                            // 前面分析的,用 flat_binder_object` 传 fd                                                                                                            // 注意下后面的 takeOwnership 是 true                                                                                                            status = writeFileDescriptor(fd,                                 true                                 /*takeOwnership*/);                                                                                                            if (!status) {                                                                                                                // 不错误的把地址保存在 Blob 中                                                                                                                outBlob->init(                                true                                 /*mapped*/, ptr, len);                                                                                                                return NO_ERROR;                                                                                                            }                                                                                                        }                                                                                                    }                                                                                                }                                                                                                ::munmap(ptr, len);                                                                                            }                                                                                            ::close(fd);                                                                                            return status;                                                                                        }                            

然后回去看 Bitmap createFromParcel 接口的实现:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                                                                                        33                                                                                        34                                                                                        35                                                                                        36                                                                                        37                                                                                        38                                                                                        39                                                                                        40                                                                                        41                                                                                        42                                                                                        43                                                                                        44                                                                                        45                                                                                        46                                                                                        47                                                                                        48                                                                                        49                                                                                        50                                                                                        51                                                                                        52                                                                                        53                                                                                        54                                                                                        55                                                                                        56                                                                                        57                                                                                        58                                                                                        59                                                                                        60                                                                                        61                                                                                        62                                                                                        63                                                                                        64                                                                                        65                                                                                        66                                                                                        67                                                                                        68                                                                                        69                                                                                        70                                                                                        71                                                                                        72                                                                                        73                                                                                        74                                                                                        75                                                                                        76                            
                                                            static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {                                                                                            if (parcel == NULL) {                                                                                                SkDebugf(                                "-------- unparcel parcel is NULL\n");                                                                                                return NULL;                                                                                            }                                                                                            // 继续先获取 native Parcel 对象                                                                                            android::Parcel* p = android::parcelForJavaObject(env, parcel);                                                                                            // 把之前写的配置读出来                                                                                            const                                 bool              isMutable = p->readInt32() !=                                 0;                                                                                            const SkBitmap::Config  config = (SkBitmap::Config)p->readInt32();                                                                                            const                                 int               width = p->readInt32();                                                                                            const                                 int               height = p->readInt32();                                                                                            const                                 int               rowBytes = p->readInt32();                                                                                            const                                 int               density = p->readInt32();                                                                                            if (SkBitmap::kARGB_8888_Config != config &&                                                                                                     SkBitmap::kRGB_565_Config != config &&                                                                                                    SkBitmap::kARGB_4444_Config != config &&                                                                                                    SkBitmap::kIndex8_Config != config &&                                                                                                    SkBitmap::kA8_Config != config) {                                                                                                SkDebugf(                                "Bitmap_createFromParcel unknown config: %d\n", config);                                                                                                return NULL;                                                                                            }                                                                                            SkBitmap* bitmap =                                 new SkBitmap;                                                                                            bitmap->setConfig(config, width, height, rowBytes);                                                                                            // 索引格式直接使用普通内存                                                                                            SkColorTable* ctable = NULL;                                                                                            if (config == SkBitmap::kIndex8_Config) {                                                                                                int count = p->readInt32();                                                                                                if (count >                                 0) {                                                                                                    size_t size = count *                                 sizeof(SkPMColor);                                                                                                    const SkPMColor* src = (                                const SkPMColor*)p->readInplace(size);                                                                                                    ctable =                                 new SkColorTable(src, count);                                                                                                }                                                                                            }                                                                                            // 根据图片的大小申请内存空间                                                                                            jbyteArray buffer = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);                                                                                            if (NULL == buffer) {                                                                                                SkSafeUnref(ctable);                                                                                                delete bitmap;                                                                                                return NULL;                                                                                            }                                                                                            SkSafeUnref(ctable);                                                                                            size_t size = bitmap->getSize();                                                                                            // 在传过来的 Parcel 中通过 Blob 读取 ashmem 的内容                                                                                            android::Parcel::ReadableBlob blob;                                                                                            android::status_t status = p->readBlob(size, &blob);                                                                                            if (status) {                                                                                                doThrowRE(env,                                 "Could not read bitmap from parcel blob.");                                                                                                delete bitmap;                                                                                                return NULL;                                                                                            }                                                                                            bitmap->lockPixels();                                                                                            // 把 Proc A ashmem 里的内容(bitmap 的 pixels 数据)                                                                                            // copy 到刚刚申请的内存中,这里算第二次了吧                                                                                            memcpy(bitmap->getPixels(), blob.data(), size);                                                                                            bitmap->unlockPixels();                                                                                            // 用完了释放下                                                                                            blob.release();                                                                                            // 拿之前申请的内存(已经 copy 了 Proc A 的pixels)创建一个 Bitmap 对象                                                                                            return GraphicsJNI::createBitmap(env, bitmap, buffer, getPremulBitmapCreateFlags(isMutable),                                                                                                    NULL, NULL, density);                                                                                        }                            

然后是 Parcel 的 readBlob:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                                                                                        30                                                                                        31                                                                                        32                            
                                                            status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob)                                 const                                                                                        {                                                                                            // 前面 writeBlob 的时候,第一个 int 是 1 来着                                                                                            int32_t useAshmem;                                                                                            status_t status = readInt32(&useAshmem);                                                                                            if (status)                                 return status;                                                                                            // 第一个 int 不是 1 就表示是普通的内存                                                                                            if (!useAshmem) {                                                                                                ALOGV(                                "readBlob: read in place");                                                                                                const                                 void* ptr = readInplace(len);                                                                                                if (!ptr)                                 return BAD_VALUE;                                                                                                    outBlob->init(                                false                                 /*mapped*/,                                 const_cast<                                void*>(ptr), len);                                                                                                return NO_ERROR;                                                                                            }                                                                                            // readFileDescriptor 和 writeFileDescriptor 对应                                                                                            // Proc B 得到经过倒腾的 fd                                                                                            ALOGV(                                "readBlob: read from ashmem");                                                                                            int fd = readFileDescriptor();                                                                                             if (fd ==                                 int(BAD_TYPE))                                 return BAD_VALUE;                                                                                            // Proc B mmap 内存到本进程                                                                                            void* ptr = ::mmap(NULL, len, PROT_READ, MAP_SHARED, fd,                                 0);                                                                                             if (!ptr)                                 return NO_MEMORY;                                                                                            // 把 mmap 到的地址、大小保存在 Blob 中                                                                                            outBlob->init(                                true                                 /*mapped*/, ptr, len);                                                                                            return NO_ERROR;                                                                                        }                            

然后最后是释放共享内存。前面 Proc A 写完后,Blob 的 release 只是 munmap 了而已,Proc B 也是读完,重新创建完 Bitmap 后,也是 release 只是 munmap。我们来看看是在哪里关闭 fd 的。本着谁 open、谁 close 的原则,应该是 Proc A 这边关闭的。后面有篇内存管理篇的, Parcel 的析构函数会调用 freeDataNoInit:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                            
                                                            void Parcel::freeDataNoInit()                                                                                        {                                                                                            if (mOwner) {                                                                                                //ALOGI("Freeing data ref of %p (pid=%d)\n", this, getpid());                                                                                                mOwner(                                this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);                                                                                            }                                 else {                                                                                                releaseObjects();                                                                                                if (mData)                                 free(mData);                                                                                                        if (mObjects)                                 free(mObjects);                                                                                              }                                                                                        }                            

内存管理那里是设置了 mOwner 了的,所以跑的是自己的 freeBuffer 回调,这里走的是下面,那主要是看 releaseObjects:

                                                            1                                                                                        2                                                                                        3                                                                                        4                                                                                        5                                                                                        6                                                                                        7                                                                                        8                                                                                        9                                                                                        10                                                                                        11                                                                                        12                                                                                        13                                                                                        14                                                                                        15                                                                                        16                                                                                        17                                                                                        18                                                                                        19                                                                                        20                                                                                        21                                                                                        22                                                                                        23                                                                                        24                                                                                        25                                                                                        26                                                                                        27                                                                                        28                                                                                        29                            
                                                            void Parcel::releaseObjects()                                                                                         {                                                                                            const sp proc(ProcessState::self());                                                                                            size_t i = mObjectsSize;                                                                                            uint8_t*                                 const data = mData;                                                                                            size_t*                                 const objects = mObjects;                                                                                            while (i >                                 0) {                                                                                                i--;                                                                                                const flat_binder_object* flat                                                                                                     =                                 reinterpret_cast(data+objects[i]);                                                                                                release_object(proc, *flat,                                 this);                                                                                            }                                                                                        }                                                                                        void release_object(                                const sp& proc,                                                                                            const flat_binder_object& obj,                                 const                                 void* who)                                                                                        {                                                                                            switch (obj.type) {                                                                                                ... ...                                                                                                case BINDER_TYPE_FD: {                                                                                                    // 前面设置了 takeOwnership 是 true 的话,cookie 就是 1                                                                                                    if (obj.cookie != (                                void*)                                0) close(obj.handle);                                                                                                    return;                                                                                                }                                                                                            }                                                                                            ALOGE(                                "Invalid object type 0x%08lx", obj.type);                                                                                        }                            

果然是在 Proc A 关闭 fd 的咧,前面 writeFileDescriptor 那里设置的 takeOwnership 是 true,所以 flat_binder_object 的 cookie 是 1 。Parcel 析构的时候,正好可以 close 掉 fd。一般 IPC 通信,Proc A 传过去的 Parcel 都是局部变量,等 IPC 通信完成,就析构了(Proc B 那边也用完了,所以这个时候 close 是安全的)。

所以从上面来看,java 层的 MemroyFile 确实没啥用,不过感觉可以用 Parcel 来代替咧,Parcel 的 Blob 就是封装好的 ashmem,也有 read、write 接口。然后如果在 binder 中传递 Bitmap 的话,使用 ashmem 需要 copy 2次 bitmap 的 pixels 数据,这个 android 应该是出于安全性考虑,把原始的 bitmap copy 了一份出来,扔 ashmem 里面,然后对方再申请一片空间把 ashmem 里的内容 copy 过去。这样话,Proc A 后面怎么折腾原始的 bitmap 都不会对 Proc B 的 bitmap有影响(包括 recycle)。

当然这样在高性能的环境下是不行的,可以自己通过 Parcel 的接口改造一下: Proc A 创建 ashmem,拿 ashmem 的 buffer 解码 bitmap,然后传 ashmem 给 Proc B,Proc B 直接在 ashmem 的 buffer 上再创建出 Bitmap。不过这样带来的风险就是你自己要管理好 ashmem 的 buffer,确保 Proc B 不用了,才能 munmap、close 。好像 SurfacFlinger 用的就是类似这样的方案,这个后面有时间再慢慢说。所以说不要有事没事跨进程传图片,还是大图片。

最后来个对比,如果 bitmap 不用 ashmem 传递,把 binder mmap 的内存改大,那么使用普通内存传递,需要 3次 copy(Proc A、Proc B 各自一次,Proc A —> kernel 一次)。如果使用普通的 IPC 那么需要 4次 copy(Proc A、Proc B 各自一次,Proc A —> kernel, kernel —> Proc B)。


原文地址:  http://light3moon.com/2015/01/28/Android%20Binder%20%E5%88%86%E6%9E%90%E2%80%94%E2%80%94%E5%8C%BF%E5%90%8D%E5%85%B1%E4%BA%AB%E5%86%85%E5%AD%98%5BAshmem%5D/

更多相关文章

  1. 一款常用的 Squid 日志分析工具
  2. GitHub 标星 8K+!一款开源替代 ls 的工具你值得拥有!
  3. RHEL 6 下 DHCP+TFTP+FTP+PXE+Kickstart 实现无人值守安装
  4. Linux 环境下实战 Rsync 备份工具及配置 rsync+inotify 实时同步
  5. Android学习笔记1 ——资源 (一)
  6. 如何提高Android代码的安全性
  7. Android运行时异常“Binary XML file line # : Error inflating
  8. Android学习【7】manifest文件讲解
  9. Android沙盒开发之系统libc库定制修改

随机推荐

  1. Node.js 中的ES模块现状[每日前端夜话0x8
  2. 一张 JVM 相关的思维脑图(4.4M)
  3. JVM 线上故障排查基本操作
  4. 如何设计一个 RPC 框架
  5. 性能测试 —— Dubbo 基准测试
  6. 如何设计一个牛逼的文件搬运工?
  7. MySQL 8 OCP(1Z0-908)认证考试题库原题(第
  8. 芋道 Spring Boot MyBatis 入门(一)之 MyBa
  9. 分布式链路追踪 SkyWalking 源码分析 —
  10. 最近,前端又火了哪些技术