Rockchip系列之客制化GPIO接口jni+service接口访问(4)

简介: Rockchip系列之客制化GPIO接口jni+service接口访问(4)

在上一篇博客中,我介绍了如何在Android HAL层中实现GPIO接口的驱动。在这篇博客中,将继续探讨如何在JNI层中实现GPIO接口的函数,以及如何在Java层中添加Server调用JNI层的函数。

JNI层的GPIO接口函数

JNI层是Java层和Native层之间的桥梁,它提供了一组标准的接口和数据类型,用于在Java层和Native层之间传递参数和返回值。JNI层的主要作用是使得Java层可以使用Native层的功能,例如访问硬件设备、执行系统命令等。

为了在JNI层中实现GPIO接口的函数步骤:

  1. 定义Java类和Native方法
  2. 实现Native方法
  3. 注册Native方法

下面我们来具体看一下每个步骤的细节。

实现Native方法

我们需要在frameworks/base/services/core/jni/com_android_server_GpioService.cpp文件中实现上述定义的Java类中的Native方法。这些Native方法主要是通过调用Android HAL层提供的GPIO接口函数来与底层的GPIO驱动进行通信。为了实现一个Native方法,我们需要遵循以下的格式:

JNIEXPORT 返回值类型 JNICALL Java_完整类名_方法名(JNIEnv *env, jobject obj, ...);

env是一个指向JNI环境的指针,它提供了一些JNI相关的函数和变量,例如获取和设置Java对象的字段和方法等。obj是一个指向Java对象的引用,它可以用于访问Java对象的属性和方法。...是可选的参数列表,它们对应了Java方法的参数。在我们的例子中,我们实现了以下几个Native方法:

#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include "android_runtime/AndroidRuntime.h"
#include <utils/misc.h>
#include <utils/Log.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <hardware/gpio_hal.h>
namespace android
{
static struct gpio_device_t* gpioDevice;
jint gpioOpen(JNIEnv *env, jobject cls)
{
    jint err;
    hw_module_t* module;
    hw_device_t* device;
    
    ALOGI("native gpioOpen ...");
    // hw_get_module finds the library by "gpio" (this is the id of hal)
    err = hw_get_module("gpio", (hw_module_t const**)&module);
    if(err == 0) {
        // Get device : module->methods->open
        err = module->methods->open(module, NULL, &device);
        if(err == 0) {
            // Call gpio_open
            gpioDevice = (gpio_device_t *)device;
            return gpioDevice->gpio_open(gpioDevice);
        } else {
            return -1;
        }
    }
    return -1;
}
void gpioClose(JNIEnv *env, jobject cls)
{
    ALOGI("native gpioClose ...");
}
jint gpioWrite(JNIEnv *env, jobject cls, jint gpio, jint value)
{
    ALOGI("native gpioWrite gpio=%d, value=%d", gpio, value);
    return gpioDevice->gpio_write(gpioDevice, gpio, value);
}
jint gpioRead(JNIEnv *env, jobject cls, jint gpio)
{
    ALOGI("native gpioRead gpio=%d", gpio);
    return gpioDevice->gpio_read(gpioDevice, gpio);
}
jint gpioDirection(JNIEnv *env, jobject cls, jint gpio, jint direction, jint value)
{
    ALOGI("native gpioRead gpio=%d", gpio);
    return gpioDevice->gpio_direction(gpioDevice, gpio, direction, value);
}
jint gpioRegKeyEvent(JNIEnv *env, jobject cls, jint gpio)
{
    ALOGI("native gpioRegKeyEvent gpio=%d", gpio);
    return gpioDevice->gpio_reg_key_event(gpioDevice, gpio);
}
jint gpioUnregKeyEvent(JNIEnv *env, jobject cls, jint gpio)
{
    ALOGI("native gpioUnregKeyEvent gpio=%d", gpio);
    return gpioDevice->gpio_unreg_key_event(gpioDevice, gpio);
}
jint gpioGetNumber(JNIEnv *env, jobject cls)
{
    ALOGI("native gpioGetNumber");
    return gpioDevice->gpio_get_number(gpioDevice);
}
// Register native methods
static const JNINativeMethod methods[] = {
    {"native_gpioOpen", "()I", (void *)gpioOpen},
    {"native_gpioClose", "()V", (void *)gpioClose},
    {"native_gpioWrite", "(II)I", (void *)gpioWrite},
    {"native_gpioRead", "(I)I", (void *)gpioRead},
    {"native_gpioDirection", "(III)I", (void *)gpioDirection},
    {"native_gpioRegKeyEvent", "(I)I", (void *)gpioRegKeyEvent},
    {"native_gpioUnregKeyEvent", "(I)I", (void *)gpioUnregKeyEvent},
    {"native_gpioGetNumber", "()I", (void *)gpioGetNumber},
};
    
int register_android_server_GpioService(JNIEnv *env)
{
    // The Java method corresponding to the local method GpioService
    return jniRegisterNativeMethods(env, "com/android/server/GpioService",
    methods, NELEM(methods));
}
}

注册Native方法

我们需要在frameworks/base/services/core/jni/onload.cpp文件中注册Native方法,以便Java层可以通过JNI接口来调用Native层的函数。这一步主要是通过调用jniRegisterNativeMethods函数,传入Java类的完整名字和Native方法的数组,来完成注册。代码如下:

//--------这一步可以参考其他jni的添加 , 看源码就懂了。
int register_android_server_GpioService(JNIEnv* env);
register_android_server_GpioService(env);

Service层的GPIO接口服务

Service层是Android系统中提供各种系统服务的层级,它主要是通过Binder机制来与应用层进行通信。Binder机制是一种跨进程通信(IPC)的方式,它可以实现不同进程之间的数据传输和方法调用。Binder机制的主要优点是高效、安全和灵活。

为了在Service层中实现GPIO接口的服务,我们需要遵循以下几个步骤:

  1. 定义GPIO服务的AIDL接口
  2. 实现GPIO服务的Java类

定义GPIO服务的AIDL接口

首先,需要在frameworks/base/core/java/android/btf/IGpioService.aidl文件中定义一个GPIO服务的AIDL接口IGpioService,它声明了一些GPIO相关的方法,例如打开、关闭、读写、方向设置等。AIDL接口是一种用于描述Binder通信协议的语言,它可以自动地生成Java和Native层之间的代理和存根代码,从而简化了IPC的过程。代码如下:

package android.btf;
interface IGpioService
{
        int gpioWrite(int gpio, int value);
        int gpioRead(int gpio);
        int gpioDirection(int gpio, int direction, int value);
        int gpioRegKeyEvent(int gpio);
        int gpioUnregKeyEvent(int gpio);
        int gpioGetNumber();
}

实现GPIO服务的Java类

我们需要在frameworks/base/services/core/java/com/android/server/GpioService.java文件中实现一个GPIO服务的Java类GpioService,它继承自IGpioService.Stub类,并实现了IGpioService接口。这个类主要是用于提供给应用层调用的服务类,它包含了一些GPIO相关的Native方法,例如打开、关闭、读写、方向设置等。这些Native方法都是在Native层的C代码中完成的,而不是在Java代码中。为了声明一个Native方法,我们需要在方法前加上native关键字,并且不需要提供方法体。代码如下:

package com.android.server;
import android.btf.IGpioService;
public class GpioService extends IGpioService.Stub
{
    private static final String TAG = "GpioService";
    /* call native c function to access hardware */
    public int gpioWrite(int gpio, int value) throws android.os.RemoteException
    {
        return native_gpioWrite(gpio, value);
    }
    
    public int gpioRead(int gpio) throws android.os.RemoteException
    {
        return native_gpioRead(gpio);
    }
    
    public int gpioDirection(int gpio, int direction, int value) throws android.os.RemoteException
    {
        return native_gpioDirection(gpio, direction, value);
    }
    
    public int gpioRegKeyEvent(int gpio) throws android.os.RemoteException
    {
        return native_gpioRegKeyEvent(gpio);
    }
    
    public int gpioUnregKeyEvent(int gpio) throws android.os.RemoteException
    {
        return native_gpioUnregKeyEvent(gpio);
    }
    
    public int gpioGetNumber() throws android.os.RemoteException
    {
        return native_gpioGetNumber();
    }
    
    public GpioService()
    {
        native_gpioOpen();
    }
    public static native int native_gpioOpen();
    public static native void native_gpioClose();
    public static native int native_gpioWrite(int gpio, int value);
    public static native int native_gpioRead(int gpio);
    public static native int native_gpioDirection(int gpio, int direction, int value);
    public static native int native_gpioRegKeyEvent(int gpio);
    public static native int native_gpioUnregKeyEvent(int gpio);
    public static native int native_gpioGetNumber();
}

总结

本篇文章介绍了如何在Android native中添加JNI 对Hardware的接口调用 , 基本到这我们就可以在Android应用中利用我们添加的Gpio Server来调用 , 最后一篇作为补充 简单讲解一下封装和应用如何调用。

相关文章
|
1月前
|
存储 Java Android开发
Rockchip系列之UART 新增framework系统jni+service接口访问(2)
Rockchip系列之UART 新增framework系统jni+service接口访问(2)
31 1
|
1月前
|
Java Android开发 C++
Rockchip系列之CAN 新增framework系统jni接口访问(2)
Rockchip系列之CAN 新增framework系统jni接口访问(2)
28 3
|
1月前
|
Java Android开发
Rockchip系列之VendorStorage 新增framework系统jni+service接口访问(3)
Rockchip系列之VendorStorage 新增framework系统jni+service接口访问(3)
32 0
|
1月前
|
存储 Linux 开发工具
Rockchip系列之浅度分析UART接口系列(1)
Rockchip系列之浅度分析UART接口系列(1)
120 1
|
1月前
|
内存技术
【HARDWARE】 --- SPI接口协议介绍与应用说明
【HARDWARE】 --- SPI接口协议介绍与应用说明
112 3
|
1月前
|
存储 传感器 JSON
Rockchip系列之VendorStorage 新增framework封装VendorStorageManager访问(4)
Rockchip系列之VendorStorage 新增framework封装VendorStorageManager访问(4)
31 0
|
1月前
|
Java Shell Android开发
Rockchip系列之CAN 新增framework封装service+manager访问(3)
Rockchip系列之CAN 新增framework封装service+manager访问(3)
26 2
|
11月前
|
API
API&SPI的区别?
API&SPI的区别?
380 0
|
Shell Linux 网络性能优化
|
网络性能优化