Rockchip系列之CAN 新增framework封装service+manager访问(3)

简介: Rockchip系列之CAN 新增framework封装service+manager访问(3)

Rockchip系列之深度分析CAN接口系列(1)_一歲抬頭的博客-CSDN博客

Rockchip系列之CAN 新增framework系统jni接口访问(2)-CSDN博客

Rockchip系列之CAN 新增framework封装service+manager访问(3)-CSDN博客

Rockchip系列之CAN APP测试应用实现(4)_一歲抬頭的博客-CSDN博客

Rockchip CAN 部分波特率收发不正常解决思路_一歲抬頭的博客-CSDN博客

Android JNI与CAN通信遇到的问题总结_android can通信-CSDN博客

Android 内核关闭CAN 串口设备回显功能_一歲抬頭的博客-CSDN博客

在上一篇博客中,我介绍了如何在Android平台上使用JNI来实现CAN通信的功能。在JNI层编写了一些本地方法,用于与CAN设备进行交互,并在Java层定义了相应的本地方法,用于调用JNI层的功能。在这篇博客中,将介绍如何在framework层编写一个服务类CanService和SystemCan,用于提供CAN通信的接口给其他应用程序或模块。

CanService类的定义

在frameworks/base/services/core/java/com/android/server/CanService.java文件中定义了CanService类,这个类继承了ICanService.Stub类,实现了ICanService接口。ICanService是一个AIDL接口,用于定义跨进程通信的方法。可以在frameworks/base/core/java/android/xxx/ICanService.aidl文件中看到它的定义:

package android.xxx;
 
interface ICanService {
    int dev_openCan(String canx);
    int dev_closeCan(int fd);
    int dev_sendCan(int fd, long canid, long eff, long rtr, int len, int[] data);
    long[] dev_receiveCan(int fd);
}

这个接口定义了四个方法,分别是:

  • dev_openCan:打开指定的CAN设备,并返回一个文件描述符
  • dev_closeCan:关闭指定的文件描述符
  • dev_sendCan:向指定的文件描述符发送一帧CAN数据
  • dev_receiveCan:从指定的文件描述符接收一帧CAN数据,并返回一个长整型数组

这些方法和JNI层的本地方法是一一对应的,只是在名称前加了native_前缀。可以通过实现这个接口来调用JNI层的本地方法。

CanService类的实现

在CanService类中实现了ICanService接口的四个方法,以及一个init方法和五个本地方法。看一下其中一个方法的实现:

@Override
public int dev_openCan(String canx) {
    Slog.i(TAG, "dev_openCan: " + canx);
    return native_dev_openCan(canx);
}

这个方法接受一个字符串参数canx,表示要打开的CAN设备的名称,例如"can0"或"can1"。打印一条日志信息,表示进入了这个方法,然后调用本地方法native_dev_openCan,并将canx作为参数传递。最后返回本地方法的返回值,表示打开设备后得到的文件描述符,如果打开失败,则返回负数。

其他三个方法的实现逻辑类似

init方法是用于初始化JNI层的,它没有参数和返回值,只是简单地调用本地方法init:

public void init() {
    Slog.i(TAG, "init");
    native_init();
}

五个本地方法是用于声明JNI层对应的本地方法,它们使用native关键字标识,并且没有具体的实现,在C/C++层完成:

private native void init();
 
private native int native_dev_openCan(String canx);
 
private native int native_dev_closeCan(int fd);
 
private native int native_dev_sendCan(int fd, long canid, long eff, long rtr, int len,
        int[] data);
 
private native long[] native_dev_receiveCan(int fd);

这些本地方法的签名必须和JNI层定义的签名一致,否则会导致注册失败或者运行时错误 直接崩溃 懂我意思吧。。

CanService类的使用

在CanService类的构造函数中打印了一条日志信息,表示启动了CanService,并调用了init方法:

public CanService() {
    Slog.i(TAG, "Starting Can Service");
    init();
}

这个构造函数会在系统启动时被调用,可以在frameworks/base/services/core/java/com/android/server/SystemServer.java文件中看到它的调用:

private void startOtherServices() {
    // ...
    try {
        Slog.i(TAG, "Can Service");
        mSystemServiceManager.startService(CanService.class);
    } catch (Throwable e) {
        reportWtf("starting Can Service", e);
    }
    // ...
}

这个方法是用于启动系统服务的,其中有一行代码是用于启动CanService类,即mSystemServiceManager.startService(CanService.class)。这样,就可以在系统中创建一个CanService对象,并初始化JNI层。

SystemCan类的定义

在frameworks/base/core/java/android/btf/SystemCan.java文件中定义了SystemCan类,当需要使用CanService类提供的CAN通信功能时,可以通过Binder机制来获取一个ICanService接口的引用,然后调用其方法。例如,可以使用以下代码来获取一个ICanService接口的引用:

ICanService canService = ICanService.Stub.asInterface(
        ServiceManager.getService("can"));

SystemCan类的实现

在SystemCan类中实现了四个方法,分别对应了CanService类提供的四个接口。还实现了一个构造函数,用于初始化sService对象和设置CAN设备的参数。看一下其中一个方法的实现:

public int dev_openCan(String canx) throws RemoteException {
    return sService.dev_openCan(canx);
}

这个方法接受一个字符串参数canx,表示要打开的CAN设备的名称。它直接调用sService对象的dev_openCan方法,并返回其结果。这样,就可以通过SystemCan对象来简化对CanService对象的调用,而不需要每次都获取一个ICanService接口的引用。

在构造函数中实现了对sService对象的初始化和对CAN设备的配置。看一下它的实现:

public SystemCan(String canx, int baudrate) {
    if (!canx.equals("can0") && !canx.equals("can1")) {
        throw new IllegalArgumentException("canx must be either can0 or can1");
    }
    if (baudrate < 0) {
        throw new IllegalArgumentException("baudrate cannot be less than 0");
    }
 
    try {
        sService = ICanService.Stub.asInterface(ServiceManager.getService("can"));
        //ShellUtils.execCmd("ip link set " + canx + " type can tq 133 prop-seg 6 phase-seg1 6 phase-seg2 2 sjw 1", true);
        ShellUtils.CommandResult commandResult = ShellUtils.execCmd("ip link set " + canx + " down && ip link set " + canx + " type can bitrate " + baudrate + " && ip link set " + canx + " up", true);
        Log.d(TAG, "SystemCan:" + commandResult.result + "," + commandResult.successMsg + "," + commandResult.errorMsg);
    } catch (Exception e) {
        Log.e(TAG, "Error setting up CAN system: " + e.getMessage());
    }
 
}

这个构造函数接受两个参数:canx表示要打开的CAN设备的名称,baudrate表示要设置的CAN设备的波特率。它首先检查两个参数是否合法,如果不合法,就抛出异常。然后,它尝试获取CanService类的实例,并赋值给sService变量。接着,它执行一个shell命令,用于设置CAN设备的波特率,并将其关闭再打开。最后,它打印shell命令的执行结果。如果在这个过程中发生异常,它就打印错误信息。

SystemCan类的使用

在SystemCan类中封装了CanService类提供的接口,并提供了一个简单的构造函数,用于初始化和配置CAN设备。这样,就可以更方便地使用SystemCan类来实现CAN通信的功能。看一下一个使用示例:

SystemCan systemCan = new SystemCan("can0", 500000); //创建一个SystemCan对象,指定要打开和设置的CAN设备为"can0",波特率为500000
int fd = systemCan.dev_openCan("can0"); //调用SystemCan对象的dev_openCan方法,打开"can0"设备,并返回一个文件描述符
if (fd >= 0) { //如果文件描述符不是负数,表示打开成功
    int[] data = {0x11, 0x22, 0x33, 0x44}; //定义一个整型数组,表示要发送的数据内容
    int ret = systemCan.dev_sendCan(fd, 0x123, 0, 0, 4, data); //调用SystemCan对象的dev_sendCan方法,向文件描述符发送一帧CAN数据,帧ID为0x123,标准帧,数据帧,长度为4
    if (ret > 0) { //如果返回值大于0,表示发送成功
        long[] frame = systemCan.dev_receiveCan(fd); //调用SystemCan对象的dev_receiveCan方法,从文件描述符接收一帧CAN数据,并返回一个长整型数组
        if (frame != null) { //如果返回值不是空,表示接收成功
            Log.d("TEST-CAN","Received CAN frame: " + Arrays.toString(frame)); //打印接收到的CAN数据
        }
    }
    systemCan.dev_closeCan(fd); //调用SystemCan对象的dev_closeCan方法,关闭文件描述符
}

这这样,就可以更简洁地使用SystemCan类来实现CAN通信的功能。

总结

在这篇博客中,介绍了如何在Java层编写一个服务类CanService和SystemCan类,用于提供CAN通信的接口给其他应用程序或模块。分别介绍了CanService/SystemCan类的定义,实现和使用。利用了AIDL接口和Binder机制来实现跨进程通信,并调用JNI层提供的本地方法来实现与CAN设备的交互。

相关文章
|
1月前
|
存储 Java Android开发
Rockchip系列之UART 新增framework系统jni+service接口访问(2)
Rockchip系列之UART 新增framework系统jni+service接口访问(2)
31 1
|
1月前
|
Java Android开发
Rockchip系列之VendorStorage 新增framework系统jni+service接口访问(3)
Rockchip系列之VendorStorage 新增framework系统jni+service接口访问(3)
32 0
|
1月前
|
存储 传感器 JSON
Rockchip系列之VendorStorage 新增framework封装VendorStorageManager访问(4)
Rockchip系列之VendorStorage 新增framework封装VendorStorageManager访问(4)
31 0
|
对象存储
SAP Gateway Service Builder 里的 OData Model 定义方式
SAP Gateway Service Builder 里的 OData Model 定义方式
103 0
SAP Gateway Service Builder 里的 OData Model 定义方式
|
存储 数据可视化
SAP Gateway Service Builder 里 Project 的概念
SAP Gateway Service Builder 里 Project 的概念
88 0
SAP Gateway Service Builder 里 Project 的概念
|
Android开发
Android源码分析--Service的启动和绑定
Android源码分析--Service的启动和绑定
285 0
Android源码分析--Service的启动和绑定
如何使用SAP Cloud for Customer里的ABSL代码调用Web service
需求:在C4C UI里创建web service(maintain ticket),然后通过ABSL代码消费。 1. 创建一个新的Communication Arrangement
如何使用SAP Cloud for Customer里的ABSL代码调用Web service
如何处理SAP CRM Web Service错误 - Virtual Interface Method XXXX not supported
如何处理SAP CRM Web Service错误 - Virtual Interface Method XXXX not supported
163 0
如何处理SAP CRM Web Service错误 - Virtual Interface Method XXXX not supported
CRM WebClient UI的external service功能介绍
CRM WebClient UI的external service功能介绍
103 0
CRM WebClient UI的external service功能介绍
使用C4C ABSL调用外部web service创建service request
使用C4C ABSL调用外部web service创建service request