1、 System表,合法设定值校验。
外部三方应用可随意设定值,不安全,新版本在Settings.java中增加了Validator。
检查时机:在SettingsProvider中,在做insert动作前:
private void validateSystemSettingValue(String name, String value) {
Settings.System.Validator validator = Settings.System.VALIDATORS.get(name);
if (validator != null && !validator.validate(value)) {
throw new IllegalArgumentException("Invalid value: " + value
+ " for setting: " + name);
}
}
2、 允许用户进行权限限制
在系统设置—应用—配置应用—修改系统设置,提供页面,供用户设定那些应用可以操作SettingsProvider数据库。
例如:之前的版本允许三方应用对屏幕休眠时间设定非法数值.像:起点读书.
启动页面:adb shell am start –a “android.settings.action.MANAGE_WRITE_SETTINGS”
涉及权限:
private static final String PM_WRITE_SETTINGS = Manifest.permission.WRITE_SETTINGS;
private static final String PM_CHANGE_NETWORK_STATE = Manifest.permission.CHANGE_NETWORK_STATE;
ps:CHANGE_NETWORK_STATE is now merged with WRITE_SETTINGS
3、 根据应用对SettinsProvider写入数据进行限制。
针对PackageName,对进程使用的SettingsProvider数据进行限定.{android}包名对用的进程除外.
针对每个应用,可允许设定的数据总大小依次是:
【System】限制20000,【Global】、【Secure】无限制。
private void ensureSettingsStateLocked(int key) {
if (mSettingsStates.get(key) == null) {
final int maxBytesPerPackage = getMaxBytesPerPackageForType(getTypeFromKey(key));
SettingsState settingsState = new SettingsState(mLock, getSettingsFile(key), key,
maxBytesPerPackage);
mSettingsStates.put(key, settingsState);
}
}
4、 在数据库升级中使用UpdateController替代onUpgrade方法:
用户的手机在每次升级,是不能全清数据的,安卓M以前的版本,依赖onUpgrade,在安卓M中,依赖UpdateController.
UpgradeController upgrader = new UpgradeController(userId);
upgrader.upgradeIfNeededLocked();
5、 涉及多用户的表:
多用户相关:【Secure】、【Global】.【System】数据表不涉及多用户.
private void notifyForSettingsChange(int key, String name) {
// Update the system property *first*, so if someone is listening for
// a notification and then using the contract class to get their data,
// the system property will be updated and they'll get the new data.
boolean backedUpDataChanged = false;
mHandler.obtainMessage(MyHandler.MSG_NOTIFY_URI_CHANGED,
userId, 0, uri).sendToTarget();
if (isSecureSettingsKey(key)) {
maybeNotifyProfiles(userId, uri, name, sSecureCloneToManagedSettings);
} else if (isSystemSettingsKey(key)) {
maybeNotifyProfiles(userId, uri, name, sSystemCloneToManagedSettings);
}
}
6、 关于SettingsState。
每个数据表对应一个SettingsState,其中保存了SettingsProvider每张表的数据Tag常量、缓冲区mSettings。
Ps:该缓冲区,所有进程共享。
7、 关于Settings
Settings.java编译在framework.jar中,即运行在调用方进程中。
其中有个缓存区:
HashMap<String, String> mValues = new HashMap<String, String>();
Ps:该缓存区每个进程独自享有,且每个进程的缓存区内容都不同。
8、 关于双缓冲
1、 写操作
通过Settings.java跨进程调用SettingsProvder
获取SettingsState
调用insert方法。
2、 读操作
通过Settings.java 的Settings.System.getInt,getString等接口调用
缓存区是否dirty,dirty则清缓存。
如果缓存可用,则从缓存中读取数据返回。
发起ContentProvider安卓标准query请求。
9、 关于写入
大批量、多次的Settings.System.putInt请求,不会立即写入,会间隔2000毫秒。
写入通过后台进程来完成。
private final class MyHandler extends Handler {
public static final int MSG_PERSIST_SETTINGS = 1;
public MyHandler() {
super(BackgroundThread.getHandler().getLooper());
}
@Override
public void handleMessage(Message message) {
switch (message.what) {
case MSG_PERSIST_SETTINGS: {
Runnable callback = (Runnable) message.obj;
doWriteState();
if (callback != null) {
callback.run();
}
}
break;
}
}
}
10、 关于写入位置
一般情况下是/data/system/user/0/,其中{0}代表多用户的id.
private File getSettingsFile(int key) {
if (isGlobalSettingsKey(key)) {
final int userId = getUserIdFromKey(key);
return new File(Environment.getUserSystemDirectory(userId),
SETTINGS_FILE_GLOBAL);
} else if (isSystemSettingsKey(key)) {
final int userId = getUserIdFromKey(key);
return new File(Environment.getUserSystemDirectory(userId),
SETTINGS_FILE_SYSTEM);
} else if (isSecureSettingsKey(key)) {
final int userId = getUserIdFromKey(key);
return new File(Environment.getUserSystemDirectory(userId),
SETTINGS_FILE_SECURE);
} else {
throw new IllegalArgumentException("Invalid settings key:" + key);
}
}
关注我的技术公众号,查看更多优质技术文章推送
微信扫一扫下方二维码即可关注: