色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Android APP如何進(jìn)行訪問(wèn)硬件驅(qū)動(dòng)

CHANBAEK ? 來(lái)源:飛車(chē)俠 ? 作者: Pual Lin ? 2023-12-04 13:50 ? 次閱讀

本文我們要講的是在用 i.MX8 平臺(tái)開(kāi)發(fā)時(shí),Android APP 如何進(jìn)行訪問(wèn)硬件驅(qū)動(dòng)。

主要內(nèi)容包括:框架代碼編寫(xiě)和注意事項(xiàng)(Linux Driver、C Library、SystemServer、APP 等五個(gè)部分)、Sepolicy 信息配置,話不多說(shuō),我們直接進(jìn)入正題吧~

一、Android 應(yīng)用層訪問(wèn)硬件服務(wù)框架

圖片

Android 應(yīng)用層訪問(wèn)硬件服務(wù)框架主要可以分為:① APP;② SystemServer;③ C Library;④ Linux Driver。

① APP:

從 service_manager 里獲取相關(guān)服務(wù),再通過(guò)接口調(diào)用,接口里實(shí)現(xiàn)對(duì)本地方法的調(diào)用。

涉及到的相關(guān)文件:MainActivity.java、activity_main.xml、ILedService.aidl、LedService.java

② SystemServer:

通過(guò)注冊(cè) android 服務(wù)的方式加載 C 庫(kù),再將服務(wù)加入 service_manager 里面。

涉及到的相關(guān)文件:SystemServer.java、SystemServiceRegistry.java、LedManager.java

③ C Library:

HAL 層操作 /dev/myled,JNI 層加載 HAL 文件和向上注冊(cè) java 本地方法。

涉及到的相關(guān)文件:onload.cpp、com_android_server_LedService.cpp、led_hal.c、led_hal.h

④ Linux Driver

和 Linux 驅(qū)動(dòng)完全一樣,編寫(xiě)驅(qū)動(dòng),向上提供 /dev/myled 節(jié)點(diǎn)。

涉及到的相關(guān)文件:myled.c

二、框架代碼編寫(xiě)

2.1 編寫(xiě) Linux Driver

通過(guò) Linux Driver 來(lái)實(shí)現(xiàn)從應(yīng)用層到底層的控制,這里主要實(shí)現(xiàn)對(duì) LED 燈的 ON/OFF 控制及 GPIO 引腳電平 HIGH/LOW 的上報(bào)。

在 vendor/nxp-opensource/kernel_imx/drivers/leds 目錄下創(chuàng)建 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_ioctln");
  switch(cmd) {


        case 0:
      if(arg == 0)
      {
        gpio_set_value(USER_LED, 0);
        printk("led is offn");
        break;
      }else
        {
                   gpio_set_value(USER_LED, 1);
                    printk("led is onn");
                    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: %dn", 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");//第一個(gè)參數(shù),為要申請(qǐng)的引腳,第二個(gè)為你要定義的名字
  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);

      //創(chuàng)建設(shè)備信息,執(zhí)行后會(huì)出現(xiàn) /sys/class/myled
      myled_class = class_create(THIS_MODULE, "myled");


  //創(chuàng)建設(shè)備節(jié)點(diǎn),就是根據(jù)上面的設(shè)備信息來(lái)的
      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. 構(gòu)建platform_driver 結(jié)構(gòu)體*/
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. 注冊(cè)平臺(tái)驅(qū)動(dòng)*/
  platform_driver_register(&myled_driver);
  printk("[pual] Enter %s - %d -- n",__func__,__LINE__);
  return 0;
}


static void __exit myled_exit(void)
{
  /*3. 注銷(xiāo)平臺(tái)驅(qū)動(dòng)*/
  platform_driver_unregister(&myled_driver);
}
module_init(myled_init);
module_exit(myled_exit);


/* 描述驅(qū)動(dòng)程序的一些信息,不是必須的 */
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.

修改默認(rèn)配置文件 vendor/nxp-opensource/kernel_imx/arch/arm64/configs/android_defconfig,添加代碼

CONFIG_MYLED=y

由于這里給的值是 y,會(huì)把我們的 driver 編譯進(jìn)內(nèi)核,不會(huì)生成 ko 文件,也不需要我們?nèi)ナ謩?dòng)掛載。注意,必須是給 y,因?yàn)槲覀兒罄m(xù)會(huì)把 led 添加進(jìn) system server 里面,會(huì)在系統(tǒng)啟動(dòng)的時(shí)候就調(diào)用到 open 來(lái)打開(kāi) /dev/myled。

執(zhí)行如下命令,開(kāi)始編譯 kernel 內(nèi)核

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

2.2 編寫(xiě) C Library

2.2.1 修改 onload.cpp

SystemServer.java 會(huì)加載 C 庫(kù),調(diào)用到 onload.cpp,需要在 onload.cpp 注冊(cè) LED 服務(wù)。
修改 frameworks/base/services/core/jni/onload.cpp,添加:

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

2.2.2 創(chuàng)建 com_android_server_LedService.cpp

前面用到了 register_android_server_LedService(),是在 com_android_server_LedService.cpp 里實(shí)現(xiàn)的。

com_android_server_LedService.cpp 理論上可以直接操作節(jié)點(diǎn) /dev/myled,但一般不這樣做。

通常的做法是,向上提供本地方法 (native_ledOpen),向下加載 HAL 文件 (led_hal.c),并調(diào)用 HAL 的函數(shù)。

這樣操作有兩個(gè)好處:

  1. 方便修改;

如果需要修改硬件部分的操作,只需要修改 led_hal.c,生成 so 文件,放入系統(tǒng)即可,而不需要編譯整個(gè) Android 系統(tǒng);

  1. 保密代碼;

因?yàn)?Linux 的 GPL 協(xié)議,一旦使用的內(nèi)核代碼,自己的代碼也得開(kāi)源出去,硬件廠商為了保密硬件的具體細(xì)節(jié),只在內(nèi)核實(shí)現(xiàn)操作寄存器的接口,具體的操作邏輯放在 HAL 文件里,而 Android 采用 Apache 協(xié)議,修改了代碼而無(wú)需開(kāi)源,這樣就實(shí)現(xiàn)了保密代碼;

編寫(xiě)步驟如下:

  1. 定義 JNINativeMethod,建立 Java 本地方法與 C 庫(kù)函數(shù)名的映射關(guān)系;
  2. 使用 jniRegisterNativeMethods 注冊(cè)本地方法,將在 onload.cpp 被調(diào)用;
  3. 在 open() 里:

① 使用 hw_get_module 獲得 hw_module_t 結(jié)構(gòu)體;

② 使用 module->methods->open 獲得 hw_device_t 結(jié)構(gòu)體;

③ 將 hw_device_t 轉(zhuǎn)換為 led_device_t,調(diào)用對(duì)應(yīng) open;

  1. 完成其它函數(shù) ctrl、close 的調(diào)用;

在 frameworks/base/services/core/jni/ 路徑下創(chuàng)建 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 < stdio.h >
#include < sys/types.h >
#include < sys/stat.h >
#include < fcntl.h >
#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",

執(zhí)行 mmm frameworks/base/services 編譯 com_android_server_LedService.cpp 和 onload.cpp

2.2.3 創(chuàng)建 HAL 文件:led_hal.c 和 led_hal.h

在 hardware/libhardware/modules 目錄下新建一個(gè)目錄 test_led

在 hardware/libhardware/modules/test_led 目錄下創(chuàng)建 led_hal.c

#include < hardware/hardware.h >
#include < cutils/log.h >
#include < stdio.h >
#include < unistd.h >
#include < fcntl.h >
#include < errno.h >
#include < stdlib.h >
#include < sys/types.h >
#include < sys/stat.h >
#include < fcntl.h >
#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 下創(chuàng)建 led_hal.h

#ifndef ANDROID_LED_INTERFACE_H    
#define ANDROID_LED_INTERFACE_H  
#include < stdint.h >   
#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 目錄下創(chuàng)建 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)

執(zhí)行 mmm hardware/libhardware/modules/test_led 編譯 led_hal.c

編譯完成后會(huì)在 out/target/product/mek_8q/obj_arm/SHARED_LIBRARIES/led.default_intermediates 目錄下生成 so 文件 led.default.so

2.3 編寫(xiě) SystemServer

2.3.1 修改 SystemServer.java

SystemServer.java 主要做兩件事,一是加載 C 庫(kù),二是使用 addService 將 LED 服務(wù)加入 service_manager 里面。
加載 C 庫(kù)這個(gè)是調(diào)用 onload.cpp,這個(gè)前面已經(jīng)修改 onload.cpp,這里就不需要改了。
修改frameworks/base/services/java/com/android/server/SystemServer.java,添加:

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

2.3.2 創(chuàng)建 LedManager.java

在目錄 frameworks/base/core/java/android/app 下,創(chuàng)建 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 中注冊(cè)我們的 LedManager Service 服務(wù)。

修改 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 編寫(xiě) APP

2.4.1 創(chuàng)建 AIDL

AIDL(Android Interface Definition Language),即 Android 接口定義語(yǔ)言,顧名思義就是定義接口,提供給 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 目錄下執(zhí)行編譯

mmm frameworks/base/

編譯完成后將會(huì)自動(dòng)生成:

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

2.4.2 創(chuàng)建 LedService.java

前面生成了 ILedService.java,需要實(shí)現(xiàn) ILedService 接口的成員函數(shù)。

在 frameworks/base/services/core/java/com/android/server/ 路徑下,創(chuàng)建 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,并調(diào)用本地方法實(shí)現(xiàn)了成員函數(shù)。并在構(gòu)造函數(shù)里調(diào)用 native_ledOpen()。

其 Android.mk 自動(dòng)包含了所有 java 文件,不需要修改 Android.mk。

執(zhí)行完以上步驟后就可以執(zhí)行 make -j16 命令開(kāi)始編譯

2.4.3 創(chuàng)建 APP 工程

① 打開(kāi) Android Studio,選擇 “Start a new Android Studio project” 創(chuàng)建一個(gè)新 APP 工程;

圖片

② 然后選擇 “Empty Activity” 空主界面,點(diǎn)擊下一步;

圖片

③ 最后設(shè)置 APP 信息、保存路徑、選擇語(yǔ)言、兼容API版本、勾選支持安裝 apps,點(diǎn)擊完成。

圖片

等待自動(dòng)創(chuàng)建完成后,會(huì)自動(dòng)生成工程文件,生成的工程文件中會(huì)包含MainActivity.java 和 activity_main.xml,appsrcmainreslayoutactivity_main.xml,界面控件布局文件,既可通過(guò)圖形界面設(shè)計(jì)控件,也可直接編輯 xml;

appsrcmainjavacomexampleled_demoMainActivity.java,實(shí)現(xiàn)控件各種具體功能,邏輯關(guān)系。

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

< ?xml version="1.0" encoding="utf-8"? >
< androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >


    < LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >


        < TextView
            android:id="@+id/TEXT"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:layout_marginTop="30dp"
            android:text="Android access hardware"
            android:textColor="#008577"
            android:textSize="25sp"
            android:textStyle="bold" / >


        < Button
            android:id="@+id/BUTTON1"
            android:layout_width="50pt"
            android:layout_height="wrap_content"
            android:layout_marginTop="30dp"
            android:layout_gravity="center"
            android:text="LED ON" / >


        < Button
            android:id="@+id/BUTTON2"
            android:layout_width="50pt"
            android:layout_height="wrap_content"
            android:layout_marginTop="30dp"
            android:layout_gravity="center"
            android:text="HIGH" / >


    < /LinearLayout >


< /androidx.constraintlayout.widget.ConstraintLayout >

由于這里會(huì)調(diào)用到我們前面定義好的 ledctrl 函數(shù)接口,但是我們還沒(méi)有把對(duì)應(yīng)的庫(kù)導(dǎo)進(jìn)來(lái),需要執(zhí)行如下操作:

將 out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar 放在 Windows 里。
在 Android Studio 里,選擇 File->Project Structure,此時(shí)彈出配置界面,點(diǎn)擊 Modules 窗口左上角的 +,選擇 Import .JAR/.AAR Package,選擇剛才的 classes.jar。

切換到 Dependencies 選項(xiàng)卡,選擇 app,點(diǎn)擊 Declared Dependencies 窗口左上角的 + 號(hào),選擇 3 Module dependency,在彈出的界面選擇剛才添加的 classes,最后點(diǎn)擊 OK。

圖片

以上操作后,會(huì)在 APP 工程根目錄下生成 classes 文件夾,里面就包含了 classes.jar。

完成后可以點(diǎn)擊 Build -> Build Bundle(s) / APK(s) -> Build APK(s) 開(kāi)始編譯

圖片

2.4.4 APK 安裝

上面編譯生成的 APK 名稱(chēng)為 :app-debug.apk,我們需要連接好開(kāi)發(fā)板的 USB TypeC 接口,在 Windows 終端輸入如下命令開(kāi)始安裝:

adb install app-debug.apk

安裝完成后,打開(kāi) APK 即可看到如下界面:

圖片

三、Sepolicy 權(quán)限配置

3.1 denied error

在完成各層代碼添加后,還需要添加 Sepolicy 權(quán)限,否則系統(tǒng)在啟動(dòng)的時(shí)候回出現(xiàn)類(lèi)似如下報(bào)錯(cuò)

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 };

添加完后編譯,出現(xiàn)了如下報(bào)錯(cuò):

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

雖然前面我們已經(jīng)將 myled 添加到系統(tǒng)啟動(dòng)的進(jìn)程中,并且也可以在 /dev/ 目錄下查找到了我們的 myled 設(shè)備,但是查看啟動(dòng) logcat 仍然出現(xiàn) open error 的現(xiàn)象。出現(xiàn)這樣現(xiàn)象的原因主要是跟 system server 沒(méi)有權(quán)限去操作我們的 myled 設(shè)備有關(guān),解決權(quán)限的問(wèn)題需要分兩步走:

  1. myled 設(shè)備的權(quán)限

打開(kāi)目錄文件 android_build/system/core/rootdir/ueventd.rc ,添加如下內(nèi)容:

/dev/myled 0666 root root
  1. system server 訪問(wèn) myled 設(shè)備的權(quán)限

這里主要涉及的是 Android 的 Sepolicy 安全機(jī)制,需要修改 android_build/device/fsl/imx8q/sepolicy 目錄下的三個(gè)文件:file_contexts、device.te、system_server.te

① file_contexts

仿照這個(gè)文件里面的寫(xiě)法,添加一個(gè)自定義的設(shè)備名字,myled_device 為自定義,其他內(nèi)容保持一致:

/dev/myled u:object_r:myled_device:s0

② device.te

仿照這個(gè)文件里的寫(xiě)法,將剛剛上一步寫(xiě)的 myled_device 聲明為 dev_type:

type myled_device, dev_type;

③ system_server.te

加入允許 system_server 對(duì) /dev/myled 的讀寫(xiě)權(quán)限:

allow system_server myled_device:chr_file rw_file_perms;

chr_file表示字符設(shè)備文件,如果是普通文件用file,目錄請(qǐng)用dir

rw_file_perms代表讀寫(xiě)權(quán)限

完成以上步驟后,執(zhí)行 make -j16 開(kāi)始編譯

編譯完成后會(huì)在 out/target/product/mek_8q 目錄下生成鏡像文件

四、注意事項(xiàng)

① 如果把 LED_SERVICE 添加到 system server 成功的話,系統(tǒng)啟動(dòng)完成可以通過(guò) adb shell service list 可以看到 led service,如果沒(méi)有則說(shuō)明沒(méi)有添加成功。

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 文件沒(méi)有正確添加(HAL 文件沒(méi)有編譯),會(huì)出現(xiàn)如下 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

檢查設(shè)備中 /system/lib/led.default.so 文件是否存在,如果不存在則需要在主機(jī)端中將 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 文件,則還要重新執(zhí)行 mmm hardware/libhardware/modules/test_led,來(lái)生成 so 文件。

理論上我們也可以將 so 文件直接 push 到開(kāi)發(fā)板的 /system/lib 目錄中,但是由于權(quán)限問(wèn)題,會(huì)出現(xiàn) Read-only file system 的錯(cuò)誤提示,所以只能通過(guò)重新編譯生成系統(tǒng)文件來(lái)實(shí)現(xiàn)。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Android
    +關(guān)注

    關(guān)注

    12

    文章

    3935

    瀏覽量

    127339
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11292

    瀏覽量

    209328
  • 硬件
    +關(guān)注

    關(guān)注

    11

    文章

    3312

    瀏覽量

    66200
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4779

    瀏覽量

    68521
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Android App環(huán)境檢測(cè)分析

    這個(gè)原理就是APPAndroidManifest.xml文件中application是否配置了android:debuggable="true",設(shè)置true支持動(dòng)態(tài)調(diào)試
    的頭像 發(fā)表于 12-01 10:26 ?899次閱讀

    DMK如何進(jìn)行硬件調(diào)試???

    有哪位大俠,能講解一下DMK如何進(jìn)行硬件調(diào)試???(不是軟件設(shè)計(jì),而是打開(kāi)一個(gè)程序,要看看它運(yùn)行到哪里了?該如何做?先前51單片機(jī)用的少,我查了一些資料,網(wǎng)上也搜了一下,都不是很具體。)
    發(fā)表于 05-03 16:06

    Android手機(jī)操控ARM開(kāi)發(fā)板外圍硬件設(shè)備【創(chuàng)科之龍】原創(chuàng)

    ,如何進(jìn)行驅(qū)動(dòng)開(kāi)發(fā)與Android進(jìn)行控制(工作中必須要用到的)以及教你如何理解linux設(shè)備模型的驅(qū)動(dòng)架構(gòu)【目前企業(yè)必須用到的
    發(fā)表于 01-12 22:31

    Android程序中進(jìn)行串口訪問(wèn)

    Android程序中進(jìn)行串口訪問(wèn)首先下載我們提供的開(kāi)源示例Demo:git clone https://github.com/friendlyarm
    發(fā)表于 11-14 15:04

    淺談Android與Linux系統(tǒng)之間的差異

    程序APP—>硬件訪問(wèn)服務(wù)—>Android內(nèi)核驅(qū)動(dòng)程序(2)Linux應(yīng)用程序訪問(wèn)linux
    發(fā)表于 07-05 06:06

    手把手演示示波器是如何進(jìn)行遠(yuǎn)程訪問(wèn)的?

    手把手演示示波器是如何進(jìn)行遠(yuǎn)程訪問(wèn)的?
    發(fā)表于 05-08 07:23

    PLC與單片機(jī)硬件是如何進(jìn)行通信的

    單片機(jī)和PLC的應(yīng)用分別有哪些?PLC與單片機(jī)硬件通信的原理是什么?PLC與單片機(jī)硬件是如何進(jìn)行通信的?
    發(fā)表于 08-12 07:34

    Android5.1系統(tǒng)下的uart串口是如何進(jìn)行調(diào)試的

    Android5.1系統(tǒng)下的uart串口是如何進(jìn)行調(diào)試的?有哪些調(diào)試步驟?
    發(fā)表于 03-03 09:48

    求助apk要怎么使用基于rk3288 Android硬件訪問(wèn)框架呢

    上一篇寫(xiě)了一個(gè)oled驅(qū)動(dòng),那么現(xiàn)在有一個(gè)問(wèn)題:apk要怎么使用這個(gè)硬件,這里就需要提供一個(gè)硬件服務(wù),apk通過(guò)這個(gè)服務(wù)就可以操作到硬件了。基于rk3288
    發(fā)表于 05-11 10:33

    Android手機(jī)的輕量級(jí)訪問(wèn)控制

    以A ndroid 手機(jī)為平臺(tái), 提出了一種適用于Android 手機(jī)的訪問(wèn)控制方法, 該方法在Android手機(jī)的內(nèi)核中增加訪問(wèn)控制模塊, 并根據(jù)手機(jī)用戶定制的
    發(fā)表于 04-17 15:06 ?44次下載
    <b class='flag-5'>Android</b>手機(jī)的輕量級(jí)<b class='flag-5'>訪問(wèn)</b>控制

    何進(jìn)行硬件連接,啟動(dòng)GUI并運(yùn)行馬達(dá)

    啟動(dòng)馬達(dá)吧!快速,簡(jiǎn)單,有趣!本視頻將向用戶展示如何進(jìn)行硬件連接,啟動(dòng)GUI并運(yùn)行馬達(dá)。
    的頭像 發(fā)表于 11-28 06:04 ?3095次閱讀

    基于AndroidAPP安全檢測(cè)技術(shù)淺析

    基于AndroidAPP安全檢測(cè)技術(shù)淺析
    發(fā)表于 06-28 16:03 ?16次下載
    基于<b class='flag-5'>Android</b>的<b class='flag-5'>APP</b>安全檢測(cè)技術(shù)淺析

    Java代碼加密支持Android App Bundle動(dòng)態(tài)化框架

    傳統(tǒng)App加殼技術(shù)無(wú)法應(yīng)用在App Bundle模式生成的數(shù)據(jù)包之上。然而,幾維安全推出的Java2C加固方案完美支持Android App Bundle動(dòng)態(tài)化框架,守護(hù)企業(yè)的核心代碼
    的頭像 發(fā)表于 07-29 16:13 ?2304次閱讀
    Java代碼加密支持<b class='flag-5'>Android</b> <b class='flag-5'>App</b> Bundle動(dòng)態(tài)化框架

    基于Android的果蠅識(shí)別APP

    本文檔的主要內(nèi)容詳細(xì)介紹的是基于Android的果蠅識(shí)別APP采用隨機(jī)森林,神經(jīng)網(wǎng)絡(luò)等多種算法。
    發(fā)表于 03-01 09:28 ?6次下載

    如何在Android 10設(shè)備上通過(guò)App控制GPIO

    本文檔提供了在 Android 10 設(shè)備上通過(guò)應(yīng)用程序(App)控制通用輸入輸出(GPIO)的詳細(xì)指南。這涵蓋了從創(chuàng)建 gpio驅(qū)動(dòng)App 配置 以及 SELinux 策略以允許特
    的頭像 發(fā)表于 07-22 17:59 ?1188次閱讀
    主站蜘蛛池模板: 亚洲精品沙发午睡系列| videos gratis欧美另类| 美女脱光app| 国产精品99久久久久久AV下载| 伦理片飘花手机在线| 国产AV一区二区三区传媒| 在线观看亚洲免费视频| 色综合精品无码一区二区三区| 久久妇女高潮几次MBA| 老湿司午夜爽爽影院榴莲视频 | 与嫂子同居的日子在线观看 | silk118中文字幕无删减| 亚洲乱码爆乳精品成人毛片| 欧美乱子YELLOWVIDEO| 久久理论片迅播影院一级| 国产乱色伦影片在线观看| 把英语老师强奷到舒服动态图| 亚洲永久精品ww47| 性色AV一区二区三区V视界影院 | 2021精品高清卡1卡2卡3麻豆| 爽爽影院线观看免费| 强奸日本美女小游戏| 看 视频一一级毛片| 激情床戏揉胸吃胸视频| 国产精品伊人| 国产精品久久久久久久人人看| 白丝女仆被啪到深夜漫画| 456亚洲人成在线播放网站| 一个人在线观看免费中文www| 亚洲国产成人久久一区www妖精 | 再深点灬舒服灬太大了在线视频| 亚洲99精品A片久久久久久| 午夜福利理论片在线播放| 色小说在线| 色悠悠电影网| 色情内射少妇兽交| 色中色最新地址登陆| 涩涩免费网站| 无套日出白浆在线播放| 午夜伦午夜伦锂电影| 香蕉人人超人人超碰超国产|