android SettingsProvider onCreate执行流程

/ android / 没有评论 / 942浏览

用到的代码文件

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

代码执行流程图

SettingsProvider 查看原图

模块编译

mm frameworks/base/packages/SettingsProvider/
adb remount
adb push generated_apk_path/SettingsProvider.apk /system/priv-app/SettingsProvider/
adb reboot

android SettingsProvider onCreate()执行流程

下面的代码是以android N(api 24)为基础。

本文基于高通(Qualcomm)平台基线。

本次流程分析的背景:

  1. 手机不是第一次开机,已经正常开关机几次了;
  2. 手动删除/data/system/users/0/settings_global.xml;
  3. 抓取删除后关机再开机的adb log;

启动SettinsProvider的初始化log,后面再针对log进行流程分析。

I SystemServer: InstallSystemProviders
W LoadedApk: **********************
W LoadedApk: mResDir: /system/priv-app/SettingsProvider/SettingsProvider.apk
W LoadedApk: myResfileName: /data/dalvik-cache/arm/system
@priv-app@SettingsProvider@SettingsProvider.apk@classes.dex

W LoadedApk: myResfileName: /data/dalvik-cache/arm/system@priv-app
@SettingsProvider@SettingsProvider.apk@classes.dex is exist

W LoadedApk: /vendor/overlay/SettingsProvider/SettingsProvider-overlay.apk
W LoadedApk: =====================

W system_server: type=1400 audit(0.0:6): avc: denied { write } for name=
"system@priv-app@SettingsProvider@SettingsProvider.apk@classes.dex" 
dev="mmcblk0p40" ino=8205 scontext=u:r:system_server:s0 
tcontext=u:object_r:dalvikcache_data_file:s0 tclass=file permissive=0

W System  : ClassLoader referenced unknown path: 
/system/priv-app/SettingsProvider/lib/arm

D SettingsProvider: onCreate

SettingsProvider继承自ContentProvider。

@Override
public boolean onCreate() {
    synchronized (mLock) {
        mUserManager = UserManager.get(getContext());
        mPackageManager = AppGlobals.getPackageManager();
        if (null != mPackageManager) {
            // com.android.server.pm.PackageManagerService
            Log.d(LOG_TAG,"mPackageManager: "
                    +mPackageManager.getClass().getName());
        }
        mHandlerThread = new HandlerThread(LOG_TAG,
                Process.THREAD_PRIORITY_BACKGROUND);
        mHandlerThread.start();
        //先看这个构造方法的执行
        mSettingsRegistry = new SettingsRegistry();
    }
    registerBroadcastReceivers();
    startWatchingUserRestrictionChanges();
    return true;
}

SettingsRegistry是定义在SettinsProvider中的内部类。
下面先来看SettinsRegistry类的构造方法的执行。

public SettingsRegistry() {
    mHandler = new MyHandler(getContext().getMainLooper());
    mGenerationRegistry = new GenerationRegistry(mLock);
    mBackupManager = new BackupManager(getContext());
    //进入这里
    migrateAllLegacySettingsIfNeeded();
}

下面进入SettingsRegistry类的migrateAllLegacySettingsIfNeeded()方法。
这个方法的名为迁移所有遗留的设置。

private void migrateAllLegacySettingsIfNeeded() {
    synchronized (mLock) {
        final int key = makeKey(SETTINGS_TYPE_GLOBAL, 
                UserHandle.USER_SYSTEM);
        //key: 0
        File globalFile = getSettingsFile(key);
        //globalFile: /data/system/users/0/settings_global.xml
        //如果这个文件存在就返回
        if (globalFile.exists()) {
            return;
        }

        final long identity = Binder.clearCallingIdentity();
        try {
            List<UserInfo> users = mUserManager.getUsers(true);
            //userCount: 1
            final int userCount = users.size();
            for (int i = 0; i < userCount; i++) {
                final int userId = users.get(i).id;
                Log.d(SRTAG,"user id: "+userId); // 0
                /**
                  * 执行DatabaseHelper
                  * DatabaseHelper继承自SQLiteOpenHelper
                  * 所以只有当db不存在的时候才会执行DatabaseHelper类
                  * 的onCreate()方法。
                  * 这里删除/data/system/users/0/settings_global.xml来进行研究。
                  */
                DatabaseHelper dbHelper = 
                        new DatabaseHelper(getContext(), userId);
                SQLiteDatabase database = dbHelper.getWritableDatabase();
                
                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);
        }
    }
}

下面查看SettingsRegistry类中的migrateLegacySettingsForUserLocked()方法。

private void migrateLegacySettingsForUserLocked(
    DatabaseHelper dbHelper,SQLiteDatabase database, int userId) {
    /*
      * 这块儿主要是进行/data/system/users/0/settings_system.xml
      * 这个文件的操作
      */
    // Move over the system settings.
    final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, 
                                                    userId);
    ensureSettingsStateLocked(systemKey);
    SettingsState systemSettings = mSettingsStates.get(systemKey);
    migrateLegacySettingsLocked(systemSettings, 
            database, TABLE_SYSTEM);
    systemSettings.persistSyncLocked();

    /*
      *  /data/system/users/0/settings_secure.xml
      */
    // 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();

    /*
      * 重点关注这里
      * 下面的流程从这个开始
      *  /data/system/users/0/settings_global.xml
      */
    // 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);
        Log.d(SRTAG,"globalKey: "+globalKey);// 0
        //进入这个方法
        ensureSettingsStateLocked(globalKey);
        SettingsState globalSettings = mSettingsStates.get(globalKey);
        migrateLegacySettingsLocked(globalSettings, 
                database, TABLE_GLOBAL);
        globalSettings.persistSyncLocked();
    }

    // Drop the database as now all is moved and persisted.
    if (DROP_DATABASE_ON_MIGRATION) {
        dbHelper.dropDatabase();
    } else {
        dbHelper.backupDatabase();
    }
}

下面进入SettingsRegistry类的ensureSettingsStateLocked()方法。

private void ensureSettingsStateLocked(int key) {
    // 0
    Log.d(SRTAG,"ensureSettingsStateLocked() key: "+key);
    if (mSettingsStates.get(key) == null) {
        final int maxBytesPerPackage = 
                getMaxBytesPerPackageForType(getTypeFromKey(key));
        // -1
        Log.d(SRTAG,"maxBytesPerPackage: "+maxBytesPerPackage);
        /*
          * 进入这里
          */
        SettingsState settingsState = 
                new SettingsState(mLock, getSettingsFile(key), key,
                maxBytesPerPackage, mHandlerThread.getLooper());
        mSettingsStates.put(key, settingsState);
    }
}

下面是SettingsState类的构造方法。

public SettingsState(Object lock, File file, int key, 
        int maxBytesPerAppPackage,Looper looper) {
    // It is important that we use the same lock as the settings 
    // provider to ensure multiple mutations on this state are 
    // atomicaly persisted as the async persistence should be 
    // blocked while we make changes.
    mLock = lock;
    mStatePersistFile = file;
    //mStatePersistFile: /data/system/users/0/settings_global.xml
    mKey = key;
    mHandler = new MyHandler(looper);
    if (maxBytesPerAppPackage == 
            MAX_BYTES_PER_APP_PACKAGE_LIMITED) {// -> false
        mMaxBytesPerAppPackage = maxBytesPerAppPackage;
        mPackageToMemoryUsage = new ArrayMap<>();
    } else {// 执行这里
        mMaxBytesPerAppPackage = maxBytesPerAppPackage;
        mPackageToMemoryUsage = null;
    }
    synchronized (mLock) {
        readStateSyncLocked();
    }
}

下面进入SettingsState类的readStateSyncLocked()方法。

private void readStateSyncLocked() {
    FileInputStream in;
    /*
      * 判断/data/system/users/0/settings_global.xml是否存在
      * 我在这里删除删除了这个文件,所以不存在。
      */
    if (!mStatePersistFile.exists()) { // -> true
        return;
    }
    try {
        in = new AtomicFile(mStatePersistFile).openRead();
    } catch (FileNotFoundException fnfe) {
        Slog.i(LOG_TAG, "No settings state");
        return;
    }
    try {
        XmlPullParser parser = Xml.newPullParser();
        parser.setInput(in, StandardCharsets.UTF_8.name());
        parseStateLocked(parser);

    } catch (XmlPullParserException | IOException e) {
        throw new IllegalStateException(
                "Failed parsing settings file: "
                + mStatePersistFile , e);
    } finally {
        IoUtils.closeQuietly(in);
    }
}

下面回到SettingsRegistry类中的migrateLegacySettingsForUserLocked()方法。

    ......
    if (userId == UserHandle.USER_SYSTEM) {
        final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, 
                userId);
        Log.d(SRTAG,"globalKey: "+globalKey);// 0
        ensureSettingsStateLocked(globalKey);
        SettingsState globalSettings = mSettingsStates.get(globalKey);
        /*
          * 继续执行这里
          */
        migrateLegacySettingsLocked(globalSettings, 
                database, TABLE_GLOBAL);
        globalSettings.persistSyncLocked();
    }
    ......

下面进入SettingsRegistry类中的migrateLegacySettingsLocked()方法。

private void migrateLegacySettingsLocked(
        SettingsState settingsState,
        SQLiteDatabase database, String table) {
    SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
    queryBuilder.setTables(table);

    Cursor cursor = queryBuilder.query(database, ALL_COLUMNS,
            null, null, null, null, null);

    if (cursor == null) {
        return;
    }

    try {
        if (!cursor.moveToFirst()) {
            return;
        }

        final int nameColumnIdx = 
              cursor.getColumnIndex(
                      Settings.NameValueTable.NAME);
        final int valueColumnIdx = 
                cursor.getColumnIndex(
                      Settings.NameValueTable.VALUE);

        //先看这里
        settingsState.setVersionLocked(database.getVersion());

        while (!cursor.isAfterLast()) {
            String name = cursor.getString(nameColumnIdx);
            String value = cursor.getString(valueColumnIdx);
            settingsState.insertSettingLocked(name, value,
                    SettingsState.SYSTEM_PACKAGE_NAME);
            cursor.moveToNext();
        }
    } finally {
        cursor.close();
    }
}

下面进入SettingsState类的setVersionLocked()方法。

public void setVersionLocked(int version) {
    if (version == mVersion) {
        return;
    }
    mVersion = version;
    scheduleWriteIfNeededLocked();
}


private void scheduleWriteIfNeededLocked() {
    // If dirty then we have a write already scheduled.
    if (!mDirty) {// -> true
        mDirty = true;
        writeStateAsyncLocked();
    }
}


private void writeStateAsyncLocked() {
    final long currentTimeMillis = SystemClock.uptimeMillis();

    if (mWriteScheduled) {// -> false
        mHandler.removeMessages(
                MyHandler.MSG_PERSIST_SETTINGS);

        // If enough time passed, write without holding off anymore.
        final long timeSinceLastNotWrittenMutationMillis = 
                currentTimeMillis - mLastNotWrittenMutationTimeMillis;
        if (timeSinceLastNotWrittenMutationMillis >= 
                MAX_WRITE_SETTINGS_DELAY_MILLIS) {
            mHandler
                    .obtainMessage(
                      MyHandler.MSG_PERSIST_SETTINGS)
                    .sendToTarget();
            return;
        }

        // Hold off a bit more as settings are frequently changing.
        final long maxDelayMillis = 
                Math.max(mLastNotWrittenMutationTimeMillis
                + MAX_WRITE_SETTINGS_DELAY_MILLIS 
                - currentTimeMillis, 0);
        final long writeDelayMillis = 
                Math.min(WRITE_SETTINGS_DELAY_MILLIS,
                               maxDelayMillis);

        Message message = 
                mHandler.obtainMessage(
                        MyHandler.MSG_PERSIST_SETTINGS);
        mHandler.sendMessageDelayed(message, writeDelayMillis);
    } else {
        /*
          * 进入这里
          * 在这里构建一个延时消息
          */
        mLastNotWrittenMutationTimeMillis = currentTimeMillis;
        Message message = 
                mHandler.obtainMessage(
                        MyHandler.MSG_PERSIST_SETTINGS);
        mHandler.sendMessageDelayed(message, 
                WRITE_SETTINGS_DELAY_MILLIS);
        mWriteScheduled = true;
    }
}

下面回到SettinsRegistry类的migrateLegacySettingsLocked()方法中。

private void migrateLegacySettingsLocked(
        SettingsState settingsState,
        SQLiteDatabase database, String table) {
    ......
    /*
      * 1.设置数据库的版本号
      * 2.构建一个延时消息
      */
    settingsState.setVersionLocked(database.getVersion());
    
    /*
     * 开始从settings.db中读取数据
     * /data/user_de/0/com.android.providers.settings/databases/settings.db
     * 将从数据库中读出来的数据用当前类别的SettingsState对象存储起来
     */
    while (!cursor.isAfterLast()) {
        String name = cursor.getString(nameColumnIdx);
        String value = cursor.getString(valueColumnIdx);
        //看下这个方法的实现
        settingsState.insertSettingLocked(name, value,
                SettingsState.SYSTEM_PACKAGE_NAME);
        cursor.moveToNext();
    }
    ......
}

下面进入SettingsState类的insertSettingLocked()方法。

@GuardedBy("mLock")
private final ArrayMap<String, Setting> mSettings 
                        = new ArrayMap<>();
    
// The settings provider must hold its lock when calling here.
public boolean insertSettingLocked(String name, 
        String value, String packageName) {
    if (TextUtils.isEmpty(name)) {
        return false;
    }

    Setting oldState = mSettings.get(name);
    String oldValue = (oldState != null) ? oldState.value : null;
    /*
      * 从数据库中读取出来的key和value构成一个Setting对象。
      * 这个Setting对象是定义在SettingsState类中的内部类
      */
    if (oldState != null) {
        if (!oldState.update(value, packageName)) {
            return false;
        }
    } else {
        Setting state = new Setting(name, value, packageName);
        mSettings.put(name, state);
    }

    /**
      * 在当前的情况下面这两个方法不执行了
      * 因为
      * mMaxBytesPerAppPackage 
      *         == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED
      *                为true
      * mDirty = true;
      */
    updateMemoryUsagePerPackageLocked(packageName, 
            oldValue, value);

    scheduleWriteIfNeededLocked();

    return true;
}

下面再次回到SettingsProvider类的migrateLegacySettingsForUserLocked()方法。

    ......
    if (userId == UserHandle.USER_SYSTEM) {
        final int globalKey = makeKey(
                SETTINGS_TYPE_GLOBAL, userId);
        Log.d(SRTAG,"globalKey: "+globalKey);// 0
        ensureSettingsStateLocked(globalKey);
        SettingsState globalSettings = mSettingsStates
              .get(globalKey);
        /*
          * 执行完了 
          * 将所有定义的变量值从数据库读取出来存
          * 储在mSettings这个ArrayMap中。
          */
        migrateLegacySettingsLocked(globalSettings, 
                database, TABLE_GLOBAL);
        /**
          * 开始执行这里
          */
        globalSettings.persistSyncLocked();
    }
    ......

下面进入SettingsState类中的persistSyncLocked()方法。

// The settings provider must hold its lock when calling here.
public void persistSyncLocked() {
    //从消息队列移除MSG_PERSIST_SETTINGS这个延时消息
    //上面写的是延时200ms发送这个消息,
    // 看来从数据库中读取数据执行的还挺快
    mHandler.removeMessages(
            MyHandler.MSG_PERSIST_SETTINGS);
    /**
      * 终于来到了核心的操作
      * 1.res/values/defaults.xml中定义的值->settings.db
      * 2.settings.db读取出来到->ArrayMap<String, Setting> mSettings;
      * 3.将mSettings中的值写入settings_global.xml
      * 这个方法就是执行的是第三步操作。
      */
    doWriteState();
}

下面进入SettingsState类中的doWriteState()方法。 这个方法就是生成xml文件,不细化它了。

private void doWriteState() {

    AtomicFile destination = new AtomicFile(mStatePersistFile);

    final int version;
    final ArrayMap<String, Setting> settings;

    synchronized (mLock) {
        version = mVersion;
        settings = new ArrayMap<>(mSettings);
        mDirty = false;
        mWriteScheduled = false;
    }

    FileOutputStream out = null;
    try {
        out = destination.startWrite();

        XmlSerializer serializer = Xml.newSerializer();
        serializer.setOutput(out, StandardCharsets.UTF_8.name());
        serializer.setFeature(
                "http://xmlpull.org/v1/doc/features.html#indent-output", 
                true);
        serializer.startDocument(null, true);
        serializer.startTag(null, TAG_SETTINGS);
        serializer.attribute(null, ATTR_VERSION, 
              String.valueOf(version));

        final int settingCount = settings.size();
        for (int i = 0; i < settingCount; i++) {
            Setting setting = settings.valueAt(i);

            writeSingleSetting(mVersion, serializer, 
                  setting.getId(), setting.getName(),
                    setting.getValue(), setting.getPackageName());
        }

        serializer.endTag(null, TAG_SETTINGS);
        serializer.endDocument();
        destination.finishWrite(out);

        if (DEBUG_PERSISTENCE) {
            Slog.i(LOG_TAG, "[PERSIST END]");
        }
    } catch (Throwable t) {
        Slog.wtf(LOG_TAG, 
                "Failed to write settings, restoring backup", t);
        destination.failWrite(out);
    } finally {
        IoUtils.closeQuietly(out);
    }
}

下面我们再再次回到SettingsProvider类的migrateLegacySettingsForUserLocked()方法。

private static final boolean DROP_DATABASE_ON_MIGRATION
         = !Build.IS_DEBUGGABLE;

    ......
    if (userId == UserHandle.USER_SYSTEM) {
        final int globalKey = makeKey(
              SETTINGS_TYPE_GLOBAL, userId);
        Log.d(SRTAG,"globalKey: "+globalKey);// 0
        ensureSettingsStateLocked(globalKey);
        SettingsState globalSettings = 
                mSettingsStates.get(globalKey);
        /*
          * 执行完了 
          * 将所有定义的变量从数据库读取出来存储在mSettings的ArrayMap中。
          */
        migrateLegacySettingsLocked(globalSettings, 
                database, TABLE_GLOBAL);
        /**
          * 执行完了 
          * 写xml
          */
        globalSettings.persistSyncLocked();
    }
    /**
      * 开始执行这里
      * 我这里当前android rom为eng版本
      * 所以DROP_DATABASE_ON_MIGRATION为false。
      *
      */
    // Drop the database as now all is moved and persisted.
    if (DROP_DATABASE_ON_MIGRATION) {
        dbHelper.dropDatabase();
    } else {
        dbHelper.backupDatabase();
    }
    ......

下面进入DatabaseHelper类的backupDatabase()方法。

//settings.db相关操作,不细化了。
public void backupDatabase() {
    close();
    // No need to backup files if db is in memory
    if (isInMemory()) {
        return;
    }
    File databaseFile = mContext.
            getDatabasePath(getDatabaseName());
    if (!databaseFile.exists()) {
        return;
    }
    File backupFile = mContext.
            getDatabasePath(getDatabaseName()
            + DATABASE_BACKUP_SUFFIX);
    if (backupFile.exists()) {
        return;
    }
    databaseFile.renameTo(backupFile);
}

至此SettingsProvider类的onCreate()方法主要的就执行完了,剩下的暂不深究了。