Этот документ обеспечивает Android 10 Подробное руководство по управлению вводом и выводом общего назначения (GPIO) на устройстве через приложение (App). Это охватывает все: от создания драйвер gpio для приложения Конфигурация а также SELinux Все необходимые шаги для политики, разрешающей определенный доступ.
Добавьте и создайте драйвер управления gpio bsp\kernel\kernel4.14\drivers\gpio\gpio_led.c и добавьте соответствующий файл Makfile для компиляции.
#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, читая и записывая файлы устройства.
существовать App по определению JNI метод достижения с помощью GPIO Взаимодействие устройств.
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); }
Создайте папку cpp в существующем каталогеapp/src/main (если ваш проект написан на Kotlin).,Этот шаг по-прежнему актуален,Потому что JNI реализован на C/C++). Поместите файл libjni_gpiocontrol.cpp в этот каталог cpp.
Примечание. Убедитесь, что сигнатура собственного метода верна. Между сигнатурой метода Java и собственной реализацией метода (C/C++) должно быть точное совпадение.
#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;}
использовать CMake или ndk-build Инструменты для составления вашего native Код является общим Библиотека (.so документ).
Добавьте app\src\main\cpp\CMakeLists.txt
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} )
проходить JNI интерфейссуществовать App Реализовано путем звонка native метод контроля GPIO。
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); // Обработка результатов в соответствии с результатом }}
Благодаря прямому доступу аппаратное оборудование существует Android получено в SELinux Ограничения политики необходимо изменить SELinux политика, позволяющая App доступ GPIO Файлы устройства.
Определить тип устройства: Определите новый тип SELinux для устройств GPIO (например, gpio_led_device_t).
существоватьSDK_dir/device/sprd/sharkle/common/sepolicy/device.te добавить в
# Определить новый тип устройства gpio_led_device_t, dev_type;
Назначить контекст файла: назначьте новый определенный тип SELinux файлу устройства GPIO.
SDK_dir/device/sprd/sharkle/common/sepolicy/file_contextsсерединадобавить в
/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
# позволять system_app доступ gpio_led_deviceallow system_app gpio_led_device_t:chr_file { read write };
Перекомпилировать SELinux Стратегия: к переменам SELinux стратегия составления,и разверните его на устройстве. Цель этого шага — применить изменения пользовательской политики безопасности к предустановленной политике SELinux системы сборки Android.,Убедитесь, что они существуют при компиляции образа системы.,Эти изменения будут учтены.
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
тест Приложение: существует с необходимой аппаратной поддержкой. Android 10 тест на устройстве Приложение. убеждаться App можно успешно загрузить native Библиотека,И можетпроходить JNI управление вызовами GPIO。
SELinux Тест стратегии: Проверка SELinux Разрешены ли изменения в политике? App Доступность GPIO оборудование.
Поиск неисправностей:Если вы столкнетесьдоступслучай отказа,Проверьте, пожалуйста SELinux Проведите аудит журналов, чтобы определить, необходимы ли дальнейшие корректировки политики.
Безопасность: существуют Модификация SELinux стратегии по увеличениюдоступразрешения,Будь осторожен,Избегайте появления уязвимостей безопасности.
Совместимость устройств. Убедитесь, что ваша реализация учитывает различия в аппаратном и программном обеспечении, которые могут существовать на разных устройствах.
Документация и обслуживание. Надлежащим образом документируйте процессы проектирования и реализации, включая интерфейсы JNI, собственный код и изменения политики SELinux, чтобы облегчить будущий аудит и обслуживание.
проходитьследуйте инструкциям выше,Вы можете существовать соблюдать Android модель безопасности при реализации App верно GPIO эффективный контроль.