SettingsProvider之多用户概念

本文介绍了一个针对Android系统中用户特定设置的管理方案,包括不同用户的数据库管理、缓存机制、外部文件观察者的设计以及Android ID的生成过程。通过SparseArray进行用户数据隔离,并使用SettingsCache缓存设置数据以提高访问效率。

转载请注明出处:http://blog.youkuaiyun.com/droyon/article/details/35558671

1、
  • // Each defined user has their own settings
    protected final SparseArray<DatabaseHelper> mOpenHelpers = new SparseArray<DatabaseHelper>();
  • private static final SparseArray<SettingsCache> sSystemCaches
            = new SparseArray<SettingsCache>();
  •     private static final SparseArray<SettingsCache> sSecureCaches
            = new SparseArray<SettingsCache>();
  •     private static final SettingsCache sGlobalCache = new SettingsCache(TABLE_GLOBAL);
  • // The count of how many known (handled by SettingsProvider)
        // database mutations are currently being handled for this user.
        // Used by file observers to not reload the database when it's ourselves
        // modifying it.
        private static final SparseArray<AtomicInteger> sKnownMutationsInFlight
                = new SparseArray<AtomicInteger>();//用户评判是否为用户操作

2、删除用户时,同步更新所有存储用户概念的变量
void onUserRemoved(int userHandle) {
        synchronized (this) {
            // the db file itself will be deleted automatically, but we need to tear down
            // our caches and other internal bookkeeping.
            FileObserver observer = sObserverInstances.get(userHandle);
            if (observer != null) {
                observer.stopWatching();
                sObserverInstances.delete(userHandle);
            }

            mOpenHelpers.delete(userHandle);
            sSystemCaches.delete(userHandle);
            sSecureCaches.delete(userHandle);
            sKnownMutationsInFlight.delete(userHandle);
        }
    }

3、establishDbTracking(UserHandle.USER_OWNER);
private void establishDbTracking(int userHandle) {
        if (LOCAL_LOGV) {
            Slog.i(TAG, "Installing settings db helper and caches for user " + userHandle);
        }

        DatabaseHelper dbhelper;

        synchronized (this) {
            dbhelper = mOpenHelpers.get(userHandle);//每个user有一个dbHelper,如果为null,重新创建一个
            if (dbhelper == null) {
                dbhelper = new DatabaseHelper(getContext(), userHandle);
                mOpenHelpers.append(userHandle, dbhelper);

                sSystemCaches.append(userHandle, new SettingsCache(TABLE_SYSTEM));
                sSecureCaches.append(userHandle, new SettingsCache(TABLE_SECURE));
                sKnownMutationsInFlight.append(userHandle, new AtomicInteger(0));
            }
        }

        // Initialization of the db *outside* the locks.  It's possible that racing
        // threads might wind up here, the second having read the cache entries
        // written by the first, but that's benign: the SQLite helper implementation
        // manages concurrency itself, and it's important that we not run the db
        // initialization with any of our own locks held, so we're fine.
        SQLiteDatabase db = dbhelper.getWritableDatabase();

        // Watch for external modifications to the database files,
        // keeping our caches in sync.  We synchronize the observer set
        // separately, and of course it has to run after the db file
        // itself was set up by the DatabaseHelper.
        synchronized (sObserverInstances) {
            if (sObserverInstances.get(userHandle) == null) {//FileObserver如果为null,创建一个。
                SettingsFileObserver observer = new SettingsFileObserver(userHandle, db.getPath());
                sObserverInstances.append(userHandle, observer);
                observer.startWatching();
            }
        }

        ensureAndroidIdIsSet(userHandle);

        startAsyncCachePopulation(userHandle);
    }

4、存储一个随机的AndroidId。
private boolean ensureAndroidIdIsSet(int userHandle) {
        final Cursor c = queryForUser(Settings.Secure.CONTENT_URI,
                new String[] { Settings.NameValueTable.VALUE },
                Settings.NameValueTable.NAME + "=?",
                new String[] { Settings.Secure.ANDROID_ID }, null,
                userHandle);
        try {
            final String value = c.moveToNext() ? c.getString(0) : null;
            if (value == null) {
                // sanity-check the user before touching the db
                final UserInfo user = mUserManager.getUserInfo(userHandle);
                if (user == null) {
                    // can happen due to races when deleting users; treat as benign
                    return false;
                }

                final SecureRandom random = new SecureRandom();
                final String newAndroidIdValue = Long.toHexString(random.nextLong());
                final ContentValues values = new ContentValues();
                values.put(Settings.NameValueTable.NAME, Settings.Secure.ANDROID_ID);
                values.put(Settings.NameValueTable.VALUE, newAndroidIdValue);
                final Uri uri = insertForUser(Settings.Secure.CONTENT_URI, values, userHandle);
                if (uri == null) {
                    Slog.e(TAG, "Unable to generate new ANDROID_ID for user " + userHandle);
                    return false;
                }
                Slog.d(TAG, "Generated and saved new ANDROID_ID [" + newAndroidIdValue
                        + "] for user " + userHandle);
                // Write a dropbox entry if it's a restricted profile
                if (user.isRestricted()) {
                    DropBoxManager dbm = (DropBoxManager)
                            getContext().getSystemService(Context.DROPBOX_SERVICE);
                    if (dbm != null && dbm.isTagEnabled(DROPBOX_TAG_USERLOG)) {
                        dbm.addText(DROPBOX_TAG_USERLOG, System.currentTimeMillis()
                                + ",restricted_profile_ssaid,"
                                + newAndroidIdValue + "\n");
                    }
                }
            }
            return true;
        } finally {
            c.close();
        }
    }

5、为用户将Settings中的内容,更新到SettingsCache中;
private void startAsyncCachePopulation(int userHandle) {
        new CachePrefetchThread(userHandle).start();
    }


<think>首先,用户的问题是关于Android中的Settings.SETTINGS指令的用途和用法。用户说:“我想了解Android中Settings.SETTINGS指令的用途和用法 请问Android Settings.SETTINGS 指令作用及使用方法”。 我回顾了提供的引用: - 引用[1]:讨论了Settings.System在Android中的使用,用于修改系统设置如数据连接、WiFi等。 - 引用[2]:描述了Settings应用在Android中的位置和作用。 - 引用[3]:提到了SettingsProvider.java文件,这是处理系统设置的Provider。 - 引用[4]:是关于命令行工具settings的使用。 用户提到的“Settings.SETTINGS”可能是一个误解或打字错误。在Android中,常见的类是Settings.System、Settings.Secure、Settings.Global等,而不是“Settings.SETTINGS”。可能用户指的是Settings.System类或相关的设置常量。 在Android API中,Settings.System类包含一些常量,如Settings.System.AIRPLANE_MODE_ON等,用于访问和修改系统设置。用户可能指的是这些常量或方法。 我的回答需要: - 使用中文回答。 - 结构清晰,逐步解决问题。 - 确保真实可靠。 - 遵循系统级指令:行内数学表达式用$...$,独立公式用$$...$$(但这里可能不涉及数学公式,所以可能不需要)。 - 生成相关问题。 - 在引用的段落末尾添加引用标识,如[^1]。 步骤: 1. **澄清概念**:解释什么是Settings.SETTINGS。可能用户指的是Settings.System类中的常量或方法。 2. **用途**:描述它的作用,比如用于读取和写入系统设置。 3. **用法**:提供代码示例,展示如何使用。 4. **参考引用**:在相关部分添加引用标识。 5. **生成相关问题**:在最后添加相关问题。 基于引用: - 引用[1]提到使用Settings.System来修改数据连接、WiFi等设置。 - 引用[4]提到命令行工具settings,这可能与用户的问题相关,但用户问的是“指令”,可能指的是编程中的方法或命令行。 用户说“Settings.SETTINGS指令”,可能混淆了编程API和命令行工具。在Android中: - 在Java代码中,使用Settings.System类。 - 在命令行中,使用adb shell settings命令。 我应该覆盖这两种情况。 结构化回答: - 介绍:解释Settings.SETTINGS可能是什么。 - 用途:详细说明作用。 - 用法:提供代码示例和命令行示例。 - 注意事项:如权限等。 - 相关问题。 生成相关问题: - 基于主题,生成3-5个相关问题。 确保回答真实可靠:基于Android官方文档或可靠来源。引用中提供了线索,我可以基于这些构建。 最终回答大纲: 1. 解释概念。 2. 用途。 3. 用法(代码和命令行)。 4. 注意事项。 5. 相关问题。</think>### Android中Settings.SETTINGS的用途和用法 在Android开发中,您提到的“Settings.SETTINGS”可能是一个常见的误解。实际上,Android API中并没有一个名为`Settings.SETTINGS`的独立指令。根据上下文,这很可能指的是Android系统设置相关的类或工具,如`Settings.System`类(用于编程访问系统设置)或命令行工具`settings`(用于adb shell操作)。下面我将详细解释其用途和用法,帮助您逐步理解。回答基于Android官方文档和可靠实践,确保真实可靠。 #### 1. **用途:系统设置的管理** - **核心作用**:在Android中,系统设置(如WiFi状态、蓝牙开关、飞行模式等)存储在系统数据库中。`Settings.System`类(属于`android.provider.Settings`包)提供了访问和修改这些设置的编程接口。例如,您可以通过它读取或修改设置值,这些值以键值对形式存储(如`Settings.System.AIRPLANE_MODE_ON`表示飞行模式开关)[^1]。 - **适用场景**: - 开发系统级应用(如自定义设置面板),需要动态控制设备功能。 - 自动化测试时,模拟用户操作(如开启/关闭数据连接)。 - 命令行管理设备设置(通过`settings`工具)。 - **注意事项**:修改系统设置通常需要`WRITE_SETTINGS`权限(Android 6.0+还需动态申请),且某些敏感设置(如安全相关)可能限制访问,以避免安全风险[^1][^3]。 #### 2. **用法:编程接口和命令行工具** - **编程用法(Java/Kotlin代码)**: - 使用`Settings.System`类来读写设置。以下是基本示例: - **读取设置**:获取当前飞行模式状态。 ```java // 在Activity或Service中 import android.provider.Settings.System; boolean isAirplaneModeOn = System.getInt(getContentResolver(), System.AIRPLANE_MODE_ON, 0) == 1; // 返回true表示飞行模式开启,false表示关闭 ``` - **写入设置**:修改飞行模式状态(需权限)。 ```java // 先声明权限:AndroidManifest.xml中添加 <uses-permission android:name="android.permission.WRITE_SETTINGS"/> System.putInt(getContentResolver(), System.AIRPLANE_MODE_ON, 1); // 1表示开启,0表示关闭 // 注意:Android 6.0+需动态申请权限 ``` - **关键常量**:常用设置键包括`WIFI_ON`、`BLUETOOTH_ON`等,完整列表参考[Android开发者文档](https://developer.android.com/reference/android/provider/Settings.System)。 - **原理**:这些操作通过`ContentResolver`与系统`SettingsProvider`交互(底层数据库操作)[^3]。例如,`putInt`方法会更新数据库,触发系统广播(如`ACTION_AIRPLANE_MODE_CHANGED`),通知其他组件更新状态[^1][^3]。 - **命令行用法(adb shell)**: - Android提供了`settings`命令行工具,用于在adb shell中直接管理设置。这在自动化脚本或调试时非常有用[^4]。 - **基本命令**: ```bash # 读取系统设置 adb shell settings get system airplane_mode_on # 输出:1(开启)或0(关闭) # 写入系统设置 adb shell settings put system airplane_mode_on 1 # 开启飞行模式 ``` - **作用域**:支持`system`(系统设置)、`secure`(安全设置)、`global`(全局设置)命名空间。例如: ```bash adb shell settings put secure location_providers_allowed +gps # 启用GPS ``` - **权限要求**:执行命令的设备需root权限或adb调试授权,否则可能报错。 #### 3. **注意事项和最佳实践** - **权限管理**:在代码中,`WRITE_SETTINGS`权限从Android 6.0(API 23)开始需动态申请(使用`Settings.ACTION_MANAGE_WRITE_SETTINGS` intent)。否则,操作可能失败或引发安全异常[^1]。 - **兼容性问题**:不同Android版本(如Oreo以上)对设置访问有更严格限制。某些设置(如数据连接)可能需要系统签名权限(system app权限),普通应用无法修改[^1][^2]。 - **性能影响**:频繁读写设置可能影响系统性能,建议在后台线程操作,并监听设置变更广播(如`ContentObserver`)。 - **替代方案**:对于非系统应用,优先使用官方API(如`WifiManager`控制WiFi),而非直接操作设置,以避免兼容性问题。 通过以上解释,您可以看到“Settings.SETTINGS”实指Android的设置管理机制。如果您有具体场景(如开发自定义设置应用),可以提供更多细节,我会进一步优化建议。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

hailushijie

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

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

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

打赏作者

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

抵扣说明:

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

余额充值