i.MX8 系列 | Android APP 访问硬件驱动可以这样做!

本文我们要讲的是在用 i.MX8 平台开发时,Android APP 如何进行访问硬件驱动。

主要内容包括:框架代码编写和注意事项(Linux Driver、C Library、SystemServer、APP 等五个部分)、Sepolicy 权限配置,话不多说,我们直接进入正题吧~


一、Android 应用层访问硬件服务框架 

          

Android 应用层访问硬件服务框架主要可以分为: APP;② SystemServer;③ C Library;④ Linux Driver

 

 APP

从 service_manager 里获取相关服务,再通过接口调用,接口里实现对本地方法的调用。

涉及到的相关文件:MainActivity.javaactivity_main.xmlILedService.aidlLedService.java

 

 SystemServer

通过注册 android 服务的方式加载 C 库,再将服务加入 service_manager 里面。

涉及到的相关文件:SystemServer.javaSystemServiceRegistry.javaLedManager.java

 

 C Library

HAL 层操作 /dev/myled,JNI 层加载 HAL 文件和向上注册 java 本地方法。

涉及到的相关文件:onload.cppcom_android_server_LedService.cppled_hal.cled_hal.h

 

 Linux Driver

和 Linux 驱动完全一样,编写驱动,向上提供 /dev/myled 节点。

涉及到的相关文件:myled.c



二、框架代码编写 
2.1 编写 Linux Driver
通过 Linux Driver 来实现从应用层到底层的控制,这里主要实现对 LED 灯的 ON/OFF 控制及 GPIO 引脚电平 HIGH/LOW 的上报。

在 vendor/nxp-opensource/kernel_imx/drivers/leds 目录下创建 myled.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/device.h>
#include <linux/uaccess.h>

#include <linux/platform_device.h>

#include <linux/cdev.h>
#include <linux/slab.h> /*kmalloc*/
#include <linux/vmalloc.h> /*vmalloc*/
#include <linux/types.h> /*ssize_t*/
#include <linux/gpio_keys.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <asm-generic/ioctl.h>
#include <asm-generic/errno-base.h>

#define USER_LED 374 /*GPIO LED GPIO4_22*/
#define USER_BUTTON 357 /*GPIO LED GPIO4_05*/
int major;
static struct class *myled_class;
static struct class_device *myled_class_devs;

static int myled_drv_open(struct inode *inode, struct file *file)
{
printk("[pual] Enter %s - %d -- \n",__func__,__LINE__);

return 0;
}

static long myled_drv_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int read_val;
printk("gpio_ioctl\n");
switch(cmd) {

case 0:
if(arg == 0)
{
gpio_set_value(USER_LED, 0);
printk("led is off\n");
break;
}else
{
gpio_set_value(USER_LED, 1);
printk("led is on\n");
break;
}
case 1:
read_val = gpio_get_value(USER_BUTTON);
if(copy_to_user((int __user*)arg,&read_val,sizeof(read_val)))
return ENOTTY;

printk("gpio input: %d\n", read_val);

break;
default:
return -EINVAL;
}
return 0;
}

static struct file_operations myled_drv_fops = {
.owner = THIS_MODULE,
.open = myled_drv_open,
.unlocked_ioctl = myled_drv_ioctl,
};

static int myled_probe(struct platform_device *pdev)
{
int ret;
printk("[pual] Enter %s - %d -- \n",__func__,__LINE__);
ret = gpio_request(USER_LED, "LED");//第一个参数,为要申请的引脚,第二个为你要定义的名字
if (ret)
{
return ret;
}
printk("[pual] Enter %s - %d -- \n",__func__,__LINE__);
gpio_direction_output(USER_LED, 1);
printk("[pual] Enter %s - %d -- \n",__func__,__LINE__);
gpio_set_value(USER_LED, 1);
printk("[pual] Enter %s - %d -- \n",__func__,__LINE__);
major = register_chrdev(0,"myled",&myled_drv_fops);

//创建设备信息,执行后会出现 /sys/class/myled
myled_class = class_create(THIS_MODULE, "myled");

//创建设备节点,就是根据上面的设备信息来的
myled_class_devs = device_create(myled_class, NULL, MKDEV(major, 0), NULL, "myled"); /* /dev/myled */
return 0;
}

static int myled_remove(struct platform_device *pdev)
{
gpio_free(USER_LED);
unregister_chrdev(major,"myled");
device_unregister(myled_class_devs);
class_destroy(myled_class);
return 0;
}

static const struct of_device_id myled_ids[] = {

{ .compatible = "fsl,myled", },
{ },
};

MODULE_DEVICE_TABLE(of, myled_ids);

/*1. 构建platform_driver 结构体*/
static struct platform_driver myled_driver={
.probe = myled_probe,
.remove = myled_remove,
.driver = {
.name = "myled",
.of_match_table = myled_ids,
}
};

static int __init myled_init(void)
{
/*2. 注册平台驱动*/
platform_driver_register(&myled_driver);
printk("[pual] Enter %s - %d -- \n",__func__,__LINE__);
return 0;
}

static void __exit myled_exit(void)
{
/*3. 注销平台驱动*/
platform_driver_unregister(&myled_driver);
}
module_init(myled_init);
module_exit(myled_exit);

/* 描述驱动程序的一些信息,不是必须的 */
MODULE_AUTHOR("WPI Pual Lin");
MODULE_VERSION("1.0");
MODULE_DESCRIPTION("i.MX8 LED Driver");
MODULE_LICENSE("GPL");

 

修改 vendor/nxp-opensource/kernel_imx/drivers/leds 目录下 Makefile 及 Kconfig,添加代码

 

Makefile

obj-$(CONFIG_MYLED)                     += myled.o

 

Kconfig

config MYLED
tristate "MYLED support"
depends on LEDS_CLASS
help
This option enables support for userspace LEDs. Say 'y' to enable this
support in kernel. To compile this driver as a module, choose 'm' here:
the module will be called uleds.

 

修改默认配置文件 vendor/nxp-opensource/kernel_imx/arch/arm64/configs/android_defconfig,添加代码

CONFIG_MYLED=y

 

由于这里给的值是 y,会把我们的 driver 编译进内核,不会生成 ko 文件,也不需要我们去手动挂载。注意,必须是给 y,因为我们后续会把 led 添加进 system server 里面,会在系统启动的时候就调用到 open 来打开 /dev/myled。

 

执行如下命令,开始编译 kernel 内核

source build/envsetup.sh 
lunch mek_8q-eng
make bootimage -j16

 

2.2 编写 C Library 

2.2.1修改 onload.cpp

SystemServer.java 会加载 C 库,调用到 onload.cpp,需要在 onload.cpp 注册 LED 服务。

修改 frameworks/base/services/core/jni/onload.cpp,添加:

int register_android_server_LedService(JNIEnv* env);
……
register_android_server_LedService(env);

 

2.2.2 创建 com_android_server_LedService.cpp

前面用到了 register_android_server_LedService(),是在 com_android_server_LedService.cpp 里实现的。

com_android_server_LedService.cpp 理论上可以直接操作节点 /dev/myled,但一般不这样做。

通常的做法是,向上提供本地方法 (native_ledOpen),向下加载 HAL 文件 (led_hal.c),并调用 HAL 的函数。

 

这样操作有两个好处:

1.方便修改;

如果需要修改硬件部分的操作,只需要修改 led_hal.c,生成 so 文件,放入系统即可,而不需要编译整个 Android 系统;

2.保密代码;

因为 Linux 的 GPL 协议,一旦使用的内核代码,自己的代码也得开源出去,硬件厂商为了保密硬件的具体细节,只在内核实现操作寄存器的接口,具体的操作逻辑放在 HAL 文件里,而 Android 采用 Apache 协议,修改了代码而无需开源,这样就实现了保密代码;


编写步骤如下:

1、定义 JNINativeMethod,建立 Java 本地方法与 C 库函数名的映射关系;

2、使用 jniRegisterNativeMethods 注册本地方法,将在 onload.cpp 被调用;

3、在 open() 里:

 3.1、使用 hw_get_module 获得 hw_module_t 结构体;

 3.2、使用 module->methods->open 获得 hw_device_t 结构体;

 3.3、将 hw_device_t 转换为 led_device_t,调用对应 open;

4、完成其它函数 ctrl、close 的调用;

 

在 frameworks/base/services/core/jni/ 路径下创建 com_android_server_LedService.cpp

/*/frameworks/base/services/core/jni/*/
#define LOG_TAG "LedService"

#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include "android_runtime/AndroidRuntime.h"
#include <utils/misc.h>
#include <utils/Log.h>
#include
#include <sys/types.h>
#include <sys/stat.h>
#include
#include <sys/ioctl.h>
#include <hardware/led_hal.h>

namespace android
{
static led_device_t* led_device;

jint ledOpen(JNIEnv *env, jobject cls)
{
jint err;
hw_module_t* module;
hw_device_t* device;

ALOGI("[pual] native ledOpen");

//1. hw_get_module for get module
err = hw_get_module("led", (hw_module_t const**)&module);
ALOGE("[pual] native ledOpen");
if (err == 0) {
//2. module->methods->open for get device
err = module->methods->open(module, NULL, &device);
if (err == 0) {
//3. conversion, call led_open
led_device = (led_device_t *)device;
return led_device->led_open(led_device);
} else {
return -1;
}
}
return -1;
}

void ledClose(JNIEnv *env, jobject cls)
{
ALOGI("[pual] nativeled Close");

return;
}

jint ledCtrl(JNIEnv *env, jobject cls, jint number, jint status)
{
ALOGI("[pual] native ledCtrl %d, %d", number, status);
return led_device->led_ctrl(led_device, number, status);
}

static const JNINativeMethod method_table[] = {
{"native_ledOpen", "()I", (void *)ledOpen},
{"native_ledClose", "()V", (void *)ledClose},
{"native_ledCtrl", "(II)I", (void *)ledCtrl},
};

int register_android_server_LedService(JNIEnv *env)
{
return jniRegisterNativeMethods(env, "com/android/server/LedService",
method_table, NELEM(method_table));
}
};

 

修改 frameworks/base/services/core/jni/Android.bp,添加

"com_android_server_LedService.cpp",

 

执行 mmm frameworks/base/services 编译 com_android_server_LedService.cpp 和 onload.cpp



2.2.3 创建 HAL 文件:led_hal.c 和 led_hal.h

在 hardware/libhardware/modules 目录下新建一个目录 test_led

在 hardware/libhardware/modules/test_led 目录下创建 led_hal.c

#include <hardware/hardware.h>
#include <cutils/log.h>
#include
#include
#include
#include
#include
#include <sys/types.h>
#include <sys/stat.h>
#include
#include <sys/ioctl.h>
#include <utils/Log.h>
#include <hardware/led_hal.h>

//#define LOG_TAG "LED_HAL"

static int fd;

static int led_open(struct led_device_t* dev __unused)
{
fd = open("/dev/myled", O_RDWR);
ALOGI("led_open : %d", fd);
if (fd >= 0)
return 0;
else
return -1;
}

static int led_ctrl(struct led_device_t* dev __unused, int number, int status)
{
int read_val,ret = 0;
switch(number)
{
case 0:
ret = ioctl(fd, 0, status);
ALOGI("[pual] led_write : status = %d, ret = %d", status, ret);
return ret;
case 1:
ioctl(fd,1,&read_val);
ALOGI("[pual] led_read : read_val = %d", read_val);
return read_val;
default:
return -1;
}
}

static int led_close(struct hw_device_t* device __unused)
{
close(fd);
ALOGI("led_close : %d", fd);
return 0;
}

static struct led_device_t myled_dev = {
.common = {
.tag = HARDWARE_DEVICE_TAG,
.close = led_close,
},
.led_open = led_open,
.led_ctrl = led_ctrl,
};

static int led_device_open(const struct hw_module_t* module __unused, const char* id __unused,
struct hw_device_t** device)
{
//return by id
*device = (hw_device_t*) &myled_dev;
return 0;
}

static struct hw_module_methods_t led_module_methods = {
.open = led_device_open,
};

struct hw_module_t HAL_MODULE_INFO_SYM = {
.tag = HARDWARE_MODULE_TAG,
.id = "led",
.methods = &led_module_methods,
};

 

在目录 hardware/libhardware/include/hardware 下创建 led_hal.h

#ifndef ANDROID_LED_INTERFACE_H    
#define ANDROID_LED_INTERFACE_H
#include
#include <sys/cdefs.h>
#include <sys/types.h>
#include <hardware/hardware.h>

__BEGIN_DECLS

struct led_device_t {
struct hw_device_t common;
int (*led_open) (struct led_device_t* dev);
int (*led_ctrl) (struct led_device_t* dev, int number, int status);
};

__END_DECLS

#endif

 

在 hardware/libhardware/modules/test_led 目录下创建 Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := led.default

LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_C_INCLUDES := hardware/libhardware
LOCAL_SRC_FILES := led_hal.c
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_MODULE_TAGS := eng

include $(BUILD_SHARED_LIBRARY)

 

执行 mmm hardware/libhardware/modules/test_led 编译 led_hal.c

编译完成后会在 out/target/product/mek_8q/obj_arm/SHARED_LIBRARIES/led.default_intermediates 目录下生成 so 文件 led.default.so

 

2.3 编写 SystemServer 

2.3.1 修改 SystemServer.java

SystemServer.java 主要做两件事,一是加载 C 库,二是使用 addService 将 LED 服务加入 service_manager 里面。

加载 C 库这个是调用 onload.cpp,这个前面已经修改 onload.cpp,这里就不需要改了。

修改 frameworks/base/services/java/com/android/server/SystemServer.java,添加:

traceBeginAndSlog("StartLedService");
ServiceManager.addService("led", new LedService());
traceEnd();

 

2.3.2 创建 LedManager.java

在目录 frameworks/base/core/java/android/app 下,创建 LedManager.java

package android.app;

import android.content.Context;
import android.os.ILedService;
import android.os.RemoteException;

public class LedManager {
ILedService mService;
public LedManager(Context ctx,ILedService service){
mService = service;
}

public void ledCtrl(int number, int status){
try {
mService.ledCtrl(number, status);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}



2.3.3 修改 SystemServiceRegistry.java

在 SystemServiceRegistry.java 中注册我们的 LedManager Service 服务。

修改 frameworks/base/core/java/android/app/ SystemServiceRegistry.java,在 static 块中添加

registerService(Context.LED_SERVICE, LedManager.class,

new CachedServiceFetcher() {
@Override
public LedManager createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(Context.LED_SERVICE);
ILedService service = ILedService.Stub.asInterface(b);
return new LedManager(ctx, service);
}});

 

这里面的 LED_SERVIC,需要在 frameworks/base/core/java/android/content/Context.java 中声明

@StringDef(suffix = { "_SERVICE" }, value = {
LED_SERVICE,

})

public static final String LED_SERVICE="led";

 

2.4 编写 APP 

2.4.1 创建 AIDL

AIDL(Android Interface Definition Language),即 Android 接口定义语言,顾名思义就是定义接口,提供给 APP 使用。

frameworks/base/core/java/android/os/ 目录下新建:ILedService.aidl :

package android.os;

interface ILedService {
int ledCtrl(int number, int status);
}

 

frameworks/base 目录下修改:Android.bp,添加:

"core/java/android/os/ILedService.aidl",

 

在 android_build 目录下执行编译

"core/java/android/os/ILedService.aidl",

 

在 android_build 目录下执行编译

mmm frameworks/base/

 

编译完成后将会自动生成:

out/soong/.intermediates/frameworks/base/framework/android_common/gen/aidl/frameworks/base/core/java/android/os/ILedService.java

 

2.4.2 创建 LedService.java

前面生成了 ILedService.java,需要实现 ILedService 接口的成员函数。

在 frameworks/base/services/core/java/com/android/server/ 路径下,创建 LedService.java

/*frameworks/base/services/core/java/com/android/server/*/
package com.android.server;
import android.os.ILedService;
import android.util.Slog;

public class LedService extends ILedService.Stub {
private static final String TAG = "ILedService";

//Call native c function to access hardware
public int ledCtrl(int number, int status) throws android.os.RemoteException
{
Slog.i(TAG, "[pual] enter ledCtrl.");
return native_ledCtrl(number, status);
}

public LedService() {
Slog.i(TAG, "[pual] enter native_ledOpen.");
native_ledOpen();
}

//Function declaration
public static native int native_ledCtrl(int number, int status);
public static native int native_ledOpen();
public static native void native_ledClose();
}

 

可以看到 LedService.java 继承于 ILedService,并调用本地方法实现了成员函数。并在构造函数里调用  native_ledOpen()

其 Android.mk 自动包含了所有 java 文件,不需要修改 Android.mk

 

执行完以上步骤后就可以执行 make -j16 命令开始编译

 

2.4.3 创建 APP 工程

① 打开 Android Studio,选择 “Start a new Android Studio project” 创建一个新 APP 工程;

          


② 然后选择 “Empty Activity” 空主界面,点击下一步;

          


③ 最后设置 APP 信息、保存路径、选择语言、兼容 API 版本、勾选支持安装 apps,点击完成。

          

 

等待自动创建完成后,会自动生成工程文件,生成的工程文件中会包含 MainActivity.java 和 activity_main.xmlapp\src\main\res\layout\activity_main.xml,界面控件布局文件,既可通过图形界面设计控件,也可直接编辑xml;

app\src\main\java\com\example\led_demo\MainActivity.java,实现控件各种具体功能,逻辑关系。

 

MainActivity.java

package com.example.led_demo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.view.View;
import android.os.ILedService;
import android.os.ServiceManager;
//import static android.os.ServiceManager.getService;

public class MainActivity extends AppCompatActivity {

private boolean ledStatus = false;
private int gpiostatus;
private final String TAG="MainActivity";
private Button button1,button2 = null;
private ILedService iLedService = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG,"[pual] AppService onCreate");
initView();
}

private void initView() {
iLedService =ILedService.Stub.asInterface(ServiceManager.getService("led"));
if(iLedService==null)
Log.e(TAG,"iLedService = null");
else
Log.e(TAG,"iLedService not null");

button1 = (Button) findViewById(R.id.BUTTON1);
button1.setOnClickListener(new MyButtonListener1());

button2 = (Button) findViewById(R.id.BUTTON2);
button2.setOnClickListener(new MyButtonListener2());
}

class MyButtonListener1 implements View.OnClickListener {
@Override
public void onClick(View v) {
ledStatus = !ledStatus;
if (ledStatus) {
button1.setText("LED OFF");
try {
iLedService.ledCtrl(0, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
button1.setText("LED ON");
try {
iLedService.ledCtrl(0, 1);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}

class MyButtonListener2 implements View.OnClickListener {
@Override
public void onClick(View v) {
try {
gpiostatus = iLedService.ledCtrl(1, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
if (gpiostatus == 1) {
button2.setText("HIGH");
} else {
button2.setText("LOW");
}
}
}
}

 

activity_main.xml















 

由于这里会调用到我们前面定义好的 ledctrl 函数接口,但是我们还没有把对应的库导进来,需要执行如下操作:

将 out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar 放在 Windows 里。

在 Android Studio 里,选择 File->Project Structure,此时弹出配置界面,点击 Modules 窗口左上角的+,选择 Import .JAR/.AAR Package,选择刚才的 classes.jar。

切换到 Dependencies 选项卡,选择 app,点击 Declared Dependencies 窗口左上角的+号,选择 3 Module dependency,在弹出的界面选择刚才添加的 classes,最后点击 OK。

          

 

以上操作后,会在 APP 工程根目录下生成 classes 文件夹,里面就包含了 classes.jar。

 

完成后可以点击 Build -> Build Bundle(s) / APK(s) -> Build APK(s) 开始编译

 
          

 

2.4.4  APK 安装

上面编译生成的 APK 名称为 :app-debug.apk,我们需要连接好开发板的 USB TypeC 接口,在 Windows 终端输入如下命令开始安装:

adb install app-debug.apk

 

安装完成后,打开 APK 即可看到如下界面:

          



三、Sepolicy 权限配置

3.1 denied error 

在完成各层代码添加后,还需要添加 Sepolicy 权限,否则系统在启动的时候回出现类似如下报错

avc: denied { find } for service=led pid=4363 uid=10067 scontext=u:r:untrusted_app:s0:c67,c256,c512,c768 tcontext=u:object_r:default_android_service:s0 tclass=service_manager permissive=0

avc: denied { module_load } for pid=4566 comm="insmod" path="/data/pual/myled.ko" dev="mmcblk0p12" ino=221 scontext=u:r:su:s0 tcontext=u:object_r:system_data_file:s0 tclass=system permissive=1

 

我们需要在 device/fsl/imx8q/sepolicy/system_server.te 中添加:

allow system_server default_android_service:service_manager { add }; 
allow untrusted_app default_android_service:service_manager { find };
allow su system_data_file:system { module_load };

 

添加完后编译,出现了如下报错:

libsepol.report_failure: neverallow on line 1314 of system/sepolicy/public/domain.te (or line 10945 of policy.conf) violated by allow su system_data_file:system { module_load };

 

修改以下目录中的 domain.te

system/sepolicy/public/domain.te

system/sepolicy/prebuilts/api/28.0/public/domain.te

将 1314 行代码注释如下:

#neverallow * ~{ system_file vendor_file rootfs }:system module_load;



3.2 open error 

虽然前面我们已经将 myled 添加到系统启动的进程中,并且也可以在 /dev/ 目录下查找到了我们的 myled 设备,但是查看启动 logcat 仍然出现 open error 的现象。

出现这样现象的原因主要是跟 system server 没有权限去操作我们的 myled 设备有关,解决权限的问题需要分两步走:

 

1. myled 设备的权限

打开目录文件 android_build/system/core/rootdir/ueventd.rc ,添加如下内容:

/dev/myled 0666 root root



2. system server 访问 myled 设备的权限

这里主要涉及的是 Android 的 Sepolicy 安全机制,需要修改 android_build/device/fsl/imx8q/sepolicy 目录下的三个文件:file_contextsdevice.tesystem_server.te

① file_contexts

仿照这个文件里面的写法,添加一个自定义的设备名字,myled_device 为自定义,其他内容保持一致:

/dev/myled u:object_r:myled_device:s0

 

 device.te

仿照这个文件里的写法,将刚刚上一步写的 myled_device 声明为 dev_type:

type myled_device, dev_type;



 system_server.te

加入允许 system_server 对 /dev/myled 的读写权限:

allow system_server myled_device:chr_file rw_file_perms;

 

# chr_file表示字符设备文件,如果是普通文件用file,目录请用dir  

# rw_file_perms代表读写权限

 

完成以上步骤后,执行 make -j16 开始编译

编译完成后会在 out/target/product/mek_8q 目录下生成镜像文件

 

四、注意事项 

① 如果把 LED_SERVICE 添加到 system server 成功的话,系统启动完成可以通过 adb shell service list 可以看到 led service,如果没有则说明没有添加成功。

60      window: [android.view.IWindowManager]
61 alarm: [android.app.IAlarmManager]
62 consumer_ir: [android.hardware.IConsumerIrService]
63 led: [android.os.ILedService]
64 vibrator: [android.os.IVibratorService]
65 content: [android.content.IContentService]

 

② 如果 so 文件没有正确添加(HAL 文件没有编译),会出现如下 log

-------- beginning of crash 
09-04 08:42:57.134 3404 3792 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x80 in tid 3792 (Binder:3404_7), pid 3404 (system_server)
09-04 08:42:57.247 4652 4652 I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstone
09-04 08:42:57.248 3299 3299 I /system/bin/tombstoned: received crash request for pid 3792
09-04 08:42:57.249 4652 4652 I crash_dump64: performing dump of process 3404 (target tid = 3792)
09-04 08:42:57.265 4652 4652 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
09-04 08:42:57.265 4652 4652 F DEBUG : Build fingerprint: 'Android/mek_8q/mek_8q:9/2.0.0-ga-rc4/pual09030609:eng/dev-keys'
09-04 08:42:57.265 4652 4652 F DEBUG : Revision: '0'
09-04 08:42:57.265 4652 4652 F DEBUG : ABI: 'arm64'
09-04 08:42:57.265 4652 4652 F DEBUG : pid: 3404, tid: 3792, name: Binder:3404_7 >>> system_server <<< 09-04 08:42:57.265 4652 4652 F DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x80
09-04 08:42:57.265 4652 4652 F DEBUG : Cause: null pointer dereference
09-04 08:42:57.265 4652 4652 F DEBUG : x0 0000000000000000 x1 0000000000000001 x2 0000000000000001 x3 0000000000000003
09-04 08:42:57.265 4652 4652 F DEBUG : x4 0000000000000067 x5 0080000000000000 x6 0aff646268757164 x7 7f7f7f7f7f7f7f7f
09-04 08:42:57.265 4652 4652 F DEBUG : x8 0000f12def02b000 x9 601f5be1668242d3 x10 0000f12de3a7f580 x11 0000000000000014
09-04 08:42:57.265 4652 4652 F DEBUG : x12 0000f12de3a7f6b8 x13 ffffffffffffffff x14 ffffffffff000000 x15 ffffffffffffffff
09-04 08:42:57.265 4652 4652 F DEBUG : x16 0000f12e0a4fbcc0 x17 0000f12e0cb317e0 x18 0000f12de3a7ee7a x19 0000000000000001
09-04 08:42:57.265 4652 4652 F DEBUG : x20 0000000000000001 x21 0000f12e09dc6c00 x22 0000f12de3a7fdc0 x23 0000000072e471d2
09-04 08:42:57.265 4652 4652 F DEBUG : x24 0000000000000008 x25 0000f12de3a81588 x26 0000f12e09dc6ca0 x27 0000000000000002
09-04 08:42:57.265 4652 4652 F DEBUG : x28 0000000000000002 x29 0000f12de3a7fbe8
09-04 08:42:57.265 4652 4652 F DEBUG : sp 0000f12de3a7faf0 lr 000000007195e9a4 pc 0000f12deeff5e30

 

 

检查设备中 /system/lib/led.default.so 文件是否存在,如果不存在则需要在主机端中将 out/target/product/mek_8q/obj/SHARED_LIBRARIES/led.default_intermediates/led.default.so 拷贝到

out/target/product/mek_8q/system/lib 目录中,再重新编译烧录。如果 led.default_intermediates 目录中也不存在 so 文件,则还要重新执行 mmm hardware/libhardware/modules/test_led,来生成 so 文件。

理论上我们也可以将 so 文件直接 push 到开发板的 /system/lib 目录中,但是由于权限问题,会出现 Read-only file system 的错误提示,所以只能通过重新编译生成系统文件来实现。

 

 关于 Android APP 访问硬件驱动 的分享就到这儿了,如果需要更深入的技术交流欢迎关注我给我留言~~~

【参考资料】:

【1】 Android硬件抽象层(HAL)概要介绍和学习计划

【2】 Android HAL层例子

【3】 Android系统服务(SystemService)简介

★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★文明上网,请理性发言。内容一周内被举报5次,发文人进小黑屋喔~

评论

Topone

Topone

7 个月前
根据步骤,将framework的jar包导入应用中,编译出来的的apk产生了错误信息:java.lang.NoSuchMethodError: No static method asInterface(Landroid/os/IBinder;)Landroid/os/ILedService; in class Landroid/os/ILedService$Stub; or its super classes (declaration of 'android.os.ILedService$Stub' appears in /system/framework/framework.jar!classes2.dex),请问这个需要修改下哪里
Joe

Joe

2021年12月3日
按步驟中,使用evk_8mn-userdebug,執行 mmm hardware/libhardware/modules/test_led 編譯 led_hal.c時,產生了以下訊息: FAILED: ninja: unknown target 'MODULES-IN-hardware-libhardware-modules-test_led' 15:16:25 ninja failed with: exit status 1 不知是否有那裡需要同步修正之處?