在之前的文章 ashmem原理中提到过,ashmem 通信原理是每个进程打开同一个文件,所以文件描述符需要通过其他方式传递给其他进程,所以这里采用了 Service + aidl 的方式把共享内存的文件描述符传递过去。然后客户端获取到的文件描述符读取该内存下的内容具体步骤如下:其中 MemoryFile 是通过 ashmem 实现的
Server 端
// IFileDescriptorInterface.aidl
package com.process.server;
interface IFileDescriptorInterface {
// 定义接口 返回 ParcelFileDescriptor 文件描述符
ParcelFileDescriptor getPfd();
}
ParcelFileDescriptor 实现了Parcelable 所以可以通过binder传输。
class MyService : Service() {
/**
* aidl 定义获取文件描述符的方法
*/
var stub: IFileDescriptorInterface.Stub = object : IFileDescriptorInterface.Stub() {
@Throws(RemoteException::class)
override fun getPfd(): ParcelFileDescriptor {
return createMemoryFile()
}
}
override fun onBind(intent: Intent): IBinder {
return stub
}
/**
* 创建
* @return ParcelFileDescriptor
*/
fun createMemoryFile(): ParcelFileDescriptor {
// 定义空间大小 这里只是随便定义了哥 1024
val memoryFile = MemoryFile("test_ashmem", 1024)
val writeString = "hi client,am server msg... "
memoryFile.outputStream.write(writeString.toByteArray())
// 可以接下来写各种想写的东西...
val method: Method = memoryFile.javaClass.getDeclaredMethod("getFileDescriptor")
val fd = method.invoke(memoryFile) as FileDescriptor
return ParcelFileDescriptor.dup(fd);
}
}
客户端准备:
package com.process.server;
// Declare any non-default types here with import statements
interface IFileDescriptorInterface {
ParcelFileDescriptor getPfd();
}
class MainActivity : AppCompatActivity() {
private val conn = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
val asInterface = IFileDescriptorInterface.Stub.asInterface(service)
val pfd = asInterface.pfd
val fileDescriptor = pfd.fileDescriptor
val fis = FileInputStream(fileDescriptor)
val string = fis.bufferedReader().use { it.readText() }
Log.e("tag", "read result = $string")
}
override fun onServiceDisconnected(name: ComponentName?) {
Log.e("tag", "onServiceDisconnected")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
fun bindService(view: View) {
val intent = Intent()
intent.component = ComponentName("com.process.server", "com.process.server.MyService")
val bindService = bindService(intent, conn, Context.BIND_AUTO_CREATE)
Log.e("tag", "bindService = $bindService")
}
}