Android7.0 APP调用驱动流程 Selinux 权限配置

 最近受到肺炎疫情的影响,刚复工不久事情也没那么多,于是就整理下以前做的东西,写下博客好了。其实工作之余也会经常写工作相关的技术文档,只是不习惯发布到博客而已,毕竟有些也是跟公司相关的技术,发布到网上感觉不太好。不过有些自己花时间去学习倒可以跟大家分享讨论与进步。

 

Android 操作系统层面开发在 2017年左右开发过。从APP层、SystemServices、jni、HAL层都有涉及到。当时公司与深圳一家操作系统厂商合作,在Android7.0的基础上对方提个MTK8785芯片板子,我方定制操作系统。本人主要本人主要负责SystemServices到HAL层的驱动调用,举个简单的例子的比如内核层有个节点需要交互,从SystemServices到HAL层打通通道,这样APP就可以调用SystemServices的接口访问了。

以下是当时写的一些文档记录:

Android7.0 APP调用驱动流程 Selinux 权限配置

本文以LED节点为例简单写下开发流程。Android系统没启用Selinux 前APP访问内核节点是很方便的。后来权限越来越严格的时候,应用层就不能随便访问了,加上我们是做银行业务的,硬件设备节点肯定是不能随便开放给第三方。

以下是  A n d r o i d 7 . 0 系 统 开 发 流 程 介 绍 章节:

Android7.0 APP调用驱动流程 Selinux 权限配置

2. Selinux 简介与配置 
         Google 在发布 Android 6.0 版本后对系统增加了权限保护机制,6.0 版本之前访问底层驱动 在 Java 端写个 JNI 就可以直接调用。但加上 Selinux 权限之后这种方式就不可行了,因为第三方 APP 没有权限去操作底层的驱动文件,即使 ROOT 后也不能对底层驱动文件进行写的权限。在开发过程中需要针对摸个模块进行权限配置。 
        现在需要上层 APP 去控制 GPIO 口,以此来控制 LED 灯的亮灭。而控 制 GPIO 口需要对应的驱动,也就是说 APP 需要访问底层驱动来控制灯的亮灭。如本例中 GPIO 口驱动文件挂载在:
(1) 身份证 GPIO 驱动挂载点:
/proc/ID_card_led_on
(2) 验钞灯 GPIO 驱动挂载点:
/proc/md_led_on
(3) 指示灯 GPIO 驱动挂载点:
/proc/led1_on
解决方法有两种:
(1) 通过 system server service 或者 init 启动的 service 读写, 然后 app 通过
binder/socket 等方式连接 APP 访问。此类安全可靠,,并且可以在 service 中做相关的
安全审查, 推崇这种方法。
(2) 修改对应节点的 SELinux Security Label, 为特定的 APP, 如 system app, radio,
bluetooth 等内置 APP 开启权限, 但严禁为 untrsted app 开启权限。具体的做法下面以
app 控制/proc/ ID_card_led_on 节点来说明。
第一种方法可以参考后面介绍的 SystemService 方法,第二种可以将 APP 内置成系统应用,这
样就可以有比较高的权限。
 
2.1.Selinux 权限配置
在 M20 源代码中,进入到
android_8785/M20_Release/device/mediatek/common/sepolicy/basic 目录中:
(1) 在 file.te 文件中定义变量属性:
如:type proc_ID_card_led_on, fs_type, sysfs_type;
表示 proc_ID_card_led_on 节点具有 fs_type 和 sysfs_type 属性。
(2) 在 genfs_contexts 中把属性变量与驱动节点进行绑定.
如:genfscon proc/driver/ID_card_led_on u:object_r:proc_ID_card_led_on:s0
表示把 proc/ID_card_led_on 这个驱动节点与定义的变量 proc_ID_card_led_on 进行绑
定。 
(3) 在 untrusted_app.te、platform_app.te 中调用。
untrusted_app.te 中:allow untrusted_app proc_ID_card_led_on:file rw_file_perms;
其中 untrusted_app.te 为第三方应用配置
在 platform_app.te 中:allow platform_app proc_ID_card_led_on:file rw_file_perms;
其中 platform_app 为 platform 前面的系统应用配置
到此 SElinux 权限配置完成。
 
2.2.如何把 APP 内置成系统应用
目前 Android7.0 已经不支持第三方 APP 对节点有写的权限,需要将 APP 内置成系统级别应用
才可以访问,或者采用第二种方案 systemServer 的方法。下面介绍如何将 APP 内置成系统应用。
例如将网金项目中的 IBankController.apk 内置到系统:
(1) 在\packages\apps 目录下创建文件夹 IBankController。
(2) 因为 IBankController.apk 里需要使用到第三方的 so 库,使用在 IBankController 目录
下创建 lib 文件夹,用来存放 so 库如下图所示:

Android7.0 APP调用驱动流程 Selinux 权限配置

(3) 创建 Android.mk 文件,内容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := IBankController
LOCAL_MODULE_CLASS := APPS
LOCAL_DEX_PREOPT := false
LOCAL_CERTIFICATE := platform
LOCAL_MODULE_PATH := $(TARGET_OUT)/priv-app
LOCAL_SRC_FILES :=IBankController.apk
LOCAL_PREBUILT_JNI_LIBS:= \
 
@lib/armeabi/libdc_mobile_mate.so \
@lib/armeabi/libdcrf32.so \
@lib/armeabi/libFpDriverSTD.so \
@lib/armeabi/libGrgEmvKernel.so \
@lib/armeabi/libGrgEMVModule.so \
@lib/armeabi/libserial_port.so \
@lib/armeabi/libwlt2bmp.so
include $(BUILD_PREBUILT)
其中 LOCAL_DEX_PREOPT := false 开关配置是否分离 odex,三方应用要求分离 oedx,加快开
机速度。开关配置为 false 时为不分离,正常情况这个开关不做配置。需验证分离 odex 时三方应
用是否正常,若不正常,要求三方修正,支持分离。
(4) 创建添加 so 的 mk 文件如:add_IBankController.mk 文件内容如下:
LOCAL_PATH :=$(TOPDIR)packages/apps/IBankController
PRODUCT_PACKAGES += IBankController
PRODUCT_COPY_FILES += $(LOCAL_PATH)/lib/libdc_mobile_mate.so:system/priv
app/IBankController/lib/arm/libdc_mobile_mate.so \
$(LOCAL_PATH)/lib/libdcrf32.so:system/priv
app/IBankController/lib/arm/libdcrf32.so \
$(LOCAL_PATH)/lib/libFpDriverSTD.so:system/priv
app/IBankController/lib/arm/libFpDriverSTD.so \
$(LOCAL_PATH)/lib/libGrgEmvKernel.so:system/priv
app/IBankController/lib/arm/libGrgEmvKernel.so \
$(LOCAL_PATH)/lib/libGrgEMVModule.so:system/priv
app/IBankController/lib/arm/libGrgEMVModule.so \
$(LOCAL_PATH)/lib/libserial_port.so:system/priv
app/IBankController/lib/arm/libserial_port.so \
$(LOCAL_PATH)/lib/libwlt2bmp.so:system/priv
app/IBankController/lib/arm/libwlt2bmp.so
其中 PRODUCT_COPY_FILES 表示复制文件到对应目录下。
(5) 在 device\mediatek\common\device.mk 添加:
$(call inherit-product-if-exists, packages/apps/IBankController/add_IBankController.mk)
(6) 在\system\sepolicy\domain.te 找到以下内容:
# Do not allow the introduction of new execmod rules. Text relocations
# and modification of executable pages are unsafe.
# The only exceptions are for NDK text relocations associated with
# https://code.google.com/p/android/issues/detail?id=23203
# which, long term, need to go away.
neverallow * {
file_type
-system_data_file
-apk_data_file
-app_data_file
-asec_public_file
}:file execmod;
修改成:
neverallow * {
file_type
-system_data_file
-system_file
-apk_data_file
-app_data_file
-asec_public_file
}:file execmod;
 
最后的目录结构如下图所示: 
Android7.0 APP调用驱动流程 Selinux 权限配置
 
重新编译后会在 out\target\product\pri8785_tb_n\system/priv-app 目录下看到
IBankController 应用。
2.3.系统 APP 如何访问 GPIO 驱动
到此为止我们已经在 SElinux 中把 GPIO 的驱动节点的权限设置成系统应用可以访问,然后也
把 IBankController.apk 内置成系统应用,所以在 IBankController.apk 中应该就能控制 GPIO 口
了。 
在 IBankController.apk 中编写以下代码进行控制:
try {
String[] cmdMode = new String[]{"/system/bin/sh","-c","echo" + " " + cmd + " > /proc/driver/
ID_card_led_on "};
Runtime.getRuntime().exec(cmdMode);
} catch (IOException e) {
e.printStackTrace();
}
2.4.Cmd 命令调试
在开发中可以先通过命令对节点进行调试。
(1) 打开 cmd 输入 adb shell 进入到系统。
(2) 进入到节点目录,如 ID_card_led_on 目录在 /proc 下执行:
echo 1 > ID_card_led_on 表示对节点写 1,也就是打开 GPIO 口
echo 0 > ID_card_led_on 表示对节点写 0,也就是关闭 GPIO 口
(3) 通过目录 cat 查看节点的值。
cat ID_card_led_on 查看 GPIO 当前值。