Android Ashmem匿名共享内存

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,并拿到 ParcelFileDescriptor
val 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 执行结果是:「$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 即可。
    */
    class MyBinder: Binder() {

/**

  • 文件描述符 和 数据大小 通过 data 传入。
    */
    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
    val parent = super.onTransact(code, data, reply, flags)
    if (code != MY_TRANSACT_CODE && code != 931114) {
    return parent
    }

// 读取 ParcelFileDescriptor 并转为 FileDescriptor
val pfd = data.readParcelable(javaClass.classLoader)
if (pfd == null) {
return parent
}
val descriptor = pfd.fileDescriptor

// 读取共享内存中数据的大小
val size = data.readInt()

// 根据 FileDescriptor 创建 InputStream
val input = FileInputStream(descriptor)
// 从 共享内存 中读取字节,并转为文字
val bytes = input.readBytes()
val message = String(bytes, 0, size, Charsets.UTF_8)
Log.i(“ZHP”, “读取到另外一个进程写入的字符串:「 m e s s a g e 」 " ) / / 回复调用进程 r e p l y ? . w r i t e S t r i n g ( " S e r v e r 端收到 F i l e D e s c r i p t o r , 并且从共享内存中读到了:「 message」") // 回复调用进程 reply?.writeString("Server 端收到 FileDescriptor, 并且从共享内存中读到了:「 message")//回复调用进程reply?.writeString("Server端收到FileDescriptor,并且从共享内存中读到了:「message」”)
return true
}
}
这里拿到 FileDescriptor 后不仅可以读也能写入数据,还可以再创建一个 MemoryFile 对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值