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推出全新企业智能数据平台,用以帮助用户一站式的管理企业数据服务资产,包括创建, 管理,探索, 监控等; 助力企业在现有平台之上快速构建起数据服务资产体系
相关文章
|
28天前
|
开发框架 前端开发 Android开发
Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势
本文深入探讨了 Flutter 与原生模块(Android 和 iOS)之间的通信机制,包括方法调用、事件传递等,分析了通信的必要性、主要方式、数据传递、性能优化及错误处理,并通过实际案例展示了其应用效果,展望了未来的发展趋势。这对于实现高效的跨平台移动应用开发具有重要指导意义。
111 4
|
29天前
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
|
16天前
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
20天前
|
Java 开发工具 Android开发
安卓与iOS开发环境对比分析
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文深入探讨了这两个平台的开发环境,从编程语言、开发工具到用户界面设计等多个角度进行比较。通过实际案例分析和代码示例,我们旨在为开发者提供一个清晰的指南,帮助他们根据项目需求和个人偏好做出明智的选择。无论你是初涉移动开发领域的新手,还是寻求跨平台解决方案的资深开发者,这篇文章都将为你提供宝贵的信息和启示。
27 8
|
18天前
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
23天前
|
安全 Android开发 iOS开发
深入探讨Android与iOS系统的差异及未来发展趋势
本文旨在深入分析Android和iOS两大移动操作系统的核心技术差异、用户体验以及各自的市场表现,进一步探讨它们在未来技术革新中可能的发展方向。通过对比两者的开放性、安全性、生态系统等方面,本文揭示了两大系统在移动设备市场中的竞争态势和潜在变革。
|
23天前
|
安全 Android开发 数据安全/隐私保护
深入探索Android与iOS系统安全性的对比分析
在当今数字化时代,移动操作系统的安全已成为用户和开发者共同关注的重点。本文旨在通过比较Android与iOS两大主流操作系统在安全性方面的差异,揭示两者在设计理念、权限管理、应用审核机制等方面的不同之处。我们将探讨这些差异如何影响用户的安全体验以及可能带来的风险。
30 1
|
1月前
|
开发框架 前端开发 Android开发
探索安卓和iOS应用开发中的跨平台解决方案
【10月更文挑战第42天】在移动应用开发的广阔天地中,安卓和iOS系统如同两座巍峨的山峰,分别占据着半壁江山。开发者们在这两座山峰之间穿梭,努力寻找一种既能节省资源又能提高效率的跨平台开发方案。本文将带你走进跨平台开发的世界,探讨各种解决方案的优势与局限,并分享一些实用的代码示例,助你在应用开发的道路上更加游刃有余。
|
16天前
|
搜索推荐 前端开发 API
探索安卓开发中的自定义视图:打造个性化用户界面
在安卓应用开发的广阔天地中,自定义视图是一块神奇的画布,让开发者能够突破标准控件的限制,绘制出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战技巧,逐步揭示如何在安卓平台上创建和运用自定义视图来提升用户体验。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开新的视野,让你的应用在众多同质化产品中脱颖而出。
40 19
|
16天前
|
JSON Java API
探索安卓开发:打造你的首个天气应用
在这篇技术指南中,我们将一起潜入安卓开发的海洋,学习如何从零开始构建一个简单的天气应用。通过这个实践项目,你将掌握安卓开发的核心概念、界面设计、网络编程以及数据解析等技能。无论你是初学者还是有一定基础的开发者,这篇文章都将为你提供一个清晰的路线图和实用的代码示例,帮助你在安卓开发的道路上迈出坚实的一步。让我们一起开始这段旅程,打造属于你自己的第一个安卓应用吧!
41 14