Android从硬件到APP:增加硬件服务

作者: 爱因私谈 | 来源:发表于2018-12-11 08:52 被阅读33次

    Android从硬件到APP:增加硬件服务

    Android平台应用越来越广泛,在一些应用领域我们经常需要增加一些硬件控制等特殊功能,而标准Android框架仅支持手机、平板等常见外围器件,比如:相机、震动、电话、蓝牙、音频等。下面就以某个项目需要实现APP操作GPIO来讲述开发的整个过程。

    驱动

    1. 在kernel/drivers/misc/目录下新建topband_gpio目录,并增加下面几个文件:
      topband_gpio.c
    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/device.h>
    #include <linux/errno.h>
    #include <linux/err.h>
    #include <linux/kernel.h>
    #include <linux/ctype.h>
    #include <linux/delay.h>
    #include <linux/idr.h>
    #include <linux/sched.h>
    #include <linux/slab.h>
    #include <linux/interrupt.h>
    #include <linux/signal.h>
    #include <linux/pm.h>
    #include <linux/notifier.h>
    #include <linux/fb.h>
    #include <linux/input.h>
    #include <linux/ioport.h>
    #include <linux/io.h>
    #include <linux/clk.h>
    #include <linux/pinctrl/consumer.h>
    #include <linux/platform_device.h>
    #include <linux/kthread.h>
    #include <linux/time.h>
    #include <linux/timer.h>
    #include <linux/regulator/consumer.h>
    #include <linux/gpio.h>
    #include <linux/of.h>
    #include <linux/of_irq.h>
    #include <linux/of_gpio.h>
    #include <linux/of_platform.h>
    #include <linux/miscdevice.h>
    #include <linux/uaccess.h>
    
    #define TOPBAND_GPIO_NAME "topband,gpio"
    
    // ioctl cmd
    #define TOPBAND_GPIO_IOC_MAGIC  'f'
    
    #define TOPBAND_GPIO_IOC_SET_VALUE _IOW(TOPBAND_GPIO_IOC_MAGIC, 1, int)
    
    #define TOPBAND_GPIO_IOC_MAXNR 1
    
    struct topband_gpio_data {
        struct platform_device  *platform_dev;
        struct miscdevice topband_gpio_device;
        int                     gpio1;
        int                     gpio2;
        int                     gpio3;
        int                     gpio4;
    };
    
    static void topband_gpio_free_io_port(struct topband_gpio_data *topband_gpio)
    {
        if(gpio_is_valid(topband_gpio->gpio1)) {
            gpio_free(topband_gpio->gpio1);
        }
        if(gpio_is_valid(topband_gpio->gpio2)) {
            gpio_free(topband_gpio->gpio2);
        }
        if(gpio_is_valid(topband_gpio->gpio3)) {
            gpio_free(topband_gpio->gpio3);
        }
        if(gpio_is_valid(topband_gpio->gpio4)) {
            gpio_free(topband_gpio->gpio4);
        }
        return;
    }
    
    static int topband_gpio_parse_dt(struct device *dev,
                                  struct topband_gpio_data *topband_gpio)
    {
        struct device_node *np = dev->of_node;
    
        topband_gpio->gpio1 = of_get_named_gpio(np, "gpio-1", 0);
        if(!gpio_is_valid(topband_gpio->gpio1)) {
            dev_err(dev, "No valid gpio1");
        }
    
        topband_gpio->gpio2 = of_get_named_gpio(np, "gpio-2", 0);
        if(!gpio_is_valid(topband_gpio->gpio2)) {
            dev_err(dev, "No valid gpio2");
        }
    
        topband_gpio->gpio3 = of_get_named_gpio(np, "gpio-3", 0);
        if(!gpio_is_valid(topband_gpio->gpio3)) {
            dev_err(dev, "No valid gpio3");
        }
    
        topband_gpio->gpio4 = of_get_named_gpio(np, "gpio-4", 0);
        if(!gpio_is_valid(topband_gpio->gpio4)) {
            dev_err(dev, "No valid gpio4");
        }
    
        return 0;
    }
    
    static int topband_gpio_request_io_port(struct topband_gpio_data *topband_gpio)
    {
        int ret = 0;
    
        if(gpio_is_valid(topband_gpio->gpio1)) {
            ret = gpio_request(topband_gpio->gpio1, "topband_gpio_1");
    
            if(ret < 0) {
                dev_err(&topband_gpio->platform_dev->dev,
                        "Failed to request GPIO1:%d, ERRNO:%d\n",
                        (s32)topband_gpio->gpio1, ret);
                return -ENODEV;
            }
    
            gpio_direction_output(topband_gpio->gpio1, 0);
            dev_info(&topband_gpio->platform_dev->dev, "Success request gpio1\n");
        }
    
        if(gpio_is_valid(topband_gpio->gpio2)) {
            ret = gpio_request(topband_gpio->gpio2, "topband_gpio_2");
    
            if(ret < 0) {
                dev_err(&topband_gpio->platform_dev->dev,
                        "Failed to request GPIO2:%d, ERRNO:%d\n",
                        (s32)topband_gpio->gpio2, ret);
                return -ENODEV;
            }
    
            gpio_direction_output(topband_gpio->gpio2, 0);
            dev_info(&topband_gpio->platform_dev->dev, "Success request gpio2\n");
        }
    
        if(gpio_is_valid(topband_gpio->gpio3)) {
            ret = gpio_request(topband_gpio->gpio3, "topband_gpio_3");
    
            if(ret < 0) {
                dev_err(&topband_gpio->platform_dev->dev,
                        "Failed to request GPIO3:%d, ERRNO:%d\n",
                        (s32)topband_gpio->gpio3, ret);
                return -ENODEV;
            }
    
            gpio_direction_output(topband_gpio->gpio3, 0);
            dev_info(&topband_gpio->platform_dev->dev, "Success request gpio3\n");
        }
    
        if(gpio_is_valid(topband_gpio->gpio4)) {
            ret = gpio_request(topband_gpio->gpio4, "topband_gpio_4");
    
            if(ret < 0) {
                dev_err(&topband_gpio->platform_dev->dev,
                        "Failed to request GPIO4:%d, ERRNO:%d\n",
                        (s32)topband_gpio->gpio4, ret);
                return -ENODEV;
            }
    
            gpio_direction_output(topband_gpio->gpio4, 0);
            dev_info(&topband_gpio->platform_dev->dev, "Success request gpio4\n");
        }
    
        return ret;
    }
    
    static int topband_gpio_set_value(int gpio, int value) {
        if(gpio_is_valid(gpio)) {
            gpio_set_value(gpio, value);
            return 0;
        }
        return -1;
    }
    
    static int topband_gpio_ctrl(struct topband_gpio_data *topband_gpio, int data) {
        int ret = 0;
        int gpio, value;
    
        gpio = (data >> 4) & 0x0f;
        value = data & 0x0f;
    
        dev_info(&topband_gpio->platform_dev->dev, 
                        "%s, gpio=%d, value=%d\n", __func__, gpio, value);
        switch (gpio) {
            case 1:
                ret = topband_gpio_set_value(topband_gpio->gpio1, value);
                break;
            case 2:
                ret = topband_gpio_set_value(topband_gpio->gpio2, value);
                break;
            case 3:
                ret = topband_gpio_set_value(topband_gpio->gpio3, value);
                break;
            case 4:
                ret = topband_gpio_set_value(topband_gpio->gpio4, value);
                break;
            default:
                ret = -1;
                break;
        }
        return ret;
    }
    
    static int topband_gpio_dev_open(struct inode *inode, struct file *filp)
    {
        int ret = 0;
    
        struct topband_gpio_data *topband_gpio = container_of(filp->private_data,
                                   struct topband_gpio_data,
                                   topband_gpio_device);
        filp->private_data = topband_gpio;
        dev_info(&topband_gpio->platform_dev->dev,
             "device node major=%d, minor=%d\n", imajor(inode), iminor(inode));
    
        return ret;
    }
    
    static long topband_gpio_dev_ioctl(struct file *pfile,
                         unsigned int cmd, unsigned long arg)
    {
        int ret = 0;
        int data = 0;
        struct topband_gpio_data *topband_gpio = pfile->private_data;
    
        if (_IOC_TYPE(cmd) != TOPBAND_GPIO_IOC_MAGIC) 
            return -EINVAL;
        if (_IOC_NR(cmd) > TOPBAND_GPIO_IOC_MAXNR) 
            return -EINVAL;
    
        if (_IOC_DIR(cmd) & _IOC_READ)
            ret = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
        else if (_IOC_DIR(cmd) & _IOC_WRITE)
            ret = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
        if (ret) 
            return -EFAULT;
    
        dev_info(&topband_gpio->platform_dev->dev,
                     "%s, (%x, %lx):\n", __func__, cmd,
                     arg);
        
        switch (cmd) {
            case TOPBAND_GPIO_IOC_SET_VALUE:
                if (copy_from_user(&data, (int *)arg, sizeof(int))) {
                    dev_err(&topband_gpio->platform_dev->dev, 
                        "%s, copy from user failed\n", __func__);
                    return -EFAULT;
                }
                ret = topband_gpio_ctrl(topband_gpio, data);
                break;
                
            default:
                return -EINVAL;
        }
    
        return ret;
    }
    
    static const struct file_operations topband_gpio_dev_fops = {
        .owner = THIS_MODULE,
        .open = topband_gpio_dev_open,
        .unlocked_ioctl = topband_gpio_dev_ioctl
    };
    
    static int topband_gpio_probe(struct platform_device *pdev)
    {
        int ret = 0;
        struct topband_gpio_data *topband_gpio;
    
        topband_gpio = devm_kzalloc(&pdev->dev, sizeof(*topband_gpio), GFP_KERNEL);
    
        if(topband_gpio == NULL) {
            dev_err(&pdev->dev, "Failed alloc ts memory");
            return -ENOMEM;
        }
    
        if(pdev->dev.of_node) {
            ret = topband_gpio_parse_dt(&pdev->dev, topband_gpio);
    
            if(ret) {
                dev_err(&pdev->dev, "Failed parse dts\n");
                goto exit_free_data;
            }
        }
    
        topband_gpio->platform_dev = pdev;
    
        ret = topband_gpio_request_io_port(topband_gpio);
    
        if(ret < 0) {
            dev_err(&pdev->dev, "Failed request IO port\n");
            goto exit_free_data;
        }
    
        platform_set_drvdata(pdev, topband_gpio);
    
        topband_gpio->topband_gpio_device.minor = MISC_DYNAMIC_MINOR;
        topband_gpio->topband_gpio_device.name = "topband_gpio";
        topband_gpio->topband_gpio_device.fops = &topband_gpio_dev_fops;
    
        ret = misc_register(&topband_gpio->topband_gpio_device);
        if (ret) {
            dev_err(&pdev->dev, "Failed misc_register\n");
            goto exit_free_io_port;
        }
    
        dev_info(&pdev->dev, "%s, over\n", __func__);
        return 0;
    
    exit_free_io_port:
        topband_gpio_free_io_port(topband_gpio);
        
    exit_free_data:
        devm_kfree(&pdev->dev, topband_gpio);
    
        return ret;
    }
    
    static int topband_gpio_remove(struct platform_device *pdev)
    {
        struct topband_gpio_data *topband_gpio = platform_get_drvdata(pdev);
        topband_gpio_free_io_port(topband_gpio);
        kfree(topband_gpio);
    
        return 0;
    }
    
    static const struct of_device_id topband_gpio_of_match[] = {
        { .compatible =  "topband,gpio"},
        {},
    };
    
    MODULE_DEVICE_TABLE(of, topband_gpio_of_match);
    
    static struct platform_driver topband_gpio_driver = {
        .probe = topband_gpio_probe,
        .remove = topband_gpio_remove,
        .driver = {
            .name = TOPBAND_GPIO_NAME,
            .owner  = THIS_MODULE,
            .of_match_table = topband_gpio_of_match,
        },
    };
    
    module_platform_driver(topband_gpio_driver);
    
    MODULE_AUTHOR("shenhb@topband.com");
    MODULE_DESCRIPTION("Topband GPIO for application control");
    MODULE_VERSION("1.0");
    MODULE_LICENSE("GPL");
    

    Kconfig

    #
    #  TOPBAND GPIO driver configuration
    #
    config TOPBAND_GPIO_DRIVER
           tristate  "Topband GPIO driver"    
           default n
           help
               Topband GPIO driver for application control
    

    Makefile

    obj-$(CONFIG_TOPBAND_GPIO_DRIVER) += topband_gpio.o
    
    1. 修改上级目录的Kconfig与Makefile
    diff --git a/kernel/drivers/misc/Kconfig b/kernel/drivers/misc/Kconfig
    index b72da72..f22ca49 100755
    --- a/kernel/drivers/misc/Kconfig
    +++ b/kernel/drivers/misc/Kconfig
    @@ -577,4 +577,5 @@ source "drivers/misc/genwqe/Kconfig"
     source "drivers/misc/echo/Kconfig"
     source "drivers/misc/cxl/Kconfig"
     source "drivers/misc/n76e003/Kconfig"
    +source "drivers/misc/topband_gpio/Kconfig"
    
    diff --git a/kernel/drivers/misc/Makefile b/kernel/drivers/misc/Makefile
    index e8d597b..2e97a69 100755
    --- a/kernel/drivers/misc/Makefile
    +++ b/kernel/drivers/misc/Makefile
    @@ -62,3 +62,4 @@ obj-$(CONFIG_UID_SYS_STATS) += uid_sys_stats.o
     obj-$(CONFIG_MEMORY_STATE_TIME) += memory_state_time.o
     obj-$(CONFIG_USB_CAM_GPIO)     += usb_cam_gpio.o
     obj-$(CONFIG_N76E003_DRIVER)   += n76e003/
    +obj-$(CONFIG_TOPBAND_GPIO_DRIVER)      += topband_gpio/
    
    1. 修改内核defconfig,将驱动编译至内核
    diff --git a/kernel/arch/arm/configs/topband_pos_defconfig b/kernel/arch/arm/configs/topband_pos_defconfig
    index 36c7947..cabe18c 100755
    --- a/kernel/arch/arm/configs/topband_pos_defconfig
    +++ b/kernel/arch/arm/configs/topband_pos_defconfig
    @@ -715,4 +715,5 @@ CONFIG_CRYPTO_SHA256_ARM=y
     CONFIG_CRYPTO_SHA512_ARM=y
     CONFIG_CRYPTO_AES_ARM_BS=y
     
    +CONFIG_TOPBAND_GPIO_DRIVER=y
    
    1. 配置dts文件
    diff --git a/kernel/arch/arm/boot/dts/topband-pos-lvds-1280x800.dts b/kernel/arch/arm/boot/dts/topband-pos-lvds-12
    index 45b0e45..0d99a97 100755
    --- a/kernel/arch/arm/boot/dts/topband-pos-lvds-1280x800.dts
    +++ b/kernel/arch/arm/boot/dts/topband-pos-lvds-1280x800.dts
    @@ -96,6 +96,15 @@
                    mwsensor,delay_time = <3>;
                    mwsensor,is_poll = <1>;
            };
    +       
    +       topband_gpio: topband_gpio { 
    +               status = "okay";
    +               compatible = "topband,gpio";
    +               gpio-1 = <&gpio7 8 GPIO_ACTIVE_HIGH>;
    +               gpio-2 = <&gpio8 1 GPIO_ACTIVE_HIGH>;
    +               gpio-3 = <&gpio8 2 GPIO_ACTIVE_HIGH>;
    +               gpio-4 = <&gpio8 3 GPIO_ACTIVE_HIGH>;
    +       };
     };
     
     &cpu0 {
    
    1. 修改设备文件权限为:0666,否则Hal层无权限访问
    diff --git a/system/core/rootdir/ueventd.rc b/system/core/rootdir/ueventd.rc
    old mode 100644
    new mode 100755
    index eadf219..f0a3609
    --- a/system/core/rootdir/ueventd.rc
    +++ b/system/core/rootdir/ueventd.rc
    @@ -65,6 +65,9 @@ subsystem sound
     # kms driver for drm based gpu
     /dev/dri/*                0666   root       graphics
     
    +# topband gpio driver
    +/dev/topband_gpio         0666   system     system
    +
     # these should not be world writable
     /dev/diag                 0660   radio      radio
     /dev/diag_arm9            0660   radio      radio
    shenhb@dqrd01:~/code/rk3288$ 
    

    Hal&Framework

    修改文件:

        modified:   frameworks/base/Android.mk
        modified:   frameworks/base/core/java/android/app/SystemServiceRegistry.java
        modified:   frameworks/base/core/java/android/content/Context.java
        new file:   frameworks/base/core/java/android/os/IGpioService.aidl
        new file:   frameworks/base/core/java/android/os/SystemGpio.java
        new file:   frameworks/base/services/core/java/com/android/server/GpioService.java
        modified:   frameworks/base/services/core/jni/Android.mk
        new file:   frameworks/base/services/core/jni/com_android_server_GpioService.cpp
        modified:   frameworks/base/services/core/jni/onload.cpp
        modified:   frameworks/base/services/java/com/android/server/SystemServer.java
        new file:   hardware/libhardware/include/hardware/gpio_hal.h
        modified:   hardware/libhardware/modules/Android.mk
        new file:   hardware/libhardware/modules/gpio/Android.mk
        new file:   hardware/libhardware/modules/gpio/gpio_hal.c
        modified:   system/core/rootdir/ueventd.rc
    

    HAL层

    1.在hardware/libhardware/modules/下新建目录gpio目录,在gpio目录下创建Android.mk和gpio_hal.c

    Android.mk

    # Copyright (C) 2012 The Android Open Source Project
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #      http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, oftware
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or mplied.
    # See the License for the specific language governing permissions nd
    # limitations under the License.
    
    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_MODULE := gpio.default
    
    LOCAL_MODULE_RELATIVE_PATH := hw
    LOCAL_PROPRIETARY_MODULE := true
    LOCAL_SRC_FILES := gpio_hal.c
    LOCAL_HEADER_LIBRARIES := libhardware_headers
    LOCAL_SHARED_LIBRARIES := liblog libcutils libutils
    LOCAL_MODULE_TAGS := optional
    
    include $(BUILD_SHARED_LIBRARY)
    

    gpio_hal.c

    #include <hardware/hardware.h>
    #include <cutils/log.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <hardware/gpio_hal.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/ioctl.h>
    #include <utils/Log.h>
    
    #define DEVICE "/dev/topband_gpio"
    
    #define GPIO_IOC_MAGIC  'f'
    #define GPIO_IOC_SET_VALUE  _IOW(GPIO_IOC_MAGIC, 1, int)
    
    static int fd;
    
    static int gpio_close(struct hw_device_t* device)
    {
        close(fd);
        return 0;
    }
    
    static int gpio_open(struct gpio_device_t* dev)
    {
        fd = open(DEVICE, O_RDWR);
        ALOGI("gpio_open : %d", fd);
    
        if(fd >= 0) {
            return 0;
        } else {
            return -1;
        }
    }
    
    static int gpio_ctrl(struct gpio_device_t* dev, int gpio, int value)
    {
        int ret = 0;
        int data = 0;
        
        if(fd < 0) {
            ret = gpio_open(dev);
            if (ret < 0) {
                return -1;
            }
        }
    
        data = ((gpio & 0x0f) << 4) | (value & 0x0f);
        ret = ioctl(fd, GPIO_IOC_SET_VALUE, &data);
        
        ALOGI("gpio_ctrl: gpio=%d, value=%d, data=%d, ret=%d", gpio, alue, data, ret);
        
        return ret;
    }
    
    static struct gpio_device_t gpio_dev = {
        .common = {
            .tag   = HARDWARE_DEVICE_TAG,
            .close = gpio_close,
        },
        .gpio_open  = gpio_open,
        .gpio_ctrl  = gpio_ctrl,
    };
    
    static int gpio_device_open(const struct hw_module_t* module, const har* id,
                               struct hw_device_t** device)
    {
        *device = &gpio_dev;
        return 0;
    }
    
    static struct hw_module_methods_t gpio_module_methods = {
        .open = gpio_device_open,
    };
    
    struct hw_module_t HAL_MODULE_INFO_SYM = {
        .tag = HARDWARE_MODULE_TAG,
        .id = "gpio",
        .methods = &gpio_module_methods,
    };
    

    2.增加文件:hardware/libhardware/include/hardware/gpio_hal.h

    #ifndef ANDROID_GPIO_INTERFACE_H
    #define ANDROID_GPIO_INTERFACE_H
    
    #include <stdint.h>
    #include <sys/cdefs.h>
    #include <sys/types.h>
    #include <hardware/hardware.h>
    
    __BEGIN_DECLS
    struct gpio_device_t {
        struct hw_device_t common;
    
        int (*gpio_open)(struct gpio_device_t* dev);
        int (*gpio_ctrl)(struct gpio_device_t* dev, int gpio, int alue);
    };
    
    __END_DECLS^M
    
    #endif  // ANDROID_GPIO_INTERFACE_H
    

    3.修改父级Android.mk,将gpio模块加入编译

    diff --git a/hardware/libhardware/modules/Android.mk b/hardware/libhardware/modules/Android.mk
    old mode 100644
    new mode 100755
    index 462081d..9e33f41
    --- a/hardware/libhardware/modules/Android.mk
    +++ b/hardware/libhardware/modules/Android.mk
    @@ -10,5 +10,6 @@ hardware_modules := \
         usbaudio \
         usbcamera \
         vehicle \
    -    vr
    +    vr \
    +    gpio
     include $(call all-named-subdir-makefiles,$(hardware_modules))
    

    JNI层

    1.增加文件:frameworks/base/services/core/jni/com_android_server_GpioService.cpp

    #include "jni.h"
    #include "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 al)
        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 gpioCtrl(JNIEnv *env, jobject cls, jint gpio, jint value)
    {
        ALOGI("native gpioCtrl gpio=%d, value=%d", gpio, value);
        return gpioDevice->gpio_ctrl(gpioDevice, gpio, value);
    }
    
    // Register native methods
    static const JNINativeMethod methods[] = {
        {"native_gpioOpen", "()I", (void *)gpioOpen},
        {"native_gpioClose", "()V", (void *)gpioClose},
        {"native_gpioCtrl", "(II)I", (void *)gpioCtrl},
    };
        
    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));
    }
    
    }
    

    2.修改:frameworks/base/services/core/jni/onload.cpp

    diff --git a/frameworks/base/services/core/jni/onload.cpp b/frameworks/base/services/core/jni/onload.cpp
    old mode 100644
    new mode 100755
    index 4d70384..08ddb64
    --- a/frameworks/base/services/core/jni/onload.cpp
    +++ b/frameworks/base/services/core/jni/onload.cpp
    @@ -39,6 +39,7 @@ int register_android_server_UsbMidiDevice(JNIEnv* env);
     int register_android_server_UsbHostManager(JNIEnv* env);
     int register_android_server_vr_VrManagerService(JNIEnv* env);
     int register_android_server_VibratorService(JNIEnv* env);
    +int register_android_server_GpioService(JNIEnv* env);
     int register_android_server_location_ContextHubService(JNIEnv* env);
     int register_android_server_location_GnssLocationProvider(JNIEnv* env);
     int register_android_server_connectivity_Vpn(JNIEnv* env);
    @@ -82,6 +83,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
         register_android_server_UsbHostManager(env);
         register_android_server_vr_VrManagerService(env);
         register_android_server_VibratorService(env);
    +    register_android_server_GpioService(env);
         register_android_server_SystemServer(env);
         register_android_server_location_ContextHubService(env);
         register_android_server_location_GnssLocationProvider(env);
    

    3.修改:frameworks/base/services/core/jni/Android.mk

    diff --git a/frameworks/base/services/core/jni/Android.mk b/frameworks/base/services/core/jni/Android.mk
    old mode 100644
    new mode 100755
    index b44362a..0d57546
    --- a/frameworks/base/services/core/jni/Android.mk
    +++ b/frameworks/base/services/core/jni/Android.mk
    @@ -38,6 +38,7 @@ LOCAL_SRC_FILES += \
         $(LOCAL_REL_DIR)/com_android_server_UsbMidiDevice.cpp \
         $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
         $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
    +    $(LOCAL_REL_DIR)/com_android_server_GpioService.cpp \
         $(LOCAL_REL_DIR)/com_android_server_PersistentDataBlockService.cpp \
         $(LOCAL_REL_DIR)/com_android_server_GraphicsStatsService.cpp \
         $(LOCAL_REL_DIR)/onload.cpp
    

    Framework层(将GpioService注册到Framework)

    1.增加文件:frameworks/base/core/java/android/os/IGpioService.aidl

    package android.os;
     
    /** {@hide} */
    interface IGpioService
    {
           int gpioCtrl(int gpio, int value);
    }
    

    2.增加文件:frameworks/base/services/core/java/com/android/server/GpioService.java

    package com.android.server;
    import android.os.IGpioService;
    
    public class GpioService extends IGpioService.Stub
    {
        private static final String TAG = "GpioService";
    
        /* call native c function to access hardware */
        public int gpioCtrl(int gpio, int value) throws ndroid.os.RemoteException
        {
            return native_gpioCtrl(gpio, value);
        }
        public GpioService()
        {
            native_gpioOpen();
        }
    
        public static native int native_gpioOpen();
        public static native void native_gpioClose();
        public static native int native_gpioCtrl(int gpio, int value);
    }
    

    3.修改:frameworks/base/Android.mk

    diff --git a/frameworks/base/Android.mk b/frameworks/base/Android.mk
    index 3018c4e..d301cfd 100755
    --- a/frameworks/base/Android.mk
    +++ b/frameworks/base/Android.mk
    @@ -276,6 +276,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/IGpioService.aidl \
            core/java/android/os/storage/IStorageManager.aidl \
            core/java/android/os/storage/IStorageEventListener.aidl \
            core/java/android/os/storage/IStorageShutdownObserver.aidl \
    
    1. 修改:frameworks/base/services/java/com/android/server/SystemServer.java
    diff --git a/frameworks/base/services/java/com/android/server/SystemServer.java b/frameworks/base/services/java/co
    index fdf580e..8800516 100755
    --- a/frameworks/base/services/java/com/android/server/SystemServer.java
    +++ b/frameworks/base/services/java/com/android/server/SystemServer.java
    @@ -795,6 +795,11 @@ public final class SystemServer {
                 vibrator = new VibratorService(context);
                 ServiceManager.addService("vibrator", vibrator);
                 traceEnd();
    +                      
    +            traceBeginAndSlog("StartGpioService");
    +            GpioService gpio = new GpioService();
    +            ServiceManager.addService("gpio", gpio);
    +            traceEnd();
     
                 if (!disableConsumerIr) {
                     traceBeginAndSlog("StartConsumerIrService");
    

    Framework(Application)

    1.增加文件:frameworks/base/core/java/android/os/SystemGpio.java

    package android.os;
    
    import android.content.Context;
    import android.media.AudioAttributes;
    import android.util.Log;
    
    /**
        Gpio implementation that controls the main system gpio.
    
        @hide
    */
    public class SystemGpio
    {
        private static final String TAG = "gpio";
    
        private final IGpioService mService;
        public SystemGpio()
        {
            mService = IGpioService.Stub.asInterface(
                           ServiceManager.getService("gpio"));
        }
    
        public SystemGpio(Context context)
        {
            mService = IGpioService.Stub.asInterface(
                           ServiceManager.getService("gpio"));
        }
    
        public void gpioCtrl(int gpio,int value)
        {
            try {
                mService.gpioCtrl(gpio, value);
            } catch(Exception e) {}
        }
    }
    

    2.修改:frameworks/base/core/java/android/content/Context.java

    diff --git a/frameworks/base/core/java/android/content/Context.java b/frameworks/base/core/java/android/content/Co
    index a31cb43..c18b848 100755
    --- a/frameworks/base/core/java/android/content/Context.java
    +++ b/frameworks/base/core/java/android/content/Context.java
    @@ -3352,6 +3352,8 @@ public abstract class Context {
          * @see android.os.Vibrator
          */
         public static final String VIBRATOR_SERVICE = "vibrator";
    +    
    +    public static final String GPIO_SERVICE = "gpio";
     
         /**
          * Use with {@link #getSystemService} to retrieve a {@link
    

    3.修改:frameworks/base/core/java/android/app/SystemServiceRegistry.java

    diff --git a/frameworks/base/core/java/android/app/SystemServiceRegistry.java b/frameworks/base/core/java/android/
    index e695936..ce1fe51 100755
    --- a/frameworks/base/core/java/android/app/SystemServiceRegistry.java
    +++ b/frameworks/base/core/java/android/app/SystemServiceRegistry.java
    @@ -119,6 +119,7 @@ import android.os.SystemVibrator;
     import android.os.UserHandle;
     import android.os.UserManager;
     import android.os.Vibrator;
    +import android.os.SystemGpio;
     import android.os.health.SystemHealthManager;
     import android.os.storage.StorageManager;
     import android.print.IPrintManager;
    @@ -535,6 +536,14 @@ final class SystemServiceRegistry {
                 public Vibrator createService(ContextImpl ctx) {
                     return new SystemVibrator(ctx);
                 }});
    +            
    +            
    +        registerService(Context.GPIO_SERVICE, SystemGpio.class,
    +                new CachedServiceFetcher<SystemGpio>() {
    +            @Override
    +            public SystemGpio createService(ContextImpl ctx) {
    +                return new SystemGpio(ctx);
    +            }});
     
             registerService(Context.WALLPAPER_SERVICE, WallpaperManager.class,
                     new CachedServiceFetcher<WallpaperManager>() {
    

    编译更新API

    make update-api
    

    APP

    1. 引入Android定制后的Framework jar包(out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar)
      1. 将classes.jar拷贝到app/libs/目录下
      2. 修改项目根目录build.gradle,在allprojects段内增加下面代码:
      allprojects {
          repositories {
              google()
              jcenter()
          }
      
          gradle.projectsEvaluated {
              tasks.withType(JavaCompile) {
                  options.compilerArgs.add('-Xbootclasspath/p:app\\libs\\classes.jar')
              }
          }
      }
      
      1. 修改app/build.gradle,如下:
      android{
          defaultConfig {
              multiDexEnabled true
          }
      }
      
      dependencies {
          compileOnly files('libs/classes.jar')
      }
      
      preBuild {
          doLast {
              def imlFile = file(project.name + ".iml")
              println('Change ' + project.name + '.iml order')
              try {
                  def parsedXml = (new XmlParser()).parse(imlFile)
                  def jdkNode = parsedXml.component[1].orderEntry.find { it.'@type' == 'jdk' }
                  parsedXml.component[1].remove(jdkNode)
                  def sdkString = "Android API " + android.compileSdkVersion.substring("android-".length()) + " Platform"
                  new groovy.util.Node(parsedXml.component[1], 'orderEntry', ['type': 'jdk', 'jdkName': sdkString, 'jdkType': 'Android SDK'])
                  groovy.xml.XmlUtil.serialize(parsedXml, new FileOutputStream(imlFile))
              } catch (FileNotFoundException e) {
                  // nop, iml not found
              }
          }
      }
      
    2. 系统GPIO Service类为SystemGpio,调用方式如下:
    package com.ayst.item;
    
    import android.annotation.SuppressLint;
    import android.content.Context;
    import android.os.SystemGpio;
    
    public class GpioTest {
        private SystemGpio mGpioService;
    
        @SuppressLint("WrongConstant")
        public GpioTest(Context context) {
            mGpioService = (SystemGpio) context.getSystemService("gpio");
        }
    
        /**
         * GPIO control
         * @param gpio 1,2,3,4
         * @param value 0: Low 1: High
         */
        public void gpioCtrl(int gpio, int value) {
            if (null != mGpioService) {
                mGpioService.gpioCtrl(gpio, value);
            }
        }
    }
    

    相关文章

      网友评论

      本文标题:Android从硬件到APP:增加硬件服务

      本文链接:https://www.haomeiwen.com/subject/jmzjhqtx.html