Android 系统属性完全指南

目录


版本说明

文档版本: 1.1
适用 Android 版本: Android 8.0+ (API 26+)
最后更新: 2025-01-15

重要提示

  • 本文档主要基于 Android 8.0+ 的实现,早期版本可能存在差异
  • 不同设备制造商可能对属性系统进行定制
  • 部分功能需要 root 权限或系统签名
  • 实际使用时请根据具体设备和版本进行验证

勘误与更新

  • 查看 勘误表 了解已知问题和修正

1. 系统属性概述

1.1 什么是系统属性

Android 系统属性(System Properties)是一个全局的键值对数据库,用于存储和共享系统级别的配置信息。它类似于 Windows 的注册表或 Linux 的 sysctl,但更加轻量级。

核心特性

  • 键值对结构: key=value 格式
  • 全局共享: 所有进程都可以访问(受权限控制)
  • 快速访问: 驻留在内存中,访问速度极快
  • 字符串类型: 所有值都以字符串形式存储
  • 大小限制:
    • 属性名最大长度:31 字符(PROP_NAME_MAX = 32,保留1字节给 \0)
    • 属性值最大长度:91 字符(PROP_VALUE_MAX = 92,保留1字节给 \0)

1.2 系统属性的作用

  1. 系统配置管理

    • 存储设备信息(型号、版本、序列号等)
    • 保存系统行为配置(语言、时区、调试开关等)
  2. 进程间通信

    • 提供轻量级的跨进程数据共享机制
    • 支持属性变更监听
  3. 调试与诊断

    • 动态控制日志级别
    • 开启/关闭调试功能
    • 性能分析开关
  4. 功能开关

    • Feature Flag 管理
    • A/B Testing 配置
    • 灰度发布控制

1.3 系统属性架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
┌─────────────────────────────────────────────────────┐
│ Android 应用层 │
│ SystemProperties.get/set() (Java API) │
└─────────────────┬───────────────────────────────────┘

┌─────────────────▼───────────────────────────────────┐
│ Framework 层 │
│ android.os.SystemProperties (隐藏API) │
└─────────────────┬───────────────────────────────────┘

┌─────────────────▼───────────────────────────────────┐
│ Native 层 │
│ property_get/property_set (C/C++ API) │
│ libcutils / libc │
└─────────────────┬───────────────────────────────────┘

┌─────────────────▼───────────────────────────────────┐
│ Property Service │
│ /dev/__properties__ (共享内存) │
│ property_contexts (SELinux 上下文) │
└─────────────────────────────────────────────────────┘

2. 系统属性分类

2.1 按前缀分类

Android 系统属性使用命名空间来组织,前缀决定了属性的特性和用途。

2.1.1 ro.* (Read-Only 只读属性)

特点

  • ✅ 系统启动时设置,之后不可修改
  • ✅ 通常从 build.prop 或内核命令行加载
  • ✅ 存储设备的固有信息

常见属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 设备信息
ro.product.model=Pixel 6 # 设备型号
ro.product.brand=Google # 品牌
ro.product.manufacturer=Google # 制造商
ro.product.device=oriole # 设备代号

# 系统版本
ro.build.version.release=13 # Android 版本号
ro.build.version.sdk=33 # SDK API Level
ro.build.id=TP1A.220624.014 # 构建 ID
ro.build.type=user # 构建类型 (user/userdebug/eng)
ro.build.date=Sun Jun 26 00:00:00 UTC 2022

# 硬件信息
ro.hardware=oriole # 硬件平台
ro.board.platform=gs101 # SoC 平台
ro.product.cpu.abi=arm64-v8a # CPU 架构

存储位置

  • /system/build.prop - 系统构建属性
  • /vendor/build.prop - 厂商属性
  • /product/build.prop - 产品属性
  • /odm/build.prop - ODM 属性

2.1.2 persist.* (持久化属性)

特点

  • ✅ 可读可写(需要权限)
  • ✅ 重启后仍然保留
  • ✅ 存储在 /data 分区

常见属性

1
2
3
4
5
6
7
8
9
10
11
# 调试开关
persist.sys.usb.config=adb # USB 模式
persist.log.tag=V # 全局日志级别

# 性能配置
persist.sys.dalvik.vm.lib.2=libart.so
persist.sys.strictmode.visual=false

# 功能开关
persist.sys.cached_app_freezer=true # 应用冻结开关
persist.sys.timezone=Asia/Shanghai # 时区

存储位置

  • /data/property/persistent_properties - 所有 persist.* 属性的二进制存储文件
  • Android 8.0+ 统一使用此文件,替代了早期版本的每个属性独立文件方式

2.1.3 sys.* (系统运行时属性)

特点

  • ✅ 可读可写(需要权限)
  • ❌ 重启后丢失(非持久化)
  • ✅ 用于运行时状态和临时配置

常见属性

1
2
3
4
5
6
7
8
# 系统状态
sys.boot_completed=1 # 启动完成标志
sys.powerctl=reboot # 电源控制
sys.usb.state=adb # 当前 USB 状态

# 运行时配置
sys.logbootcomplete=1
sys.retaildemo.enabled=0

2.1.4 debug.* (调试属性)

特点

  • ✅ 用于开发和调试
  • ✅ 通常在 user 版本中被忽略
  • ✅ 可动态修改

常见属性

1
2
3
4
5
6
7
8
# 调试开关
debug.atrace.tags.enableflags=0
debug.sf.enable_hwc_vds=1 # SurfaceFlinger 调试
debug.choreographer.skipwarning=1

# 性能分析
debug.performance.tuning=1
debug.hwui.profile=true

2.1.5 service.* (服务状态属性)

特点

  • ✅ 用于服务状态管理
  • ✅ 通常由 init 系统管理

常见属性

1
2
service.bootanim.exit=1           # 开机动画退出
service.adb.tcp.port=5555 # ADB TCP 端口

2.1.6 init.* (Init 进程属性)

特点

  • ✅ 由 init 进程设置
  • ✅ 用于启动流程控制

常见属性

1
2
3
init.svc.adbd=running             # adbd 服务状态
init.svc.zygote=running # zygote 进程状态
init.svc.surfaceflinger=running # SurfaceFlinger 状态

2.2 按生命周期分类

类型 持久化 可写 重启后保留 典型前缀
构建时属性 文件 ro.*
持久化属性 文件 persist.*
运行时属性 内存 sys., debug.
服务属性 内存 init.svc.*

3. 存储机制与持久化

3.1 存储架构

1
2
3
4
5
6
7
8
9
10
11
12
┌──────────────────────────────────────────────────────┐
│ 系统属性存储层次 │
└──────────────────────────────────────────────────────┘

┌────────────────┼────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌──────────────────────┐ ┌─────────────┐
│ 共享内存区域 │ │ 持久化文件 │ │ 构建文件 │
│ /dev/__prop* │ │ /data/property/ │ │ build.prop │
│ (运行时) │ │ persistent_properties│ │ (ro.*) │
└───────────────┘ └──────────────────────┘ └─────────────┘

3.2 共享内存机制

Property Service 使用共享内存实现高效的跨进程访问

实现细节

1
2
3
4
5
6
7
8
9
10
11
12
// bionic/libc/bionic/system_properties.cpp
#define PROP_SERVICE_NAME "property_service"
#define PROP_FILENAME_MAX 1024

// 属性存储在共享内存中
struct prop_area {
uint32_t magic; // 魔数验证
uint32_t version; // 版本号
uint32_t serial; // 序列号(用于监听变更)
uint32_t size; // 总大小
// ... 属性数据
};

访问流程

  1. 应用调用 SystemProperties.get()
  2. 通过 Binder 调用到 Property Service
  3. Property Service 从共享内存读取
  4. 返回属性值

3.3 持久化文件存储

3.3.1 构建属性文件

build.prop 文件格式

1
2
3
4
5
6
7
8
# /system/build.prop
# 注释行以 # 开头
ro.product.model=Example Device
ro.build.version.sdk=33
ro.build.version.release=13

# 支持环境变量展开(编译时)
ro.build.date=${BUILD_DATE}

加载顺序(优先级从低到高):

  1. /system/build.prop
  2. /vendor/build.prop
  3. /odm/build.prop
  4. /product/build.prop
  5. 后加载的同名属性会覆盖先加载的

3.3.2 持久化属性文件

persist. 属性的存储*:

在 Android 8.0+ 版本中,所有 persist.* 属性统一存储在一个二进制文件中:

1
2
3
4
5
6
# 持久化属性存储位置
/data/property/persistent_properties

# 文件结构(二进制格式)
$ ls -l /data/property/
-rw------- 1 root root 15406 2025-10-15 14:43 persistent_properties

特点

  • ✅ 所有 persist.* 属性存储在一个文件中
  • ✅ 使用 Protocol Buffer 或自定义二进制格式
  • ✅ 文件权限:root:root 0600(仅 root 可访问)
  • ✅ 写入时原子操作,保证数据一致性

历史变化

  • Android 7.x 及以前:每个属性一个文件(/data/property/persist.*
  • Android 8.0+:统一存储在 persistent_properties 文件中

注意

  • ⚠️ 不要直接修改此文件,应使用 setprop 命令
  • ⚠️ 文件格式是二进制的,无法直接用文本编辑器查看

3.4 内核命令行属性

从内核命令行加载属性

1
2
3
4
5
6
7
8
9
# 内核命令行参数
androidboot.hardware=oriole
androidboot.serialno=1234567890ABCDEF

# 转换为系统属性
ro.boot.hardware=oriole
ro.boot.serialno=1234567890ABCDEF
ro.hardware=oriole
ro.serialno=1234567890ABCDEF

转换规则

  • androidboot.*ro.boot.*
  • 某些特殊属性会同时创建简化版本(如 ro.hardware

4. 系统属性的生命周期

4.1 启动阶段的属性加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
启动流程                    属性加载
────────────────────────────────────────
Bootloader


Kernel
│ ────────────► 加载内核命令行属性
▼ androidboot.* → ro.boot.*
Init (第一阶段)
│ ────────────► 设置基础属性
▼ ro.boot.*, ro.hardware
Init (第二阶段)
│ ────────────► 加载 build.prop
▼ 解析 /system/build.prop
│ 解析 /vendor/build.prop
│ 解析 /product/build.prop
│ ────────────► 加载 persist.* 属性
▼ 从 /data/property/ 读取
Property Service 启动
│ ────────────► 启动属性服务
▼ 监听 socket 连接
│ 处理 set/get 请求
Zygote


System Server
│ ────────────► 设置运行时属性
▼ sys.boot_completed=0
Boot Complete
│ ────────────► 标记启动完成
▼ sys.boot_completed=1

4.2 运行时属性变更流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
应用进程                      Property Service
────────────────────────────────────────────────
SystemProperties.set()

├──► 检查权限

├──► Binder Call ───────► 接收请求
│ │
│ ├──► SELinux 权限检查
│ │ (property_contexts)
│ │
│ ├──► 更新共享内存
│ │
│ ├──► persist.* ?
│ │ └─► 写入文件
│ │ /data/property/*
│ │
│ └──► 触发 init 脚本
│ (on property:xxx=*)

◄────── 返回 ───────────────

4.3 属性监听机制

Java 层监听

1
2
3
4
5
6
7
8
// 监听属性变化(隐藏 API)
SystemProperties.addChangeCallback(new Runnable() {
@Override
public void run() {
String value = SystemProperties.get("persist.sys.example");
Log.d(TAG, "Property changed: " + value);
}
});

Native 层监听

1
2
3
4
5
6
7
8
#include <sys/system_properties.h>

void property_callback(void *cookie, const char *name, const char *value, uint32_t serial) {
ALOGD("Property %s changed to %s (serial=%u)", name, value, serial);
}

// 监听特定属性
__system_property_set_callback(property_callback, nullptr);

5. 读取与设置方法

5.1 Java API

5.1.1 读取属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import android.os.SystemProperties;

// 方法1:读取字符串属性(不存在返回空字符串)
String value = SystemProperties.get("ro.product.model");

// 方法2:读取字符串属性(带默认值)
String value = SystemProperties.get("debug.my.prop", "default_value");

// 方法3:读取整数属性
int sdkVersion = SystemProperties.getInt("ro.build.version.sdk", 0);

// 方法4:读取长整型属性
long value = SystemProperties.getLong("my.long.prop", 0L);

// 方法5:读取布尔属性
boolean isEnabled = SystemProperties.getBoolean("persist.sys.example", false);

注意

  • ⚠️ SystemProperties 是隐藏 API(@hide),需要通过反射调用
  • ✅ 系统应用或具有系统签名可以直接调用

反射调用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class SystemPropertiesProxy {
private static Class<?> sSystemProperties;

static {
try {
sSystemProperties = Class.forName("android.os.SystemProperties");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}

public static String get(String key, String def) {
try {
Method get = sSystemProperties.getMethod("get", String.class, String.class);
return (String) get.invoke(null, key, def);
} catch (Exception e) {
return def;
}
}

public static void set(String key, String val) {
try {
Method set = sSystemProperties.getMethod("set", String.class, String.class);
set.invoke(null, key, val);
} catch (Exception e) {
e.printStackTrace();
}
}
}

// 使用
String model = SystemPropertiesProxy.get("ro.product.model", "Unknown");

5.1.2 设置属性

1
2
3
4
5
6
7
8
// 设置属性(需要权限)
SystemProperties.set("persist.sys.example", "value");

// 设置整数属性
SystemProperties.set("persist.sys.count", String.valueOf(123));

// 删除属性(设置为空字符串)
SystemProperties.set("persist.sys.example", "");

权限要求

  • 需要 android.permission.WRITE_SECURE_SETTINGS 权限
  • 或者系统签名(platformSignature)
  • 或者 root 权限

5.2 Native C/C++ API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <cutils/properties.h>

// 读取属性
char value[PROPERTY_VALUE_MAX];
property_get("ro.product.model", value, "Unknown");

// 读取整数属性
int sdk = property_get_int32("ro.build.version.sdk", 0);

// 读取布尔属性
bool isEnabled = property_get_bool("persist.sys.example", false);

// 设置属性(需要权限)
property_set("persist.sys.example", "value");

5.3 Shell 命令

5.3.1 getprop - 读取属性

1
2
3
4
5
6
7
8
9
10
11
12
13
# 读取单个属性
adb shell getprop ro.product.model

# 列出所有属性
adb shell getprop

# 使用 grep 过滤
adb shell getprop | grep "ro.build"

# 输出格式:[key]: [value]
# 示例:
# [ro.product.model]: [Pixel 6]
# [ro.build.version.sdk]: [33]

5.3.2 setprop - 设置属性

1
2
3
4
5
6
7
8
9
10
11
# 设置属性(需要 root 或 adb root)
adb shell setprop persist.sys.example "test_value"

# 设置数字
adb shell setprop debug.level 3

# 删除属性(设置为空)
adb shell setprop persist.sys.example ""

# 验证设置
adb shell getprop persist.sys.example

限制

  • 普通应用无法通过 setprop 设置属性
  • 需要 adb root 或 su root
  • 受 SELinux 策略限制

5.4 批量操作

导出所有属性

1
2
3
4
5
6
# 导出到文件
adb shell getprop > properties.txt

# 按前缀导出
adb shell getprop | grep "^\\[ro\\." > ro_properties.txt
adb shell getprop | grep "^\\[persist\\." > persist_properties.txt

比较属性差异

1
2
3
4
5
6
7
# 导出两次属性
adb shell getprop > props_before.txt
# ... 执行某些操作 ...
adb shell getprop > props_after.txt

# 比较差异
diff props_before.txt props_after.txt

6. 系统更新的影响

6.1 OTA 更新对属性的影响

属性类型 OTA 更新后 恢复出厂设置后 数据擦除后
ro.* ✅ 更新 ✅ 保留 ✅ 保留
persist.* ✅ 保留 ❌ 清除 ❌ 清除
sys., debug. N/A(内存) N/A(内存) N/A(内存)
build.prop ✅ 更新 ✅ 更新 ✅ 更新

6.2 分区影响

1
2
3
4
5
6
7
分区结构                  属性来源                    OTA 影响
────────────────────────────────────────────────────
/system build.prop ✅ 会更新
/vendor build.prop ✅ 会更新
/product build.prop ✅ 可能更新
/odm build.prop ✅ 可能更新
/data/property/ persist.* 文件 ❌ 不影响

6.3 属性备份与恢复

6.3.1 手动备份脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/system/bin/sh
# backup_properties.sh - 备份持久化属性

BACKUP_DIR=/sdcard/property_backup
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE=$BACKUP_DIR/persist_props_$TIMESTAMP.txt

# 创建备份目录
mkdir -p $BACKUP_DIR

# 备份所有 persist.* 属性
echo "# Property Backup - $TIMESTAMP" > $BACKUP_FILE
getprop | grep "^\[persist\." >> $BACKUP_FILE

echo "Properties backed up to $BACKUP_FILE"

6.3.2 恢复脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/system/bin/sh
# restore_properties.sh - 恢复持久化属性

BACKUP_FILE=$1

if [ -z "$BACKUP_FILE" ]; then
echo "Usage: $0 <backup_file>"
exit 1
fi

# 读取备份文件并恢复
while IFS= read -r line; do
# 跳过注释行
if [[ $line =~ ^#.* ]]; then
continue
fi

# 解析格式:[key]: [value]
if [[ $line =~ ^\[(.+)\]:\ \[(.+)\]$ ]]; then
key="${BASH_REMATCH[1]}"
value="${BASH_REMATCH[2]}"
echo "Restoring: $key=$value"
setprop "$key" "$value"
fi
done < "$BACKUP_FILE"

echo "Properties restored from $BACKUP_FILE"

6.4 升级后属性验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/system/bin/sh
# verify_properties.sh - 验证关键属性

CRITICAL_PROPS=(
"persist.sys.timezone"
"persist.sys.locale"
"persist.sys.usb.config"
)

echo "=== Verifying Critical Properties ==="
for prop in "${CRITICAL_PROPS[@]}"; do
value=$(getprop "$prop")
if [ -z "$value" ]; then
echo "⚠️ WARNING: $prop is not set!"
else
echo "✅ $prop = $value"
fi
done

7. 常用系统属性详解

7.1 设备信息属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# ========== 设备基本信息 ==========
ro.product.model # 设备型号(用户可见)
ro.product.brand # 品牌名称
ro.product.manufacturer # 制造商
ro.product.device # 设备代号(内部使用)
ro.product.name # 产品名称
ro.serialno # 设备序列号
ro.boot.serialno # 从 bootloader 传递的序列号

# 示例
[ro.product.model]: [Pixel 6]
[ro.product.brand]: [Google]
[ro.product.manufacturer]: [Google]
[ro.product.device]: [oriole]

7.2 系统版本属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# ========== Android 版本 ==========
ro.build.version.release # 版本号(如 13)
ro.build.version.sdk # API Level(如 33)
ro.build.version.security_patch # 安全补丁日期
ro.build.id # 构建 ID
ro.build.display.id # 显示的构建 ID
ro.build.version.incremental # 增量版本号
ro.build.type # 构建类型(user/userdebug/eng)

# 示例
[ro.build.version.release]: [13]
[ro.build.version.sdk]: [33]
[ro.build.version.security_patch]: [2023-01-05]
[ro.build.type]: [user]

7.3 硬件信息属性

1
2
3
4
5
6
7
8
9
10
11
12
# ========== 硬件平台 ==========
ro.hardware # 硬件名称
ro.board.platform # SoC 平台(如 gs101)
ro.product.cpu.abi # 主 CPU 架构(如 arm64-v8a)
ro.product.cpu.abilist # 支持的 CPU 架构列表
ro.product.cpu.abilist64 # 64位架构列表
ro.product.cpu.abilist32 # 32位架构列表

# 示例
[ro.hardware]: [oriole]
[ro.board.platform]: [gs101]
[ro.product.cpu.abi]: [arm64-v8a]

7.4 调试相关属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# ========== ADB 调试 ==========
persist.sys.usb.config # USB 模式配置
ro.debuggable # 是否可调试(0/1)
persist.adb.tcp.port # ADB TCP 端口
ro.adb.secure # ADB 安全模式

# ========== 日志级别 ==========
persist.log.tag # 全局日志级别(V/D/I/W/E)
persist.log.tag.xxx # 特定 TAG 的日志级别
debug.logpersist # 持久化日志

# ========== 性能调试 ==========
debug.sf.showfps # 显示 FPS
debug.sf.disable_backpressure # 禁用背压
debug.hwui.profile # HWUI 性能分析

7.5 系统行为属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# ========== 语言与区域 ==========
persist.sys.locale # 系统语言(如 zh-CN)
persist.sys.timezone # 时区(如 Asia/Shanghai)

# ========== 显示设置 ==========
persist.sys.lcd_density # 屏幕密度
ro.sf.lcd_density # 默认屏幕密度

# ========== 电源管理 ==========
sys.powerctl # 电源控制(reboot/shutdown)
sys.boot_completed # 启动完成标志

# ========== 网络 ==========
persist.sys.wifi.always_on # WiFi 常开
net.hostname # 设备主机名

7.6 功能开关属性

1
2
3
4
5
6
7
8
9
10
11
12
13
# ========== 性能优化 ==========
persist.sys.cached_app_freezer # 应用冻结功能
persist.device_config.runtime_native_boot.enable_uffd_gc # UFFD GC
persist.sys.dalvik.vm.lib.2 # Dalvik 虚拟机库

# ========== 安全功能 ==========
ro.secure # Secure Boot 状态
ro.boot.verifiedbootstate # 验证启动状态
ro.boot.flash.locked # Bootloader 锁定状态

# ========== 开发者选项 ==========
persist.sys.strictmode.visual # 严格模式可视化
persist.sys.overlayfs.override_creds # OverlayFS 覆盖

8. 实践应用场景

8.1 特性开关(Feature Toggle)

场景:通过系统属性控制功能的启用/禁用,便于灰度发布和 A/B 测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class FeatureManager {
private static final String FEATURE_PREFIX = "persist.feature.";

/**
* 检查功能是否启用
*/
public static boolean isFeatureEnabled(String featureName) {
String propName = FEATURE_PREFIX + featureName;
return SystemProperties.getBoolean(propName, false);
}

/**
* 启用功能
*/
public static void enableFeature(String featureName) {
String propName = FEATURE_PREFIX + featureName;
SystemProperties.set(propName, "true");
}

/**
* 禁用功能
*/
public static void disableFeature(String featureName) {
String propName = FEATURE_PREFIX + featureName;
SystemProperties.set(propName, "false");
}
}

// 使用示例
if (FeatureManager.isFeatureEnabled("new_ui")) {
// 使用新 UI
} else {
// 使用旧 UI
}

8.2 动态日志控制

场景:在生产环境中动态调整日志级别,便于问题诊断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class LogManager {
private static final String LOG_TAG_PREFIX = "persist.log.tag.";

/**
* 设置模块日志级别
* @param tag 日志 TAG
* @param level V/D/I/W/E/S (Verbose/Debug/Info/Warn/Error/Silent)
*/
public static void setLogLevel(String tag, String level) {
String propName = LOG_TAG_PREFIX + tag;
SystemProperties.set(propName, level);
}

/**
* 获取模块日志级别
*/
public static String getLogLevel(String tag) {
String propName = LOG_TAG_PREFIX + tag;
return SystemProperties.get(propName, "I"); // 默认 INFO
}

/**
* 检查是否应该打印日志
*/
public static boolean isLoggable(String tag, int level) {
return Log.isLoggable(tag, level);
}
}

// 使用示例
// 临时开启某个模块的详细日志
LogManager.setLogLevel("MyModule", "V");

// 代码中使用
if (LogManager.isLoggable("MyModule", Log.VERBOSE)) {
Log.v("MyModule", "Detailed debug info...");
}

// 恢复默认级别
LogManager.setLogLevel("MyModule", "I");

Shell 命令

1
2
3
4
5
6
7
8
# 开启模块详细日志
adb shell setprop persist.log.tag.MyModule V

# 查看日志
adb logcat MyModule:V *:S

# 恢复默认
adb shell setprop persist.log.tag.MyModule I

8.3 设备配置管理

场景:在不同设备或配置下使用不同的参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class DeviceConfig {

/**
* 获取设备型号
*/
public static String getDeviceModel() {
return SystemProperties.get("ro.product.model", "Unknown");
}

/**
* 判断是否是平板
*/
public static boolean isTablet() {
String characteristics = SystemProperties.get("ro.build.characteristics", "");
return characteristics.contains("tablet");
}

/**
* 获取 RAM 大小(GB)
*/
public static int getRamSizeGB() {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
am.getMemoryInfo(memInfo);
return (int) (memInfo.totalMem / (1024 * 1024 * 1024));
}

/**
* 根据设备配置调整参数
*/
public static int getOptimalThreadCount() {
int ram = getRamSizeGB();
if (ram >= 8) {
return 4;
} else if (ram >= 4) {
return 2;
} else {
return 1;
}
}
}

8.4 性能监控与优化

场景:通过属性控制性能监控和优化策略。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class PerformanceMonitor {

/**
* 检查是否启用性能监控
*/
public static boolean isPerformanceMonitorEnabled() {
return SystemProperties.getBoolean("debug.performance.monitor", false);
}

/**
* 获取采样率(百分比)
*/
public static int getSamplingRate() {
return SystemProperties.getInt("debug.performance.sampling_rate", 10);
}

/**
* 上报性能数据
*/
public static void reportPerformance(String metric, long value) {
if (!isPerformanceMonitorEnabled()) {
return;
}

int samplingRate = getSamplingRate();
if (Math.random() * 100 < samplingRate) {
// 上报到分析平台
Analytics.report(metric, value);
}
}
}

// 使用
long startTime = SystemClock.elapsedRealtime();
// ... 执行操作 ...
long duration = SystemClock.elapsedRealtime() - startTime;
PerformanceMonitor.reportPerformance("operation_duration", duration);

8.5 A/B Testing 实现

场景:基于系统属性实现 A/B 测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class ABTestManager {
private static final String AB_TEST_PREFIX = "persist.abtest.";

/**
* 获取实验组(A/B)
*/
public static String getExperimentGroup(String experimentName) {
String propName = AB_TEST_PREFIX + experimentName;
String group = SystemProperties.get(propName, "");

if (group.isEmpty()) {
// 首次访问,随机分配组
group = Math.random() < 0.5 ? "A" : "B";
SystemProperties.set(propName, group);
}

return group;
}

/**
* 检查是否在 A 组
*/
public static boolean isGroupA(String experimentName) {
return "A".equals(getExperimentGroup(experimentName));
}

/**
* 重置实验
*/
public static void resetExperiment(String experimentName) {
String propName = AB_TEST_PREFIX + experimentName;
SystemProperties.set(propName, "");
}
}

// 使用示例
if (ABTestManager.isGroupA("new_algorithm")) {
// 使用新算法
useNewAlgorithm();
} else {
// 使用旧算法
useOldAlgorithm();
}

9. 调试技巧

9.1 查看和过滤属性

常用 Shell 命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1. 查看所有属性
adb shell getprop

# 2. 按前缀过滤
adb shell getprop | grep "ro.build" # 构建信息
adb shell getprop | grep "persist." # 持久化属性
adb shell getprop | grep "debug." # 调试属性

# 3. 按正则表达式过滤
adb shell getprop | grep -E "ro\.(product|build)"

# 4. 查看特定属性
adb shell getprop ro.product.model

# 5. 统计属性数量
adb shell getprop | wc -l

# 6. 查看最近修改的属性(需要 root)
adb shell ls -lt /data/property/ | head -20

9.2 监控属性变化

实时监控脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/bin/bash
# monitor_property.sh - 监控属性变化

PROP_NAME=$1
INTERVAL=${2:-1} # 默认 1 秒

if [ -z "$PROP_NAME" ]; then
echo "Usage: $0 <property_name> [interval_seconds]"
exit 1
fi

echo "Monitoring property: $PROP_NAME"
echo "Press Ctrl+C to stop"
echo "─────────────────────────────────────"

LAST_VALUE=""
while true; do
CURRENT_VALUE=$(adb shell getprop "$PROP_NAME")

if [ "$CURRENT_VALUE" != "$LAST_VALUE" ]; then
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
echo "[$TIMESTAMP] $PROP_NAME: $LAST_VALUE -> $CURRENT_VALUE"
LAST_VALUE="$CURRENT_VALUE"
fi

sleep "$INTERVAL"
done

使用示例

1
2
3
4
5
# 监控 USB 状态变化
./monitor_property.sh sys.usb.state

# 监控启动完成标志
./monitor_property.sh sys.boot_completed

9.3 导出与对比

导出脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash
# export_properties.sh - 导出系统属性

OUTPUT_DIR="./property_exports"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
DEVICE_MODEL=$(adb shell getprop ro.product.model | tr -d '\r')

mkdir -p "$OUTPUT_DIR"

echo "Exporting properties from $DEVICE_MODEL..."

# 导出所有属性
adb shell getprop > "$OUTPUT_DIR/all_${DEVICE_MODEL}_${TIMESTAMP}.txt"

# 按类别导出
adb shell getprop | grep "^\[ro\." > "$OUTPUT_DIR/ro_${DEVICE_MODEL}_${TIMESTAMP}.txt"
adb shell getprop | grep "^\[persist\." > "$OUTPUT_DIR/persist_${DEVICE_MODEL}_${TIMESTAMP}.txt"
adb shell getprop | grep "^\[sys\." > "$OUTPUT_DIR/sys_${DEVICE_MODEL}_${TIMESTAMP}.txt"
adb shell getprop | grep "^\[debug\." > "$OUTPUT_DIR/debug_${DEVICE_MODEL}_${TIMESTAMP}.txt"

echo "Properties exported to $OUTPUT_DIR"

对比脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/bash
# compare_properties.sh - 对比两次导出的属性

FILE1=$1
FILE2=$2

if [ -z "$FILE1" ] || [ -z "$FILE2" ]; then
echo "Usage: $0 <file1> <file2>"
exit 1
fi

echo "Comparing properties..."
echo "File 1: $FILE1"
echo "File 2: $FILE2"
echo "─────────────────────────────────────"

# 新增的属性
echo ""
echo "=== New Properties ==="
diff <(cut -d: -f1 "$FILE1") <(cut -d: -f1 "$FILE2") | grep "^>" | cut -d' ' -f2-

# 删除的属性
echo ""
echo "=== Removed Properties ==="
diff <(cut -d: -f1 "$FILE1") <(cut -d: -f1 "$FILE2") | grep "^<" | cut -d' ' -f2-

# 变化的属性
echo ""
echo "=== Changed Properties ==="
diff "$FILE1" "$FILE2" | grep "^[<>]" | grep -v "^---"

9.4 性能分析

测量属性访问性能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class PropertyBenchmark {

public static void benchmarkGet() {
int iterations = 10000;
String key = "ro.product.model";

long startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
SystemProperties.get(key);
}
long endTime = System.nanoTime();

long avgTime = (endTime - startTime) / iterations;
Log.d("Benchmark", String.format(
"Average get time: %d ns (%d µs)",
avgTime, avgTime / 1000
));
}

public static void benchmarkSet() {
int iterations = 1000;
String key = "debug.benchmark.test";

long startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
SystemProperties.set(key, String.valueOf(i));
}
long endTime = System.nanoTime();

long avgTime = (endTime - startTime) / iterations;
Log.d("Benchmark", String.format(
"Average set time: %d ns (%d µs)",
avgTime, avgTime / 1000
));
}
}

典型性能指标

  • property_get(): ~1-5 µs(微秒)
  • property_set(): ~50-200 µs(需要 Binder IPC)

9.5 调试日志收集

完整日志收集脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/system/bin/sh
# collect_debug_logs.sh - 收集调试信息

LOG_DIR=/sdcard/debug_logs
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
LOG_FILE=$LOG_DIR/debug_$TIMESTAMP.txt

mkdir -p $LOG_DIR

echo "=== System Properties Debug Info ===" > $LOG_FILE
echo "Timestamp: $(date)" >> $LOG_FILE
echo "" >> $LOG_FILE

# 系统属性
echo "=== All Properties ===" >> $LOG_FILE
getprop >> $LOG_FILE
echo "" >> $LOG_FILE

# 持久化属性存储
echo "=== Persist Property Storage ===" >> $LOG_FILE
ls -la /data/property/ >> $LOG_FILE
echo "" >> $LOG_FILE
echo "=== Persist Properties (from getprop) ===" >> $LOG_FILE
getprop | grep "^\[persist\." >> $LOG_FILE
echo "" >> $LOG_FILE

# 构建属性文件
echo "=== Build Property Files ===" >> $LOG_FILE
for file in /system/build.prop /vendor/build.prop /product/build.prop; do
if [ -f "$file" ]; then
echo "--- $file ---" >> $LOG_FILE
cat "$file" >> $LOG_FILE
echo "" >> $LOG_FILE
fi
done

# logcat 最近的日志
echo "=== Recent Logcat ===" >> $LOG_FILE
logcat -d -t 500 >> $LOG_FILE

# 压缩
cd $LOG_DIR
tar -czf debug_$TIMESTAMP.tar.gz debug_$TIMESTAMP.txt
rm debug_$TIMESTAMP.txt

echo "Debug logs collected: $LOG_DIR/debug_$TIMESTAMP.tar.gz"

10. 安全与权限

10.1 SELinux 策略

系统属性的访问受 SELinux 策略控制,策略定义在 property_contexts 文件中。

property_contexts 文件位置

  • /system/etc/selinux/plat_property_contexts
  • /vendor/etc/selinux/vendor_property_contexts

示例策略

1
2
3
4
5
6
# property_contexts 格式
# property_name selinux_context

ro. u:object_r:default_prop:s0
persist.sys. u:object_r:system_prop:s0
debug. u:object_r:debug_prop:s0

权限检查流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
应用进程

├──► SystemProperties.set()


Property Service

├──► SELinux 策略检查
│ property_contexts
│ │
│ ├──► 检查进程的 SELinux 上下文
│ │ (u:r:untrusted_app:s0)
│ │
│ └──► 检查属性的 SELinux 上下文
│ (u:object_r:system_prop:s0)

├──► 允许?
│ ├──► Yes ──► 设置属性
│ └──► No ──► 返回权限错误

10.2 权限分类

属性前缀 SELinux 上下文 读权限 写权限 说明
ro.* default_prop 所有进程 ❌ 无 只读属性
persist.sys.* system_prop 所有进程 system_server, init 系统属性
debug.* debug_prop 所有进程 shell, root, eng 构建 调试属性
sys.* system_prop 所有进程 system_server, init 运行时系统属性
vendor.* vendor_prop 所有进程 vendor 进程 厂商属性

10.3 添加自定义属性权限

步骤1: 定义 SELinux 类型

1
2
# device/vendor/sepolicy/private/property.te
type custom_prop, property_type;

步骤2: 添加到 property_contexts

1
2
# device/vendor/sepolicy/private/property_contexts
persist.custom. u:object_r:custom_prop:s0

步骤3: 授权进程访问

1
2
3
4
5
6
# device/vendor/sepolicy/private/system_app.te
# 允许系统应用读取
get_prop(system_app, custom_prop)

# 允许系统应用设置
set_prop(system_app, custom_prop)

10.4 权限检查示例

Java 层权限检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class PropertyPermissionChecker {

/**
* 检查是否有权限设置属性
*/
public static boolean canSetProperty(String propName) {
try {
SystemProperties.set(propName, SystemProperties.get(propName, ""));
return true;
} catch (Exception e) {
Log.e("Permission", "Cannot set property: " + propName, e);
return false;
}
}

/**
* 安全地设置属性
*/
public static boolean setPropertySafely(String propName, String value) {
try {
SystemProperties.set(propName, value);
return true;
} catch (SecurityException e) {
Log.e("Permission", "Permission denied for: " + propName);
return false;
} catch (Exception e) {
Log.e("Permission", "Failed to set property: " + propName, e);
return false;
}
}
}

检查当前进程的 SELinux 上下文

1
2
3
4
5
# 查看当前进程的 SELinux 上下文
adb shell ps -eZ | grep <process_name>

# 示例输出
u:r:untrusted_app:s0:c123,c256 u0_a123 12345 ... com.example.app

11. 最佳实践

11.1 命名规范

推荐的命名模式

1
2
3
4
5
6
7
8
[prefix].[module].[feature].[name]

示例:
persist.sys.power.low_battery_threshold
│ │ │ └─ 具体功能名称
│ │ └─ 模块名称
│ └─ 子系统
└─ 属性类型前缀

命名建议

  1. 使用有意义的前缀

    1
    2
    3
    4
    5
    6
    7
    # ✅ Good
    persist.app.myapp.feature_enabled
    persist.custom.mycompany.config

    # ❌ Bad
    persist.x
    persist.temp
  2. 保持层次清晰

    1
    2
    3
    4
    5
    6
    7
    # ✅ Good
    persist.network.wifi.auto_reconnect
    persist.network.mobile.prefer_5g

    # ❌ Bad
    persist.wifi_reconnect
    persist.mobile_5g
  3. 避免特殊字符

    1
    2
    3
    4
    5
    6
    # ✅ Good
    persist.my.app.setting_value

    # ❌ Bad
    persist.my.app.setting-value # 使用连字符
    persist.my.app.setting value # 包含空格

11.2 性能优化

1. 缓存频繁访问的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class CachedPropertyManager {
private static final Map<String, String> sCache = new ConcurrentHashMap<>();
private static final Set<String> sCachedKeys = new HashSet<>();

static {
// 预定义需要缓存的属性
sCachedKeys.add("ro.product.model");
sCachedKeys.add("ro.build.version.sdk");
// ... 其他常用属性
}

public static String get(String key, String defaultValue) {
// 检查是否应该缓存
if (sCachedKeys.contains(key)) {
String cached = sCache.get(key);
if (cached != null) {
return cached;
}

// 首次访问,读取并缓存
String value = SystemProperties.get(key, defaultValue);
sCache.put(key, value);
return value;
}

// 不缓存的属性直接读取
return SystemProperties.get(key, defaultValue);
}

/**
* 清除缓存(在属性可能变更时调用)
*/
public static void clearCache() {
sCache.clear();
}
}

2. 批量读取优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class BatchPropertyReader {

/**
* 批量读取属性
*/
public static Map<String, String> getProperties(String... keys) {
Map<String, String> result = new HashMap<>();

// 一次性读取,减少 Binder 调用
for (String key : keys) {
result.put(key, SystemProperties.get(key, ""));
}

return result;
}

/**
* 按前缀批量读取
*/
public static Map<String, String> getPropertiesByPrefix(String prefix) {
Map<String, String> result = new HashMap<>();

// 通过 shell 命令批量获取
try {
Process process = Runtime.getRuntime().exec("getprop");
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream())
);

String line;
while ((line = reader.readLine()) != null) {
if (line.contains(prefix)) {
// 解析格式:[key]: [value]
Matcher matcher = Pattern.compile("\\[(.+?)\\]: \\[(.+?)\\]")
.matcher(line);
if (matcher.find()) {
result.put(matcher.group(1), matcher.group(2));
}
}
}
} catch (IOException e) {
Log.e("BatchReader", "Failed to read properties", e);
}

return result;
}
}

11.3 错误处理

健壮的属性访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public class SafePropertyAccess {

/**
* 安全地获取字符串属性
*/
public static String getString(String key, String defaultValue) {
try {
return SystemProperties.get(key, defaultValue);
} catch (Exception e) {
Log.w("Property", "Failed to get property: " + key, e);
return defaultValue;
}
}

/**
* 安全地获取整数属性
*/
public static int getInt(String key, int defaultValue) {
try {
String value = SystemProperties.get(key, "");
if (value.isEmpty()) {
return defaultValue;
}
return Integer.parseInt(value);
} catch (NumberFormatException e) {
Log.w("Property", "Invalid integer value for: " + key);
return defaultValue;
} catch (Exception e) {
Log.w("Property", "Failed to get property: " + key, e);
return defaultValue;
}
}

/**
* 安全地获取布尔属性
*/
public static boolean getBoolean(String key, boolean defaultValue) {
try {
String value = SystemProperties.get(key, "").toLowerCase();
if (value.isEmpty()) {
return defaultValue;
}

// 支持多种格式
return value.equals("true")
|| value.equals("1")
|| value.equals("yes")
|| value.equals("on");
} catch (Exception e) {
Log.w("Property", "Failed to get property: " + key, e);
return defaultValue;
}
}

/**
* 安全地设置属性
*/
public static boolean set(String key, String value) {
try {
SystemProperties.set(key, value);
return true;
} catch (IllegalArgumentException e) {
Log.e("Property", "Invalid property name or value", e);
return false;
} catch (SecurityException e) {
Log.e("Property", "Permission denied", e);
return false;
} catch (Exception e) {
Log.e("Property", "Failed to set property", e);
return false;
}
}
}

11.4 测试建议

单元测试示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@RunWith(AndroidJUnit4.class)
public class PropertyTest {

@Test
public void testReadOnlyProperty() {
// ro.* 属性应该可读
String model = SystemProperties.get("ro.product.model");
assertNotNull(model);
assertFalse(model.isEmpty());
}

@Test
public void testPropertyDefaultValue() {
// 不存在的属性应该返回默认值
String value = SystemProperties.get("test.nonexistent.prop", "default");
assertEquals("default", value);
}

@Test
public void testPropertyTypes() {
// 测试不同类型的转换
assertEquals(33, SystemProperties.getInt("ro.build.version.sdk", 0));
assertTrue(SystemProperties.getBoolean("ro.debuggable", false)
|| !SystemProperties.getBoolean("ro.debuggable", false));
}

@Test
@RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
public void testSetProperty() {
// 测试设置属性(需要权限)
String testKey = "debug.test.property";
String testValue = "test_value_" + System.currentTimeMillis();

try {
SystemProperties.set(testKey, testValue);
assertEquals(testValue, SystemProperties.get(testKey));
} finally {
// 清理
SystemProperties.set(testKey, "");
}
}
}

集成测试脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/system/bin/sh
# test_properties.sh - 属性功能测试

echo "=== Property System Test ==="

# 测试1:读取只读属性
echo "Test 1: Read ro.* properties"
MODEL=$(getprop ro.product.model)
if [ -n "$MODEL" ]; then
echo "✅ PASS: ro.product.model = $MODEL"
else
echo "❌ FAIL: Cannot read ro.product.model"
fi

# 测试2:设置和读取持久化属性
echo ""
echo "Test 2: Set/Get persist.* properties"
TEST_KEY="persist.test.property"
TEST_VALUE="test_$(date +%s)"

setprop "$TEST_KEY" "$TEST_VALUE"
RESULT=$(getprop "$TEST_KEY")

if [ "$RESULT" = "$TEST_VALUE" ]; then
echo "✅ PASS: Property set/get successful"
else
echo "❌ FAIL: Property set/get failed"
fi

# 清理
setprop "$TEST_KEY" ""

# 测试3:检查持久化存储
echo ""
echo "Test 3: Check persistent storage"
PERSIST_FILE="/data/property/persistent_properties"
if [ -f "$PERSIST_FILE" ]; then
FILE_SIZE=$(stat -c%s "$PERSIST_FILE" 2>/dev/null || stat -f%z "$PERSIST_FILE" 2>/dev/null)
echo "✅ PASS: Persistent properties file exists (size: $FILE_SIZE bytes)"
else
echo "❌ FAIL: Persistent properties file not found"
fi

echo ""
echo "=== Test Complete ==="

11.5 文档化

属性清单文档模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 应用系统属性清单

## persist.app.myapp.*

### persist.app.myapp.feature_enabled
- **类型**: Boolean
- **默认值**: false
- **说明**: 新功能开关
- **修改方式**: `setprop persist.app.myapp.feature_enabled true`
- **生效时机**: 应用重启后生效
- **影响范围**: 主功能模块

### persist.app.myapp.log_level
- **类型**: String (V/D/I/W/E)
- **默认值**: I (Info)
- **说明**: 应用日志级别
- **修改方式**: `setprop persist.app.myapp.log_level D`
- **生效时机**: 立即生效
- **影响范围**: 所有日志输出

## debug.app.myapp.*

### debug.app.myapp.performance_monitor
- **类型**: Boolean
- **默认值**: false
- **说明**: 性能监控开关
- **修改方式**: `setprop debug.app.myapp.performance_monitor true`
- **生效时机**: 立即生效
- **影响范围**: 性能统计模块
- **注意事项**: 仅在 debug 版本有效

12. 参考资料

12.1 源码文件

核心源码位置

1
2
3
4
5
bionic/libc/bionic/system_properties.cpp    # Native 实现
frameworks/base/core/jni/AndroidRuntime.cpp # JNI 绑定
frameworks/base/core/java/android/os/SystemProperties.java # Java API
system/core/init/property_service.cpp # Property Service
system/sepolicy/private/property_contexts # SELinux 策略

12.2 相关文档

12.3 工具

工具 用途 命令
getprop 读取属性 adb shell getprop [key]
setprop 设置属性 adb shell setprop key value
watchprops 监控属性变化(部分版本) adb shell watchprops
dumpsys 系统诊断 adb shell dumpsys

12.4 常见问题

Q1: 为什么 setprop 设置后属性没有变化?

A: 可能的原因:

  1. 权限不足(需要 root 或特定权限)
  2. SELinux 策略阻止
  3. 属性是只读的(ro.* 前缀)
  4. 属性值超过长度限制(91 字符)

Q2: persist. 属性在哪些情况下会丢失?*

A: 会丢失的情况:

  • 恢复出厂设置(Factory Reset)
  • 清除数据(Wipe Data)
  • /data 分区被格式化

不会丢失的情况:

  • 普通 OTA 更新
  • 应用卸载/重装
  • 系统重启

Q3: 如何判断一个属性是否存在?

A: 方法:

1
2
3
4
String value = SystemProperties.get("key", null);
if (value != null && !value.isEmpty()) {
// 属性存在且有值
}

或使用 shell:

1
2
3
if [ -n "$(getprop key)" ]; then
echo "Property exists"
fi

总结

Android 系统属性是一个功能强大且高效的配置管理系统,正确使用可以:

简化配置管理 - 统一的键值对接口
提升开发效率 - 动态调试和功能开关
增强系统灵活性 - 运行时配置调整
支持跨进程通信 - 轻量级数据共享

但也需要注意:

⚠️ 权限控制 - 严格的 SELinux 策略
⚠️ 性能考虑 - 避免频繁的 set 操作
⚠️ 命名规范 - 遵循统一的命名约定
⚠️ 持久化策略 - 理解不同前缀的生命周期

通过本文的系统学习,您应该能够:

  • 理解系统属性的架构和机制
  • 正确使用各种 API 读写属性
  • 根据场景选择合适的属性类型
  • 遵循最佳实践开发健壮的代码
  • 有效调试和诊断属性相关问题

文档版本: 1.1
最后更新: 2025-01-15
作者: Android Framework 团队
适用版本: Android 8.0+ (API 26+)
修订说明: 修正持久化属性存储机制描述(感谢用户反馈)

相关文档