Android(安卓)Binder 应用层调用过程分析
Android 上的多进程情景
Android 中每个应用的进程都 fork 自 Zygote 进程, Zygote 进程在启动时自己会创建一个虚拟机,从而也就让每个应用拥有了自己的虚拟机。
当应用涉及多进程时,想当于启动了多个虚拟机,在单进程情况下的一些情景将会失效:
- 静态变量: 由于静态变量是位于虚拟机内存的方法区,每个虚拟机彼此独立,多个进程访问的也就不会是同一个变量
- 单利模式:单利也是基于一个虚拟机的,多个虚拟机将失效
- 线程同步机制:同步锁基于同一进程
- SharedPerfrence 不再可靠: SP 内部是以读写 xml 文件的方式,且只有线程锁。多进程环境下,文件同时读写将不可靠。
- Application 类的
onCreate
会在每个进程启动时被调用: 在含有多进程的应用里,需要在 Application 类的onCreate
里区分当前的进程,避免多个进程都执行了重复的代码。
如何开启多进程
在 AndroidManifest
中,给四大组件设置单独的 android:process
属性。
这种方式,有两种情况:
- 当前应用私有的进程,声明
process
属性带:
号,其他应用的组件不能运行在该进程中。
- 不带
:
号的全局进程。其他应用可以通过 SharedUID 方式跑在该进程中。
序列化和反序列化
Java Serializable 接口
让对象支持序列化,只需实现 Serializable
接口,并声明一个serialVersionUID
。serialVersionUID
不是必需的,但是如果不声明会对反序列化过程产生影响。序列化后的数据中的serialVersionUID
只有和当前类的serialVersionUID
相同时,才能被正常地反序列化。
- 静态属性属于类,不会被序列化
-
transitent
声明的属性不会被序列化
Android Parcelable 接口
Android 提供的序列化接口,相比 Serializable
性能更好,因为它主要用于在内存上序列化和反序列化。实现方式就是类实现 Parcelable
接口,并实现 createFromParcel
和 writeToParcel
等方法。
Binder
- 从 IPC 角度,Binder 是 Android 的一种跨进程通信方式
- 从 Android Framework 角度,Binder 是 ServiceManager 连接各种 Manager 和相应 ManagerService 的桥梁
- 从 Android 应用层,Binder 是客户端和服务端进行通信的媒介,当
bindService
时,服务端会返回一个包含了服务端业务调用的 Binder 对象,通过这个 Binder 对象,客户端就可以像调用客户端本地方法一样调用服务端的方法。 - 普通 Service 中的 Binder 不涉及进程间通信
- 多进程的应用会较多涉及 Binder,Binder 也主要用在 Service 上
Android 提供了 AIDL
描述语言来方便开发者创建 Binder 类,也可以自己手写实现 Binder 类。
模拟一个数据类 User
,并实现 Parcelable
接口,使用跨进程的方式,从远程 Service
中获取 User
。
public class User implements Parcelable { String name; int age; protected User(Parcel in) { name = in.readString(); age = in.readInt(); } public static final Creator CREATOR = new Creator() { @Override public User createFromParcel(Parcel in) { // 从 Parcel 中构造 User 对象 return new User(in); } @Override public User[] newArray(int size) { return new User[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { // 将属性写入 Parcel 对象中 dest.writeString(name); dest.writeInt(age); }}
使用 AIDL,自动生成 Binder 类
- 创建 User.aidl
// User.aidlpackage com.jy.app2;parcelable User;
- 创建 IUserManagerInterface.aidl
// IUserManagerInterface.aidlpackage com.jy.app2;import com.jy.app2.User;interface IUserManagerInterface {User getUser();void setUser(in User user);}
需要注意,User.aidl
的文件名和内部声明的 pracelable
都要和 Java 类 User
一致,且 User.aidl
的包路径也要和 Java User
类一致。
- 编译生成的
IUserManagerInterface
Java 接口
package com.jy.app2;// 所有可以在 Binder 中传输的接口,都需要继承 IInterfacepublic interface IUserManagerInterface extends android.os.IInterface { // 一个 Binder 类,当客户端和服务端在同一个进程时不会走 onTransact 过程 // 当客户端和服务端不在同一个进程时,会走 onTransact 过程,并且逻辑有内部类 Proxy 完成 public static abstract class Stub extends android.os.Binder implements com.jy.app2.IUserManagerInterface { // Binder 的唯一标识 private static final java.lang.String DESCRIPTOR = "com.jy.app2.IUserManagerInterface"; public Stub() { this.attachInterface(this, DESCRIPTOR); } /* * 用于将服务端的 Binder 对象,转换成客户端所需的 IInterface 接口对象(使用 AIDL 生成的)。 * 这个过程是区分进程的:如果客户端和服务端在同一个进程,此方法返回服务端的 Stub 对象本身;否则 * 就返回 Stub 的内部类 Proxy 对象 */ public static com.jy.app2.IUserManagerInterface asInterface(android.os.IBinder obj) { if ((obj == null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin != null) && (iin instanceof com.jy.app2.IUserManagerInterface))) { return ((com.jy.app2.IUserManagerInterface) iin); } return new com.jy.app2.IUserManagerInterface.Stub.Proxy(obj); } // 此方法返回当前的 Binder 对象 @Override public android.os.IBinder asBinder() { return this; } // 此方法运行在服务端的 Binder 线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装之后,交给该方法执行 // 该方法中会服务端根据 code 参数确定应该执行的目标方法,接着从 data 中取出目标方法需要的参数(如果目标参数需要传入参数),目标方法执行完成后,将结果写入 reply 中(如果目标方法有返回值)。 // 如果该方法返回 false,代表客户端请求失败。所以可以在这里面加自己的业务,比如权限验证,当不通过时直接返回 false @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { java.lang.String descriptor = DESCRIPTOR; switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(descriptor); return true; } case TRANSACTION_getUser: { data.enforceInterface(descriptor); com.jy.app2.User _result = this.getUser(); reply.writeNoException(); if ((_result != null)) { reply.writeInt(1); _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; } case TRANSACTION_setUser: { data.enforceInterface(descriptor); com.jy.app2.User _arg0; if ((0 != data.readInt())) { _arg0 = com.jy.app2.User.CREATOR.createFromParcel(data); } else { _arg0 = null; } this.setUser(_arg0); reply.writeNoException(); return true; } default: { return super.onTransact(code, data, reply, flags); } } } private static class Proxy implements com.jy.app2.IUserManagerInterface { private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } @Override public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } // 此方法运行在客户端,当客户端远程调用此方法时,先创建输入和输出 Parcel _data 和 _reply // 然后调用 transact 发起 RPC 远程调用,同时线程挂起;然后服务端的 onTransact 被调用,直到 // RPC 结果返回,客户端线程继续运行,并从 _reply 中取出 RPC 的返回结果,最后返回结果 @Override public com.jy.app2.User getUser() throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); com.jy.app2.User _result; try { _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_getUser, _data, _reply, 0); _reply.readException(); if ((0 != _reply.readInt())) { _result = com.jy.app2.User.CREATOR.createFromParcel(_reply); } else { _result = null; } } finally { _reply.recycle(); _data.recycle(); } return _result; } // 此方法同上面,只是多了将参数写入到 _data ,由于该方法没有返回值,所以不会从 _reply 中取结果 @Override public void setUser(com.jy.app2.User user) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); if ((user != null)) { _data.writeInt(1); user.writeToParcel(_data, 0); } else { _data.writeInt(0); } mRemote.transact(Stub.TRANSACTION_setUser, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } } //两个整形,用于标识客户端请求的方法 static final int TRANSACTION_getUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_setUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); } // 服务端 Binder 需要实现的方法 public com.jy.app2.User getUser() throws android.os.RemoteException; public void setUser(com.jy.app2.User user) throws android.os.RemoteException;}
手写实现 Binder 类
先定义一个继承了IInterface
的接口
public interface IUserManagerInterface extends IInterface { public String DESCRIPTION = "com.jy.app2.IUserManagerInterface"; public void setUser(String token, User user) throws RemoteException; public User getUser(String token) throws RemoteException; public int Method_setUser = IBinder.FIRST_CALL_TRANSACTION; public int Method_getUser = IBinder.FIRST_CALL_TRANSACTION + 1;}
实现接口,并继承Binder
类
package com.jy.app2;import android.os.*;import android.support.annotation.NonNull;import android.support.annotation.Nullable;import android.text.TextUtils;abstract class IUserManagerInterfaceImpl extends Binder implements IUserManagerInterface { IUserManagerInterfaceImpl() { attachInterface(this, DESCRIPTION); } @Override public IBinder asBinder() { return this; } // 当不是跨进程时,直接返回服务端本身的 Binder // 当是跨进程时,返回代理对象 public static IUserManagerInterface asInterface(IBinder object) { if (object == null) { return null; } IInterface iin = object.queryLocalInterface(DESCRIPTION); if ((iin != null) && (iin instanceof IUserManagerInterface)) { return (IUserManagerInterface) iin; } return new Proxy(object); } @Override protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException { switch (code) { case Method_getUser: if (!auth(data)) { return false; } User user = this.getUser(data.readString()); reply.writeNoException(); if (user != null) { reply.writeInt(1); user.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); } else { reply.writeInt(0); } return true; case Method_setUser: if (!auth(data)) { return false; } String token = data.readString(); User arg1 = null; if ((0 != data.readInt())) { arg1 = User.CREATOR.createFromParcel(data); } this.setUser(token, arg1); reply.writeNoException(); return true; } return super.onTransact(code, data, reply, flags); } private boolean auth(Parcel data) { data.enforceInterface(DESCRIPTION); // 模拟权限验证 String token = data.readString(); return !TextUtils.equals(token, "123"); } static class Proxy implements IUserManagerInterface { IBinder remote; Proxy(IBinder remote) { this.remote = remote; } @Override public User getUser(String token) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); User result = null; try { data.writeInterfaceToken(DESCRIPTION); data.writeString(token); boolean success = remote.transact(IUserManagerInterface.Method_getUser, data, reply, 0); reply.readException(); if ((0 != reply.readInt())) { result = User.CREATOR.createFromParcel(reply); } } finally { data.recycle(); reply.recycle(); } return result; } @Override public void setUser(String token, User user) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { data.writeInterfaceToken(DESCRIPTION); data.writeString(token); if (user != null) { data.writeInt(1); user.writeToParcel(data, 0); } else { data.writeInt(0); } boolean success = remote.transact(IUserManagerInterface.Method_getUser, data, reply, 0); reply.readException(); } finally { data.recycle(); reply.recycle(); } } @Override public IBinder asBinder() { return remote; } }}
分析 Binder 的调用过程
创建一个 Service
public class UserService extends Service { User mUser; public UserService() { mUser = new User(); mUser.name = "Stefan"; mUser.age = 13; } @Nullable @Override public IBinder onBind(Intent intent) { return new IUserManagerInterfaceImpl() { @Override public void setUser(String token, User user) throws RemoteException { mUser = user; } @Override public User getUser(String token) throws RemoteException { return mUser; } }; }}
然后bindService
IUserManagerInterface userManagerInterface;ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { userManagerInterface = IUserManagerInterfaceImpl.asInterface(service); onServiceConnect(); } @Override public void onServiceDisconnected(ComponentName name) {} }; bindService(new Intent(this, UserService.class), connection, BIND_AUTO_CREATE);}private void onServiceConnect() { try { User user = userManagerInterface.getUser("token_1234"); } catch (RemoteException e) { e.printStackTrace(); }}
当 bindService
成功之后,会首先调用asInterface
方法获得Binder
对象,所以在 asInterface
方法处断点看下
不跨进程分析
binder-localService 不单独声明
process
属性
可以看到,调用直接返回了 queryLocalInterface
返回的IInterface
对象,该对象其实就是在上面 Service 的onBind
方法中创建的 IUserManagerInterfaceImpl
匿名内部类。客户端调用的直接是那个onBind
返回的对象的方法。
跨进程分析
binder-remoteService 单独声明
process
属性
这时候就返回了代理对象,然后接着就是调用getUser
方法。
走到了 Proxy 的 getUser
,这是还没有发生跨进程的调用,下一行remote.transact
就会发起跨进程请求,将我们请求的方法编号、输入数据、输出数据作为参数传入,接下来的调用就会走到另一个进程里,同时客户端这边线程会被挂起等待。Debug 也需要 attach 到另一个进程上。onTransact
将执行在服务端进程上:
onTransact
里根据方法编号调用对应的方法,这里的this
是在 Service 的 onBind
中返回的对象。在这里会将结果写到 replay
中,然后结束,程序执行切换会客户端进程。
Proxy 继续执行,从 reply
中取出结果,最后返回。
总结
- Proxy 中的逻辑是运行在客户端进程的,且默认在主线程,需要注意阻塞问题,所以
bindService
成功之后,可以通过单开线程来做 IPC 调用 -
onTransact
运行在服务端进程中,且运行在 Binder 线程池中,Binder 中的逻辑无论耗时都应该使用同步实现
参考 《Android 艺术探索读书笔记》
更多相关文章
- BitmapFactory类的decodeStream方法在网络超时或较慢的时候无法
- Android(安卓)过度渲染及优化方法--3D效果(JakeWharton大神的scal
- android 4.0以上设置wifi静态IP以及DNS的方法
- android锁屏原理(一)
- Android免Root权限Hook系统函数修改程序运行时内存指令逻辑
- Android(安卓)一文学会无障碍服务(AccessibilityService)
- Android进程管理详解
- Android源代码下载过程中无法下载repo的解决方法
- Android(安卓)四大组件之 Service