Android系统 init.rc sys/class系统节点写不进解决方案和原理分析

本文涉及的产品
阿里云百炼推荐规格 ADB PostgreSQL,4核16GB 100GB 1个月
简介: Android系统 init.rc sys/class系统节点写不进解决方案和原理分析

Android 9.0及以上版本中,由于系统对安全要求越来越严格,不允许app往/sys/class这样的系统节点写入数据,即使是系统应用也没有这个权限了。这给一些需要控制硬件设备的app带来了困难。例如,如果app需要控制LED灯的亮度,但是没有节点权限,怎么办呢?本文将介绍一种解决方案,利用init.rc文件中的write命令和on property触发器,来实现在app中正确往系统节点写数据的功能。

系列文章

Android系统 init.rc 第一次开机创建文件节点实现和原理分析

Android系统 init.rc开机执行shell脚本

Android系统 init.rc sys/class系统节点写不进解决方案和原理分析

Android系统 init.rc文件详解

Android系统 自定义动态修改init.custom.rc

为什么没有权限写入?

在Android 9.0及以上版本中,Google对系统进行了一些修改,增加了对文件系统的加密和保护。这意味着一些敏感的目录,如/data, /mnt等,不能被任意访问和修改。只有在特定的阶段,才能对这些目录进行操作。

而/sys/class目录是一个特殊的目录,它是一个虚拟文件系统,用于提供内核和用户空间之间的通信接口。它包含了一些硬件设备的状态和控制信息,如LED灯、电池、温度等。如果任何app都可以随意往这些节点写入数据,可能会造成系统的不稳定或安全风险。因此,Google限制了对/sys/class目录的访问权限,只有root用户或者拥有特定SELinux策略的进程才能操作这些节点。

从app的角度来看,app运行在一个沙盒环境中,它只能访问自己的数据目录和一些公共目录。它不能直接访问/sys/class目录或其他系统目录。即使是系统应用,也需要申请一些特殊的权限或者签名才能访问这些目录。因此,在Android 9.0及以上版本中,app往/sys/class目录写入数据是不可能的。

从adb的角度来看,adb是一个调试工具,它可以通过USB或网络连接到Android设备上,并执行一些命令或操作。adb可以以root用户或者shell用户身份运行。如果以root用户身份运行,adb可以访问/sys/class目录并往其中写入数据。但是,在Android 9.0及以上版本中,默认情况下adb是以shell用户身份运行的,并且不能切换到root用户身份。除非你对设备进行了root操作或者解锁了bootloader,并且安装了一个支持root的内核或者ROM。因此,在Android 9.0及以上版本中,默认情况下adb也不能往/sys/class目录写入数据。

解决方案

解决方案1: 把设备root

如果你要在adb shell去写入 请看方案2

如果你要在app 去写入/sys/class 节点 , 你需要设备root权限 , 方案非常多

可以看我另外一篇: 链接: Android13 Root实现和原理分析

然后在网上随便抄个shell utils工具类 , 通过root执行 非常简单 不过多赘述 , 如果实在不清楚 可以留言私信。

ShellUtils.execCmd("echo '2 0 1' > /sys/devices/platform/leds/leds/led ", true);

解决方案2: 把节点权限改成

1|rk3568_r:/sys # ls -ll devices/platform/leds/leds/led
-rw-r--r-- 1 root root 4096 2023-07-27 17:38:16.813334118 +0800 devices/platform/leds/leds/led

在Android系统中,节点的权限是由设备驱动在创建节点时设置的,通常情况下,这些权限是固定的,不能被修改。在我的例子中,节点的权限是rw-r--r--,这意味着只有root用户可以写入这个节点,其他用户只能读取这个节点。

如果你想让普通app和adb shell能写入这个节点,你需要修改设备驱动的代码,让它在创建节点时设置更宽松的权限。但是,这可能会带来安全风险,因为任何app都可以修改这个节点,可能会导致系统不稳定或者硬件设备损坏。

如果你的设备已经root,你可以使用chmod命令来修改节点的权限。例如,你可以使用以下命令来修改节点的权限:

chmod 777 /sys/devices/platform/leds/leds/led

这个命令会把节点的权限修改为rwxrwxrwx,这意味着任何用户都可以读取和写入这个节点。

但是,需要注意的是,这个修改只是临时的,当设备重启后,节点的权限会恢复到原来的状态。如果你想让这个修改永久生效,你需要修改设备驱动的代码,或者在init.rc文件中添加一个命令,让系统在启动时自动修改节点的权限。

# 这里证明, 已经修改了权限 也验证了 之前默认adb shell是无法写入的 , 我们尝试在init.rc 修改了权限777 所有用户均可读写。 
rk3568_r:/ # ls -ll /sys/devices/platform/leds/leds/led  
-rwxrwxrwx 1 root root 4096 2023-07-28 10:51:24.256688797 +0800 /sys/devices/platform/leds/leds/led
rk3568_r:/ # exit
rk3568_r:/ $ echo "2 0 1" > /sys/devices/platform/leds/leds/led

解决方案3: 通过on property触发器

既然app和adb都不能直接往/sys/class目录写入数据,那么我们是否有其他方法可以实现这个功能呢?答案是有的。我们可以利用init.rc文件中的write命令和on property触发器来实现这个功能。

init.rc文件是Android系统启动时由init进程读取的初始化配置文件,用于启动Android中的各种服务,以及配置系统参数。init.rc文件使用一种类似于shell脚本的语法,

在init.rc文件中,我们可以使用以下两种命令来实现我们的目的:

  • write [ ]*:向指定的文件写入一个或多个字符串。例如,write /sys/class/leds/brightness 0,就是向/sys/class/leds/brightness文件写入0,表示关闭LED灯。
  • on property:=:当指定的系统属性的值变化时,执行相应的动作。例如,on property:persist.sys.enable=1,就是当persist.sys.enable属性的值变为1时,执行后面的动作。

结合这两种命令,我们可以在init.rc文件中添加一些代码,来监听app设置的系统属性的变化,并根据不同的值来往/sys/class目录写入数据。例如,如果我们想控制LED灯的亮度,我们可以在app中使用SystemProperties.set(“persist.sys.led”, “0”)或SystemProperties.set(“persist.sys.led”, “1”)来设置persist.sys.led属性的值。然后,在init.rc文件中添加以下代码:

# 监听persist.sys.led属性的变化
on property:persist.sys.led=0
    # 当persist.sys.led属性的值为0时,关闭LED灯
    write /sys/class/leds/leds/led "2 0 1"
on property:persist.sys.led=1
    # 当persist.sys.led属性的值为1时,打开LED灯
    write /sys/class/leds/leds/led "2 0 0"

这样,当app设置了persist.sys.led属性的值后,init进程就会根据这个值来往/sys/class/leds/leds/led文件写入数据,从而控制LED灯的亮度。

为什么app和adb无法访问,而init.rc可以写入?

这是因为init进程在系统启动时以root用户身份运行,它有权限访问/sys/class目录并往其中写入数据。而app和adb默认是以非root用户身份运行的,它们没有权限访问/sys/class目录。这是Android系统为了保护系统安全和稳定性,防止非授权的访问和修改系统节点而设置的限制。

怎么解决写入节点值是动态的如何传参?

如果需要传递参数,可以在write命令后面添加参数。例如,如果需要控制LED灯的亮度和颜色,可以在app中使用SystemProperties.set(“persist.sys.led”, “1 0 1”)或SystemProperties.set(“persist.sys.led”, “1 0 0”)来设置persist.sys.led属性的值。然后,在init.rc文件中添加

以下代码:

# 监听persist.sys.led属性的变化
on property:persist.sys.led=*
    # 当persist.sys.led属性的值变化时,根据其值来控制LED灯
    write /sys/class/leds/leds/led ${persist.sys.led}

这样,当app设置了persist.sys.led属性的值后,init进程就会根据这个值来往/sys/class/leds/leds/led文件写入数据,从而控制LED灯的亮度和颜色。

测试验证

130|rk3568_r:/ # setprop persist.sys.led "2 0 0" //我们尝试写入把第3组的第1个LED打开
rk3568_r:/ # getprop persist.sys.led //查看一下写入的值
2 0 0  
rk3568_r:/ # logcat | grep persist.sys.led //可以看到action已经被触发
01-01 08:00:06.017     0     0 E init    : Could not set 'persist.sys.led' to '2 >> out/target/product/rk3568_r/vendor/build.prop;  echo 0 >> out/target/product/rk3568_r/vendor/build.prop;  echo 0' while loading .prop filesProperty value too long
07-28 10:48:43.868     0     0 I init    : processing action (persist.sys.led=*) from (/system/etc/init/hw/init.rc:535)
07-28 10:49:56.382     0     0 I init    : processing action (persist.sys.led=*) from (/system/etc/init/hw/init.rc:535)
07-28 10:50:37.042     0     0 I init    : processing action (persist.sys.led=*) from (/system/etc/init/hw/init.rc:535)
07-28 10:51:19.331     0     0 I init    : processing action (persist.sys.led=*) from (/system/etc/init/hw/init.rc:535)
07-28 10:51:24.381     0     0 I init    : processing action (persist.sys.led=*) from (/system/etc/init/hw/init.rc:535)
^C
130|rk3568_r:/ # dmesg | grep led_   //这是我加的driver打印 证明已经写入了
[    4.399010] 11 led_probe 55
[    4.399179] led_init_state to request GPIO pin 14 for LED 0 color 0
[    4.399197] led_init_state to request GPIO pin 13 for LED 0 color 1
[    4.399213] led_init_state to request GPIO pin 19 for LED 1 color 0
[    4.399229] led_init_state to request GPIO pin 18 for LED 1 color 1
[    4.399245] led_init_state to request GPIO pin 91 for LED 2 color 0
[    4.399260] led_init_state to request GPIO pin 97 for LED 2 color 1
[    4.399274] led_init_state to request GPIO pin 59 for LED 3 color 0
[    4.399288] led_init_state to request GPIO pin 58 for LED 3 color 1
[    4.399303] led_init_state to request GPIO pin 57 for LED 4 color 0
[    4.399317] led_init_state to request GPIO pin 56 for LED 4 color 1
[    4.399331] led_init_state to request GPIO pin 99 for LED 5 color 0
[    4.399345] led_init_state to request GPIO pin 98 for LED 5 color 1
[    4.399361] led_init_state to request GPIO pin 94 for LED 6 color 0
[    4.399376] led_init_state to request GPIO pin 90 for LED 6 color 1
[    4.399390] led_init_state to request GPIO pin 101 for LED 7 color 0
[    4.399404] led_init_state to request GPIO pin 100 for LED 7 color 1
[    4.399418] led_init_state to request GPIO pin 5 for LED 8 color 0
[    4.399432] led_init_state to request GPIO pin 0 for LED 8 color 1
[    5.907318] selinux: SELinux: Loaded policy from /odm/etc/selinux/precompiled_sepolicy
rk3568_r:/ #
此时我看设备上的灯已经亮了

注意

虽然这个解决方案可以有效地实现我们的目的,但是也有一些注意事项:

  • 不要在init.rc文件中添加过多的on property触发器,可能会影响init进程的性能和内存占用。最好只添加你需要的触发器,并且尽量简化触发器中的动作。
  • 正常情况下推荐是方案3 , 一般设备是不root的 , 同时也能避免有些sb驱动 不改driver权限的问题。
  • 验证发现如果打开SELINUX的话 普通app和adb shell 是压根没有权限写prop的。
  • 后面我跟了下代码流程发现这里是检测SELINUX权限的 会检测UID等信息, 所以我们屏蔽掉 这样普通app和adb shell都能执行写入prop。这种不是正规的搞法 适合不过GMS的源码 正常情况还是要去写上下文的。

总结

本文介绍了一种在Android 9.0及以上版本中解决app往/sys/class目录写不进数据的问题的方案,即利用init.rc文件中的write命令和on property触发器,来实现在app中正确往系统节点写数据的功能。本文也分析了这个方案的原理和注意事项,

希望对你有所帮助。如果你有任何问题或建议,欢迎留言讨论。谢谢

相关实践学习
阿里云百炼xAnalyticDB PostgreSQL构建AIGC应用
通过该实验体验在阿里云百炼中构建企业专属知识库构建及应用全流程。同时体验使用ADB-PG向量检索引擎提供专属安全存储,保障企业数据隐私安全。
AnalyticDB PostgreSQL 企业智能数据中台:一站式管理数据服务资产
企业在数据仓库之上可构建丰富的数据服务用以支持数据应用及业务场景;ADB PG推出全新企业智能数据平台,用以帮助用户一站式的管理企业数据服务资产,包括创建, 管理,探索, 监控等; 助力企业在现有平台之上快速构建起数据服务资产体系
相关文章
|
13天前
|
安全 Android开发 Kotlin
Android经典实战之SurfaceView原理和实践
本文介绍了 `SurfaceView` 这一强大的 UI 组件,尤其适合高性能绘制任务,如视频播放和游戏。文章详细讲解了 `SurfaceView` 的原理、与 `Surface` 类的关系及其实现示例,并强调了使用时需注意的线程安全、生命周期管理和性能优化等问题。
45 7
|
10天前
|
开发工具 Android开发 Swift
安卓与iOS开发环境对比分析
在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统无疑是主角。它们各自拥有独特的特点和优势,为开发者提供了不同的开发环境和工具。本文将深入浅出地探讨安卓和iOS开发环境的主要差异,包括开发工具、编程语言、用户界面设计、性能优化以及市场覆盖等方面,旨在帮助初学者更好地理解两大平台的开发特点,并为他们选择合适的开发路径提供参考。通过比较分析,我们将揭示不同环境下的开发实践,以及如何根据项目需求和目标受众来选择最合适的开发平台。
23 2
|
21天前
|
Android开发
基于android-11.0.0_r39,系统应用的手动签名方法和过程
本文介绍了基于Android 11.0.0_r39版本进行系统应用手动签名的方法和解决签名过程中遇到的错误,包括处理`no conscrypt_openjdk_jni-linux-x86_64`和`RegisterNatives failed`的问题。
63 2
|
20天前
|
JavaScript 前端开发 Java
[Android][Framework]系统jar包,sdk的制作及引用
[Android][Framework]系统jar包,sdk的制作及引用
36 0
|
9天前
|
编解码 前端开发 Android开发
Android经典实战之TextureView原理和高级用法
本文介绍了 `TextureView` 的原理和特点,包括其硬件加速渲染的优势及与其他视图叠加使用的灵活性,并提供了视频播放和自定义绘制的示例代码。通过合理管理生命周期和资源,`TextureView` 可实现高效流畅的图形和视频渲染。
39 12
|
15天前
|
Android开发
Android学习 —— 测试init.rc中的条件触发的处理顺序
Android学习 —— 测试init.rc中的条件触发的处理顺序
|
14天前
|
Android开发 UED 开发者
Android经典实战之WindowManager和创建系统悬浮窗
本文详细介绍了Android系统服务`WindowManager`,包括其主要功能和工作原理,并提供了创建系统悬浮窗的完整步骤。通过示例代码,展示了如何添加权限、请求权限、实现悬浮窗口及最佳实践,帮助开发者轻松掌握悬浮窗开发技巧。
29 1
|
15天前
|
IDE 开发工具 Android开发
安卓与iOS开发环境对比分析
本文将探讨安卓和iOS这两大移动操作系统在开发环境上的差异,从工具、语言、框架到生态系统等多个角度进行比较。我们将深入了解各自的优势和劣势,并尝试为开发者提供一些实用的建议,以帮助他们根据自己的需求选择最适合的开发平台。
22 1
|
21天前
|
Java 物联网 Android开发
移动应用与系统:技术演进与未来展望探索安卓应用开发:从新手到专家的旅程
【8月更文挑战第28天】本文将深入探讨移动应用开发的技术演进、移动操作系统的发展历程以及未来的发展趋势。我们将通过实例和代码示例,展示如何利用最新的技术和工具来开发高效、可靠的移动应用。无论你是初学者还是经验丰富的开发者,这篇文章都将为你提供有价值的信息和见解。 【8月更文挑战第28天】在这个数字时代,掌握安卓应用的开发技能不仅是技术人员的追求,也成为了许多人实现创意和梦想的途径。本文将通过深入浅出的方式,带领读者从零基础开始,一步步走进安卓开发的奇妙世界。我们将探讨如何配置开发环境,理解安卓应用的核心组件,以及如何通过实际编码来构建一个功能完整的应用。无论你是编程新手还是希望提升自己的开发者
|
19天前
|
存储 监控 数据库
Android经典实战之OkDownload的文件分段下载及合成原理
本文介绍了 OkDownload,一个高效的 Android 下载引擎,支持多线程下载、断点续传等功能。文章详细描述了文件分段下载及合成原理,包括任务创建、断点续传、并行下载等步骤,并展示了如何通过多种机制保证下载的稳定性和完整性。
24 0