0%

Android IPC

前言

Android IPC (Inter-Process Communication) 进程间通信或跨进程通信。

主要是 Binder 、AIDL 及 Android 跨进程通信的实现方式及原理简单梳理。

Android 中如何实现多进程。

通过给四大组件 (Activity、Service、Broadcast Receiver、ContentProvider )在 AndroidManifest.xml
文件中指定 android:process 属性即可。

当然,除了自身实现多进程之外,和其他应用通信其实也是在不经意中做了跨进程通信的事情。

Service 多进程

1
2
3
4
5
<service
android:name=".ipc.messenger.MessengerService"
android:enabled="true"
android:process=":remote"
android:exported="false" />

Activity 多进程

1
2
3
4
5
6
<activity
android:name=".ui.behavior.lifecycle.ActivityB"
android:process="com.engineer.android.mini.remote" />
<activity
android:name=".ui.behavior.lifecycle.ActivityC"
android:process=":remote" />

以上两种 process 属性的实现下,

  • ActivityB 的进程名即为: com.engineer.android.mini.remote, 同时此类进程属于全局进程,其他应用通过 ShareUID 的方式可以和他运行在同一个进程中。
  • ActivityC 的进程名为:{pacakage}:remote,同时此类进程属于当前应用的私有进程。

Android 跨进程的几种方式

Bundle

Activity/Service/Receiver 都可以通过 Intent 传递数据,同时 Intent.putExtras(Bundle bundle) 方法支持传递 Bundle,通过 Bundle 我们可以封装细碎的数据,比如基本类似,实现了 Parcelable 接口的对象和 Android 支持的一些特殊的对象。

使用文件共享

并入 A 进程写入,B 进程进行读操作。当然,需要考虑并发读写的问题。SharedPerference 不支持多进程。

Messenger

Messenger 其实就是对 AIDL 的一层封装,是一种轻量级的 IPC。

  • 创建服务端 Service
1
2
3
4
5
6
7
8
9
10
11
12
13
public class MessengerService extends Service {
private static final String TAG = "MessengerService";

public MessengerService() {
}

private final Messenger messenger = MessengerDelegate.provideMessenger();

@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
}
1
2
3
4
5
<service
android:name=".ipc.messenger.MessengerService"
android:enabled="true"
android:process=":remote"
android:exported="false" />

Service 在启动之后,在 onBind 中就可以通过 Messenger 获取到 IBinder 了。

  • 客户端启动 Service

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     private Messenger mRepliedMessenger = MessengerDelegate.provideMessenger();


    private ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
    Messenger messenger = new Messenger(service);
    Message message = Message.obtain(null, IPCConstants.MESSAGE_FROM_CLIENT);
    Bundle bundle = new Bundle();
    bundle.putString("msg", "this is from client");
    message.setData(bundle);
    message.replyTo = mRepliedMessenger;
    try {
    messenger.send(message);
    } catch (RemoteException e) {
    e.printStackTrace();
    }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
    };

    // 启动 Service

    Intent intent = new Intent(IpcActivity.this, MessengerService.class);
    bindService(intent, mConnection, Context.BIND_AUTO_CREATE);

在 onServiceConnected 中,通过服务端返回的 IBinder 对象,我们创建了本地的 Messenger 对象。同时创建了一个 Message 通过 Messenger.send(Message) 的方式,将一些数据发送到服务端去。**同时设定 Message 的 replayTo 属性为我们在本地创建的另一个 Messenger;mRepliedMessenger 。下面看看 Messenger 是如何处理消息的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class MessengerDelegate {
private static final String TAG = "MessengerDelegate";

public static Messenger provideMessenger() {
return new Messenger(new MessengerHandler(Looper.myLooper()));
}

private static class MessengerHandler extends Handler {
public MessengerHandler(Looper looper) {
super(looper);
}

@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case IPCConstants.MESSAGE_FROM_CLIENT:
Bundle data = msg.getData();
String result = data.getString("msg");

Log.e(TAG, "handleMessage: data = " + data);
Log.e(TAG, "handleMessage: result = " + result);

Messenger client = msg.replyTo;
Message reply = Message.obtain(null, IPCConstants.MESSAGE_FROM_SERVER);
Bundle bundle = new Bundle();
bundle.putString("reply", "server got message, and replied with happy");
reply.setData(bundle);
try {
client.send(reply);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case IPCConstants.MESSAGE_FROM_SERVER:
Bundle data1 = msg.getData();
String result1 = data1.getString("reply");

Log.e(TAG, "handleMessage: data = " + data1);
Log.e(TAG, "handleMessage: result = " + result1);
break;
default:
super.handleMessage(msg);
}
}
}
}

简单总结 ;

  1. 服务端收到客户端发送的消息后,通过 message.replyTo 获取到客户端要接收消息的 Messenger 对象。然后从服务端发送了新的消息去往客户端。
  2. 客户端接收消息也是,也是通过本地创建的 Messenger;mRepliedMessenger 的接收信息。
  3. 就服务端和客户端来说,他们本地的 Messenger 对象都是通过 Handler 创建的,客户端在启动服务端之后,为了向服务端发送消息,创建 Messenger 是通过服务端返回的 IBinder 对象实现的。

可以看到 Messenger 主要是串行的在服务端和客户端之间进行消息的传递。

AIDL

准备

  • 创建实现了 Parcelable 接口的类,以便用于在进程间通信
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.engineer.android.mini.ipc.aidl;

public class Book implements Parcelable {

public int bookId;
public String bookName;

public Book(int bookId, String bookName) {
this.bookId = bookId;
this.bookName = bookName;
}


@Override
public int describeContents() {
return 0;
}

@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(bookId);
dest.writeString(bookName);
}
public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {

@Override
public Book createFromParcel(Parcel source) {
return new Book(source);
}

@Override
public Book[] newArray(int size) {
return new Book[size];
}
};

private Book(Parcel in) {
bookId = in.readInt();
bookName = in.readString();
}
}
  • 创建 AIDL 接口
1
2
3
// Book.aidl
package com.engineer.android.mini.ipc.aidl;
parcelable Book;
1
2
3
4
5
6
7
8
9
10
11
12
// IBookInterface.aidl
package com.engineer.android.mini.ipc.aidl;
import com.engineer.android.mini.ipc.aidl.Book;

interface IBookInterface {

void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
//
List<Book> getBookList();
void addBook(in Book book);
}
加个鸡腿呗.