# AndroidBinderDemo **Repository Path**: liulei9385/android-binder-demo ## Basic Information - **Project Name**: AndroidBinderDemo - **Description**: aidl 使用例子 - **Primary Language**: Unknown - **License**: AGPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2022-02-16 - **Last Updated**: 2023-03-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # AndroidBinderDemo #### 介绍 aidl 使用例子 APP开发的时候,Binder对程序员几乎不可见,但是作为Android的数据运输系统,Binder的影响是全面性的,所以有时候如果不了解 Binder的一些限制,在出现问题的时候往往是没有任何头绪,比如在Activity之间传输BitMap的时候,如果Bitmap过大,就会引起问题, 比如崩溃等, 这其实就跟Binder传输数据大小的限制有关系,在上面的一次拷贝中分析过,mmap函数会为Binder数据传递映射一块连续的虚拟地址, 这块虚拟内存空间其实是有大小限制的,不同的进程可能还不一样。 ## AIDL和Messenger的区别: 1. Messenger不适用大量并发的请求:Messenger以串行的方式来处理客户端发来的消息,如果大量的消息同时发送到服务端,服务端仍然只能一个个的去处理。 2. Messenger主要是为了传递消息:对于需要跨进程调用服务端的方法,这种情景不适用Messenger。 3. Messenger的底层实现是AIDL,系统为我们做了封装从而方便上层的调用。 4. AIDL适用于大量并发的请求,以及涉及到服务端端方法调用的情况 #### 跨进程传输文件: 利用ParcelFileDescriptor实现文件的读写,ParcelFileDescriptor.createPipe()创建管道,一个为读,一个为写,这就为跨进程传输提供了条件 服务端: ```kotlin override fun sendfile(bundle: Bundle?, callback: IAidlCallback?) { CLogUtil.d("received sendfile") job?.cancel() job = scope.launch { val fileDescriptor = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { bundle?.getParcelable("fileFd", ParcelFileDescriptor::class.java) ?: return@launch } else { bundle?.getParcelable("fileFd") ?: return@launch } val cis = ParcelFileDescriptor.AutoCloseInputStream(fileDescriptor) val buffer = ByteArray(1024) val bos = ByteArrayOutputStream() while (true) { val len = cis.read(buffer) if (len != -1) { bos.write(buffer, 0, len) } else { break } } cis.close() val readStr = bos.toString() CLogUtil.d("read str is $readStr") withContext(Dispatchers.Main) { UiHelper.invokeCallback(readStr) } callback?.onExecComplete() } } ``` 客户端: ```kotlin lifecycleScope.launch { withContext(Dispatchers.IO) { val file = getFdWithAssets("a.txt") val timeoutJob = launch(Dispatchers.Default) { delay(20_000L) isInSendFile.compareAndSet(true, false) coroutineContext.job.cancelChildren() } file?.writeText("a ${System.currentTimeMillis()}") ?: return@withContext CLogUtil.d("file is " + file.path) file.let { val createPipe = ParcelFileDescriptor.createPipe() // 0 read 1 write val outputStream = ParcelFileDescriptor.AutoCloseOutputStream(createPipe[1]) val inputStream = file.inputStream() file.inputStream().copyTo(outputStream) outputStream.flush() outputStream.close() inputStream.close() val bundle = Bundle() bundle.putParcelable("fileFd", createPipe[0]) CLogUtil.d("## put fileFd") try { CLogUtil.d("## put sendFile") iBookInterface?.sendfile(bundle, object : IAidlCallback.Stub() { override fun onExecComplete() { timeoutJob.cancel() CLogUtil.e("## onExecComplete") isInSendFile.compareAndSet(true, false) } }) CLogUtil.d("## put sendfile after") } catch (ex: DeadObjectException) { ex.printStackTrace() } } } } ```