C语言中getprop如何获取系统属性?

99ANYc3cd6
预计阅读时长 21 分钟
位置: 首页 C语言 正文

getprop 并不是一个标准的 C 库函数(比如像 printfmalloc 那样),它是 Android 系统特有的一个函数,主要用于在 C/C++ 层面读取 Android 的属性系统。

什么是 Android 属性系统?

在 Android 中,属性系统是一个轻量级的键值对存储机制,用于在整个系统中共享配置信息和状态,这些属性在系统启动时被初始化,之后可以被修改,但通常需要特定的权限。

  • 存储位置: 主要存储在内存中,而不是文件里,因此读取速度非常快。
  • 用途:
    • 系统核心配置:如 ro.build.version.sdk(SDK 版本)、ro.product.model(设备型号)。
    • 服务状态:如 init.svc.zygote(Zygote 服务是否运行)。
    • 调试开关:如 debug.sf.hw(是否启用硬件加速)。
    • 开发者选项:如 persist.sys.dalvik.vm.lib(使用的 ART 虚拟机库)。
  • 前缀含义:
    • ro. (Read-only): 只读属性,在系统启动后不能被修改。
    • persist.: 持久化属性,修改后会写入 /data/property 文件,重启后仍然保留。
    • ctl.: 控制属性,用于向 init 进程发送命令,如 ctl.start 启动服务。
    • 没有前缀: 普通属性,可以被修改,但重启后会丢失。

getprop 函数详解

getprop 函数定义在 Android 的 C 库 libcutils 中,如果你想在你的 C/C++ 代码中使用它,需要包含相应的头文件并链接库。

函数原型

#include <cutils/properties.h>
int property_get(const char *key, char *value, const char *default_value);

参数说明

  1. const char *key:

    • 你想要查询的属性的键名
    • "ro.build.version.release"(获取 Android 版本号)。
  2. char *value:

    • 一个预先分配好的字符缓冲区,用于存储属性的值。
    • 如果属性存在,其值会被复制到这个缓冲区中。
    • 非常重要:你必须确保这个缓冲区足够大,以容纳属性的值,否则会导致缓冲区溢出,引发严重的安全问题,属性值的最大长度通常是 PROPERTY_VALUE_MAX (在源码中定义为 92)。
  3. const char *default_value:

    • 一个默认值的字符串。
    • 如果指定的 key 不存在,或者值为空,default_value 会被复制到 value 缓冲区中。
    • 如果这个参数是 NULL,并且属性不存在,value 缓冲区的内容将不会被修改。

返回值

  • 成功: 返回属性值的长度(不包括结尾的 \0)。
  • 失败: 如果属性不存在,返回 0value 缓冲区为 NULL,也会返回 0

使用示例

下面我们通过几个 C 代码示例来演示如何使用 getprop

示例 1:获取只读属性(如 Android 版本号)

这个例子展示了如何获取一个已知的、只读的系统属性。

#include <stdio.h>
#include <string.h>
#include <cutils/properties.h> // 必须包含的头文件
int main() {
    // 1. 定义一个足够大的缓冲区来存储属性值
    // PROPERTY_VALUE_MAX 通常是 92,为了安全,可以定义大一点
    char value[128];
    const char *key = "ro.build.version.release"; // Android 版本号的键
    const char *default_value = "unknown";        // 默认值
    printf("尝试获取属性: %s\n", key);
    // 2. 调用 property_get 函数
    // 如果属性存在,其值会被复制到 value 数组中
    // 如果属性不存在,value 将被设置为 "unknown"
    int len = property_get(key, value, default_value);
    // 3. 处理返回结果
    if (len > 0) {
        printf("成功获取! 属性值: %s (长度: %d)\n", value, len);
    } else {
        printf("获取失败或属性不存在,使用默认值: %s\n", value);
    }
    return 0;
}

如何编译和运行 (在 Android NDK 环境下):

  1. 将代码保存为 getprop_example.c
  2. 使用 ndk-build 编译,或者在 CMakeLists.txt 中链接 cutils 库。
    • 对于 ndk-build,确保你的 Android.mk 中有 libcutils 依赖。
    • 对于 CMake,使用 target_link_libraries(your_target_name libcutils)
  3. 将编译后的可执行文件 push 到 Android 设备上运行:
    adb push getprop_example /data/local/tmp/
    adb shell
    cd /data/local/tmp
    ./getprop_example

预期输出:

尝试获取属性: ro.build.version.release
成功获取! 属性值: 13.0.0 (长度: 6)  // 版本号会根据你的设备而变化

示例 2:获取不存在的属性

这个例子演示了当属性不存在时,default_value 如何工作。

#include <stdio.h>
#include <string.h>
#include <cutils/properties.h>
int main() {
    char value[128];
    const char *key = "this.property.does.not.exist";
    const char *default_value = "this is the default value";
    printf("尝试获取属性: %s\n", key);
    int len = property_get(key, value, default_value);
    if (len > 0) {
        printf("成功获取! 属性值: %s (长度: %d)\n", value, len);
    } else {
        // 因为属性不存在,value 会被设置为 default_value
        // 但 property_get 仍然返回 0
        printf("获取失败或属性不存在,使用默认值: %s\n", value);
    }
    return 0;
}

预期输出:

尝试获取属性: this.property.does.not.exist
获取失败或属性不存在,使用默认值: this is the default value

示例 3:检查服务的运行状态

我们可以通过检查 init.svc.<服务名> 来判断一个系统服务是否正在运行。

  • init.svc.zygote 的值可能是 runningstoppedrestarting
#include <stdio.h>
#include <string.h>
#include <cutils/properties.h>
int main() {
    char value[32];
    const char *key = "init.svc.zygote";
    const char *default_value = "unknown";
    printf("检查 Zygote 服务状态...\n");
    property_get(key, value, default_value);
    if (strcmp(value, "running") == 0) {
        printf("Zygote 服务正在运行,\n");
    } else {
        printf("Zygote 服务未运行 (状态: %s),\n", value);
    }
    return 0;
}

预期输出:

检查 Zygote 服务状态...
Zygote 服务正在运行。

getpropadb shell getprop 的区别

特性 adb shell getprop (Shell 命令) C 函数 property_get
使用环境 Shell 终端 (ADB, Terminal Emulator) C/C++ 应用程序代码
实现语言 通常是 Shell 脚本或 C 可执行文件 C 语言库函数 (libcutils)
用途 手动查询、调试、脚本自动化 程序内部逻辑判断、获取配置
输出 直接打印所有属性或指定属性到标准输出 将属性值存入你提供的缓冲区,返回长度
灵活性 可以轻松查看所有属性 (getprop) 只能精确查询一个属性

adb shell getprop 是开发者用于交互式调试的工具,而 property_get 是开发者用于在应用程序中集成系统属性的编程接口。


在不同环境下的使用

在 Android NDK 项目中

这是最常见的使用场景,你需要:

  1. CMakeLists.txtAndroid.mk 中链接 libcutils 库。
    • CMakeLists.txt:
      find_library(cutils_lib cutils)
      target_link_libraries(your-native-lib ${cutils_lib})
    • Android.mk:
      LOCAL_LDLIBS += -lcutils
  2. 包含头文件 #include <cutils/properties.h>

在原生 Android 应用 (Android 10+) 中

从 Android 10 开始,Google 推荐使用更安全、更现代的 SystemProperties API,它通过 Java 的 @SystemApi 暴露给框架,如果你在 C++ 代码中运行在应用进程内,并且可以调用 Java 层,这是更好的选择,但对于纯粹的原生进程或需要直接访问属性的场景,property_get 仍然是有效的。

在 AOSP (Android 开源项目) 源码中

直接包含和使用即可,因为 libcutils 是 AOSP 的一部分。


重要注意事项

  1. 缓冲区大小: 再次强调,必须为 value 参数分配足够大的缓冲区,防止缓冲区溢出,一个安全的做法是定义一个足够大的数组,如 char value[256];
  2. 权限: 大部分 ro.* 属性是所有应用都可以读取的,但修改属性或访问某些特定属性可能需要 android.permission.READ_SYSTEM_PROPERTIES 等权限,对于 property_get 读取通常没有权限限制。
  3. 性能: 属性系统在内存中,property_get 的性能非常高,可以安全地在性能敏感的代码路径(如渲染循环)中调用。
  4. 替代方案: 在新的 Android 应用开发中,如果可能,优先使用 Android 框架提供的 Java/Kotlin API 来获取系统信息,而不是直接依赖底层属性,使用 Build.VERSION.RELEASE 代替 property_get("ro.build.version.release", ...),但对于纯粹的原生代码,property_get 是不二之选。
-- 展开阅读全文 --
头像
dede如何不调用自身数据实现内容展示?
« 上一篇 今天
dede注册登录模板如何修改或自定义?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

目录[+]