--- 跨进程传递大图片 --- 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 机制