源码基于:Android R
0. 前言
在之前的几篇博文中,对Android binder 的通信原理进行的深入的剖析,这些博文包括:binder 简介、servicemanager启动、service注册、service获取、Java 端的service 注册和获取。
在前一文中,通过实例,详细地说明了native 下 的C-S 通信原理。
本文在之前的基础上,以实例的形式进一步的分析 java 下的 C-S 通信。
1. aidl
App 中使用 binder 进行通信时都会使用 aidl,这样的使用 framework 也很常见,而系统在编译的时候都会根据 aidl 的接口定义,自动编译出对应的 Java 文件。
最新的版本中 aidl 不但能够保证 Java 端的 C - S通信,也能保证 Java client - native service 的通信。
这里以PMS 的install 为例,PMS 在进行APK 安装时,会进行dex 的翻译,依赖守护进程installd 完成。
frameworks/native/cmds/installd/binder/android/os/IInstalld.aidl
package android.os;
/** {@hide} */
interface IInstalld {
...
}
2. Java 端调用
frameworks/base/services/core/java/com/android/server/pm/installer.java
import android.os.IInstalld;
public class Installer extends SystemService {
private volatile IInstalld mInstalld;
private void connect() {
IBinder binder = ServiceManager.getService("installd");
if (binder != null) {
...
}
if (binder != null) {
mInstalld = IInstalld.Stub.asInterface(binder);
...
}
}
public long createAppData(String uuid, String packageName, int userId, int flags, int appId,
String seInfo, int targetSdkVersion) throws InstallerException {
if (!checkBeforeRemote()) return -1;
try {
return mInstalld.createAppData(uuid, packageName, userId, flags, appId, seInfo,
targetSdkVersion);
} catch (Exception e) {
throw InstallerException.from(e);
}
}
...
}
上述代码中主要注意:
- 引用的aidl 为android.os.IInstalld;
- 通过 getService("installd") 获取到IBinder;
- IInstalld.Stub.asInterface() 获取代理;
主要是确定aidl 编译后的源码位置,对于Android R,framework 下的aidl 会统一到目录out\soong\.intermediates\frameworks\base\module-lib-api\android_common\gen\aidl 下。
aidl 编译后的JAVA 文件都会最终打包到 aidl*.srcjar 中,那具体的文件怎么确定呢?需要依赖frameworks 文件夹或者 system 文件夹的 *.aidl.d 文件。
如果aidl 文件是定义在frameworks 下,那么就可以到framework 下对应的目录查找对应的 *.aidl.d 文件。同样,如果aidl 是在 system 下定义,则可以到system 文件夹下查找 *.aidl.d 文件。例如这里的 IInstalld.aidl 是定义在 frameworks/native/cmds/installd 下,那就到frameworks 文件夹下对应位置找到 IIntalld.aidl.d 文件:
out/soong/.intermediates/frameworks/base/module-lib-api/android_common/gen/aidl/aidl27.tmp/frameworks/native/cmds/installd/binder/android/os/IInstalld.java : \
frameworks/native/cmds/installd/binder/android/os/IInstalld.aidl \
frameworks/native/cmds/installd/binder/android/os/storage/CrateMetadata.aidl
frameworks/native/cmds/installd/binder/android/os/IInstalld.aidl :
frameworks/native/cmds/installd/binder/android/os/storage/CrateMetadata.aidl :
第一行指定了 IInstalld.aidl 编译出的Java 文件位于aidl27.tmp,即上图中的 aidl27.srcjar 文件中,解压后就能找到 IInstalld.java:
package android.os;
/** {@hide} */
public interface IInstalld extends android.os.IInterface
{
...
public static abstract class Stub extends android.os.Binder implements android.os.IInstalld
{
...
public static android.os.IInstalld asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof android.os.IInstalld))) {
return ((android.os.IInstalld)iin);
}
return new android.os.IInstalld.Stub.Proxy(obj);
}
}
...
}
3. Java client 与 service 通信
对于binder service 有两种方式存在,java 端和native 端。但是对于client 只负责通过getService 查找到service 的代理,并通过此代理调用transact 通信,而对于service ,驱动只会通知其BBinder,并通过 onTransact 进行处理。
而,BBinder 也有两种方式存在,java service 为JavaBBinder(继承自BBinder),而native service 为BBinder。
所以,无论client 或service 位于java 端,还是native 端,根本原因都是BpBinder 与BBinder 的通信。
对于 Java 端的 binder 通信下面这个框架图,在 Java 端的service 注册和获取 一文中详细说明。
继续上面的 IInstalld.aidl,会在 out/soong/.intermediates/frameworks/native/cmds/installd/installd/.../gen/aidl/ 目录下面编译出几个文件。
该目录下 android/os 下面是编译出来的头文件:
该目录下 frameworks/native/cmds/installd/binder/android/os 下面是编译出来的实现文件:
而,installd 在native 有个service 继承了 BnInstalld:文章来源:https://www.toymoban.com/news/detail-508389.html
frameworks/native/cmds/installd/InstalldNativeService.h
class InstalldNativeService : public BinderService<InstalldNativeService>, public os::BnInstalld {
public:
...
};
至此,java下 C-S 的实例已经基本说明完毕,结合实际操作可以更好的理解 binder 的通信。 文章来源地址https://www.toymoban.com/news/detail-508389.html
到了这里,关于Android Binder通信原理(七):java 下的C-S的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!