AndroidQ SettingsProvider和Settings原理
一, 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文件中管理了。分别是:
- 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";
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原理相关推荐
- AndroidQ(10.0) Settings DatePick bug修改
问题现象 上图展示的很清楚,在系统->日期和时间选项页面中,点击日期 Preference,左边的上一月显示都透出来了 修改历程 一开始觉得是 DatePick 系统控件出问题了吧,自己新建了a ...
- SettingsProvider简单分析
SettingsProvider顾名思义是一个提供数据共享的Provider,SettingsProvider和Android系统其它Provider有很多不一样的地方: 1.SettingsProv ...
- Android系统之SettingsProvider(二)
(1)概述 (A) SettingsProvider顾名思义是一个提供设置数据共享的Provider,SettingsProvider和Android系统其它Provider有很多不一样的地方,如: ...
- Android-Q颜色模式
0 前言 Android-Q可通过"Settings > Display > Colors"选择颜色模式: 图0.1 Colors(第3个模式是本文增加的) Andro ...
- Android源码解析--dropbox日志:DropBoxManagerService(DBMS)服务详解
DropBoxManagerService 简介 DropBoxManagerService(简称DBMS)是日志相关的服务,用于生成与管理 系统运行时的一些日志文件.日志文件大多记录的是系统或某个应 ...
- aap渗透_Android App渗透测试工具汇总
一. drozer简介 drozer(以前称为Mercury)是一款Android安全测试框架. drozer允许您通过承担应用程序的角色并与Dalvik VM,其他应用程序的IPC端点和底层操作系统 ...
- [深入理解Android卷二 全文-第三章]深入理解SystemServer
由于<深入理解Android 卷一>和<深入理解Android卷二>不再出版,而知识的传播不应该因为纸质媒介的问题而中断,所以我将在CSDN博客中全文转发这两本书的全部内容 第 ...
- aap渗透_Android App渗透测试工具分享
这段时间因为某些原因接触了Android App渗透测试,发现了几个不错的App渗透测试工具(虽然这些工具早就出来了 2333),搭建测试环境的过程中遇到了一些问题,特地总结一下,希望能给大家带来帮助 ...
- Ionic 更换主题风格方案
需求 最近涉及到的一个需求是--用户可更换页面风格,因此,查了一些资料后,写一下Ionic更换主题方案 方案 动态改变根标签类名,比如亮色风格时,class="light",比如暗 ...
最新文章
- 按照文字内容动态设置TableViewCell的高度
- 编写一个函数itob(int n,char s[], int b),将整数n转换为以b进制的数。保存到s中。...
- conky在ubuntu xfce4下面的配置
- 圆章能随便刻吗_自己晒干的蒲公英能长期当茶随便喝吗?医生:3个危害不请自来...
- fsck 修复文件系统_微软推出Win10 20H2 Build 19042.608测试版 修复多种已知错误
- 大数据分析平台在企业的重要性
- 国内银行卡BIN号速查简表(2016)
- CKFinder baseDir 和 baseURL参数解释
- 三台Centos7虚拟机之间实现ssh,rsh互连,虚拟机和本机基于ssh进行文件传输
- 移动端VUE实现一周课程表
- 软考是什么?怎么准备----软考相关资讯
- 六:抽象队列同步器AQS应用之BlockingQueue详解
- mingw64官方下载地址
- java实现高德地图app,Android 高德地图入门demo,最新高德地图实现方法,附源码及apk...
- libjpeg的安装与使用
- 突破技术限制,实现Web端静默打印
- 区块链:Neutral Dollar(NUSD)亚稳态的可视化
- 指南解读:急性心力衰竭中国急诊管理指南(2022)
- 甲乙丙三人一起进行百米赛跑(假定三人均为匀速直线运动)如果当甲到达终点时,乙距终点有5米,丙距终点还有10米,那么当乙到达终点时,丙距终点还有()米
- php swoft 路由,Swoft 源码解读
热门文章
- sketchup 计算机配置,流畅运行SU草图大师软件的最低电脑配置要求
- 在统计学中_[求助] OR在统计学中指什么?
- 赛灵思FPGA功耗实测与XPE模拟计算对比分析
- 力扣(leetcode)[118. 杨辉三角] 简单
- 推荐一个rss源搜索引擎
- android 键盘 自动消失,android 键盘状态,获取键盘显示和隐藏
- 七彩cms云转码_最新版七彩CMS 2019云转码完全开源版本 程序源码带安装教程
- 第二章 Java基本语言
- win7 u盘 正在计算机,U盘在Win7电脑上读不出来怎么办?两种解决方法全教给你!...
- 两次获得微信生态支持的如祺出行,如何破局网约车市场?