Android 11.0 SettingsProvider 源码分析


一、SettingsProvider 的概述

SettingsProvider 是一个为 Android 系统设置提供数据共享的 Provider,它包含全局、安全和系统级别的用户偏好设置。并且,它是跟随 framework 一起编译,以apk的形式内置到系统的应用程序,所以源码的位置在:

frameworks\base\packages\SettingsProvider

数据分类:
SettingsProvider 对数据进行了分类,主要分为 Global、System 和 Secure 三种类型:

  • Global:全局偏好设置 ,对系统中所有用户公开;
  • System:系统偏好设置
  • Secure:安全偏好设置。

此外,为了方便对数据的操作,系统对 SettingsProvider 的一些接口进行封装处理。在 Settings 类中,分别声明了 Global、Secure、System 三个静态内部类,分别对应上述的三种数据类型。通过调用 这三个内部类中定义好的方法及属性,就可以对系统设置的数据进行相应的操作。 Settings 类的路径在:

frameworks\base\core\java\android\provider\Settings.java

下面是它的部分代码:



/**
 * The Settings provider contains global system-level device preferences.
 */
public final class Settings {

	……	
	//内部类 System
    public static final class System extends NameValueTable {
        private static final float DEFAULT_FONT_SCALE = 1.0f;
        
       public static String getString(ContentResolver resolver, String name) {
            return getStringForUser(resolver, name, resolver.getUserId());
        }

        public static String getStringForUser(ContentResolver resolver, String name,
                int userHandle) {
            if (MOVED_TO_SECURE.contains(name)) {
                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
                        + " to android.provider.Settings.Secure, returning read-only value.");
                return Secure.getStringForUser(resolver, name, userHandle);
            }
            if (MOVED_TO_GLOBAL.contains(name) || MOVED_TO_SECURE_THEN_GLOBAL.contains(name)) {
                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
                        + " to android.provider.Settings.Global, returning read-only value.");
                return Global.getStringForUser(resolver, name, userHandle);
            }
            return sNameValueCache.getStringForUser(resolver, name, userHandle);
        }

        public static boolean putString(ContentResolver resolver, String name, String value) {
            return putStringForUser(resolver, name, value, resolver.getUserId());
        }

        public static boolean putStringForUser(ContentResolver resolver, String name, String value,
                int userHandle) {
            if (MOVED_TO_SECURE.contains(name)) {
                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
                        + " to android.provider.Settings.Secure, value is unchanged.");
                return false;
            }
            if (MOVED_TO_GLOBAL.contains(name) || MOVED_TO_SECURE_THEN_GLOBAL.contains(name)) {
                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
                        + " to android.provider.Settings.Global, value is unchanged.");
                return false;
            }
            return sNameValueCache.putStringForUser(resolver, name, value, null, false, userHandle);
        }
        ……
	}
	
	……
	//内部类 Secure
    public static final class Secure extends NameValueTable {
        public static final Uri CONTENT_URI =
            Uri.parse("content://" + AUTHORITY + "/secure");

        @UnsupportedAppUsage
        private static final ContentProviderHolder sProviderHolder =
                new ContentProviderHolder(CONTENT_URI);
        ……        
        }               

	……
	//内部类 Global
    public static final class Global extends NameValueTable {
        public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/global");

        public static final String NOTIFICATION_BUBBLES = "notification_bubbles";

        private static final Validator NOTIFICATION_BUBBLES_VALIDATOR = BOOLEAN_VALIDATOR;

		……
 }       
 

数据储存位置及方式:

Android 6.0(M) 以前:

/data/data/com.android.providers.settings/databases/settings.db

Android 6.0(M) 及其以后:

/data/system/users/ <user_id>/settings_system.xml
/data/system/users/ <user_id>/settings_global.xml
/data/system/users/<user_id>/settings_secure.xml

数据存储方式:SettingsProvider只接受 int、float 和 String 等类型的数据,且这些数据最终都会被转换为 String 类型,然后以键-值对的形式存放在对应的 xml 文件中。

改变存储方式的目的主要有以下三点:

  • 提高系统性能(400ms降低到10ms);
  • 为每一个用户独立储存偏好设置;
  • 限制了第三方应用对偏好设置的写入,增加了安全性。

此外,除了上述三个数据文件以外,在8.0以后,用户所安装的每个 APP (package) 都会产生一组独立的 ID (SSAID)和对应的描述,这些数据被存放在 “/data/system/users/<user_id>/settings_ssaid.xml"。下面是系统用户 0 存放上述 xml 文件的示例图 :

在这里插入图片描述

二、SettingsProvider 的启动流程

程序启动流程图:

img-blog.csdnimg.cn/d91f8c009f084dfc9c9f3324f1995430.png)

1、SettingsProvider 是一个系统 Provider,和其他系统 Provider 的启动流程一样,它会在 SystemServer 启动系统服务的过程中被安装进系统。以下是实现代码:

FilePath: frameworks/base/services/java/com/android/server/SystemServer.java


    /**
     * Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
     */
    private void startOtherServices() {
   		……
    	traceBeginAndSlog("InstallSystemProviders");
        mActivityManagerService.installSystemProviders();
        // Now that SettingsProvider is ready, reactivate SQLiteCompatibilityWalFlags
        SQLiteCompatibilityWalFlags.reset();
        traceEnd();
        ……
  } 
  

上述代码中,在 SystemServer 启动系统服务的 startOtherServices() 方法中,通过调用 ActivityManagerService 的 installSystemProviders() 方法完成 SettingsProvider 的安装和创建。

2、ActivityManagerService 的 installSystemProviders() 方法。

FilePath: frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java


public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
        ……
    public final void installSystemProviders() {
		// 1、获取系统中所有的 Provider。这个过程最终会通过调用包管理模块 PackageManagerService 中的
        // queryContentProviders() 方法来获取所有的 Provider
        List<ProviderInfo> providers;
        synchronized (this) {
            ProcessRecord app = mProcessList.mProcessNames.get("system", SYSTEM_UID);
            providers = generateApplicationProvidersLocked(app);
            if (providers != null) {
                for (int i=providers.size()-1; i>=0; i--) {
                    ProviderInfo pi = (ProviderInfo)providers.get(i);
                    if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
                        Slog.w(TAG, "Not installing system proc provider " + pi.name
                                + ": not system .apk");
                        providers.remove(i);
                    }
                }
            }
        }

		//2、调用 ActivityThread 的 installSystemProviders 方法完成系统 Provider 的安装启动,
		//其中就包括 SettingsProvider
        if (providers != null) {
            mSystemThread.installSystemProviders(providers);
        }

        synchronized (this) {
            mSystemProvidersInstalled = true;
        }
        mConstants.start(mContext.getContentResolver());
        mCoreSettingsObserver = new CoreSettingsObserver(this);
        mActivityTaskManager.installSystemProviders();
        mDevelopmentSettingsObserver = new DevelopmentSettingsObserver();
        SettingsToPropertiesMapper.start(mContext.getContentResolver());
        mOomAdjuster.initSettings();

        // Now that the settings provider is published we can consider sending
        // in a rescue party.
        
        //3、处理 SettingsProvider 安装之前某些依赖程序
        RescueParty.onSettingsProviderPublished(mContext);

        //mUsageStatsService.monitorPackages();
    }
  ……
  

其中,上述代码第二步调用到 ActivityThread 的 installSystemProviders() 方法涉及到比较复杂的处理逻辑,和 SettingsProvider 的启动流程关系不大,这里就不做分析了,但它最终是会调用到 SettingsProvider 中的 onCreate() 方法。

3、SettingsProvider 中的 onCreate() 方法。

FilePath: frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java


@SuppressWarnings("deprecation")
public class SettingsProvider extends ContentProvider {
……
    @Override
    public boolean onCreate() {
        Settings.setInSystemServer();

        // fail to boot if there're any backed up settings that don't have a non-null validator
        ensureAllBackedUpSystemSettingsHaveValidators();
        ensureAllBackedUpGlobalSettingsHaveValidators();
        ensureAllBackedUpSecureSettingsHaveValidators();

        synchronized (mLock) {
            mUserManager = UserManager.get(getContext());
            mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
            mPackageManager = AppGlobals.getPackageManager();
            //1、创建 HandlerThread 对象,用来执行异步操作
            mHandlerThread = new HandlerThread(LOG_TAG,
                    Process.THREAD_PRIORITY_BACKGROUND);
            mHandlerThread.start();
            mHandler = new Handler(mHandlerThread.getLooper());
            //2、创建 SettingsRegistry 对象
            mSettingsRegistry = new SettingsRegistry();
        }
        mHandler.post(() -> {
            //3、注册广播接收器
            registerBroadcastReceivers();
            startWatchingUserRestrictionChanges();
        });
        //4、向系统添加SettingsService、DeviceConfigService 服务
        ServiceManager.addService("settings", new SettingsService(this));
        ServiceManager.addService("device_config", new DeviceConfigService(this));
        return true;
    }
……
    

上述中的关键部分是创建 SettingsRegistry 对象,而 SettingsRegistry 是SettingsProvider 的内部类。

4、内部类 SettingsRegistry

FilePath: frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java


	final class SettingsRegistry {
        private static final String DROPBOX_TAG_USERLOG = "restricted_profile_ssaid";

        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";

        private static final String SSAID_USER_KEY = "userkey";

        private final SparseArray<SettingsState> mSettingsStates = new SparseArray<>();

        private GenerationRegistry mGenerationRegistry;

        private final Handler mHandler;

        private final BackupManager mBackupManager;

        private String mSettingsCreationBuildId;

        public SettingsRegistry() {
            mHandler = new MyHandler(getContext().getMainLooper());
            //1、创建 GenerationRegistry 对象,对xml文件的更改做版本管理
            mGenerationRegistry = new GenerationRegistry(mLock);
            //2、创建 BackupManager 对象,系统备份
            mBackupManager = new BackupManager(getContext());
            //3、迁移所有的系统设置数据
            migrateAllLegacySettingsIfNeeded();
            syncSsaidTableOnStart();
        }
……
}

在 SettingsRegistry 的构造方法中,注释1处创建了一个GenerationRegistry对象,GenerationRegistry对象的核心作用类似于对xml文件的更改做版本管理。
注释2处创建BackupManager对象,和系统备份有关。
注释3是迁移所有的系统设置数据,是重点方法。

5、migrateAllLegacySettingsIfNeeded()方法的分析:

FilePath: frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java


private void migrateAllLegacySettingsIfNeeded() {
            synchronized (mLock) {
                final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
                File globalFile = getSettingsFile(key);
                //1、判断"settings_global.xml"文件是否存在
                //存在,则不做数据迁移
                //不存在,则要做数据迁移
                //文件不存在的情况有:1.机器首次启动;2.恢复出厂设置后的首次开机;3.系统版本低于6.0
                if (SettingsState.stateFileExists(globalFile)) {
                    return;
                }

                mSettingsCreationBuildId = Build.ID;

                final long identity = Binder.clearCallingIdentity();
                try {
                    //2、获取系统中所有的用户(多用户,一般用户0)
                    List<UserInfo> users = mUserManager.getUsers(true);

                    final int userCount = users.size();
                    for (int i = 0; i < userCount; i++) {
                        final int userId = users.get(i).id;

                        //3、创建数据库 settings.db 和数据表,然后将 系统默认设置 加载到数据表中(临时数据库)
                        DatabaseHelper dbHelper = new DatabaseHelper(getContext(), userId);
                        SQLiteDatabase database = dbHelper.getWritableDatabase();
                        //4、生成xml文件,并迁移数据库数据到文件中
                        migrateLegacySettingsForUserLocked(dbHelper, database, userId);

                        // Upgrade to the latest version.
                        UpgradeController upgrader = new UpgradeController(userId);
                        upgrader.upgradeIfNeededLocked();

                        // Drop from memory if not a running user.
                        if (!mUserManager.isUserRunning(new UserHandle(userId))) {
                            removeUserStateLocked(userId, false);
                        }
                    }
                } finally {
                    Binder.restoreCallingIdentity(identity);
                }
            }
        }
        

注释1处先判断"/data/system/users/0/settings_global.xml"文件是否存在,如果不存在,migrateAllLegacySettingsIfNeed()方法会直接返回,即不做后续的数据迁移操作,而文件不存在的情况一般发生机器首次启动或恢复出厂设置后的第一次开机。如果存在,则对系统设置做数据迁移。
注释2处是获取系统中所有用户,并通过for循环遍历对每个用户执行数据迁移的过程。
注释3处通过 DatabaseHelper 类创建了数据库和数据表,并使用默认设置对数据库表数据初始化。此外,这里数据库是一个临时数据库。之所以创建这个临时数据库,是为了兼容 Android 6.0 以前的版本而设计。
注释4处的代码是为用户生成 xml 文件,并将数据库数据迁移到 xml 文件的核心代码。

6、数据库创建和初始化的核心:DatabaseHelper

构造方法 DatabaseHelper() 中执行了dbNameForUser() 方法,SQLiteOpenHelper 创建了数据库 settings.db 。
在 settings.db 数据库创建后,会回调onCreate() 方法,并在方法中创建了数据表。

FilePath: frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java


class DatabaseHelper extends SQLiteOpenHelper {
    private static final String TAG = "SettingsProvider";
    private static final String DATABASE_NAME = "settings.db";

    // Please, please please. If you update the database version, check to make sure the
    // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
    // is properly propagated through your change.  Not doing so will result in a loss of user
    // settings.

	//此处省略
	……

	//获取数据库名称/路径
    static String dbNameForUser(final int userHandle) {
        // The owner gets the unadorned db name;
        if (userHandle == UserHandle.USER_SYSTEM) {
            return DATABASE_NAME;
        } else {
            // Place the database in the user-specific data tree so that it's
            // cleaned up automatically when the user is deleted.
            File databaseFile = new File(
                    Environment.getUserSystemDirectory(userHandle), DATABASE_NAME);
            // If databaseFile doesn't exist, database can be kept in memory. It's safe because the
            // database will be migrated and disposed of immediately after onCreate finishes
            if (!databaseFile.exists()) {
                Log.i(TAG, "No previous database file exists - running in in-memory mode");
                return null;
            }
            return databaseFile.getPath();
        }
    }

    public DatabaseHelper(Context context, int userHandle) {
    	//创建数据库
        super(context, dbNameForUser(userHandle), null, DATABASE_VERSION);
        mContext = context;
        mUserHandle = userHandle;
    }

	//此处省略isValidTable()、 isInMemory()、dropDatabase()、backupDatabase()
    ……
    
    private void createSecureTable(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE secure (" +
                "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
                "name TEXT UNIQUE ON CONFLICT REPLACE," +
                "value TEXT" +
                ");");
        db.execSQL("CREATE INDEX secureIndex1 ON secure (name);");
    }

    private void createGlobalTable(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE global (" +
                "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
                "name TEXT UNIQUE ON CONFLICT REPLACE," +
                "value TEXT" +
                ");");
        db.execSQL("CREATE INDEX globalIndex1 ON global (name);");
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
    	//1、创建 system 数据表
        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);");

		//2、创建 secure 数据表
        createSecureTable(db);

		//3、为用户0创建 global 数据表
        // Only create the global table for the singleton 'owner/system' user
        if (mUserHandle == UserHandle.USER_SYSTEM) {
            createGlobalTable(db);
        }

        db.execSQL("CREATE TABLE bluetooth_devices (" +
                    "_id INTEGER PRIMARY KEY," +
                    "name TEXT," +
                    "addr TEXT," +
                    "channel INTEGER," +
                    "type INTEGER" +
                    ");");

        db.execSQL("CREATE TABLE bookmarks (" +
                    "_id INTEGER PRIMARY KEY," +
                    "title TEXT," +
                    "folder TEXT," +
                    "intent TEXT," +
                    "shortcut INTEGER," +
                    "ordering INTEGER" +
                    ");");

        db.execSQL("CREATE INDEX bookmarksIndex1 ON bookmarks (folder);");
        db.execSQL("CREATE INDEX bookmarksIndex2 ON bookmarks (shortcut);");

        // Populate bookmarks table with initial bookmarks
        boolean onlyCore = false;
        try {
            onlyCore = IPackageManager.Stub.asInterface(ServiceManager.getService(
                    "package")).isOnlyCoreApps();
        } catch (RemoteException e) {
        }
        if (!onlyCore) {
            loadBookmarks(db);
        }
		
		//4、将初始音量加载到DB中
        // Load initial volume levels into DB
        loadVolumeLevels(db);
		//5、将默认设置数据加载到数据表中
        // Load inital settings values
        loadSettings(db);
    }
    ……
    

上述代码注释1、2、3处分别为用户创建system、secure和global三张数据表。此外,注释3处多了一个判断,这是因为 “settings_global.xml” 文件是所有用户共享的,所以只存储在0用户下。
注释4处的 loadVolumeLevels() 和 loadSettings() 方法是将默认数据填充数据表中。

以下是 loadSettings( ) 方法的内容:

FilePath: frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java


private void loadSettings(SQLiteDatabase db) {
		//将三种数据类型的设置数据加载到数据表中
        loadSystemSettings(db);
        loadSecureSettings(db);
        // The global table only exists for the 'owner/system' user
        if (mUserHandle == UserHandle.USER_SYSTEM) {
            loadGlobalSettings(db);
        }
    }

    private void loadSystemSettings(SQLiteDatabase db) {
        SQLiteStatement stmt = null;
        try {
            stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)"
                    + " VALUES(?,?);");

            loadBooleanSetting(stmt, Settings.System.DIM_SCREEN,
                    R.bool.def_dim_screen);
            loadIntegerSetting(stmt, Settings.System.SCREEN_OFF_TIMEOUT,
                    R.integer.def_screen_off_timeout);

            // Set default cdma DTMF type
            loadSetting(stmt, Settings.System.DTMF_TONE_TYPE_WHEN_DIALING, 0);

            // Set default hearing aid
            loadSetting(stmt, Settings.System.HEARING_AID, 0);

            // Set default tty mode
            loadSetting(stmt, Settings.System.TTY_MODE, 0);

            loadIntegerSetting(stmt, Settings.System.SCREEN_BRIGHTNESS,
                    R.integer.def_screen_brightness);

            loadIntegerSetting(stmt, Settings.System.SCREEN_BRIGHTNESS_FOR_VR,
                    com.android.internal.R.integer.config_screenBrightnessForVrSettingDefault);

            loadBooleanSetting(stmt, Settings.System.SCREEN_BRIGHTNESS_MODE,
                    R.bool.def_screen_brightness_automatic_mode);

            loadBooleanSetting(stmt, Settings.System.ACCELEROMETER_ROTATION,
                    R.bool.def_accelerometer_rotation);

            loadDefaultHapticSettings(stmt);

            loadBooleanSetting(stmt, Settings.System.NOTIFICATION_LIGHT_PULSE,
                    R.bool.def_notification_pulse);

            loadUISoundEffectsSettings(stmt);

            loadIntegerSetting(stmt, Settings.System.POINTER_SPEED,
                    R.integer.def_pointer_speed);

            loadIntegerSetting(stmt, Settings.System.SCREENSHOT_BUTTON_SHOW,
                    R.integer.def_screenshot_button_show);

            /*
             * 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.
             *
             * See: SettingsProvider.UpgradeController#onUpgradeLocked
             */
        } finally {
            if (stmt != null) stmt.close();
        }
    }
    

在上述 loadSystemSettings() 方法中,加载了很多 defaults.xml 文件中定义的与系统设置相关的默认值。在此期间,这些默认值会被加载到相应数据表中。以下是 defaults.xml 文件的部分内容:

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


<?xml version="1.0" encoding="utf-8"?>
……
<resources>
    <bool name="def_dim_screen">true</bool>
    <integer name="def_screen_off_timeout">60000</integer>
    <integer name="def_sleep_timeout">-1</integer>
    <bool name="def_airplane_mode_on">false</bool>
    <bool name="def_theater_mode_on">false</bool>
    <!-- Comma-separated list of bluetooth, wifi, and cell. -->
    <string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi,nfc,wimax</string>
    <string name="airplane_mode_toggleable_radios" translatable="false">bluetooth,wifi,nfc</string>
    <string name="def_bluetooth_disabled_profiles" translatable="false">0</string>
    <bool name="def_auto_time">true</bool>
    <bool name="def_auto_time_zone">true</bool>
    <bool name="def_accelerometer_rotation">false</bool>
    <!-- Default screen brightness, from 0 to 255.  102 is 40%. -->
    <integer name="def_screen_brightness">102</integer>
    <bool name="def_screen_brightness_automatic_mode">false</bool>
    <fraction name="def_window_animation_scale">100%</fraction>
    <fraction name="def_window_transition_scale">100%</fraction>
    <bool name="def_haptic_feedback">true</bool>

    <bool name="def_bluetooth_on">true</bool>
    <bool name="def_wifi_display_on">false</bool>
    <bool name="def_install_non_market_apps">false</bool>
    <bool name="def_package_verifier_enable">true</bool>
    <!-- 0 == off, 3 == on -->
    <integer name="def_location_mode">3</integer>
    <bool name="assisted_gps_enabled">true</bool>
    <bool name="def_netstats_enabled">true</bool>
    <bool name="def_usb_mass_storage_enabled">true</bool>
    <bool name="def_wifi_on">false</bool>
    <!-- 0 == never, 1 == only when plugged in, 2 == always -->
    <integer name="def_wifi_sleep_policy">2</integer>
    <bool name="def_wifi_wakeup_enabled">true</bool>
    <bool name="def_networks_available_notification_on">true</bool>

    <bool name="def_backup_enabled">false</bool>
    <string name="def_backup_transport" translatable="false">com.android.localtransport/.LocalTransport</string>

    <!-- Default value for whether or not to pulse the notification LED when there is a
         pending notification -->
    <bool name="def_notification_pulse">true</bool>

    <bool name="def_mount_play_notification_snd">true</bool>
    <bool name="def_mount_ums_autostart">false</bool>
    <bool name="def_mount_ums_prompt">true</bool>
    <bool name="def_mount_ums_notify_enabled">true</bool>
	……
<resources>

7、将 settings.db 数据库的数据迁移到 xml 文件中

FilePath: frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java


        private void migrateLegacySettingsForUserLocked(DatabaseHelper dbHelper,
                SQLiteDatabase database, int userId) {
            //1、迁移与 system 设置相关的数据
            // Move over the system settings.
            //1.1、生成与xml文件唯一对应的key
            final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
            ensureSettingsStateLocked(systemKey);
            //1.2、将临时数据库中设置数据存放到 SettingsState 对象中
            SettingsState systemSettings = mSettingsStates.get(systemKey);
            migrateLegacySettingsLocked(systemSettings, database, TABLE_SYSTEM);
            //1.3、把数据写入到xml文件中
            systemSettings.persistSyncLocked();

			//2、迁移与 secure 设置相关的数据
            // 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);
            ensureSettingsStateLocked(secureKey);
            SettingsState secureSettings = mSettingsStates.get(secureKey);
            migrateLegacySettingsLocked(secureSettings, database, TABLE_SECURE);
            ensureSecureSettingAndroidIdSetLocked(secureSettings);
            secureSettings.persistSyncLocked();

			//3、迁移与 global 设置相关的数据
            // 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);
                ensureSettingsStateLocked(globalKey);
                SettingsState globalSettings = mSettingsStates.get(globalKey);
                migrateLegacySettingsLocked(globalSettings, database, TABLE_GLOBAL);
                // If this was just created
                if (mSettingsCreationBuildId != null) {
                    globalSettings.insertSettingLocked(Settings.Global.DATABASE_CREATION_BUILDID,
                            mSettingsCreationBuildId, null, true,
                            SettingsState.SYSTEM_PACKAGE_NAME);
                }
                globalSettings.persistSyncLocked();
            }

			//4、删除数据库或备份数据库数据
            // Drop the database as now all is moved and persisted.
            if (DROP_DATABASE_ON_MIGRATION) {
                dbHelper.dropDatabase();
            } else {
                dbHelper.backupDatabase();
            }
	}
 

三、对 SettingsProvider 进行操作方法

1、操作方法

由于 framework下的 Settings.java 文件中对 SettingsProvider 进行了封装,而且Global、Secure、System 三种数据类型的使用方式几乎一样,所以对系统设置的操作也是相当简便的。以下是对系统设置的读写操作的示例:


//查询数据
String globalValue = Settings.Global.getString(getContentResolver(), Settings.Global.AIRPLANE_MODE_ON);

//写入数据
boolean isSuccess = Settings.System.putInt(getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 1);

2、权限限制

因为 SettingsProvider 是系统应用,所以对它的操作可能会有一些权限限制。首先查询 SettingsProvider 中的设置项数据是不需要声明任何权限,也就是说第三方应用也可以通过 Settings 类查询到 SettingsProvider 中的设置项数据,但是 Android 系统一般不允许第三方应用直接修改系统的设置项,需要用户授权才能修改,即修改设置项数据需要声明下权限:

  • android.permission.WRITE_SETTINGS
  • android.permission.WRITE_SECURE_SETTINGS

所以,一般可以直接修改系统设置的都是系统签名过的应用,也就是系统应用,如下图所示:

这里是引用

四、客制化示例

1、默认搜狗输入法

默认输入法属于安全设置, 设置项的数据类型是 Secure 类型。首先,在 defaults.xml 文件中并没有定义默认输入法设置项数据,所以只能在 DatabaseHelper 类里面的 loadSecureSettings() 添加相应方法可以进行修改,这个方法会在 loadSettings(SQLiteDatabase db) 方法被调用,然后将设置项数据加载到数据表中去。


@Deprecated
class DatabaseHelper extends SQLiteOpenHelper {
	private void loadSettings(SQLiteDatabase db) {
	        loadSystemSettings(db);
	        loadSecureSettings(db);
	        // The global table only exists for the 'owner/system' user
	        if (mUserHandle == UserHandle.USER_SYSTEM) {
	            loadGlobalSettings(db);
	        }
	}
	……
	private void loadSecureSettings(SQLiteDatabase db) {
	        SQLiteStatement stmt = null;
	        try {
			……
+				//启用搜狗输入法
+	            loadSetting(stmt, Settings.Secure.ENABLED_INPUT_METHODS, "com.sohu.inputmethod.sogou/.SogouIME");
+				//将搜狗输入法设置为默认输入法
+		        loadSetting(stmt, Settings.Secure.DEFAULT_INPUT_METHOD, "com.sohu.inputmethod.sogou/.SogouIME");
	
	            /*
	             * 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.
	             *
	             * See: SettingsProvider.UpgradeController#onUpgradeLocked
	             */
	        } finally {
	            if (stmt != null) stmt.close();
	        }
	    }
	    

获取输入法MID的命令:

adb shell ime list

2、自定义系统设置项开关

(1)在 Settings 应用相应的 xml 文件中定义一个开关控件 SwitchPreference,例如:


<SwitchPreference
            android:key="deep_sleep"
            android:title="@string/deep_sleep_title"
            settings:controller="com.android.settings.development.DeepSleepPreferenceController"/>
            

(2)定义开关的控制类,这个类需要继承一个抽象类TogglePreferenceController,然后重写 isChecked() 、setChecked()和 getAvailabilityStatus()方法,例如:


public class DeepSleepPreferenceController extends TogglePreferenceController{

    static final String DEEPSLEEP_ON = "1";
    static final String DEEPSLEEP_OFF = "0";
    private String mPreferenceKey = null;

    public DeepSleepPreferenceController(Context context, String preferenceKey) {
        super(context, preferenceKey);
        mPreferenceKey = preferenceKey;
    }

    //Synchronization switch status: set the previously saved switch status
    // when the user enters the interface where the switch is located again.
    @Override
    public boolean isChecked() {
        boolean deepSleepFlag = false;
        if (DEEPSLEEP_ON.equals(Settings.Global.getString(mContext.getContentResolver(), mPreferenceKey))){
            deepSleepFlag = true;
        }
        return deepSleepFlag;
    }

    //When the user clicks the switch, the switch state is saved.
    @Override
    public boolean setChecked(boolean isChecked) {
        final String newValue = isChecked ? DEEPSLEEP_ON : DEEPSLEEP_OFF;
        Settings.Global.putString(mContext.getContentResolver(), mPreferenceKey, newValue);
        return true;
    }

    @Override
    public int getAvailabilityStatus() {
    	//启用开关
        return AVAILABLE;
    }

}

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Android 11.0是谷歌推出的最新版本操作系统,其中包含了众多新的功能和特性。在Android系统中,Framework是系统的核心部分,它提供了许多基本功能,如UI管理、资源管理、通知机制等。因此,详细讨论整个Framework源码是非常复杂和庞大的任务。在这里,我将简要介绍一些Android 11.0最新Framework源码的解析内容。 首先,Android 11.0引入了一些新的特性,例如屏幕共享、一次性权限、自适应通知历史等。这些特性的实现涉及到多个模块,如Activity、PermissionManager和NotificationManager等。在源码中,我们可以看到这些模块的实现逻辑,以及它们与其他模块的关联。 其次,Android 11.0在安全方面做出了一些改进。例如,它增强了对应用程序之间的隔离机制,改善了应用程序的权限管理。这些安全性的提升主要是通过对Framework的修改和优化来实现的,我们可以在源码中找到相关的修改部分。 此外,Android 11.0还优化了性能和稳定性。在源码中,我们可以看到一些对性能优化的改动,如优化了UI渲染流程、资源加载机制等。这些改动旨在提高系统的响应速度和流畅性,提供更好的用户体验。 最后,需要注意的是,要完整解析整个Android 11.0 Framework源码是非常庞大和复杂的任务,需要深入研究各个模块之间的关联和实现细节。此外,由于源码的更新和改进很快,因此为了获得最新的信息,我们可以参考谷歌官方文档和开发者社区的讨论。 总而言之,Android 11.0最新Framework源码解析需要耗费大量时间和精力,涉及到众多模块和功能的实现。以上只是对一些主要方面的简要介绍,希望能够给您提供一个概览。 ### 回答2: Android 11.0 是Google最新发布的Android操作系统版本,它引入了一系列新的功能和改进,同时也对框架层的源码进行了更新和优化。 首先,在Android 11.0中,Google对用户隐私进行了更多的保护。例如,对于一些敏感权限,如位置信息、麦克风和相机访问权限,应用需要动态申请,并且用户可以选择只在使用应用时授予权限。此外,Android 11.0还对应用访问用户剪贴板中的内容进行了限制,增强了用户的隐私安全性。 其次,Android 11.0还加强了与5G网络的兼容性。在新的框架源码中,Google为开发者提供了一些新的API,以便更好地利用5G网络的优势。开发者可以根据网络的类型和条件,优化应用的网络连接和数据传输,提供更好的用户体验。 此外,Android 11.0还增加了一些新的功能,如呼吸灯通知模式、音频和视频编解码功能的改进、更强大的图像捕捉API等。这些功能的实现都离不开框架层的支持。开发者可以通过阅读最新的框架源码,了解和学习这些功能的具体实现方式,并在自己的应用中加以应用和优化。 总之,Android 11.0最新框架源码解析涵盖了对用户隐私的保护、与5G网络的兼容性以及一系列新功能的实现。了解和学习最新的框架源码,有助于开发者更好地理解Android操作系统的工作原理,提供更好的应用体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值