Binder机制,从Java到C (4. Parcel)

1. 远程调用的数据传输

在远程的函數中,必然会需要传递一些数据,那这些数据是怎么传输的呢?

在IPC中,Proxy端的作用就是将一些参数打包,然后发送出去,下面是在Proxy端经常会遇见的调用远程方法的代码。

可以看到,发送和接收的数据都是通过Parcel來打包的。

 1 class ActivityManagerProxy implements IActivityManager
 2 {
 3     public int startActivity(IApplicationThread caller, Intent intent,
 4             String resolvedType, IBinder resultTo, String resultWho, int requestCode,
 5             int startFlags, String profileFile,
 6             ParcelFileDescriptor profileFd, Bundle options) throws RemoteException {
 7         Parcel data = Parcel.obtain();
 8         Parcel reply = Parcel.obtain();
 9         data.writeInterfaceToken(IActivityManager.descriptor);
10         data.writeStrongBinder(caller != null ? caller.asBinder() : null);
11         intent.writeToParcel(data, 0);
12         data.writeString(resolvedType);
13         data.writeStrongBinder(resultTo);
14         data.writeString(resultWho);
15        ...
16         mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
17         reply.readException();
18         int result = reply.readInt();
19         ...
20         return result;
21     }
22 }

 

一些基本类型,比如String,int可以直接写进Parcel中,那么对于一些比较复杂的数据类型,比如一些自己定义的对象,要怎么写进Parcel里呢?
    
我們通过一个类new一个对象時,这个object的有效范围只是在一个进程里。如果通过IPC机制直接传递一个object是不现实的。因为Java环境里的对象是通过引用來访问的,一个object对其他object,会是通过一个类似指针的引用來访问的,会涉及到类似地址的访问。
所以在传递复杂对象時,必须把object拆解成中间形式,然後在IPC里传输这种中间格式。
那怎么把一个object拆解成中间形式呢?

-->這裏就需要Parcelable接口了

 

2.Parcelable

当需要在进程间传输一个object時,这个object必須实现Parcelable接口的属性或方法。

例如:
单进程中,有这样一个类:

 1 class TaskInfo {
 2     public int mPid;
 3     public int mUid;
 4     public String mPackageName;
 5 
 6     TaskInfo () {
 7         mPid = -1;
 8         mUid = -1;
 9         mPackageName = null;
10     }

 

在实现了Parcelable后,就可以跨进程传输了,定义的TaskInfo类:

 

 1 public class TaskInfo implements Parcelable {
 2     public int mPid;
 3     public int mUid;
 4     public String mPackageName;
 5 
 6     TaskInfo () {
 7         mPid = -1;
 8         mUid = -1;
 9         mPackgeName = null;
10     }
11     public int describeContents() { //返回值描述Parcel是起什么作用的,一般是0.
12         return 0;
13     }
14 
15     public void writeToParcel(Parcel out, int flags) { //用于发送,把需要传输的属性写入Parcel。
16         out.writeInt(mPid);
17         out.writeInf(mUid);
18         out.writeString(mPackageName);
19     }
20 
21     public static final Parcelable.Creator<TaskInfo> CREATOR = new Parcelable.Creator<TaskInfo>() {//对应writeToParcel(),接收端process会把Parcel object的中间object回复出來,传递新对象。
22         public TaskInfo createFromParcel(Parcel in) {//初始化 Parcel object
23             return new TaskInfo(in);
24         }
25 
26         public TaskInfo[] newArray(int size) {//用于创建多个空对象,使用默认的初始化方法。
27             return new TaskInfo[size];
28         }
29     };
30     private TaskInfo(Parcel in) {//使用Parcel的readInt()、readLong()等方法从Parcel里读出來
31         mPid = in.readInt();
32         mUid = in.readInt();
33         mPackageName = in.readString();
34     }
35 }

 

3.Parcel的传送

对于Parcel的传输,我们可以比喻成用传真机來发送一个纸盒子到远方。传真机不是時空传送带,并不会真正可以实现某个物品的跨进程传送,但可以变通來完成:

(这部分是从网上看到的,但忘了网址是啥了。。)

 这样,传送一个纸盒子就可以分为三个部分了:

1.把纸盒拆解,得到平面化的图形。
2.把平面化的图形通过传真及传到远端。
3.远端的传真机收到平面化的图形后,就可以打印到纸上,再裁剪,粘帖,就可以得到一個一模一样的紙盒子了。

 

所以,我們在发送時,可以认为是把对象進行拆解打包,然后塞进Parcel对象里。Parcel就相当于是容器,其中会有一段buffer存放中间结果。这个过程会是通过writeToParcel()方法,将对象的属性拆开,填写到Parcel的buffer中。

 

 

而读取端,会通过某种方法,將Parcel读取出來。

 

 

 

unflatten操作是通过CREATOR的createFromParcel()來完成。

 

4.Parcel支持的数据类型

Parcel能支持的數據類型有:
  null
  String
  Byte
  Short
  Integer
  Long
  Float
  Double
  Boolean
  String[]
  boolean[]
  byte[]
  int[]
  long[]
  Object[]
  Bundle
  Map
  Parcelable
  Parcelable[]
  CharSequence
  List
  SparseArray
  IBinder
  Serializable

看,IBinder是可以在进程间传输的!

转载于:https://www.cnblogs.com/zhangxinyan/p/3487856.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
com.miui.frameworks.servicestests (1 Test) [1/1] com.android.server.location.gnss.hal.Gpo4ClientTest#init: FAILED (141ms) STACKTRACE: java.lang.SecurityException: uid 10289 does not have android.permission.ACCESS_COARSE_LOCATION or android.permission.ACCESS_FINE_LOCATION. at android.os.Parcel.createExceptionOrNull(Parcel.java:3011) at android.os.Parcel.createException(Parcel.java:2995) at android.os.Parcel.readException(Parcel.java:2978) at android.os.Parcel.readException(Parcel.java:2920) at android.location.ILocationManager$Stub$Proxy.registerLocationListener(ILocationManager.java:1291) at android.location.LocationManager.requestLocationUpdates(LocationManager.java:1551) at android.location.LocationManager.requestLocationUpdates(LocationManager.java:1234) at android.location.LocationManager.requestLocationUpdates(LocationManager.java:1199) at com.android.server.location.gnss.hal.Gpo4Client.registerPassiveLocationUpdates(Gpo4Client.java:198) at com.android.server.location.gnss.hal.Gpo4Client.init(Gpo4Client.java:78) at com.android.server.location.gnss.hal.Gpo4ClientTest.init(Gpo4ClientTest.java:209) ... 8 trimmed Caused by: android.os.RemoteException: Remote stack trace: at com.android.server.location.LocationPermissions.enforceLocationPermission(LocationPermissions.java:116) at com.android.server.location.LocationManagerService.registerLocationListener(LocationManagerService.java:786) at android.location.ILocationManager$Stub.onTransact(ILocationManager.java:582) at android.os.Binder.execTransactInternal(Binder.java:1285) at android.os.Binder.execTransact(Binder.java:1249)
06-01

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值