跨进程通信--共享内存(ashmem)实例

文章目录

在之前的文章 ashmem原理中提到过,ashmem 通信原理是每个进程打开同一个文件,所以文件描述符需要通过其他方式传递给其他进程,所以这里采用了 Service + aidl 的方式把共享内存的文件描述符传递过去。然后客户端获取到的文件描述符读取该内存下的内容具体步骤如下:其中 MemoryFile 是通过 ashmem 实现的

Server 端

  • 第一步定义 aidl 接口,如何使用 aidl 略
// IFileDescriptorInterface.aidl
package com.process.server;

interface IFileDescriptorInterface {
	// 定义接口 返回 ParcelFileDescriptor 文件描述符
      ParcelFileDescriptor getPfd();
}

ParcelFileDescriptor 实现了Parcelable 所以可以通过binder传输。

  • 接下来定义 service ,为了方便测试只是简简单单的创建了个 MemoryFile 并返回操作符,MemoryFile 内部采用了ashmem 。记住在 manifest 中注册 service 并且设置 action 因为不是本地 service。
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);
    }
}

客户端准备:

  • 客户端要定义和服务端一样的 aidl 规则:
package com.process.server;

// Declare any non-default types here with import statements

interface IFileDescriptorInterface {
    ParcelFileDescriptor getPfd();
}
  • 接下来连接 service
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")
    }
}

版权声明:本文为ldxlz224原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。