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.
89 lines
2.5 KiB
89 lines
2.5 KiB
5 years ago
|
---
|
||
|
跨进程传递大图片
|
||
|
---
|
||
|
|
||
|
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())<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;
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
```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 机制
|