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中正确往系统节点写数据的功能。本文也分析了这个方案的原理和注意事项,

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

相关实践学习
AnalyticDB PostgreSQL 企业智能数据中台:一站式管理数据服务资产
企业在数据仓库之上可构建丰富的数据服务用以支持数据应用及业务场景;ADB PG推出全新企业智能数据平台,用以帮助用户一站式的管理企业数据服务资产,包括创建, 管理,探索, 监控等; 助力企业在现有平台之上快速构建起数据服务资产体系
相关文章
|
3月前
|
Linux 测试技术 语音技术
【车载Android】模拟Android系统的高负载环境
本文介绍如何将Linux压力测试工具Stress移植到Android系统,用于模拟高负载环境下的CPU、内存、IO和磁盘压力,帮助开发者优化车载Android应用在多任务并发时的性能问题,提升系统稳定性与用户体验。
234 6
|
3月前
|
Java 数据库 Android开发
基于Android的电子记账本系统
本项目研究开发一款基于Java与Android平台的开源电子记账系统,采用SQLite数据库和Gradle工具,实现高效、安全、便捷的个人财务管理,顺应数字化转型趋势。
|
8月前
|
安全 搜索推荐 Android开发
Android系统SELinux安全机制详解
如此看来,SELinux对于大家来说,就像那位不眠不休,严阵以待的港口管理员,守护我们安卓系统的平安,维护这片海港的和谐生态。SELinux就这样,默默无闻,却卫士如山,给予Android系统一份厚重的安全保障。
268 18
|
9月前
|
监控 Shell Linux
Android调试终极指南:ADB安装+多设备连接+ANR日志抓取全流程解析,覆盖环境变量配置/多设备调试/ANR日志分析全流程,附Win/Mac/Linux三平台解决方案
ADB(Android Debug Bridge)是安卓开发中的重要工具,用于连接电脑与安卓设备,实现文件传输、应用管理、日志抓取等功能。本文介绍了 ADB 的基本概念、安装配置及常用命令。包括:1) 基本命令如 `adb version` 和 `adb devices`;2) 权限操作如 `adb root` 和 `adb shell`;3) APK 操作如安装、卸载应用;4) 文件传输如 `adb push` 和 `adb pull`;5) 日志记录如 `adb logcat`;6) 系统信息获取如屏幕截图和录屏。通过这些功能,用户可高效调试和管理安卓设备。
|
12月前
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
Linux API Android开发
Android中mmap原理及应用简析
Android中mmap原理及应用简析
623 0
Android中mmap原理及应用简析
|
前端开发 Java API
Android drawFunctor原理及应用
一. 背景AntGraphic项目Android平台中使用了基于TextureView环境实现GL渲染的技术方案,而TextureView需使用与Activity Window独立的GraphicBuffer,RenderThread在上屏TextureView内容时需要将GraphicBuffer封装为EGLImage上传为纹理再渲染,内存占用较高。为降低内存占用,经仔细调研Android源码,
723 0
|
2月前
|
移动开发 前端开发 Android开发
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
283 12
【02】建立各项目录和页面标准化产品-vue+vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
|
2月前
|
移动开发 JavaScript 应用服务中间件
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡
232 5
【06】优化完善落地页样式内容-精度优化-vue加vite开发实战-做一个非常漂亮的APP下载落地页-支持PC和H5自适应提供安卓苹果鸿蒙下载和网页端访问-优雅草卓伊凡

热门文章

最新文章