Android系统属性和设置项读取

一、系统属性值

(1)系统属性定义了Android 系统的一些公共系统属性,都是字符串格式,可用于业务代码中区分不同机型、系统版本等

业务代码中可读取属性值后进行特定业务逻辑,比如区分手机或者平板设备等,/system/build.prop文件能看到部分系统属性,可通过adb shell getprop查看全部系统属性,相关命令如下:
adb shell getprop vendor.xxx.xxxadb查看特定属性值
adb shell setprop [key] [value]设置指定key的属性值
watchprops命令可监听系统属性的变化
这三个命令都是toolbox的子命令,对应的源码:system/core/toolbox/
部分属性举例:

getprop ro.serialno 序列号
getprop ro.carrier CID号
getprop ro.hardware 板子代号
getprop ro.bootloader SPL(Hboot)版本号
getprop ro.build.version.sdk Android版本号
getprop ro.build.characteristics 如果是平板属性值为tablet,可用于区分手机和平板

ps.只有有权限的进程才能修改属性

系统属性的四个优点,当然缺点也很明显,只能支持三种基本类型:string、int、boolean
1)全局:只要拥有对应的权限,就可以同步获取和修改;
2)通用:在Java层,native层,shell层都可以获取和修改;
3)初始化早:属性服务实在 init 进程中启动的;
4)简单:主要就两个方法 set 和 get

(2)主要属性简介:
  • ro开头的是只读属性,一旦赋值不能修改
  • persist.开头以文件的形式保存在/data/property/persistent_properties(相对旧点的Android版本是/data/property),persist.属性由于将其保存在了用户空间中,所以在property_init中是不能对其更新的,只能将其更新过程交给用户来处理
  • ctl. 开头虽然是以属性的形式来进行设置,其实它的目的是为了启动或关闭它指定的service 属性“ ctrl.start ”和“ ctrl.stop ”是用来启动和停止服务。每一项服务必须在/init.rc中定义.系统启动时,init守护进程将解析init.rc和启动属性服务。一旦收到设置“ ctrl.start ”属性的请求,属性服务将使用该属性值作为服务名找到该服务,启动该服务。这项服务的启动结果将会放入“ init.svc.<服务名>“属性中 。客户端应用程序可以轮询那个属性值,以确定结果
  • gsm开头的是移动电话的一些版本信息(软硬件,基带版本等信息)、所在国家、漫游状态、序列号等信息等一系列与sim相关的信息
  • sys开头的是系统信息
  • init.svc手机当前进程的状态(启动的显示running未启动的显示stopped),进程是否启动由init.rc文件定义
  • net开头的是与网络相关的信息,比如dns、主机名、为各功能预留的缓冲区大小
  • dhcp.wlan 是网关、IP地址等无线网络相关信息;
  • external_sd_path 是外部存储SD卡的路径
  • fmradio.driver 是FMradio相关属性
(3)Java反射读取系统属性
private static final String CLASS_SYSTEM_PROPERTIES = "android.os.SystemProperties";

/**
 * 获取get prop 字符串类型配置值(SystemProperties读取的配置)
 *
 * @param cfgName 配置名
 * @param defValue 获取不到的默认值
 * @return 成功返回实际的值,识别返回默认值
 */
public static String getStringOfRoConfig(String cfgName, String defValue) {
    Object result = invoke(CLASS_SYSTEM_PROPERTIES, "get", new Class<?>[] {String.class, String.class},
            cfgName, defValue);
    if (result instanceof String) {
        return (String) result;
    }
    return defValue;
}

/**
 * 反射调用指定类中的指定方法
 *
 * @param className 方法所在的类名
 * @param methodName 方法名
 * @param parameterTypes 可变参数class类型数组,注意args要和其一致
 * @param args 方法可变参数
 * @return 方法调用返回的结果
 */
public static Object invoke(String className, String methodName, Class<?>[] parameterTypes, Object... args) {
    Object value = null;

    try {
        Class<?> clz = Class.forName(className);
        Method method = clz.getDeclaredMethod(methodName, parameterTypes);
        value = method.invoke(clz, args);
    } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
            | SecurityException | ClassNotFoundException e) {
        Logger.e(TAG, "invoke " + e.getClass().getSimpleName());
    } catch (Exception e) {
        Logger.e(TAG, "unknown Exception in invoke");
    }
    return value;
}
(4)Native层C++读取属性值

NDKndk\21.0.6113669\toolchains\llvm\prebuilt\windows-x86_64\sysroot\usr\include\bits路径下get_device_api_level_inlines.h代码

// Avoid circular dependencies since this is exposed from <sys/cdefs.h>.
int __system_property_get(const char* __name, char* __value);
int atoi(const char* __s) __attribute_pure__;

__BIONIC_GET_DEVICE_API_LEVEL_INLINE int android_get_device_api_level() {
  char value[92] = { 0 };
  if (__system_property_get("ro.build.version.sdk", value) < 1) return -1;
  int api_level = atoi(value);
  return (api_level > 0) ? api_level : -1;
}

故可通过__system_property_get函数读取系统属性,同时还提供了获取android版本的属性例子方法android_get_device_api_level
这里char value[92]设置为92是由于属性key的最大字符长度为31,value最大字符长度为91,可看到源码中有如下限制:

public static final int PROP_NAME_MAX = 31;
public static final int PROP_VALUE_MAX = 91;

......

public static void set(String key, String val) {
    if (key.length() > PROP_NAME_MAX) {
        throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
    }
    if (val != null && val.length() > PROP_VALUE_MAX) {
        throw new IllegalArgumentException("val.length > " +
            PROP_VALUE_MAX);
    }
    native_set(key, val);  // 调用Native方法设置属性
}

二、Android设置项开关值

(1)设置App中的各个开关值,存储在/data/system/users/0/下的三个文件中,这些文件在手机中有被加密,具体路径如下:

/data/system/users/0/settings_global.xml
/data/system/users/0/settings_secure.xml
/data/system/users/0/settings_system.xml
业务中可读取或者监听开关变化进行自身业务逻辑,App有写设置的权限可往其中写开关值。比如业务可以自定义一个开关值判断,当开关通过adb打开时,执行一些测试逻辑。
adb shell settings put global intelliability_enabled 1 比如通过adb打开intelliability_enabled开关,开关在global文件中
adb shell settings get global intelliability_enabled 通过adb查看开关值

settings_global.xml文件中部分设置项示例如下:

<setting id="89" name="adb_wifi_enabled" value="0" package="android" defaultValue="0" defaultSysSet="true" />
<setting id="40" name="low_battery_sound_timeout" value="0" package="android" defaultValue="0" defaultSysSet="true" />
<setting id="32" name="car_undock_sound" value="/system/media/audio/ui/Undock.ogg" package="android" defaultValue="/system/media/audio/ui/Undock.ogg" defaultSysSet="true" />
<setting id="152" name="keyguard_occluded_notify" value="keyguard_no_occluded" package="com.android.systemui" defaultValue="keyguard_no_occluded" defaultSysSet="true" />
<setting id="169" name="captive_portal_notification_shown" value="0" package="android" defaultValue="0" defaultSysSet="true" />
<setting id="157" name="aps_display_resolution" value="2" package="com.huawei.android.hwaps" defaultValue="2" defaultSysSet="true" />

通过Java读取设置项的值,需要先知道设置项的名称和所在的文件

Settings.System.getInt(context.getContentResolver(), xxSettingName, 0);  // System表示存在于settings_system.xml中的开关
Settings.Global.getInt(context.getContentResolver(), xxSettingName, 0);
Settings.Secure.getInt(context.getContentResolver(), xxSettingName, 0);

ps.有些应用或以SDK的形式附加在其它使用此SDK的应用,获取到修改设置的权限后可能会写唯一标识到设置项文件中,使得用户设备被唯一标识,因为其它APP也能读取到这个值,故能用于精准广告推荐。
还有些设置开关是广播,比如位置信息开关,广播Aciton是 LocationManager.MODE_CHANGED_ACTION
收到广播后再根据LocationManager查询是否打开
LocationManager lm = (LocationManager) context.getSystemService(Service.LOCATION_SERVICE);
boolean isEnabled = lm.isLocationEnabled();

(2)监听设置项开关值变化

根据上述,通过文件名+字段名方式构造URI,注册设置变化监听
content://settings/设置文件/文件中的具体设置值

Uri uri = Uri.parse("content://settings/secure/ui_night_mode");  // 监听深色模式开关
ContentObserver contentObserver = new ContentObserver(null) {
    @Override
    public void onChange(boolean isSelfChange, Uri uri) {
        if (uri == null) {
            Logger.e(TAG, "setting item uri is null");
            return;
        }
        Logger.d(TAG, "onChange uri = " + uri);
        // 可通过uri.toString()字符串中解析文件名和字段名,然后Settings.System.getInt()查询变化后的开关值
    }
};
context.getContentResolver().registerContentObserver(uri, true, contentObserver);

注意:不监听时需解注册内容观察者

context.getContentResolver().unregisterContentObserver(uriObserverStore.get(name));

参考:
Android属性系统简介及使用
Android系统属性set、get详解
Android source官网-添加系统属性

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容