Android Binder通信原理(七):java 下的C-S

源码基于: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:

frameworks/native/cmds/installd/InstalldNativeService.h

class InstalldNativeService : public BinderService<InstalldNativeService>, public os::BnInstalld {
public:
    ...
};

至此,java下 C-S 的实例已经基本说明完毕,结合实际操作可以更好的理解 binder 的通信。 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

私房菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值