一, SettingsProvider

1. SettingsProvider顾名思义是一个提供设置数据共享的Provider,SettingsProvider和Android系统其它Provider有很多不一样的地方,如:

  • SettingsProvider只接受int、float、string等基本类型的数据;
  • SettingsProvider由Android系统framework进行了封装,使用更加快捷方便
  • SettingsProvider的数据由键值对组成

SettingsProvider有点类似Android的properties系统(Android属性系统):SystemProperties。SystemProperties除具有SettingsProvider以上的三个特性,SettingsProvider和SystemProperties的不同点在于:

  • 数据保存方式不同:SystemProperties的数据保存属性文件中(/system/build.prop等),开机后会被加载到system properties store;SettingsProvider的数据保存在文件/data/system/users/0/settings_***.xml和数据库settings.db中;
  • 作用范围不同:SystemProperties可以实现跨进程、跨层次调用,即底层的c/c++可以调用,java层也可以调用;SettingProvider只能能在java层(APP)使用;
  • 公开程度不同:SettingProvider有部分功能上层第三方APP可以使用,SystemProperties上层第三方APP不可以使用。

用一句话概括SettingsProvider的作用,SettingsProvider包含全局性、系统级别的用户编好设置。在手机中有一个Settings应用,用户可以在Settings里面做很多设备的设置,这些用户偏好的设置很多就保存在SettingsProvider中。例如,飞行模式。

旧版是使用数据库管理,数据库的名字是settings.db。而在新版本上,不知道是哪个版本开始的,至少Android6.0已经是这样了,键值对放到xml文件中管理了。分别是:

  1. private static final String SETTINGS_FILE_GLOBAL = "settings_global.xml";
  2. private static final String SETTINGS_FILE_SYSTEM = "settings_system.xml";
  3. private static final String SETTINGS_FILE_SECURE = "settings_secure.xml";

2. 为什么从settings.db修改为三个xml文件?

https://blog.csdn.net/peng_cao/article/details/50594958

初始化默认数据还是用到了settings.db,只是后续把db内存导入了xml中然后及时删除该db,为啥不直接操作xml呢?

  • 这次修改,主要是基于性能的考量(写入一条耗时从400ms降低为10ms),同时也能够使得保存数据的过程更加可信!
  • 实际上,得保存数据的过程更加可信这一条并不是问题的关键,写入失败的情况不仅非常罕见,而且上层应用修改SettingsProvider设置都是通过SettingsProvider来实现的。所以当上层APP下次再次启动的时候,并不知道数据写入失败!
  • 还有一种情况需要注意,改变SettingsProvider的实现方式(从db改为xml以及相应逻辑),可以有效的防止某些恶意APP监听某些设置选项,进而频繁的进行操作
  • 每个用户都有自己的一份SettingsProvider设置xml文档。通常位于/data/system/users/userid/

#/data/system/users/0 # ls -l

-rw------- 1 system system 238 2020-07-27 21:40 settings_config.xml

-rw------- 1 system system 11145 2020-08-02 23:19 settings_global.xml

-rw------- 1 system system 11724 2020-08-02 22:18 settings_secure.xml

-rw------- 1 system system 5290 2020-08-01 23:48 settings_system.xml

  • 为了方便向下兼容,数据从数据库迁移到xml的时机:当数据库升级完毕之后,即可开始将数据迁移到xml
  • SettingsProvider的升级由SettingsProvider.UpgradeController控制,而不再由DatabaseHelper控制
  • 控制APP针对SettingsProvider的写入(合法性的判断)
  • 控制SettingsProvider的大小(数据量大小,占用内存大小,etc.)
  • 当某个app写入的设置,当该APP写在之后,对应的设置也一同被清除。

Settings共有三种分类,分别如下:

  • Global:所有的偏好设置对系统的所有用户公开,第三方APP有读没有写的权限;
  • System:包含各种各样的用户偏好系统设置;
  • Secure:安全性的用户偏好系统设置,第三方APP有读没有写的权限。
  • Config : 系统硬件设备相关的设置,该项为新添加settings_config.xml

总的来说:

  • 改善了性能 写入的速率是400ms vs 10ms
  • 提高了安全性
  • 换了架构
  • 提高了稳定性 xml异步性能更加优良的

二, DEBUG

1. 如何修改系统默认的一些设置配置值? 在如下xml文件中修改或添加设置的默认值

frameworks/base/packages/SettingsProvider/res/values/defaults.xml

vendor/mediatek/proprietary/packages/apps/SettingsProvider/res/values/defaults.xml

vendor/mediatek/proprietary/packages/apps/SettingsProvider/res/values/mtk_defaults.xml

注意:在defauls.xml设置的默认值,究竟是会存入settings_global.xml, settings_secure.xml, settings_system.xml 表,是由Settings.java中的class System, Global, Secure 类中管理添加的字段有关,比如MOVED_TO_GLOBAL, MOVED_TO_SECURE, 剩下的就是system的了?????

2. 通过ADB修改

settings put system [key] [value] settings get system [key]

settings put global [key] [value] settings get global [key]

settings put secure [key] [value] settings get secure [key]

3. 代码中如何修改

@Settings.java (frameworks\base\core\java\android\provider)

比如:

Settings.System.putInt(mContext.getContentResolver(), name, value);

int value = Settings.System.getInt(mContext.getContentResolver(), name);

Settings.Global.putInt(...)

Settings.Secure.putInt(...)

三,代码分析

@Settings.java (frameworks\base\core\java\android\provider)

1. @SettingsProvider.java (vendor\mediatek\proprietary\packages\apps\settingsprovider\src\com\android\providers\settings)

@SettingsProvider.java (frameworks\base\packages\settingsprovider\src\com\android\providers\settings)

public class SettingsProvider extends ContentProvider {

private SettingsRegistry mSettingsRegistry;

public boolean onCreate() {

mSettingsRegistry = new SettingsRegistry();

ServiceManager.addService("settings", new SettingsService(this));

ServiceManager.addService("device_config", new DeviceConfigService(this));

return true;

}

final class SettingsRegistry {

private static final String SETTINGS_FILE_GLOBAL = "settings_global.xml";

private static final String SETTINGS_FILE_SYSTEM = "settings_system.xml";

private static final String SETTINGS_FILE_SECURE = "settings_secure.xml";

private static final String SETTINGS_FILE_SSAID = "settings_ssaid.xml";

private static final String SETTINGS_FILE_CONFIG = "settings_config.xml";

public SettingsRegistry() {

migrateAllLegacySettingsIfNeeded();

}

private void migrateAllLegacySettingsIfNeeded() {

synchronized (mLock) {

final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);

File globalFile = getSettingsFile(key);

//检查data/system/users/0/settings_global.xml文件是否存在?存在表示已经由settings.db转换为xml中的设置了

if (SettingsState.stateFileExists(globalFile)) {

return;

}

//借助DatabaseHelper 把系统默认的设置写入settings.db

DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);

SQLiteDatabase database = dbHelper.getWritableDatabase();

migrateLegacySettingsForUserLocked(dbHelper, database, userId);

}

private void migrateLegacySettingsForUserLocked(DatabaseHelper dbHelper,

SQLiteDatabase database, int userId) {

// Move over the system settings.

final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);

SettingsState systemSettings = mSettingsStates.get(systemKey);

migrateLegacySettingsLocked(systemSettings, database, TABLE_SYSTEM);

// Move over the secure settings.

// Do this after System settings, since this is the first thing we check when deciding

// to skip over migration from db to xml for a secondary user.

final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);

SettingsState secureSettings = mSettingsStates.get(secureKey);

migrateLegacySettingsLocked(secureSettings, database, TABLE_SECURE);

// Move over the global settings if owner.

// Do this last, since this is the first thing we check when deciding

// to skip over migration from db to xml for owner user.

if (userId == UserHandle.USER_SYSTEM) {

final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, userId);

SettingsState globalSettings = mSettingsStates.get(globalKey);

migrateLegacySettingsLocked(globalSettings, database, TABLE_GLOBAL);

}

// Drop the database as now all is moved and persisted.

if (DROP_DATABASE_ON_MIGRATION) { // 默认为true

dbHelper.dropDatabase(); //删除临时生成的settings.db, 以后数据操作xml

} else {

dbHelper.backupDatabase();

}

}

2. DatabaseHelper.java (vendor\mediatek\proprietary\packages\apps\settingsprovider\src\com\android\providers\settings)

* Legacy settings database helper class for {@link SettingsProvider}.

* IMPORTANT: Do not add any more upgrade steps here as the global,

* secure, and system settings are no longer stored in a database

* but are kept in memory and persisted to XML.

@Deprecated

class DatabaseHelper extends SQLiteOpenHelper {

private static final String TAG = "SettingsProvider";

private static final String DATABASE_NAME = "settings.db";

//只处理以下三张表

private static final String TABLE_SYSTEM = "system";

private static final String TABLE_SECURE = "secure";

private static final String TABLE_GLOBAL = "global";

static String dbNameForUser(final int userHandle) {

// The owner gets the unadorned db name;

if (userHandle == UserHandle.USER_SYSTEM) {

return DATABASE_NAME;

} else {

...

}

public DatabaseHelper(Context context, int userHandle) {

//依旧创建了settings.db数据库在本APP的database下

super(context, dbNameForUser(userHandle), null, DATABASE_VERSION);

}

public void onCreate(SQLiteDatabase db) {

db.execSQL("CREATE TABLE system (" +

"_id INTEGER PRIMARY KEY AUTOINCREMENT," +

"name TEXT UNIQUE ON CONFLICT REPLACE," +

"value TEXT" +

");");

db.execSQL("CREATE INDEX systemIndex1 ON system (name);");

createSecureTable(db);

// Only create the global table for the singleton 'owner/system' user

if (mUserHandle == UserHandle.USER_SYSTEM) {

createGlobalTable(db);

}

// Load initial volume levels into DB

loadVolumeLevels(db); //装载默认的声音系统设置值到system表

// Load inital settings values

loadSettings(db); //装载默认的各种设置值到对应的表

}

private void loadSettings(SQLiteDatabase db) {

loadSystemSettings(db);//装载系统设置到system表 -> settings_system.xml

loadSecureSettings(db);//装载个人安全设置到sercure表 -> settings_secure.xml

// The global table only exists for the 'owner/system' user

if (mUserHandle == UserHandle.USER_SYSTEM) {

loadGlobalSettings(db); //装载全局设置到global表 -> settings_global.xml

}

}

private void loadSystemSettings(SQLiteDatabase db) {

SQLiteStatement stmt = null;

try {

stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"

+ " VALUES(?,?);");

//那些设置默认放到system表(或settings_system.xml)在此决定

loadBooleanSetting(stmt, Settings.System.DIM_SCREEN,

R.bool.def_dim_screen);

loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,

R.integer.def_screen_off_timeout);

....

}

四,小节

1. 为了兼容以前的代码设计, 系统第一次开机的时候会检查 data/system/users/0/settings_global.xml 文件是否存在?

  • 如果不存在则通过原有DatabaseHelper获取默认的各种系统设置(在SettingsProvider这个APP里设置的default.xml文件中)存入settings.db数据库中;然后把settings.db中的system, global, sercure表中的默认设置导入对应的settings_system.xml, settings_global.xml, settings_secure.xml。
  • 如果存在则表示已经导入了默认值,不做任何操作

2. 目前系统还是通过DatabaseHelper的逻辑来决定那些默认的设置放到对应的Settings.System, Settings.Secure, Settings.Global中, 那Settings.Config (settings_config.xml)的默认值从何而来? 没有默认值xml可读取,

只能是通过DeviceConfig.setProperty -> Settings.Config.putString来设置

DeviceConfig.getProperty -> Settings.Config.getString 来获取

参考 https://www.jianshu.com/p/d48977f220ee

AndroidQ SettingsProvider和Settings原理相关推荐

  1. AndroidQ(10.0) Settings DatePick bug修改

    问题现象 上图展示的很清楚,在系统->日期和时间选项页面中,点击日期 Preference,左边的上一月显示都透出来了 修改历程 一开始觉得是 DatePick 系统控件出问题了吧,自己新建了a ...

  2. SettingsProvider简单分析

    SettingsProvider顾名思义是一个提供数据共享的Provider,SettingsProvider和Android系统其它Provider有很多不一样的地方: 1.SettingsProv ...

  3. Android系统之SettingsProvider(二)

    (1)概述 (A) SettingsProvider顾名思义是一个提供设置数据共享的Provider,SettingsProvider和Android系统其它Provider有很多不一样的地方,如: ...

  4. Android-Q颜色模式

    0 前言 Android-Q可通过"Settings > Display > Colors"选择颜色模式: 图0.1 Colors(第3个模式是本文增加的) Andro ...

  5. Android源码解析--dropbox日志:DropBoxManagerService(DBMS)服务详解

    DropBoxManagerService 简介 DropBoxManagerService(简称DBMS)是日志相关的服务,用于生成与管理 系统运行时的一些日志文件.日志文件大多记录的是系统或某个应 ...

  6. aap渗透_Android App渗透测试工具汇总

    一. drozer简介 drozer(以前称为Mercury)是一款Android安全测试框架. drozer允许您通过承担应用程序的角色并与Dalvik VM,其他应用程序的IPC端点和底层操作系统 ...

  7. [深入理解Android卷二 全文-第三章]深入理解SystemServer

    由于<深入理解Android 卷一>和<深入理解Android卷二>不再出版,而知识的传播不应该因为纸质媒介的问题而中断,所以我将在CSDN博客中全文转发这两本书的全部内容 第 ...

  8. aap渗透_Android App渗透测试工具分享

    这段时间因为某些原因接触了Android App渗透测试,发现了几个不错的App渗透测试工具(虽然这些工具早就出来了 2333),搭建测试环境的过程中遇到了一些问题,特地总结一下,希望能给大家带来帮助 ...

  9. Ionic 更换主题风格方案

    需求 最近涉及到的一个需求是--用户可更换页面风格,因此,查了一些资料后,写一下Ionic更换主题方案 方案 动态改变根标签类名,比如亮色风格时,class="light",比如暗 ...

最新文章

  1. 按照文字内容动态设置TableViewCell的高度
  2. 编写一个函数itob(int n,char s[], int b),将整数n转换为以b进制的数。保存到s中。...
  3. conky在ubuntu xfce4下面的配置
  4. 圆章能随便刻吗_自己晒干的蒲公英能长期当茶随便喝吗?医生:3个危害不请自来...
  5. fsck 修复文件系统_微软推出Win10 20H2 Build 19042.608测试版 修复多种已知错误
  6. 大数据分析平台在企业的重要性
  7. 国内银行卡BIN号速查简表(2016)
  8. CKFinder baseDir 和 baseURL参数解释
  9. 三台Centos7虚拟机之间实现ssh,rsh互连,虚拟机和本机基于ssh进行文件传输
  10. 移动端VUE实现一周课程表
  11. 软考是什么?怎么准备----软考相关资讯
  12. 六:抽象队列同步器AQS应用之BlockingQueue详解
  13. mingw64官方下载地址
  14. java实现高德地图app,Android 高德地图入门demo,最新高德地图实现方法,附源码及apk...
  15. libjpeg的安装与使用
  16. 突破技术限制,实现Web端静默打印
  17. 区块链:Neutral Dollar(NUSD)亚稳态的可视化
  18. 指南解读:急性心力衰竭中国急诊管理指南(2022)
  19. 甲乙丙三人一起进行百米赛跑(假定三人均为匀速直线运动)如果当甲到达终点时,乙距终点有5米,丙距终点还有10米,那么当乙到达终点时,丙距终点还有()米
  20. php swoft 路由,Swoft 源码解读

热门文章

  1. sketchup 计算机配置,流畅运行SU草图大师软件的最低电脑配置要求
  2. 在统计学中_[求助] OR在统计学中指什么?
  3. 赛灵思FPGA功耗实测与XPE模拟计算对比分析
  4. 力扣(leetcode)[118. 杨辉三角] 简单
  5. 推荐一个rss源搜索引擎
  6. android 键盘 自动消失,android 键盘状态,获取键盘显示和隐藏
  7. 七彩cms云转码_最新版七彩CMS 2019云转码完全开源版本 程序源码带安装教程
  8. 第二章 Java基本语言
  9. win7 u盘 正在计算机,U盘在Win7电脑上读不出来怎么办?两种解决方法全教给你!...
  10. 两次获得微信生态支持的如祺出行,如何破局网约车市场?