Binder 机制】AIDL 分析 ( AIDL 通信完整流程梳理 )

网友投稿 797 2022-05-30

文章目录

AIDL 跨进程通信完整流程梳理

1、AIDL 文件编译

2、注册服务

3、IMyAidlInterface.Stub.asInterface 方法获取远程服务

4、IMyAidlInterface.Stub.Proxy 代理类

5、IMyAidlInterface.Stub.Proxy 代理类方法执行

6、Binder.transact 方法执行

7、IMyAidlInterface.Stub.onTransact 方法执行

8、调用 Service 中实现的 IMyAidlInterface.Stub 抽象方法

AIDL 跨进程通信完整流程梳理

1、AIDL 文件编译

AIDL 文件 IMyAidlInterface.aidl 在客户端和服务端都有 , 编译时 , 都会在 " build\generated\aidl_source_output_dir\debug\out\kim\hsl\aidl_demo " 目录生成 IMyAidlInterface.java 源文件 ;

这样在客户端与服务器端都可以调用 IMyAidlInterface.Stub 类的相关方法 , 主要是 asInterface 方法 , 用于获取远程服务或代理 ;

2、注册服务

在应用中 , 通过绑定 Service 注册服务 ;

// 通过 Action 和 包名 , 绑定远程服务 Intent intent = new Intent("android.intent.action.MyService"); intent.setPackage("kim.hsl.aidl_demo"); bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);

1

2

3

4

3、IMyAidlInterface.Stub.asInterface 方法获取远程服务

开启一个 ServiceConnection , 在 ServiceConnection 的 onServiceConnected 方法中 ,

调用 IMyAidlInterface.Stub.asInterface 方法 ,

在 IMyAidlInterface.Stub.asInterface 方法中 , 传入我们需要的 Service 远程服务 ; 这里涉及到跨进程调用 , 拿到的是一个代理 ;

Stub 中定义了 asInterface 方法 , 该方法的作用是将 android.os.IBinder 对象转为 AIDL 接口对象 ; 传入的 DESCRIPTOR 描述符 , 用于描述用户想要哪个 Binder , android.os.IBinder 对象调用 queryLocalInterface 方法 , 检查本地服务是否存在 ;

如果可以找到本地服务对应的接口 , 可以直接返回本地服务 ;

如果没有找到本地服务 , 就会返回一个 Stub 代理 ;

详细的过程参考下面的代码 :

/** * 将IBinder对象强制转换为kim.hsl.aidl_demo.IMyAidlInterface接口,必要时生成代理。 */ public static kim.hsl.aidl_demo.IMyAidlInterface asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } // 传入 DESCRIPTOR 描述符 , 用于描述用户想要哪个 Binder // android.os.IBinder 对象调用 queryLocalInterface 方法 , 检查本地服务 android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); // 如果可以找到本地服务对应的接口 , 可以直接返回本地服务 if (((iin!=null)&&(iin instanceof kim.hsl.aidl_demo.IMyAidlInterface))) { return ((kim.hsl.aidl_demo.IMyAidlInterface)iin); } // 如果没有找到本地服务 , 就会返回一个 Stub 代理 return new kim.hsl.aidl_demo.IMyAidlInterface.Stub.Proxy(obj); }

1

2

3

4

5

6

7

8

9

【Binder 机制】AIDL 分析 ( AIDL 通信完整流程梳理 )

10

11

12

13

14

15

16

17

18

4、IMyAidlInterface.Stub.Proxy 代理类

上述 IMyAidlInterface.Stub.asInterface 方法 , 最终返回一个代理 , 代理如下 :

在 IMyAidlInterface.java 中的代理中 , 实现了 3 3 3 个 AIDL 接口方法 ;

private static class Proxy implements kim.hsl.aidl_demo.IMyAidlInterface { 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; } /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException { } /** * in 写入, out 输出, inout 写入和输出 */ @Override public void addStudent(kim.hsl.aidl_demo.Student student) throws android.os.RemoteException { } /** * 获取 Student 集合 */ @Override public java.util.List getStudents() throws android.os.RemoteException { return _result; } }

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

5、IMyAidlInterface.Stub.Proxy 代理类方法执行

在主应用中 , 调用 IMyAidlInterface aidl 也就是 IMyAidlInterface.Stub.asInterface 方法返回的代理对象的 addStudent 方法 , 分析代理中的该方法 , 首先生成输入和输出数据 , 传参和反参都会传入 mRemote.transact 方法中 , 这是 Binder 的方法 ;

/** * in 写入, out 输出, inout 写入和输出 */ @Override public void addStudent(kim.hsl.aidl_demo.Student student) throws android.os.RemoteException { // 通过 Parcel 池获得两个对象 , 分别用于输入和输出 // 输入对象 android.os.Parcel _data = android.os.Parcel.obtain(); // 输出对象 android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); if ((student!=null)) { _data.writeInt(1); student.writeToParcel(_data, 0); } else { _data.writeInt(0); } // 调用 Binder 的 transact 方法 boolean _status = mRemote.transact(Stub.TRANSACTION_addStudent, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().addStudent(student); return; } _reply.readException(); if ((0!=_reply.readInt())) { student.readFromParcel(_reply); } } finally { _reply.recycle(); _data.recycle(); } }

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

6、Binder.transact 方法执行

Binder 中的 transact 方法执行后 , 会回调 IMyAidlInterface.java 中的 Stub 内部类的 onTransact 方法 ,

Binder 的 transact 方法 ; 进入该方法后 , 会将原来的线程挂起 , 直到返回 , 原来的线程才会继续执行 , 这里非常容易出现 ANR ;

/** * 远程对象的基类,由{@link IBinder}定义的轻量级远程过程调用机制的核心部分。 * 此类是IBinder的一个实现,它提供了此类对象的标准本地实现。 * *

大多数开发人员不会直接实现这个类, * 而是使用aidl工具来描述所需的接口, * 让它生成适当的Binder子类。 * 然而,您可以直接从Binder派生来实现您自己的定制RPC协议, * 或者直接实例化一个原始Binder对象,将其用作可以跨进程共享的令牌。 * *

这个类只是一个基本的IPC原语; * 它对应用程序的生命周期没有影响,并且只有创建它的进程继续运行时才有效。 * 要正确使用此功能,您必须在顶级应用程序组件(a{@link android.app.Service}、 * {@link android.app.Activity}或{@link android.content.ContentProvider}) * 的上下文中执行此操作,该组件应保持运行。

* *

您必须记住流程可能会消失的情况,因此需要稍后重新创建新的活页夹, * 并在流程再次启动时重新附加它。 * 例如,如果您在{@link android.app.Activity}中使用此函数, * 则您的活动的进程可能会在活动未启动时被终止; * 如果以后重新创建活动,则需要创建新的活页夹, * 并再次将其交回正确的位置; * 您需要注意的是,您的流程可能由于其他原因(例如接收广播)而启动, * 这将不涉及重新创建活动,因此运行其代码以创建新的绑定。

* * @see IBinder */ public class Binder implements IBinder { /** * 默认实现回放地块并调用onTransact。在远程端,transact调用绑定器来执行IPC。 */ public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException { if (false) Log.v("Binder", "Transact: " + code + " to " + this); if (data != null) { data.setDataPosition(0); } boolean r = onTransact(code, data, reply, flags); if (reply != null) { reply.setDataPosition(0); } return r; } }

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

7、IMyAidlInterface.Stub.onTransact 方法执行

在 IMyAidlInterface.Stub.onTransact 方法中 , 通过方法对应的 ID 常量值匹配方法 , 在该方法中就会调用 IMyAidlInterface.Stub 中没有实现的抽象方法 ;

@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_basicTypes: { return true; } case TRANSACTION_addStudent: { return true; } case TRANSACTION_getStudents: { return true; } default: { return super.onTransact(code, data, reply, flags); } } }

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

8、调用 Service 中实现的 IMyAidlInterface.Stub 抽象方法

IMyAidlInterface.Stub 中的抽象方法 , 在 Service 中实现 ;

/** * 创建 IMyAidlInterface.Stub 抽象类子类对象 , 实现其中的 3 个抽象方法 * Binder 调用 transact 方法时 , 会调用 IMyAidlInterface.Stub 的 onTransact 方法 * 在 IMyAidlInterface.Stub.onTransact 方法中会调用下面实现的抽象方法 */ private IMyAidlInterface.Stub stub = new IMyAidlInterface.Stub() { @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException { Log.i(TAG, "anInt=" + anInt + " , aLong=" + aLong + " , aBoolean=" + aBoolean + " , aFloat=" + aFloat + " , aDouble=" + aDouble + " , aString=" + aString); } @Override public void addStudent(Student student) throws RemoteException { if (students != null) { students.add(student); } } @Override public List getStudents() throws RemoteException { return students; } };

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

任务调度

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Qt 之 ActiveX控件跑官方例程记录
下一篇:关于前端的碎碎念2-CSS装修之盒子模型
相关文章