美文网首页
Android系统属性和设置项读取

Android系统属性和设置项读取

作者: 文泰ChrisTwain | 来源:发表于2022-11-01 23:17 被阅读0次

一、系统属性值

(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路径下,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官网-添加系统属性

相关文章

  • Android系统属性和设置项读取

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

  • Android系统属性set、get详解

    基于 Android 6.0 的源码,分析 set 和 get 系统属性 设置系统属性 上一篇文章提到,设置系统属...

  • Android系统属性set/get详解

    基于 Android 6.0 的源码,分析 set 和 get 系统属性 设置系统属性 上一篇文章提到,设置系统属...

  • Android HttpProxy 工作原理(上)

    概述 Android HttpProxy 的工作原理分为代理的配置和读取,配置代理可以由系统设置中配置,也可在 A...

  • Mac开机自动运行shell脚本

    创建shell脚本 脚本内容 设置打开方式和读取权限 增加执行权限 4.加入用户登录项系统偏好设置->用户与群组-...

  • iOS 地图使用(一)

    一、地图的基本使用 设置地图类型 设置地图的其他属性(操作项)注意:设置对应的属性时,注意该属性是从哪个系统版本开...

  • 多系统开机启动项

    多系统开机启动项 1.运行 msconfig 2.我的电脑-属性-高级系统设置-启动和故障恢复-设置 3.软媒魔方...

  • Android8.0中 Only fullscreen acti

    Android 8.0系统下,如果Activity同时设置了Oriention属性 和透明主题 会出现崩溃报Onl...

  • 三、获取和设置属性值、操作属性·

    .attr()用来读取或设置指定的属性,需要读取属性时,在小括号中指定属性的名称。 one为读取位置: .addC...

  • Andriod Settings

    前言 公司开发 Android Launcher 项目,需要设置一些系统的属性,比如说修改系统语言设置,修改输入法...

网友评论

      本文标题:Android系统属性和设置项读取

      本文链接:https://www.haomeiwen.com/subject/azfctdtx.html