From de364e2bf71f6dccf37aa25b316d6bf82d257bae Mon Sep 17 00:00:00 2001 From: Omooo <869759698@qq.com> Date: Mon, 30 Mar 2020 20:10:26 +0800 Subject: [PATCH] =?UTF-8?q?Create=20=E8=B7=A8=E8=BF=9B=E7=A8=8B=E4=BC=A0?= =?UTF-8?q?=E9=80=92=E5=A4=A7=E5=9B=BE=E7=89=87.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../跨进程传递大图片.md | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 blogs/Android/Framework/Interview/技巧心得相关/跨进程传递大图片.md diff --git a/blogs/Android/Framework/Interview/技巧心得相关/跨进程传递大图片.md b/blogs/Android/Framework/Interview/技巧心得相关/跨进程传递大图片.md new file mode 100644 index 0000000..3841f79 --- /dev/null +++ b/blogs/Android/Framework/Interview/技巧心得相关/跨进程传递大图片.md @@ -0,0 +1,89 @@ +--- +跨进程传递大图片 +--- + +1. 了解各种跨进程传输数据的方式及各自优缺点 +2. 了解 TransactionTooLargeException 的触发原因和底层机制 +3. 了解 Bitmap 传输底层原理 + +#### 方案 + +1. 给图片保存到固定的地方,传 key 给对方 +2. 通过 IPC 的方式转发图片数据 + 1. Binder + 2. Socket、管道 + 3. 共享内存 + +#### TransactionTooLargeException + +1. 发出去的或者返回的数据量太大 +2. Binder 缓存用于该进程所有正在进行中的 Binder 事务 +3. 大数据量打碎分批发,或按需发 + +```c++ +jboolean BinderProxy_transact(JNIEnv* env, ...){ + status_t err = target->transact(code, *data, reply, flags); + signalExceptionForError(env, obj, err, true, data->dataSize()); + return JNI_FALSE; +} +void signalExceptionForError(JNIEnv* env, jobject obj, status_t err, ...){ + switch(err){ + case FAILED_TRANSACTION:{ + if(canThrowRemoteException && parcelSize > 200*1024){ + exceptionToThrow = "android/os/TransactionTooLargeException"; + } + jniThrowException(env, exceptionToThrow, msg); + }break; + } +} +``` + +```c++ +status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult){ + while(1){ + if((err=talkWithDriver())buffer = binder_alloc_buf(target_proc, tr->data_size, tr->offsets_size, !reply && (t->flags&TF_ONE_WAY)); + if(t>buffer == NULL){ + return_error = BR_FAILED_REPLY; + goto err_binder_alloc_buf_failed; + } +} +``` + +```java +Bundle b = new Bundle(); +b.putParcelable("bitmap", mBitmap); +intent.putExtra(b); + +Bundle b = new Bundle(); +b.putBinder("binder", new IRemoteCaller.Stub(){ + @Override + public Bitmap getBitmap() throws RemoteException{ + return mBitmap; + } +}); +intent.putExtras(b); +``` + +```java +int startActivity(IApplicationThread caller, String callingPackage, Intent intent, ...){ + Parcel data = Parcel.obtain(); + intent.writeToParcel(data, 0); + mRemote.transct(START_ACTIVITY_TRANSACTION, data, reply, 0); +} +``` + +#### 总结:怎么跨进程传递大图片? + +1. 图片写到文件,路径传到另一个进程,再读出来 +2. intent 传图,但是容易抛异常,原因是什么? +3. binder 调用传图,底层 ashmem 机制 \ No newline at end of file