Android 匿名共享内存驱动源码分析中介绍了匿名共享内存的驱动实现过程,本文在Android匿名共享内存驱动基础上,介绍Android匿名共享内存对外Android系统的匿名共享内存子系统的主体是以驱动程序的形式实现在内核空间的,同时在应用程序框架层提供了Java调用接口。在Android应用程序框架层,提供了一个MemoryFile接口来封装了匿名共享内存文件的创建和使用,它实现在frameworks/base/core/java/android/os/MemoryFile.java

public MemoryFile(String name, int length) throws IOException {
mLength = length;
//打开"/dev/ashmem"设备文件
mFD = native_open(name, length);
if (length > 0) {
//将打开的"/dev/ashmem"设备文件映射到进程虚拟地址空间中
mAddress = native_mmap(mFD, length, PROT_READ | PROT_WRITE);
} else {
mAddress = 0;
}
}
native_open函数是一个本地函数,通过JNI实现在C++层,代码位于frameworks\base\core\jni\android_os_MemoryFile.cpp 
static jobject android_os_MemoryFile_open(JNIEnv* env, jobject clazz, jstring name, jint length)
{
//字符串转换
const char* namestr = (name ? env->GetStringUTFChars(name, NULL) : NULL);
//打开设备文件"/dev/ashmem",并修改设备文件名称及共享内存大小
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);
}

函数首先将Java层传过来的你们共享内存名称转换为C++层的字符串,然后调用ashmem_create_region函数创建一个名为dev/ashmem/的匿名共享内存,并且修改该共享内存的名称及大小,然后将创建的匿名共享内存设备文件句柄值返回到Java空间中。函数ashmem_create_region在Android 匿名共享内存C接口分析中有详细分析,该接口函数就是用于创建一块匿名共享内存。

在Java空间构造MemoryFile对象时,首先打开/dev/ashmem设备文件并在内核空间创建一个ashmem_area,接着需要将内核空间分配的共享内存地址映射到进程虚拟地址空间中来,映射过程是通过native_mmap函数来完成的。
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;
}

该函数直接调用mmap来实现地址空间映射,注意标志位MAP_SHARED,表示该缓冲区以共享方式映射。映射过程是由Ashmem驱动来完成, Android 匿名共享内存驱动源码分析详细分析了Android匿名共享内存的实现过程。在构造MemoryFile对象时完成了匿名共享内存的创建及地址空间的映射过程,将创建的匿名共享内存的大小保存到MemoryFile的成员变量mLength中,成员变量mFD保存创建的匿名共享内存的文件描述符,成员变量mAddress保存匿名共享内存映射到进程地址空间的起始地址。有了这些信息后,就可以直接使用该匿名共享内存了。

匿名共享内存读

对匿名共享内存的读取操作,在Java空间被封装成MemoryInputStream来完成,该类继承于输入流InputStream,并对外提供了read方法,定义如下:
@Override
public int read() throws IOException {
if (mSingleByte == null) {
mSingleByte = new byte[1];
}
int result = read(mSingleByte, 0, 1);
if (result != 1) {
return -1;
}
return mSingleByte[0];
} @Override
public int read(byte buffer[], int offset, int count) throws IOException {
if (offset < 0 || count < 0 || offset + count > buffer.length) {
// readBytes() also does this check, but we need to do it before
// changing count.
throw new IndexOutOfBoundsException();
}
count = Math.min(count, available());
if (count < 1) {
return -1;
}
int result = readBytes(buffer, mOffset, offset, count);
if (result > 0) {
mOffset += result;
}
return result;
}

MemoryInputStream类提供了两个read重载方法,第一个无参read方法调用有参read方法来读取1字节的数据,而有参read方法的数据读取过程是调用MemoryInputStream的外部类MemoryFile的readBytes方法来实现匿名共享内存数据的读取过程。

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

该函数也仅仅作了一些判断,然后直接调用本地方法native_read在C++空间完成数据读取,在构造MemoryFile对象时,已经打开并映射了dev/ashmem设备文件,因此在这里直接将打开该设备文件得到的文件句柄值传到C++空间,以正确读取指定的匿名共享内存中的内容,mAddress为匿名共享内存映射到进程地址空间中的起始地址。


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



匿名共享内存写

将指定数据写入到匿名共享内存中,对匿名共享内存的写操作使用MemoryOutputStream来封装,该类提供了两个重载的write方法,一个用于向匿名共享内存写入多字节数据,另一个则只写入一个字节数据。这里简单介绍多字节数据写入过程:
public void write(byte buffer[], int offset, int count) throws IOException {
writeBytes(buffer, offset, mOffset, count);
mOffset += count;
}

参数buffer是指写入匿名共享内存中的字节数组,offset指定数据buffer开始写的偏移量,参数count指定写入匿名共享内存的字节长度,函数调用MemoryFile的writeBytes函数来完成数据写入。

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

该函数首先检验参数的正确性,然后调用native方法native_write通过JNI转入C++完成数据写入,第一个参数是匿名共享内存的文件描述符,第二个参数是匿名共享内存映射到进程地址空间的基地值,后面三个参数上面已经介绍了,最后一个参数mAllowPurging表示是否允许内存回收

上图描述了匿名共享内存的写入过程,本质上就是将buffer中指定位置开始的数据拷贝到匿名共享内存指定的偏移位置

frameworks\base\core\jni\android_os_MemoryFile.cpp

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函数GetByteArrayRegion完成数据的拷贝操作。


Android 匿名共享内存Java接口分析的更多相关文章

  1. Android 匿名共享内存C++接口分析

    在上一篇Android 匿名共享内存C接口分析中介绍了Android系统的匿名共享内存C语言访问接口,本文在前文的基础上继续介绍Android系统的匿名共享内存提供的C++访问接口.在C++层通过引入 ...

  2. Android 匿名共享内存C接口分析

    在Android 匿名共享内存驱动源码分析中详细分析了匿名共享内存在Linux内核空间的实现,虽然内核空间实现了匿名共享内存,但仍然需要在用户空间为用户使用匿名共享内存提供访问接口.Android系统 ...

  3. Fresco内存机制(Ashmem匿名共享内存)

    Fresco的内存机制 Fresco是Facebook出品的高性能图片加载库,采用了Ashmem匿名共享内存机制, 来解决图片加载中的OOM问题.这里不对Fresco做深入分析,只关注Fresco在A ...

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

    一.Ashmem驱动程序 ~/Android/kernel/goldfish ----include ----linux ----ashmem.h ----mm ----ashmem.c 驱动程序具体 ...

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

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6939890 在Android系统中,针对移动设 ...

  6. Android系统匿名共享内存Ashmem(Anonymous Shared Memory)驱动程序源代码分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6664554 在上一文章Android系统匿名共 ...

  7. Android系统匿名共享内存Ashmem(Anonymous Shared Memory)在进程间共享的原理分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6666491 在前面一篇文章Android系统匿 ...

  8. MemoryFile匿名共享内存

    Android提供了一个高效的共享内存机制.如果应用中涉及到在多个进程间交换数据时使用Android提高的共享内存机制将会大大的提高效率.但是也许是出于安全考虑,在应用层使用共享内存机制将会遇到很多障 ...

  9. Android 性能测试之内存 --- 追加腾讯性能案例,安卓抓取性能扫盲帖

    内存测试: 思路 目前做的是酒店APP,另下载安装几个个第三方酒店的APP以方便对比(相当于可以做竞品测试) 数据的获取来源是ADB底层命令,而且最好是不需要root权限,因为很多手机root很麻烦或 ...

随机推荐

  1. bzoj2741(分块+可持久化Trie)

    题意中文我就不说了 解析: 分块+可持久化Trie,先得到前缀异或值,插入到Trie中,然后分块,对每一块,处理出dp[i][j](i代表第几块,j代表第几个位置),dp[i][j]代表以第i块开始的 ...

  2. JAVA大整数傻瓜入门

    http://blog.csdn.net/skiffloveblue/article/details/7032290..先记着

  3. for添加用户

    #!/bin/bash #接受一个参数: #add: 添加用户user1..user10 #del: 删除用户user1..user10 #其它:退出 #定义变量 ADD=add DEL=del #判 ...

  4. errno的基本用法

    error是一个包含在 perror()和strerrot()函数可以把errno的值转化为有意义的字符输出. #include <stdio.h> #include <stdlib ...

  5. Python 异步IO、IO多路复用

    事件驱动模型 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UT ...

  6. python高级编程 编写一个包1

    #目的是:编写,发行python包可重复过程"""1:是缩短开始真正工作之前所需要的设置时间,也就是提供模板2:提供编写包的标准化方法3:简化测试驱动开发方法的使用4:为 ...

  7. operator模块

    # -*- coding: utf-8 -*- # ==================== #File: python #Author: python #Date: 2014 #========== ...

  8. java技术学习网址收藏

    Bootstrap:http://www.runoob.com/bootstrap/bootstrap-intro.html AngularJS : http://www.runoob.com/ang ...

  9. Android学习总结——去除标题栏

    1.继承app.Activity的Activity去除标题栏 @Override protected void onCreate(Bundle savedInstanceState) { super. ...

  10. java与.net比较学习系列(4) 运算符和表达式

    上一篇总结了java的数据类型,得到了冰麟轻武等兄弟的支持,他们提出并补充了非常好的建议,在这里向他们表示感谢.在后面的文章中,我会尽力写得更准确和更完善的,加油! 另外,因为C#是在java之后,也 ...