You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

2.5 KiB

跨进程传递大图片
  1. 了解各种跨进程传输数据的方式及各自优缺点
  2. 了解 TransactionTooLargeException 的触发原因和底层机制
  3. 了解 Bitmap 传输底层原理

方案

  1. 给图片保存到固定的地方,传 key 给对方
  2. 通过 IPC 的方式转发图片数据
    1. Binder
    2. Socket、管道
    3. 共享内存

TransactionTooLargeException

  1. 发出去的或者返回的数据量太大
  2. Binder 缓存用于该进程所有正在进行中的 Binder 事务
  3. 大数据量打碎分批发,或按需发
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;
    }
}
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult){
	while(1){
		if((err=talkWithDriver())<NO_ERROR)break;
        switch(cmd){
            case BR_FAILED_REPLY:
                err = FAILED_TRANSACTION;
                goto finish;
        }
	}
    return err;
}
void binder_transaction(struct binder_proc *proc, struct binder_thread *thread, struct binder_transaction_data *tr, int reply){
    t->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;
    }
}
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);
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 机制