嵌入式Linux&Android开发-Android Hal到Framwork 2

目录

一、Android应用访问驱动设备的方法

二、为什么需要JNI?

三、为什么需要Android HAL?

四、上层 app 控制 led 亮灭例子

4.1 Kenerl层添加驱动

4.2 Hal层添加驱动

4.3 JNI层添加

4.4 AIDL&Service添加

4.5 App层调用自定义service

4.6 验证

4.7 常见问题

4.8 总结

五、补丁包使用


一、Android应用访问驱动设备的方法

  • App->JNI->Kenerl Driver
  • App->JNI->HAL->Kenerl Driver
  • App->Service->JNI->HAL->Kenerl Driver

二、为什么需要JNI?

应用使用java编写,驱动一般使用c/cpp编写,提供一种Java访问c/cpp的方法。也就是Java代码可通过JNI接口 调用 C/C++方法。

JNI开发流程的步骤:

  • 第1步:编写JNI方法表并注册
  • 第2步:实现JNI的.c文件

三、为什么需要Android HAL?

Hardware Abstract Layer 硬件抽象层,由于Linux Kernel需要遵循GPL开源协议,硬件厂商为了保护自己硬件方面的各项参数不被外泄,而一个设备的驱动程序包含了硬件的一些重要参数,所以驱动的开源势必会使硬件厂商蒙受损失,Google为了保护硬件厂商的利益,所以在Android系统中加入了HAL层,在HAL层中不必遵循GPL协议,所以代码可以封闭。

也就是说,编写驱动分为两个部分,一个是HAL层的驱动代码,一个是Kernel层的驱动代码。

内核实现HAL驱动的方法有两种:

  • Android_src/hardware/libhardware_legacy 老式的HAL结构(下左图),采用直接调用so动态链接库方式。
  • Android_src/hardware/libhardware 新式HAL结构(下右图),采用Stub代理方式调用。

HAL_legacy:旧式的HAL是一个模块,采用共享库形式,在编译时会调用到。由于采用function call形式调用,因此可被多个进程使用,但会被mapping到多个进程空间中,造成浪费,同时需要考虑代码能否安全重入的问题。

HAL:新式的HAL采用HAL module和HAL stub结合形式,HAL stub不是一个share library,编译时上层只拥有访问HAL stub的函数指针,并不需要HAL stub。上层通过HAL module提供的统一接口获取并操作HAL stub,so文件只会被mapping到一个进程,也不存在重复mapping和重入问题。

Android源码中已经实现了一部分的HAL,包括Wi-Fi、GPS、RIL、Sensor等。

了解了Framework Service JNI HAL Driver后,应用APP如何访问设备?

1、在kernel层,编写和添加驱动和编译文件Malefie,创建设备节点文件/dev/led

2、在HAL层,增加模块接口,以访问驱动程序

3、JNI层,编写JNI方法,在应用程序框架层提供Java接口访问硬件

4、framework层,应用程序框架层,增加硬件服务接口

5、通过Manager调用Service

6、添加注册服务,addService开机服务就可以启动

7、更新API

8、修改节点权限

9、编译更新系统镜像到机器

10、android app 测试

10.1 eclipse做法:

  • 将out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar里的
  • android/os/LedManager.class
  • 导入eclipse 的sdk/platforms/android-xx/android.jar包中
  • 的android/os目录

10.2 Android studio做法:

将out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar导入libs目录

四、上层 app 控制 led 亮灭例子

4.1 Kenerl层添加驱动

1、在dts文件中增加 led 设备

path:kernel/arch/arm64/boot/dts/rockchip/rk3399-embeded-port.dtsi


        embeded_led {
                compatible = "embeded_led";
                led_ctr0 = <&gpio2 27 GPIO_ACTIVE_HIGH>;
                status = "okay";
        };

2、led 驱动(该驱动使用write指令一直写入0)

path:kernel/drivers/leds/led-embeded.c

/* SPDX-License-Identifier: GPL-2.0 */
#include <dt-bindings/gpio/gpio.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/err.h>
#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/slab.h>
static int My_led_ID;
static ssize_t gpio_store(struct device *dev, 
                                        struct device_attribute *attr, 
                                        const char *buf, size_t count) 
{
        unsigned long on = buf[0];
        if(!strcmp(attr->attr.name, "embeded_blue_led")){
                if(on){
                        gpio_direction_output(My_led_ID, 1);
                        printk("gpio_direction_output is %d \n",My_led_ID);
                }
                else{
                        gpio_direction_output(My_led_ID, 0);
                        printk("gpio_direction_output is 0\n");
                }
        }
        return count;
}
static ssize_t gpio_show(struct device *dev,
                 struct device_attribute *attr,
                 char *buf)
{
        int tmp = 0;
        if(!strcmp(attr->attr.name, "embeded_blue_led")){
                tmp = gpio_get_value(My_led_ID);
                printk("gpio_get_value is %d \n",tmp);
                if(tmp>0)
                        return strlcpy(buf, "1\n", 3);
                else
                        return strlcpy(buf, "0\n", 3);
        }
        return 0;
}
/*
DEVICE_ATTR的使用  使用DEVICE_ATTR,可以在sys fs中添加“文件”,
通过修改该文件内容,可以实现在运行过程中动态控制device的目的。
类似的还有DRIVER_ATTR,BUS_ATTR,CLASS_ATTR。这几个东东的区别
就是,DEVICE_ATTR对应的文件在/sys/devices/目录中对应的device下
面。而其他几个分别在driver,bus,class中对应的目录下。这次主要
介绍DEVICE_ATTR,其他几个类似。在documentation/driver-model/Device.txt
中有对DEVICE_ATTR的详细介绍,这儿主要说明使用方法。  
先看看DEVICE_ATTR的原型:
DEVICE_ATTR(_name, _mode, _show, _store) _name:   名称,也就是将在sysfs中生成的文件名称。 
_mode:上述文件的访问权限,与普通文件相同,UGO的格式。 
_show:显示函数,cat该文件时,此函数被调用。 
_store:写函数,echo内容到该文件时,此函数被调用。
*/
// S_IRWXU | S_IRWXG 读写权限
static DEVICE_ATTR(embeded_blue_led, S_IRWXU | S_IRWXG, gpio_show,gpio_store);
/*匹配dts文件中的compatible = "my_led_ctrl" */
static struct of_device_id My_led_of_match[] = {
        { .compatible = "embeded_led" },
        { }
};
/*
MODULE_DEVICE_TABLE一般用在热插拔的设备驱动中。
作用是:模块加载系统再加载模块时,就知道了什么模块对应什么硬件设备。
用法是:MODULE_DEVICE_TABLE(设备类型,设备表)
设备类型:包括USB,PCI等,也可以自己起名字。
设备表:也是自己定义的,它的最后一项必须是空,用来标识结束。
*/
MODULE_DEVICE_TABLE(of, My_led_of_match);
static int My_led_probe(struct platform_device *pdev)
{
        struct device_node *node = pdev->dev.of_node;//获取平台设备节点
        enum of_gpio_flags flags;
        int ret;
        int en_value;
        struct kobject * gpio_obj;
        printk("embeded led probe\n");
        if (!node)
            return -ENODEV; //如果设备节点不存在,则返回 -ENODEV(设备不存在)
        //从设备树中读取 my_led 的 GPIO 配置编号和标志
        //设备树: led_ctr0 = <&gpio1 RK_PB5 GPIO_ACTIVE_LOW>;
        My_led_ID = of_get_named_gpio_flags(node, "led_ctr0", 0, &flags);
        //标志获取完之后,做一个三目运算,将 1 或者 0 赋值给 en_value
        en_value = (flags == GPIO_ACTIVE_HIGH)? 1:0;
        //gpio_is_valid 判断该 GPIO 编号是否有效,IO是否合法
        if(!gpio_is_valid(My_led_ID)){
                dev_err(&pdev->dev, "invalid power gpio%d\n", My_led_ID);
        }
        //devm_gpio_request 申请占用该 GPIO
        ret = devm_gpio_request(&pdev->dev, My_led_ID, "my_gpio_led");
        if (ret) {
            dev_err(&pdev->dev,"failed to request GPIO%d for my_led \n",My_led_ID);
            return -EINVAL;//返回 -EINVAL (模式值无效)
        }
        //gpio_direction_output 设置输出高还是低电平,根据上面的 三目运算,将 1 或者 0 赋值给 en_value
        gpio_direction_output(My_led_ID, en_value);
        //create 一个节点
        gpio_obj = kobject_create_and_add("embededled", NULL);
        //如果是空的,则返回错误
        if(gpio_obj == NULL){
            printk("kobject_create_and_add error\n");
            return -EINVAL;//返回 -EINVAL (模式值无效)
        }                     
        ret = sysfs_create_file(gpio_obj,&dev_attr_embeded_blue_led.attr);
        if (ret) {
             printk("sysfs_create_file error\n");
             return ret;
        }
        return 0;
}
static int My_led_remove(struct platform_device *pdev)
{
        printk("embeded led remove");
        return 0;
}
#ifdef CONFIG_PM_SLEEP
static int My_led_suspend(struct device *dev)
{
        printk("embeded led suspend");
        return 0;
}
static int My_led_resume(struct device *dev)
{
        printk("embeded led resume");
        return 0;
}
#endif
static const struct dev_pm_ops My_led_pm_ops = {
#ifdef CONFIG_PM_SLEEP
        .suspend = My_led_suspend,
        .resume = My_led_resume,
        .poweroff = My_led_suspend,
        .restore = My_led_resume,
#endif
};
/*  定义一个平台设备  My_led_driver  */
static struct platform_driver My_led_driver = {
        .driver        = {
                .name                = "embeded_led",
                .owner                = THIS_MODULE,
                .pm                = & My_led_pm_ops,
                .of_match_table        = of_match_ptr(My_led_of_match),
        },
        .probe                = My_led_probe,
        .remove                = My_led_remove,
};
module_platform_driver(My_led_driver);
MODULE_DESCRIPTION("power for embeded led gpio Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:embeded LED");

3、Makefile

path:kernel/drivers/leds/Makefile

obj-$(CONFIG_LEDS_EMBEDED)                        += led-embeded.o

4.Kconfig

path:kernel/drivers/leds/Kconfig

config LEDS_EMBEDED
        tristate "LEDS_EMBEDEDSupport for GPIO connected LEDs"
        default y 
        help
          Enable this driver will support my_led control

5、defconfig文件中增加led

path:kernel/arch/arm64/configs/embeded_defconfig

CONFIG_LEDS_EMBEDED=y

6、编译下载

FFtools/make.sh -k -j8

下载Resource.img Kernel.img 

7、验证

rk33xx_m2g:/ $ dmesg | grep embed
[    2.091730] embeded led probe
rk33xx_m2g:/ $ su
rk33xx_m2g:/ # echo -e -n "\x01" > sys/embededled/embeded_blue_led
rk33xx_m2g:/ # echo -e -n "\x00" > sys/embededled/embeded_blue_led

8、 修改权限

diff --git a/device/rockchip/rk3399/rk3399_embeded/init.rc b/device/rockchip/rk3399/rk3399_embeded/init.rc
index e1eb2fb3a1..b6aeb966d1 100755
--- a/device/rockchip/rk3399/rk3399_embeded/init.rc
+++ b/device/rockchip/rk3399/rk3399_embeded/init.rc
@@ -560,6 +560,8 @@ on boot
     # firefly leds
     chmod 0666 /sys/class/leds/firefly\:yellow\:user/brightness
     chmod 0666 /sys/class/leds/firefly\:blue\:power/brightness
+    # embeded leds
+    chmod 0666 /sys/embededled/embeded_blue_led
 
     # Assume SMP uses shared cpufreq policy for all CPUs
     chown system system /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq

每次修改init.rc可以直接编译

make bootimage
./mkimage.sh
然后烧录rockdev/Image-rk3399_embeded/boot.img

4.2 Hal层添加驱动

  • mkdir hardware/libhardware/modules/embeded
  • path:hardware/libhardware/include/hardware/embededled_hal.h
  • path:hardware/libhardware/modules/embeded/embededled_hal.c

如何编写HAL层驱动?

推荐新式HAL结构,基于HAL框架提供了三个结构体,分别为hw_device_t , hw_module_t ,hw_module_methods_t,编写HAL层驱动则是依据这三个结构体作扩展,我们创建自己驱动的device_t,module_t代码,并且写hw_module_methods_t这个结构体中方法的实现代码,最后JNI层通过hw_get_module调用。

#define LOG_TAG "EmbededLed"
 
#include <hardware/hardware.h>
#include <hardware/embededled_hal.h>
#include <fcntl.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
 
#define DEVICE_NAME "sys/embededled/embeded_blue_led"
#define MODULE_NAME "EmbededLed"
#define MODULE_AUTHOR "kemp@gmail.com"
 
/*设备打开和关闭接口*/
static int embededled_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);
static int embededled_device_close(struct hw_device_t* device);
 
/*设备访问接口*/
static int embededled_set_val(struct embededled_device_t* dev, int val);
static int embededled_get_val(struct embededled_device_t* dev, int* val);


static int embededled_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) {
        struct embededled_device_t* dev;dev = (struct embededled_device_t*)malloc(sizeof(struct embededled_device_t));
        
        if(!dev) {
                ALOGI("embededled Stub: failed to alloc space");
                return -EFAULT;
        }
 
        memset(dev, 0, sizeof(struct embededled_device_t));
        //初始化设备相关信息,实现访问接口函数
        dev->common.tag = HARDWARE_DEVICE_TAG;
        dev->common.version = 0;
        dev->common.module = (hw_module_t*)module;
        dev->common.close = embededled_device_close;
        dev->set_val = embededled_set_val;
        dev->get_val = embededled_get_val;
 
        if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {
                ALOGI("embededled Stub: failed to open sys/embededled/embeded_blue_led -- %s.", strerror(errno));free(dev);
                return -EFAULT;
        }
        int status = 0;
        write(dev->fd, &status, sizeof(status));
        *device = &(dev->common);
        ALOGI("embededled Stub: open sys/embededled/embeded_blue_led successfully.");
 
        return 0;
}

static int embededled_device_close(struct hw_device_t* device) {
        struct embededled_device_t* embededled_device = (struct embededled_device_t*)device;
        if(embededled_device) {
                close(embededled_device->fd);
                free(embededled_device);
        }
        return 0;
}
 
static int embededled_set_val(struct embededled_device_t* dev, int val) {
        ALOGI("embededled Stub: set value %d to device.", val);
        write(dev->fd, &val, sizeof(val));
        return 0;
}
 
static int embededled_get_val(struct embededled_device_t* dev, int* val) {
        if(!val) {
                ALOGI("embededled Stub: error val pointer");
                return -EFAULT;
        }
        read(dev->fd, val, sizeof(*val));
        ALOGI("embededled Stub: get value %d from device", *val);
        return 0;
}
 
/*模块方法表*/
static struct hw_module_methods_t embededled_module_methods = {
        open: embededled_device_open
};
 
/*模块实例变量*/
struct embededled_module_t HAL_MODULE_INFO_SYM = {
        common: {
                tag: HARDWARE_MODULE_TAG,
                version_major: 1,
                version_minor: 0,
                id: EMBEDEDLED_HARDWARE_MODULE_ID,
                name: MODULE_NAME,
                author: MODULE_AUTHOR,
                methods: &embededled_module_methods,
        }
};

led_hal.h

path:hardware/libhardware/include/hardware/embededled_hal.h

#ifndef ANDROID_EMBEDEDLED_INTERFACE_H
#define ANDROID_EMBEDEDLED_INTERFACE_H
#include <hardware/hardware.h>
 
__BEGIN_DECLS
 
/*定义模块ID*/
#define EMBEDEDLED_HARDWARE_MODULE_ID "embededled_hal"
 
/*硬件模块结构体*/
struct embededled_module_t {
        struct hw_module_t common;
};
 
/*硬件接口结构体*/
struct embededled_device_t {
        struct hw_device_t common;
        int fd;
        int (*set_val)(struct embededled_device_t* dev, int val);
        int (*get_val)(struct embededled_device_t* dev, int* val);
};
 
__END_DECLS
 
#endif

Android.mk

path:hardware/rockchip/embeded/Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := embededled_hal.c
LOCAL_MODULE := embededled_hal.default
include $(BUILD_SHARED_LIBRARY)

编译:

source build/envsetup.sh
mmm hardware/libhardware/modules/embeded
out/target/product/rk3399_embeded/obj/lib/embededled_hal.default.so
也可以把模块添加到
hardware/libhardware/modulest/Android.mk中,这样编译整个Android源码时就会自动编译该模块。

4.3 JNI层添加

JNI开发流程的步骤:

  • 第1步:编写JNI方法表并注册
  • 第2步:实现JNI的.c文件

path:frameworks/base/services/core/jni/com_android_server_EmbededLedService.cpp

#define LOG_TAG "EmbededLedNativeService"

#define LOG_NDEBUG 1

#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/hardware.h>
#include <stdio.h>
#include <hardware/embededled_hal.h>

namespace android
{
         struct embededled_device_t* embededled_device = NULL;
        /*通过硬件抽象层定义的硬件访问接口设置硬件寄存器val的值*/
        static void embededled_setVal(JNIEnv* env, jobject clazz, jint value) {
                int val = value;
                ALOGD("embededled JNI: set value %d to device.", val);
                if(!embededled_device) {
                        ALOGD("embededled JNI: device is not open.");
                        return;
                }
                embededled_device->set_val(embededled_device, val);
        }
        /*通过硬件抽象层定义的硬件访问接口读取硬件寄存器val的值*/
        static jint embededled_getVal(JNIEnv* env, jobject clazz) {
                int val = 0;
                if(!embededled_device) {
                        ALOGD("embededled JNI: device is not open.");
                        return val;
                }
                embededled_device->get_val(embededled_device, &val);
                ALOGD("embededled JNI: get value %d from device.", val);
                return val;
        }
        //通过hw_module_t->methods->open调用HAL中embededled_device_open函数
        //open成功后返回需要操作的hw_device_t
        static inline int embededled_device_open(const hw_module_t* module, struct embededled_device_t** device) {
                        return module->methods->open(module, EMBEDEDLED_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
        }

        //通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件
        //hw_device_t->hw_module_t->hw_module_methods_t->open的函数
        static jboolean embededled_init(JNIEnv* env, jclass clazz) {
                embededled_module_t* module;
                ALOGD("embededled JNI: initializing......");
                //通过硬件模块ID获取hw_module_t
                if(hw_get_module(EMBEDEDLED_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {
                        ALOGD("embededled JNI: embededled Stub found.");
                        if(embededled_device_open(&(module->common), &embededled_device) == 0) {
                                ALOGD("embededled JNI: embededled device is open.");
                                //使用embededled_device调用HAL的set_val进行具体操作
                                embededled_device->set_val(embededled_device, 1);
                                return 1;
                        }
                        ALOGD("embededled JNI: failed to open embededled device.");
                        return 0;
                }
                ALOGD("embededled JNI: failed to get embededled stub module.");
                return 0;                
        }
        /*JNI方法表*/
        static const JNINativeMethod method_table[] = {
                {"init_native", "()Z", (void*)embededled_init},
                {"setVal_native", "(I)V", (void*)embededled_setVal},
                {"getVal_native", "()I", (void*)embededled_getVal},
        };
        /*注册JNI方法 EmbededLedService */
        int register_android_server_EmbededLedService(JNIEnv *env) {
                    return jniRegisterNativeMethods(env, "com/android/server/EmbededLedService", method_table, NELEM(method_table));
        }
};

Android.mk

diff --git a/frameworks/base/services/core/jni/Android.mk b/frameworks/base/services/core/jni/Android.mk
index 0f0124bd46..305773298a 100644
--- a/frameworks/base/services/core/jni/Android.mk
+++ b/frameworks/base/services/core/jni/Android.mk
@@ -36,6 +36,7 @@ LOCAL_SRC_FILES += \
     $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
     $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_PersistentDataBlockService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_EmbededLedService.cpp \
     $(LOCAL_REL_DIR)/onload.cpp
 
 LOCAL_SRC_FILES += \

Onload.cpp

把注册JNI方法函数添加到系统中

diff --git a/frameworks/base/services/core/jni/onload.cpp b/frameworks/base/services/core/jni/onload.cpp
index d5861f8c41..b52f7917fd 100644
--- a/frameworks/base/services/core/jni/onload.cpp
+++ b/frameworks/base/services/core/jni/onload.cpp
@@ -47,6 +47,7 @@ int register_android_server_PersistentDataBlockService(JNIEnv* env);
 int register_android_server_Watchdog(JNIEnv* env);
 int register_android_server_HardwarePropertiesManagerService(JNIEnv* env);
 int register_com_android_server_rkdisplay_RkDisplayModes(JNIEnv* env);
+int register_android_server_EmbededLedService(JNIEnv* env);
 };
 
 using namespace android;
@@ -89,7 +90,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
     register_android_server_Watchdog(env);
     register_android_server_HardwarePropertiesManagerService(env);
     register_com_android_server_rkdisplay_RkDisplayModes(env);
-
-
+    register_android_server_EmbededLedService(env);
     return JNI_VERSION_1_4;
 }

编译

mmm frameworks/base/services/

4.4 AIDL&Service添加

AIDL

frameworks/base/core/java/android/os/IEmbededLedService.aidl

package android.os;
 
interface IEmbededLedService {
    void setVal(int val);
    int getVal();
}

生成Stub ,添加下面mk文件内容后,执行mmm frameworks/base生成接口 

diff --git a/frameworks/base/Android.mk b/frameworks/base/Android.mk
index b9692de0e1..c426a3cd99 100755
--- a/frameworks/base/Android.mk
+++ b/frameworks/base/Android.mk
@@ -240,6 +240,7 @@ LOCAL_SRC_FILES += \
        core/java/android/os/IUpdateLock.aidl \
        core/java/android/os/IUserManager.aidl \
        core/java/android/os/IVibratorService.aidl \
+       core/java/android/os/IEmbededLedService.aidl \
        core/java/android/os/IDisplayDeviceManagementService.aidl \
        core/java/android/os/IRkDisplayDeviceManagementService.aidl \
        core/java/android/security/IKeystoreService.aidl \

Service

frameworks/base/services/java/com/android/server/EmbededLedService.java

package com.android.server;
import android.content.Context;
import android.os.IEmbededLedService;
import android.util.Slog;
public class EmbededLedService extends IEmbededLedService.Stub {
        private static final String TAG = "EmbededLedService";
        EmbededLedService() {
                
                boolean status = init_native();
                Slog.i(TAG,"EmbededLedService Stub init"+status);
        }
        public void setVal(int val) {
                setVal_native(val);
        }        
        public int getVal() {
                return getVal_native();
        }
        
        //JNI方法
        private static native boolean init_native();
        private static native void setVal_native(int val);
        private static native int getVal_native();
};

添加Service到System启动

diff --git a/frameworks/base/services/java/com/android/server/SystemServer.java b/frameworks/base/services/java/com/android/server/SystemServer.java
index cc6f1850e6..b22ecda734 100644
--- a/frameworks/base/services/java/com/android/server/SystemServer.java
+++ b/frameworks/base/services/java/com/android/server/SystemServer.java
@@ -1086,6 +1086,15 @@ public final class SystemServer {
             } catch (Throwable e) {
                 reportWtf("starting DiskStats Service", e);
             }
+
+           try {
+                  Slog.i(TAG, "Embededled Service");
+                  ServiceManager.addService("embededled", new EmbededLedService());
+            } catch (Throwable e) {
+                  Slog.e(TAG, "Failure starting Embededled Service", e);
+            }
+
+
             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
             if (!disableSamplingProfiler) {

编译&烧写

mmm frameworks/base/services/编译生成libandroid_servers.so
make snod打包后烧写system.img

验证:

通过终端查看服务是否启动成功
rk3399_embeded:/ $ service list | grep embed                                   
29      embededled: [android.os.IEmbededLedService]

4.5 App层调用自定义service

/packages/experimental/embededled

.
├── AndroidManifest.xml
├── Android.mk
├── res
│   ├── drawable
│   │   └── ic_launcher_background.xml
│   ├── drawable-v24
│   │   └── ic_launcher_foreground.xml
│   ├── layout
│   │   └── activity_main.xml
│   ├── mipmap-anydpi-v26
│   │   ├── ic_launcher_round.xml
│   │   └── ic_launcher.xml
│   ├── mipmap-hdpi
│   │   ├── ic_launcher.png
│   │   └── ic_launcher_round.png
│   ├── mipmap-mdpi
│   │   ├── ic_launcher.png
│   │   └── ic_launcher_round.png
│   ├── mipmap-xhdpi
│   │   ├── ic_launcher.png
│   │   └── ic_launcher_round.png
│   ├── mipmap-xxhdpi
│   │   ├── ic_launcher.png
│   │   └── ic_launcher_round.png
│   ├── mipmap-xxxhdpi
│   │   ├── ic_launcher.png
│   │   └── ic_launcher_round.png
│   └── values
│       ├── colors.xml
│       └── strings.xml
└── src
    └── com
        └── embeded
            └── testapplauncher
                └── MainActivity.java

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    package="com.embeded.testapplauncher"> 
 
    <application 
        android:allowBackup="true" 
        android:icon="@mipmap/ic_launcher" 
        android:label="@string/app_name" 
        android:roundIcon="@mipmap/ic_launcher_round" 
        android:supportsRtl="true"> 
        <activity android:name=".MainActivity"> 
            <intent-filter> 
                <action android:name="android.intent.action.MAIN" /> 
 
                <category android:name="android.intent.category.LAUNCHER" /> 
            </intent-filter> 
        </activity> 
    </application> 
 
</manifest>

Android.mk

# This Android.mk is empty, and >> does not build subdirectories <<.
# Individual packages in experimental/ must be built directly with "mmm".
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := embededled
include $(BUILD_PACKAGE)

MainActivity.java

package com.embeded.testapplauncher; 
 
import com.embeded.testapplauncher.R; 
import android.app.Activity; 
import android.os.ServiceManager; 
import android.os.Bundle; 
import android.os.IEmbededLedService; 
import android.os.RemoteException; 
import android.util.Log; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.Button; 
import android.widget.EditText; 
 
//import com.embeded.testapplauncher.LedNative; 
 
 
public class MainActivity extends Activity implements OnClickListener{ 
 
    private static final String LOG_TAG = "Kemp"; 
 
        private IEmbededLedService embededLedService = null; 
         
        //LedNative lednative; 
 
        private Button onButton = null; 
        private Button offButton = null; 
 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        setContentView(R.layout.activity_main); 
         
        embededLedService = IEmbededLedService.Stub.asInterface( 
                ServiceManager.getService("embededled")); 
 
        if(null == embededLedService){ 
                Log.i(LOG_TAG, "can not find service"); 
        } 
         
        onButton = (Button)findViewById(R.id.button_on); 
        offButton = (Button)findViewById(R.id.button_off); 
  
        onButton.setOnClickListener(this); 
        offButton.setOnClickListener(this); 
         
        Log.i(LOG_TAG, "Hello Activity Created"); 
        //lednative = new LedNative(); 
 
        //lednative.openDev(); 
    } 
 
    @Override 
    public void onClick(View v) { 
            if(v.equals(onButton)) { 
                try { 
                        embededLedService.setVal(1); 
                        Log.i(LOG_TAG, "embeded Open led "); 
                } catch (RemoteException e) { 
                        Log.e(LOG_TAG, "Remote Exception while reading value from device."); 
                }                 
            } 
            else if(v.equals(offButton)) { 
                try { 
                            embededLedService.setVal(0); 
                        Log.i(LOG_TAG, "embeded Close led"); 
                } catch (RemoteException e) { 
                        Log.e(LOG_TAG, "Remote Exception while writing value to device."); 
                } 
            } 
    } 
 
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"> 
 
 
    <LinearLayout 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:orientation="horizontal" 
        android:gravity="center"> 
        <Button 
            android:id="@+id/button_on" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:text="@string/LedOn"> 
        </Button> 
        <Button 
            android:id="@+id/button_off" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" 
            android:text="@string/LedOff"> 
        </Button> 
    </LinearLayout> 
</LinearLayout>

strings.xml

<resources> 
    <string name="app_name">EmbededApp</string> 
    <string name="value">Value</string> 
    <string name="hint">Please input a value...</string> 
    <string name="LedOn"> LedOn </string> 
    <string name="LedOff"> LedOff </string> 
    <string name="clear">Clear</string> 
</resources>

编译&烧录

mmm packages/experimental/embededled/ 此步骤会生成apk文件
make snod
sudo cp out/target/product/rk3399_embeded/system.img /media/sf_ubuntuShare/img3399
烧录system.img

4.6 验证

板卡启动时,Android Studio打印以下日志

2013-01-18 22:51:19.641 511-511/system_process I/SystemServer: Embededled Service
2013-01-18 22:51:19.641 511-511/system_process D/EmbededLedNativeService: embededled JNI: initializing......
2013-01-18 22:51:19.642 511-511/system_process D/EmbededLedNativeService: embededled JNI: embededled Stub found.
2013-01-18 22:51:19.643 511-511/system_process I/EmbededLed: embededled Stub: open sys/embededled/embeded_blue_led successfully.
2013-01-18 22:51:19.643 511-511/system_process D/EmbededLedNativeService: embededled JNI: embededled device is open.
2013-01-18 22:51:19.643 511-511/system_process I/EmbededLed: embededled Stub: set value 1 to device.
2013-01-18 22:51:19.643 511-511/system_process I/EmbededLedService: EmbededLedService Stub inittrue
2013-01-18 22:51:19.643 511-511/system_process I/SystemServer: IEmbededService
2013-01-18 22:51:19.644 511-511/system_process I/EmbededService: EmbededService init

打开App操作时,可以正常操作灯开关

4.7 常见问题

问题1:

解决办法:权限问题 把权限添加到init.rc,根据3.1-8编译烧写

问题2:

解决办法:Java开放类接口问题 make update-api 

问题3:

D/EMBEDEDLEDNativeService: embededled JNI: initializing......
D/EMBEDEDLEDNativeService: embededled JNI: failed to get embededled stub module.
解决办法:Hal so库未编译,重新编译3.2模块,再烧录

4.8 总结

APP调用了LedManager里的LedOn LedOff

LedManager服务通过aidl调用到LedService.java里的setOn setOff

LedService通过JNI提供的接口调用开关函数

jni层调用到HAL层里的开关函数

led_on/led_off通过write/ioctl调用到驱动调置gpio的高低电平

五、补丁包使用

补丁包下载

Docshttps://x509p6c8to.feishu.cn/docs/doccnWKSIWI5uYsLtbi6g3Mb5fd#补丁包使用

- 检查修改了哪些文件
git apply --stat 0001-add-hal-framwork-service-interface.patch
- 检查打补丁是否存在错误
git apply --check  0001-add-hal-framwork-service-interface.patch
- 执行打补丁指令
git apply 0001-add-hal-framwork-service-interface.patch
- 编译Kernel
./FFTools/make.sh -k -j8
- 编译HAL
source build/envsetup.sh
mmm hardware/libhardware/modules/embeded
输出位于out/target/product/rk3399_embeded/obj/lib/embededled_hal.default.so
- 编译Framework
mmm frameworks/base/
- 编译APP
mmm packages/experimental/embededled/ 此步骤会生成apk文件
make snod
打包后记得把out/target/product/rk3399_embeded/system.img复制到烧录路径
- 烧录固件
- 重启后打开ADB setprop persist.usb.mode peripheral
- 查看对应文件、服务、APP是否生成
- 运行APP

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值