写点什么

Android Ashmem 匿名共享内存,科学技术协会面试

用户头像
Android架构
关注
发布于: 10 小时前

val descriptor = invokeMethod("getFileDescriptor", file) as? FileDescriptor


// 如果获取失败,返回 if (descriptor == null) {Log.i("ZHP", "获取匿名共享内存的 FileDescriptor 失败")return null}


// 往共享内存中写入数据 file.writeBytes(bytes, 0, 0, bytes.size)


// 因为要跨进程传递,需要序列化 FileDescriptorreturn ParcelFileDescriptor.dup(descriptor)}


/**


  • 通过反射执行 obj.name() 方法*/private fun invokeMethod(name: String, obj: Any): Any? {val method = obj.javaClass.getDeclaredMethod(name)return method.invoke(obj)}


MemoryFile 有两个构造方法,上面是一种,另一种是根据已有的 FileDescriptor 创建。 MemoryFile 创建时指定的大小并不是实际占用的物理内存大小,实际占用内存大小由写入的数据决定,但不能超过指定的大小。

3. 将文件描述符传递到其他进程

这里选择用 Binder 传递 ParcelFileDescriptor。 我们定义一个 Code,用于 C/S 两端通信确定事件:


/**


  • 两个进程在传递 FileDescriptor 时用到的 Code。*/const val MY_TRANSACT_CODE = 920511


再在需要的地方 bindService:


// 创建服务进程 val intent = Intent(this, MyService::class.java)bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)


bind 成功之后将 文件描述符 和 数据大小 序列化,然后通过 Binder 传递到 Service 进程:


private val serviceConnection = object: ServiceConnection {


override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {if (binder == null) {return}


// 创建 MemoryFile,并拿到 ParcelFileDescriptorval descriptor = createMemoryFile() ?: return


// 传递 FileDescriptor 和 共享内存中数据的大小 val sendData = Parcel.obtain()sendData.writeParcelable(descriptor, 0)sendData.writeInt(bytes.size)


// 保存对方进程的返回值 val reply = Parcel.obtain()


// 开始跨进程传递 binder.transact(MY_TRANSACT_CODE, sendData, reply, 0)


// 读取 Binder 执行的结果 val msg = reply.readString()Log.i("ZHP", "Binder


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


执行结果是:「$msg」")}


override fun onServiceDisconnected(name: ComponentName?) {}


}


两个进程的文件描述符指向同一个文件结构体,文件结构体指向了一片内存共享区域(ASMA),使得两个文件描述符对应到同一片 ASMA 中。

4. 在其他进程接收 FileDescriptor 并读取数据

先定义一个 MyService 用于开启子进程:


class MyService : Service() {


private val binder by lazy { MyBinder() }


override fun onBind(intent: Intent) = binder}


再实现具体的 MyBinder 类,主要包含 3 个步骤: 1. 从序列化数据中读取 FileDescriptor 和 共享内存中保存的数据大小; 2. 根据 FileDescriptor 创建 FileInputStream; 3. 读取共享内存中的数据。


/**


  • 这里不必使用 AIDL,继承 Binder 类 重写 onTransact 即可。

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android Ashmem匿名共享内存,科学技术协会面试