Как реализовать Android-приложение для управления GPIO с помощью метода JNI?
Как реализовать Android-приложение для управления GPIO с помощью метода JNI?

Этот документ обеспечивает Android 10 Подробное руководство по управлению вводом и выводом общего назначения (GPIO) на устройстве через приложение (App). Это охватывает все: от создания драйвер gpio для приложения Конфигурация а также SELinux Все необходимые шаги для политики, разрешающей определенный доступ.

1. Реализация драйвера

Добавьте и создайте драйвер управления gpio bsp\kernel\kernel4.14\drivers\gpio\gpio_led.c и добавьте соответствующий файл Makfile для компиляции.

Язык кода:javascript
копировать
#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include#include    #include#include#include#include#include#include#include#include#include
#define GPIO_HIGH _IO('L', 0)#define GPIO_LOW _IO('L', 1)
#define LED_ON 1#define LED_OFF 0#define SIMPIE_LED_MAX 4
//============================== Upper interface value ==============================//// Определение имени модуля драйвера#define MODULE_NAME "gpio_led"          // Имя модуля драйвера #define MISC_NAME "gpio_led_device"     // Имя, используемое для регистрации устройства как «разное».
// Определение интерфейса функции модуля, интерфейс для вызова приложений верхнего уровня. ПроходитьMMM_DEV_MAGIC различает разные системные интерфейсы, проходить_IO() добавляет свой собственный номер в качестве номера интерфейса. #определять MM_DEV_MAGIC 'N'
// LED Команда управления #define RFID_IO1 _IO(MM_DEV_MAGIC, 93)#define RFID_IO2 _IO(MM_DEV_MAGIC, 130)#define RFID_IO3 _IO(MM_DEV_MAGIC, 121)#define RFID_LED _IO(MM_DEV_MAGIC, 138)
static int major;static struct class *cls;
// GPIO Описать структуру массива gpio_desc *led_gpio[SIMPIE_LED_MAX];
// Команда cat вызовет статическую функцию. ssize_t gpio_value_show(struct device *dev, struct device_attribute *attr, char *buf){    return sprintf(buf, "%d\n", gpiod_get_value(led_gpio[0]));}
// Команда echo вызовет статическую функцию. ssize_t gpio_value_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len){    pr_err("[vanxoak]%c\n", buf[0]);    if ('0' == buf[0])    {        gpiod_direction_output(led_gpio[0], 0);        pr_err("[vanxoak]: _%s_ :gpio off\n", __func__);    }    else if ('1' == buf[0])    {        gpiod_direction_output(led_gpio[0], 1);        pr_err("[vanxoak]: _%s_ :gpio on\n", __func__);    }    else        pr_err("I only support 0 or 1 to ctrl gpio on or off\n");    pr_err("[vanxoak]gpio_value_store\n");    return len;}
// Определите статический атрибут устройства с именем gpio_led. DEVICE_ATTR(gpio_led, 0664, gpio_value_show, gpio_value_store);
// Интерфейс, давно предоставляемый для управления верхним уровнем gpio_led_ioctl(struct file *file, unsigned int cmd, unsigned long arg){    switch (cmd)    {    case RFID_LED:        gpiod_direction_output(led_gpio[0], arg);        break;    case RFID_IO1:        gpiod_direction_output(led_gpio[1], arg);        break;    case RFID_IO2:        gpiod_direction_output(led_gpio[2], arg);        break;    case RFID_IO3:        gpiod_direction_output(led_gpio[3], arg);        break;
    default:        pr_err("[vanxoak] %s default: break\n", __func__);        break;        }    return 0;}
struct file_operations gpio_led_ops = {    .owner = THIS_MODULE,    .unlocked_ioctl = gpio_led_ioctl,};
// Инициализация светодиодной подсветки статическая int simpie_led_init(struct platform_device *pdev){    int ret = 0;    int i;
    // Подать заявку на устройство gpio    led_gpio[0] = devm_gpiod_get(&pdev->dev, "led0", GPIOD_OUT_LOW);    led_gpio[1] = devm_gpiod_get(&pdev->dev, "led1", GPIOD_OUT_LOW);    led_gpio[2] = devm_gpiod_get(&pdev->dev, "led2", GPIOD_OUT_LOW);    led_gpio[3] = devm_gpiod_get(&pdev->dev, "led3", GPIOD_OUT_LOW);
    for (i = 0; i < SIMPIE_LED_MAX; i++)    {        if (IS_ERR(led_gpio[i]))        {            ret = PTR_ERR(led_gpio[i]);            return ret;        }        // Выходной начальный уровень        ret = gpiod_direction_output(led_gpio[i], LED_OFF);    }
    device_create_file(&pdev->dev, &dev_attr_gpio_led);    return ret;}
// Ввод драйвера статический int gpio_led_probe(struct platform_device *pdev){    int ret = 0;    pr_err("[vanxoak]gpio_led_probe start...\n");
    // Светодиодный индикатор инициализации и вывода gpio Конфигурация    ret = simpie_led_init(pdev);    
    pr_err("[vanxoak]gpio_led_probe end...\n");
    return 0;}
// Привязать устройство статически struct of_device_id gpio_led_match_table[] = {    {.compatible = "yz,gpio-led"},    {}};
static int gpio_led_remove(struct platform_device *pdev){    pr_err("[vanxoak]gpio_led_remove...\n");    return 0;}
static struct platform_driver gpio_led_driver = {    .driver = {        .name = MODULE_NAME,        .owner = THIS_MODULE,        .of_match_table = gpio_led_match_table,    },    .probe = gpio_led_probe,    .remove = gpio_led_remove,};
// статическая запись инициализации gpio int gpio_led_init(void){    struct device *mydev;
    pr_err("[vanxoak]gpio_led_init start...\n");    platform_driver_register(&gpio_led_driver);
    major = register_chrdev(0, "gpiotest", &gpio_led_ops);
    // Создать устройство gpio_led_class    cls = class_create(THIS_MODULE, "gpio_led_class");
    // Создайте файл атрибутов gpio_led_device в каталоге устройства gpio_led_class.    mydev = device_create(cls, 0, MKDEV(major, 0), NULL, MISC_NAME);    if (sysfs_create_file(&(mydev->kobj), &dev_attr_gpio_led.attr))    {            return -1;    }
    return 0;}
static void gpio_led_exit(void){    pr_err("[vanxoak]gpio_led_exit...\n");    platform_driver_unregister(&gpio_led_driver);
    device_destroy(cls, MKDEV(major, 0));    class_destroy(cls);    unregister_chrdev(major, "gpiotest");}
module_init(gpio_led_init);module_exit(gpio_led_exit);
MODULE_DESCRIPTION("Device_create Driver");MODULE_LICENSE("GPL");
Конфигурация устройства gpio_led: yz,gpio-led {                status = "disabled";                compatible = "yz,gpio-led";                led0-gpio = <&ap_gpio 138 GPIO_ACTIVE_HIGH>;                led1-gpio = <&ap_gpio 93 GPIO_ACTIVE_HIGH>;                led2-gpio = <&ap_gpio 130 GPIO_ACTIVE_HIGH>;                led3-gpio = <&ap_gpio 121 GPIO_ACTIVE_HIGH>;};

Конфигурация Очень хорошийgpioПосле вождения Перекомпилироватьвозобновлятьkernel Соответствующий файл устройства можно найти в каталоге /dev.

«/dev/gpio_led_device» вы можете управлять gpio, читая и записывая файлы устройства.

1.2 Создать Native Библиотека

1.2.1 Настройки JNI метод

существовать App по определению JNI метод достижения с помощью GPIO Взаимодействие устройств.

Язык кода:javascript
копировать
publicclassNativeClass {          


    static {                  try {                      System.loadLibrary("jni_gpiocontrol");                      Log.d("NativeClass", "Native library loaded successfully.");                  } catch (UnsatisfiedLinkError e) {                      Log.e("NativeClass", "Failed to load native library: " + e.getMessage());                      // throw new RuntimeException("Failed to load native library", e);                  }              }              // Объявить локальный метод              publicnativeintcontrolGPIO(int cmd, long arg);          }

1.2.2 Реализация Native метод

Создайте папку cpp в существующем каталогеapp/src/main (если ваш проект написан на Kotlin).,Этот шаг по-прежнему актуален,Потому что JNI реализован на C/C++). Поместите файл libjni_gpiocontrol.cpp в этот каталог cpp.

Примечание. Убедитесь, что сигнатура собственного метода верна. Между сигнатурой метода Java и собственной реализацией метода (C/C++) должно быть точное совпадение.

Язык кода:javascript
копировать
#include#include#include#include#include#include#include#include
#define MM_DEV_MAGIC 'N'#define RFID_LED _IO(MM_DEV_MAGIC, 138)#define RFID_IO1 _IO(MM_DEV_MAGIC, 93)#define RFID_IO2 _IO(MM_DEV_MAGIC, 130)#define RFID_IO3 _IO(MM_DEV_MAGIC, 121)    
#define DEVICE_PATH "/dev/gpio_led_device"#define LOG_TAG "GPIOControl"

extern "C" JNIEXPORT jint JNICALLJava_com_example_gpio_NativeClass_controlGPIO(JNIEnv *env, jobject obj, jint cmd, jlong arg) {
    int device_fd;    long ioctl_result;    unsigned int ioctl_cmd = cmd;
    // Open the device file    device_fd = open(DEVICE_PATH, O_RDWR);    if (device_fd < 0) {        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Could not open device: %s", strerror(errno));        return -1;    }
    // Translate cmd to appropriate ioctl command based on input    switch (cmd) {        case 138:            ioctl_cmd = RFID_LED;            break;        case 93:            ioctl_cmd = RFID_IO1;            break;        case 130:            ioctl_cmd = RFID_IO2;            break;        case 121:            ioctl_cmd = RFID_IO3;            break;        default:            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Invalid command");            close(device_fd);            return -1;    }
    // Send an ioctl to the device    ioctl_result = ioctl(device_fd, ioctl_cmd, arg);    if (ioctl_result < 0) {        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Failed to call ioctl: %s", strerror(errno));            close(device_fd);        return -1;    }
    // Close the device    close(device_fd);
    return 0;}

1.2.3 Компиляция Native Библиотека

использовать CMake или ndk-build Инструменты для составления вашего native Код является общим Библиотека (.so документ).

Добавьте app\src\main\cpp\CMakeLists.txt

Язык кода:javascript
копировать
cmake_minimum_required(VERSION 3.4.1)project("gpiotest")add_library(jni_gpiocontrol SHARED libjni_gpiocontrol.cpp)

find_library( log-lib log )
target_link_libraries(jni_gpiocontrol                       ${log-lib} )   

1.2.4 Звонок Native метод

проходить JNI интерфейссуществовать App Реализовано путем звонка native метод контроля GPIO。

Язык кода:javascript
копировать
public class MainActivity extends AppCompatActivity {    private NativeClass nativeClass;
    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);
        nativeClass = new NativeClass();
        // Пример: Включение светодиода            int result = nativeClass.controlGPIO(138, 1);        // Обработка результатов в соответствии с результатом    }}

2. SELinux Конфигурация

Благодаря прямому доступу аппаратное оборудование существует Android получено в SELinux Ограничения политики необходимо изменить SELinux политика, позволяющая App доступ GPIO Файлы устройства.

Определить тип устройства: Определите новый тип SELinux для устройств GPIO (например, gpio_led_device_t).

существоватьSDK_dir/device/sprd/sharkle/common/sepolicy/device.te добавить в

Язык кода:javascript
копировать
# Определить новый тип устройства gpio_led_device_t, dev_type;

Назначить контекст файла: назначьте новый определенный тип SELinux файлу устройства GPIO.

SDK_dir/device/sprd/sharkle/common/sepolicy/file_contextsсерединадобавить в

Язык кода:javascript
копировать
/dev/gpio_led_device u:object_r:gpio_led_device_t:s0

предоставлять разрешения:существовать SELinux 策略серединадобавить в правиле, разрешить App доступ GPIO оборудование.

SDK_dir/device/sprd/sharkle/common/sepolicy/system_app.te

Язык кода:javascript
копировать
# позволять system_app доступ gpio_led_deviceallow system_app gpio_led_device_t:chr_file { read write };

Перекомпилировать SELinux Стратегия: к переменам SELinux стратегия составления,и разверните его на устройстве. Цель этого шага — применить изменения пользовательской политики безопасности к предустановленной политике SELinux системы сборки Android.,Убедитесь, что они существуют при компиляции образа системы.,Эти изменения будут учтены.

Язык кода:javascript
копировать
cp system/sepolicy/public/app.te system/sepolicy/prebuilts/api/29.0/public/app.tecp system/sepolicy/private/coredomain.te system/sepolicy/prebuilts/api/29.0/private/coredomain.te

3. Тестирование и развертывание

тест Приложение: существует с необходимой аппаратной поддержкой. Android 10 тест на устройстве Приложение. убеждаться App можно успешно загрузить native Библиотека,И можетпроходить JNI управление вызовами GPIO。

SELinux Тест стратегии: Проверка SELinux Разрешены ли изменения в политике? App Доступность GPIO оборудование.

Поиск неисправностей:Если вы столкнетесьдоступслучай отказа,Проверьте, пожалуйста SELinux Проведите аудит журналов, чтобы определить, необходимы ли дальнейшие корректировки политики.

3.1 Меры предосторожности

Безопасность: существуют Модификация SELinux стратегии по увеличениюдоступразрешения,Будь осторожен,Избегайте появления уязвимостей безопасности.

Совместимость устройств. Убедитесь, что ваша реализация учитывает различия в аппаратном и программном обеспечении, которые могут существовать на разных устройствах.

Документация и обслуживание. Надлежащим образом документируйте процессы проектирования и реализации, включая интерфейсы JNI, собственный код и изменения политики SELinux, чтобы облегчить будущий аудит и обслуживание.

проходитьследуйте инструкциям выше,Вы можете существовать соблюдать Android модель безопасности при реализации App верно GPIO эффективный контроль.

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose