Android系统参数修改实战:如何安全修改android.os.build.board等系统属性

1次阅读
没有评论

共计 2874 个字符,预计需要花费 8 分钟才能阅读完成。

image.webp

为什么需要修改系统参数?

在 Android 开发中,修改系统参数(如android.os.build.board)的需求主要来自两个典型场景:

Android 系统参数修改实战:如何安全修改 android.os.build.board 等系统属性

  1. 设备兼容性测试 :当需要模拟不同硬件设备进行兼容性测试时,临时修改board 值可以快速验证应用在不同设备型号的表现。

  2. 硬件伪装需求:某些特殊应用(如设备仿真工具)可能需要动态修改系统属性来模拟特定硬件环境。

技术方案解析

系统属性访问的底层原理

Android 使用 PropertyService 机制管理系统属性。属性分为两类:

  • 只读属性 :如ro. 开头的属性(read-only),通常由系统初始化时设定。
  • 可写属性 :如persist. 开头的属性,允许在运行时修改并持久化。

反射方案实现

通过反射调用 SystemProperties 类是最灵活的方案,但需要注意权限问题:

fun setSystemPropertyViaReflection(key: String, value: String): Boolean {
    return try {val systemProperties = Class.forName("android.os.SystemProperties")
        val setMethod = systemProperties.getMethod(
            "set", 
            String::class.java, 
            String::class.java
        )
        setMethod.invoke(null, key, value)
        true
    } catch (e: SecurityException) {Log.e("SystemProp", "Permission denied: ${e.message}")
        false
    } catch (e: Exception) {Log.e("SystemProp", "Reflection failed: ${e.message}")
        false
    }
}

系统 API 方案(推荐)

对于 Android 8.0+ 设备,可以使用隐藏 APISystemProperties.set,但需要 android.permission.ACCESS_SURFACE_FLINGER 权限:

@SuppressLint("PrivateApi")
fun setSystemProperty(key: String, value: String): Boolean {return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        try {
            SystemProperties::class.java
                .getMethod("set", String::class.java, String::class.java)
                .invoke(null, key, value)
            true
        } catch (e: Exception) {false}
    } else {
        // 低版本使用反射方案
        setSystemPropertyViaReflection(key, value)
    }
}

完整代码封装

object SystemPropertyHelper {
    /**
     * 安全读取系统属性
     */
    fun getProperty(key: String, default: String = ""): String {
        return try {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                SystemProperties::class.java
                    .getMethod("get", String::class.java)
                    .invoke(null, key) as? String ?: default
            } else {Class.forName("android.os.SystemProperties")
                    .getMethod("get", String::class.java)
                    .invoke(null, key) as? String ?: default
            }
        } catch (e: Exception) {default}
    }

    /**
     * 带权限检查的属性修改
     */
    fun setPropertySafely(key: String, value: String): Boolean {
        // 禁止修改只读属性
        if (key.startsWith("ro.")) {Log.w("SystemProp", "Attempt to modify read-only property: $key")
            return false
        }

        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {checkPermission() && setSystemProperty(key, value)
        } else {setSystemPropertyViaReflection(key, value)
        }
    }

    private fun checkPermission(): Boolean {
        return ContextCompat.checkSelfPermission(
            App.context,
            "android.permission.ACCESS_SURFACE_FLINGER"
        ) == PackageManager.PERMISSION_GRANTED
    }
}

安全规范

  1. 非 root 设备限制 :普通应用只能修改非ro. 开头的属性,且需要特定权限。

  2. 系统签名要求 :永久性修改(如persist. 属性)需要应用具有系统签名。

  3. 临时修改生命周期:非持久化修改会在重启后失效,适合测试场景。

延伸思考

单元测试模拟方案

使用 Mockito 模拟系统属性读取:

@RunWith(MockitoJUnitRunner::class)
class SystemPropertyTest {
    @Test
    fun testMockSystemProperty() {val mockSystemProperties = mock(Class.forName("android.os.SystemProperties"))
        `when`(mockSystemProperties.getMethod("get", String::class.java)
            .invoke(any(), eq("ro.build.board")))
            .thenReturn("MockBoard")

        assertEquals("MockBoard", SystemPropertyHelper.getProperty("ro.build.board"))
    }
}

系统属性 vs SharedPreferences

  1. 存储位置:系统属性存在于内存 / 持久化分区,而 SharedPreferences 是应用私有文件。
  2. 访问速度:系统属性通过共享内存实现,读取速度更快。
  3. 作用范围:系统属性全局可见,SharedPreferences 仅限当前应用。

实践建议

对于日常开发,建议优先使用系统 API 方案,并在代码中添加充分的版本兼容处理。如果只是测试用途,可以考虑使用 ro.product.board 等非关键属性进行试验,避免影响系统稳定性。生产环境中如需永久修改系统属性,务必确保应用具有系统签名权限。

正文完
 0
评论(没有评论)