Java 调用 Native 服务

本文介绍一下怎么通过 Java 代码使用 Native Binder Service。

接下来我们演示使用 Java 代码访问 Binder 程序示例之 aidl-cpp 篇 编写的 Native Binder Service。

device/jelly/rice14 目录下创建如下的文件与文件夹:

bash 复制代码
JavaCallNativeService/
├── Android.bp
└── com
    └── yuandaima
        └── JavaClient.java

其中 JavaClient.java 内容如下:

java 复制代码
package com.yuandaima;

import android.util.Log;
import android.os.ServiceManager;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.Parcel;

public class JavaClient {
    public static void main(String[] args) {
        //获取Native Binder Service的代理
        IBinder binder = ServiceManager.getService("IHello");
        String DESCRIPTOR = "com.yuandaima.IHello";
        
        try {
            if (binder != null) {
                Parcel data = Parcel.obtain();
                Parcel replay = Parcel.obtain();
                try {
                    data.writeInterfaceToken(DESCRIPTOR);
                    //通过 BinderProxy 进行数据交互
                    binder.transact(IBinder.FIRST_CALL_TRANSACTION + 0, data, replay, 0);
                    int result = replay.readInt();
                    Log.e("Client","get result :" + result);
                } finally {
                    replay.recycle();
                    data.recycle();
                }
            }
 
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    
    }
}

主要分为 4 步执行:

  • 获得 Hello 服务,与 C++ 程序区别是这里不做转换了,直接使用 IBinder(实际类型是 BinderProxy)
  • 构建好两个 Parcel 结构,data reply
  • 通过 BinderProxy 的 transact 方法发起远程调用
  • 处理返回的 reply

接着我们在系统源码下执行:

bash 复制代码
source build/envsetup.sh
lunch 
make installclean

然后终端进入到 device/jelly/rice14/JavaCallNativeService,编译我们的源码:

bash 复制代码
mm

接着我们进入 device/jelly/rice14/AIDLCppDemo 目录下,编译 C++ 服务端:

bash 复制代码
mm

接着回到系统源码目录下,push 源码产物到 Android 模拟器上:

bash 复制代码
adb push out/target/product/rice14/system/bin/IHelloServer /data/local/tmp
adb push out/target/product/rice14/system/framework/JavaClient.jar /data/local/tmp

接着进入 Andorid shell,执行程序:

bash 复制代码
adb shell
cd /data/local/tmp
# 执行服务端
./IHelloServer & 
# 执行客户端
export CLASSPATH=/data/local/tmp/JavaClient.jar
app_process /data/local/tmp com.yuandaima.JavaClient

最后查看log:

bash 复制代码
logcat | grep JavaClient

从 log 中看出 Client 收到了回复的数据 0,证明我们的调用成功了。

以上介绍的方法算是一种简易的零时解决方案,更为完整的做法是利用 aidl 生成的文件来"衔接" Java 层和 C++ 层:

我们把 device/jelly/rice14/AIDLCppDemo/com/yuandaima/IHello.aidl 文件拷贝到 device/jelly/rice14/JavaCallNativeService/com/yuandaima,接着我们在终端中进入 device/jelly/rice14/JavaCallNativeService/com/yuandaima 目录,接着使用 aidl 生成代码:

bash 复制代码
aidl IHello.aidl

然后修改源码:

java 复制代码
package com.yuandaima;

import android.util.Log;
import android.os.ServiceManager;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.Parcel;

public class JavaClient {

    public static final String TAG = "JavaClient";

    public static void main(String[] args) {
        //获取Native Binder Service的代理
        IBinder binder = ServiceManager.getService("IHello");
        String DESCRIPTOR = "com.yuandaima.IHello";

        IHello svr = IHello.Stub.asInterface(binder);

        try {
	        svr.hello();
	        Log.i(TAG, "call hello");
        } catch (Exception e) {

        }
           
        try {
	        int cnt = svr.sum(3, 4);
	        Log.i(TAG, "call sum(3, 4)");
        } catch (Exception e) {
    
        }
    
    }
}

然后修改编译文件 Android.bp:

json 复制代码
java_library {
    name: "JavaClient",
    installable: true,
    srcs: [ "com/yuandaima/JavaClient.java",
            "com/yuandaima/IHello.java", ],
}

接着在 device/jelly/rice14/JavaCallNativeService 目录下单编模块:

bash 复制代码
mm

最后我们来测试一下:

bash 复制代码
adb push out/target/product/rice14/system/framework/JavaClient.jar /data/local/tmp
# 进入 Android shell 环境
adb shell
cd /data/local/tmp
./IHelloServer &
export CLASSPATH=/data/local/tmp/JavaClient.jar
app_process /data/local/tmp com.yuandaima.JavaClient

接着查看 log:

less 复制代码
logcat | grep aidl_cpp
08-08 11:15:42.935 29755 29756 I aidl_cpp: hello
08-08 11:15:42.936 29755 29756 I aidl_cpp: server: sum: 3 + 4

从 Log 可以看出我们的 Java 客户端已经成功访问到 Native Binder 服务了。

参考资料

关于

我叫阿豪,2015 年本科毕业于国防科学技术大学指挥信息系统专业,毕业后从事信息化装备的研发工作,主要研究方向是 Android Framework 与 Linux Kernel。

如果你对 Android Framework 感兴趣或者正在学习 Android Framework,可以关注我的微信公众号和抖音,我会持续分享我的学习经验,帮助正在学习的你少走一些弯路。学习过程中如果你有疑问或者你的经验想要分享给大家可以添加我的微信,我拉你进技术交流群。

相关推荐
小雨cc5566ru18 分钟前
uniapp+Android智慧居家养老服务平台 0fjae微信小程序
android·微信小程序·uni-app
一切皆是定数1 小时前
Android车载——VehicleHal初始化(Android 11)
android·gitee
一切皆是定数1 小时前
Android车载——VehicleHal运行流程(Android 11)
android
problc1 小时前
Android 组件化利器:WMRouter 与 DRouter 的选择与实践
android·java
图王大胜2 小时前
Android SystemUI组件(11)SystemUIVisibility解读
android·framework·systemui·visibility
服装学院的IT男6 小时前
【Android 13源码分析】Activity生命周期之onCreate,onStart,onResume-2
android
Arms2066 小时前
android 全面屏最底部栏沉浸式
android
服装学院的IT男6 小时前
【Android 源码分析】Activity生命周期之onStop-1
android
ChinaDragonDreamer9 小时前
Kotlin:2.0.20 的新特性
android·开发语言·kotlin
网络研究院11 小时前
Android 安卓内存安全漏洞数量大幅下降的原因
android·安全·编程·安卓·内存·漏洞·技术