安卓M-SettingsProvider新功能特性总结

本文探讨了系统设置表的合法设定值校验机制、权限限制功能、针对应用的写入数据限制、数据库升级策略、多用户表管理及关键组件如SettingsState与Settings的运作原理。同时介绍了如何通过配置应用权限、限制批量写入操作和多用户相关表管理来提升系统的安全性与灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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);
            }
        }

关注我的技术公众号,查看更多优质技术文章推送

微信扫一扫下方二维码即可关注:

关注我的技术公众号,查看更多优质技术文章推送

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hailushijie

您的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值