概述
Android 中如何开启多进程
这里说一下一个应用开启多个进程的情况,不讨论多个应用多进程,Android开启多进程只有一种方法,在AndroidManifest文件中给四大组件指定 android:process属性,其实还有一种非常规的方法通过JNI在native层fork一个进程,这种属于特殊情况
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SecondActivity"
android:process=":remote" />
<activity
android:name=".ThreeActivity"
android:process="om.baidu.bpit.aibaidu.ipc.remote.aa" />
我们分别给SecondActivity和ThreeActivity指定了process属性,并且他们的属性值不同,所以现在又三个进程,MainActivity默认进程,默认进程进程名是包名,还有俩个我们自己指定的进程
我们通过shell命令,看一下是否有这些进程
$ adb shell ps | grep om.baidu.bpit.aibaidu.ipc
u0_a59 2343 204 1606528 98700 0 0000000000 S com.baidu.bpit.aibaidu.ipc
u0_a59 2360 204 1609616 97952 0 0000000000 S com.baidu.bpit.aibaidu.ipc:remote
u0_a59 2388 204 1766960 116352 0 0000000000 S om.baidu.bpit.aibaidu.ipc.remote.aa
我们发现SecondActivity和ThreeActivity指定进程名的方式不同一个是 android:process=":remote" ,一个是**android:process=“om.baidu.bpit.aibaidu.ipc.remote.aa”**这俩种有什么区别吗?
区别有两方面
- “:”的意思是在当前进程名上加上本包名,另一种是一个完整的命名方式
- “:”开头的进程,属于当前应用的私有进程,其他应用组件不可以和他跑在同一进程,完整包名的属于全局进程,应用可以通过ShareUid的方式可以和他跑在同一进程
Android 系统会为每一个进程分配一个唯一的Uid,具有相同Uid的应用才可以共享数据,比如data目录,组件信息等,不管他们是否跑在同一进程,如果他们跑在同一进程,那么除了共享data目录,组件信息,还可以共享内存
多进程会遇到的问题
每一个进程都会有一个独立的虚拟机,不同的虚拟机在内存分配不同的空间,所以只要需要通过共享内存,共享数据的操作都会失败
- 静态成员和单例完全失效
- 线程同步机制完全失效
- SharePreference可靠性下降,因为sp底层是通过读写xml来实现的,那么并发读写会发生问题
- Application多次创建
什么是Binder
- 直观来说Binder是Android中的一个类,实现了IBinder
- IPC角度来说,Binder是Android中一种跨进程通信的方式
- Binder还可以理解为一种虚拟的物理设备,他的驱动是dev/binder,这种通信方式linux中没有
- 从Android Framework角度来说,Binder是ServerManager连接各种Manager(如ActivityManager)和ManagerService的桥梁
- 从Android应用层来说,他是服务端和客户端通信的媒介
Android 中的IPC方式
- 使用Bundle,四大组件都是支持Bundle的,由于Bundle实现了Parcelable接口,可以在进程中传递数据,我们在一个进程中启动另一个进程的Bundle,可以进程间通信
- 使用文件共享
- 使用Messager
- 使用Aidl
- 使用ContentProvider
- 使用socket
分析一下AIDL源码
上篇博客我们分析了如何使用AIDL,这篇我们分析一下之前定义的BookName.aidl文件到底生成了什么,编译项目后我们可以在gen目录下找到BookName.java文件,这个就是aidl生成文件,我们看一下文件内容
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: /Users/v_renxiaohui01/Downloads/aidl/app/src/main/aidl/com/baidu/bpit/aibaidu/aidl/BookName.aidl
*/
package com.baidu.bpit.aibaidu.aidl;
public interface BookName extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.baidu.bpit.aibaidu.aidl.BookName {
private static final java.lang.String DESCRIPTOR = "com.baidu.bpit.aibaidu.aidl.BookName";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.baidu.bpit.aibaidu.aidl.BookName interface,
* generating a proxy if needed.
*/
public static com.baidu.bpit.aibaidu.aidl.BookName asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.baidu.bpit.aibaidu.aidl.BookName))) {
return ((com.baidu.bpit.aibaidu.aidl.BookName) iin);
}
return new com.baidu.bpit.aibaidu.aidl.BookName.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getName: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.getName();
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_getList: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.baidu.bpit.aibaidu.aidl.User> _result = this.getList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addInout: {
data.enforceInterface(DESCRIPTOR);
com.baidu.bpit.aibaidu.aidl.User _arg0;
if ((0 != data.readInt())) {
_arg0 = com.baidu.bpit.aibaidu.aidl.User.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addInout(_arg0);
reply.writeNoException();
if ((_arg0 != null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_addIn: {
data.enforceInterface(DESCRIPTOR);
com.baidu.bpit.aibaidu.aidl.User _arg0;
if ((0 != data.readInt())) {
_arg0 = com.baidu.bpit.aibaidu.aidl.User.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addIn(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_addout: {
data.enforceInterface(DESCRIPTOR);
com.baidu.bpit.aibaidu.aidl.User _arg0;
_arg0 = new com.baidu.bpit.aibaidu.aidl.User();
this.addout(_arg0);
reply.writeNoException();
if ((_arg0 != null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.baidu.bpit.aibaidu.aidl.BookName {
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;
}
@Override
public java.lang.String getName() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getName, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public java.util.List<com.baidu.bpit.aibaidu.aidl.User> getList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.baidu.bpit.aibaidu.aidl.User> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.baidu.bpit.aibaidu.aidl.User.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addInout(com.baidu.bpit.aibaidu.aidl.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_addInout, _data, _reply, 0);
_reply.readException();
if ((0 != _reply.readInt())) {
user.readFromParcel(_reply);
}
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void addIn(com.baidu.bpit.aibaidu.aidl.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_addIn, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void addout(com.baidu.bpit.aibaidu.aidl.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);
mRemote.transact(Stub.TRANSACTION_addout, _data, _reply, 0);
_reply.readException();
if ((0 != _reply.readInt())) {
user.readFromParcel(_reply);
}
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_addInout = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_addIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
static final int TRANSACTION_addout = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
}
public java.lang.String getName() throws android.os.RemoteException;
public java.util.List<com.baidu.bpit.aibaidu.aidl.User> getList() throws android.os.RemoteException;
public void addInout(com.baidu.bpit.aibaidu.aidl.User user) throws android.os.RemoteException;
public void addIn(com.baidu.bpit.aibaidu.aidl.User user) throws android.os.RemoteException;
public void addout(com.baidu.bpit.aibaidu.aidl.User user) throws android.os.RemoteException;
}
我们分析一下这个类,首先BookName.java继承自android.os.IInterface接口,同时他自己也是一个接口,所有在Binder传输的都需要继承IInterface接口,这个类首先声明了5个方法getName,getList,addInout,addin,addout,这些是我们在aidl文件定义的,同时他还为每个方法声明一个整形,为了在transct区分方法,当应用处于不同进程时需要走transct方法,这个逻辑由sub内部类proxy代理
IBinder
IBinder是一个接口,它代表了一种跨进程传输的能力;只要实现了这个接口,就能将这个对象进行跨进程传递;这是驱动底层支持的;在跨进程数据流经驱动的时候,驱动会识别IBinder类型的数据,从而自动完成不同进程Binder本地对象以及Binder代理对象的转换。
IInterface
这里的IInterface代表的就是远程server对象具有什么能力。具体来说,就是aidl里面的接口。
DESCRIPTOR
Binder的唯一标识,一般用Binder的类名表示,
private static final java.lang.String DESCRIPTOR = "com.baidu.bpit.aibaidu.aidl.BookName";
asInterface
用于将服务端的Binder转换为客户端所需的AIDL接口类型对象,这种转换是区分进程的,如果客户端和服务端位于同一进程,那么返回的就是服务端本身Stub的对象,如果是不同进程,就返回Stub.Proxy对象
asBinder
此方法用于返回当前的Binder对象
onTransact
该方法运行在服务端的Binder线程池中,当客户端发起跨进程请求时,请求会通过底层封装后,交由此方法处理,服务端通过code来判断客户端请求的方法是什么,接着从data取出目标方法需要的参数(如果目标方法有参数的话),然后执行目标方法,执行完之后就向reply中写入返回值(如果目标方法有返回值的话),这就是这个方法的执行过程,如果此方法返回false,那么客户端请求失败,可以以此做验证
Proxy/addList
此方法运行在客户端,当客户端调用从方法时,他的内部实现是这样的,首先准备输入型Parcel对象_data,输出型Parcel对象_reply,和返回值对象List,然后把该方法的参数写入_data(如果有参数的话),接着调用transact方法发起RPC(远程过程调用),同时当前线程挂起,然后服务端的onTransact方法会被调用,知道RPC过程返回后,当前线程继续执行,并从_reply取出返回结果
其他几个Proxy中的方法和此过程一样
这就是Binder工作机制,我们需要注意俩点
- 当客户端发起远程请求是时,当前线程会被挂起,知道服务端返回,如果远程方法是一个耗时方法,那不能在UI线程做
- 服务端的Binder方法运行在Binder线程池中,所以Binder方法不管是否耗时都可以同步调用
自定义一个Binder
从上方流程看出,其实我们可以不通过aidl就可以实现Binder,之所以有了Aidl是为了方便生成代码,那我们手动生成一个Bidner
首先生成一个aidl性质的接口,继承自IInterface即可,如下:
public interface CustomBookName extends IInterface {
static final java.lang.String DESCRIPTOR = "com.baidu.bpit.aibaidu.aidl.BookName";
static final int TRANSACTION_getName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_addInout = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_addIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
static final int TRANSACTION_addout = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
public java.lang.String getName() throws android.os.RemoteException;
public java.util.List<com.baidu.bpit.aibaidu.aidl.User> getList() throws android.os.RemoteException;
public void addInout(com.baidu.bpit.aibaidu.aidl.User user) throws android.os.RemoteException;
public void addIn(com.baidu.bpit.aibaidu.aidl.User user) throws android.os.RemoteException;
public void addout(com.baidu.bpit.aibaidu.aidl.User user) throws android.os.RemoteException;
}
之后我们需要实现一个Binder继承自Binder,和上方的接口
public abstract class CustomBinder extends Binder implements CustomBookName {
/**
* Construct the stub at attach it to the interface.
*/
public CustomBinder() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.baidu.bpit.aibaidu.aidl.BookName interface,
* generating a proxy if needed.
*/
public static CustomBookName asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof CustomBookName))) {
return (CustomBookName) iin;
}
return new CustomBinder.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getName: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.getName();
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_getList: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.baidu.bpit.aibaidu.aidl.User> _result = this.getList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addInout: {
data.enforceInterface(DESCRIPTOR);
com.baidu.bpit.aibaidu.aidl.User _arg0;
if ((0 != data.readInt())) {
_arg0 = com.baidu.bpit.aibaidu.aidl.User.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addInout(_arg0);
reply.writeNoException();
if ((_arg0 != null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
case TRANSACTION_addIn: {
data.enforceInterface(DESCRIPTOR);
com.baidu.bpit.aibaidu.aidl.User _arg0;
if ((0 != data.readInt())) {
_arg0 = com.baidu.bpit.aibaidu.aidl.User.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addIn(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_addout: {
data.enforceInterface(DESCRIPTOR);
com.baidu.bpit.aibaidu.aidl.User _arg0;
_arg0 = new com.baidu.bpit.aibaidu.aidl.User();
this.addout(_arg0);
reply.writeNoException();
if ((_arg0 != null)) {
reply.writeInt(1);
_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements CustomBookName {
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;
}
@Override
public java.lang.String getName() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(TRANSACTION_getName, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public java.util.List<com.baidu.bpit.aibaidu.aidl.User> getList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.baidu.bpit.aibaidu.aidl.User> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(TRANSACTION_getList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.baidu.bpit.aibaidu.aidl.User.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void addInout(com.baidu.bpit.aibaidu.aidl.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(TRANSACTION_addInout, _data, _reply, 0);
_reply.readException();
if ((0 != _reply.readInt())) {
user.readFromParcel(_reply);
}
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void addIn(com.baidu.bpit.aibaidu.aidl.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(TRANSACTION_addIn, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public void addout(com.baidu.bpit.aibaidu.aidl.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);
mRemote.transact(TRANSACTION_addout, _data, _reply, 0);
_reply.readException();
if ((0 != _reply.readInt())) {
user.readFromParcel(_reply);
}
} finally {
_reply.recycle();
_data.recycle();
}
}
}
}
这里面的主要方法,极其作用我们上方都讲过
下面我们使用一下自定义的Bidner类
- 首先实现自己的binder
class MyCustomBinder extends CustomBinder {
@Override
public String getName() throws RemoteException {
return "我是自定义的binder";
}
@Override
public List<User> getList() throws RemoteException {
return null;
}
@Override
public void addInout(User user) throws RemoteException {
}
@Override
public void addIn(User user) throws RemoteException {
}
@Override
public void addout(User user) throws RemoteException {
}
}
- 然后在service中返回自定义的binder
@Override
public IBinder onBind(Intent intent) {
return new MyCustomBinder();
}
- 把自定义的binder类拷进客户端
- 客户端绑定service获取binder
private void bindServer() {
Intent mIntent = new Intent();
//你定义的service的action
mIntent.setAction("com.aaa.aaa");
//这里你需要设置你应用的包名
mIntent.setPackage("com.baidu.bpit.aibaidu.aidl");
bindService(mIntent, new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
customBookName = CustomBinder.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}, BIND_AUTO_CREATE);
}
- 点击按钮调用自定义binder的getName方法
private void initView() {
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
String name = customBookName.getName();
Log.d("mmm",name);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
- 看下log
01-18 19:14:45.688 3554-3554/com.baidu.bpit.aibaidu.client D/mmm: 我是自定义的binder
成功了
最后
以上就是曾经白昼为你收集整理的Android IPC系列(二):AIDL源码分析的全部内容,希望文章能够帮你解决Android IPC系列(二):AIDL源码分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复