SettingsProvider資料儲存位置

very_on發表於2018-06-11

老早之前SettingProvider資料儲存的位置在手機目錄/data/data/com.android.providers.settings/databases下

不過目前的Android版本雖然也有這個目錄,其中卻沒有對應的檔案在,本文是看下當前的資料到底儲存在哪裡。

程式碼在在/home/lgy/code/mtk6797/frameworks/base/packages/SettingsProvider

插入流程分析

從插入程式碼為線索分析:

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

[java] view plain copy
  1. public Uri insert(Uri uri, ContentValues values) {  
  2.     ...  
  3.     switch (table) {  
  4.         ...  
  5.         case TABLE_SYSTEM: {  
  6.             if (insertSystemSetting(name, value, UserHandle.getCallingUserId())) {  
  7.                 return Uri.withAppendedPath(Settings.System.CONTENT_URI, name);  
  8.             }  
  9.         } break;  
  10.     ...  
  11. }  
只看system表的插入:

[java] view plain copy
  1. private boolean insertSystemSetting(String name, String value, int requestingUserId) {  
  2.     ...  
  3.     return mutateSystemSetting(name, value, requestingUserId, MUTATION_OPERATION_INSERT);  
  4. }  
[java] view plain copy
  1. private boolean mutateSystemSetting(String name, String value, int runAsUserId,  
  2.          int operation) {  
  3.       ...  
  4.              case MUTATION_OPERATION_INSERT: {  
  5.                  validateSystemSettingValue(name, value);  
  6.                  return mSettingsRegistry  
  7.                          .insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_SYSTEM,  
  8.                                  owningUserId, name, value, getCallingPackage());  
  9.              }  
  10.       ...  
  11.  }  
SettingsRegistry是內部類

[java] view plain copy
  1. public boolean insertSettingLocked(int type, int userId, String name, String value,  
  2.     ...  
  3.     final boolean success = settingsState.insertSettingLocked(name, value, packageName);  
  4.     ...  
  5. }  

SettingsState是另一個檔案

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

[java] view plain copy
  1. public boolean insertSettingLocked(String name, String value, String packageName) {  
  2.     ...  
  3.     updateMemoryUsagePerPackageLocked(packageName, oldValue, value);           
  4.     scheduleWriteIfNeededLocked();  
  5.     ...  
  6. }  

[java] view plain copy
  1. private void scheduleWriteIfNeededLocked() {  
  2.     if (!mDirty) {  
  3.         mDirty = true;  
  4.         writeStateAsyncLocked();  
  5.     }  
  6. }  
[java] view plain copy
  1. private void writeStateAsyncLocked() {  
  2.     final long currentTimeMillis = SystemClock.uptimeMillis();  
  3.   
  4.     if (mWriteScheduled) {  
  5.         mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS);  
  6.   
  7.         // If enough time passed, write without holding off anymore.  
  8.         final long timeSinceLastNotWrittenMutationMillis = currentTimeMillis  
  9.                 - mLastNotWrittenMutationTimeMillis;  
  10.         if (timeSinceLastNotWrittenMutationMillis >= MAX_WRITE_SETTINGS_DELAY_MILLIS) {  
  11.             mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS).sendToTarget();  
  12.             return;  
  13.         }  
  14.   
  15.         // Hold off a bit more as settings are frequently changing.  
  16.         final long maxDelayMillis = Math.max(mLastNotWrittenMutationTimeMillis  
  17.                 + MAX_WRITE_SETTINGS_DELAY_MILLIS - currentTimeMillis, 0);  
  18.         final long writeDelayMillis = Math.min(WRITE_SETTINGS_DELAY_MILLIS, maxDelayMillis);  
  19.   
  20.         Message message = mHandler.obtainMessage(MyHandler.MSG_PERSIST_SETTINGS);  
  21.         mHandler.sendMessageDelayed(message, writeDelayMillis);  
  22.     }  
  23.     ...  
  24. }  
兩條分支,不過最終都是傳送了個訊息,訊息處理中會呼叫doWriteState

[java] view plain copy
  1. private void doWriteState() {  
  2.      ...  
  3.      AtomicFile destination = new AtomicFile(mStatePersistFile);  
  4.      ...  
  5.      FileOutputStream out = null;  
  6.      try {  
  7.          out = destination.startWrite();  
  8.   
  9.          XmlSerializer serializer = Xml.newSerializer();  
  10.          serializer.setOutput(out, StandardCharsets.UTF_8.name());  
  11.          serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output"true);  
  12.          serializer.startDocument(nulltrue);  
  13.          serializer.startTag(null, TAG_SETTINGS);  
  14.          serializer.attribute(null, ATTR_VERSION, String.valueOf(version));  
  15.   
  16.          final int settingCount = settings.size();  
  17.          for (int i = 0; i < settingCount; i++) {  
  18.              Setting setting = settings.valueAt(i);  
  19.   
  20.              writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(),  
  21.                      setting.getValue(), setting.getPackageName());  
  22.   
  23.              if (DEBUG_PERSISTENCE) {  
  24.                  Slog.i(LOG_TAG, "[PERSISTED]" + setting.getName() + "=" + setting.getValue());  
  25.              }  
  26.          }  
  27.   
  28.          serializer.endTag(null, TAG_SETTINGS);  
  29.          serializer.endDocument();  
  30.          destination.finishWrite(out);  
  31.          ...  
  32.  }  
一看到xml就終於知道,是寫到了一個xml檔案中,並不是寫到sqlite中。

檔案地址確認

SettingsState中的成員

[java] view plain copy
  1. private final File mStatePersistFile;  
這個成員是xml的寫入檔案

在SettingsProvider中

[java] view plain copy
  1. private void ensureSettingsStateLocked(int key) {  
  2.     if (mSettingsStates.get(key) == null) {  
  3.         final int maxBytesPerPackage = getMaxBytesPerPackageForType(getTypeFromKey(key));  
  4.         SettingsState settingsState = new SettingsState(mLock, getSettingsFile(key), key,  
  5.                 maxBytesPerPackage);  
  6.         mSettingsStates.put(key, settingsState);  
  7.     }  
  8. }  
這個方法負責SettingsState的初始化

[java] view plain copy
  1. private File getSettingsFile(int key) {  
  2.     if (isGlobalSettingsKey(key)) {  
  3.         final int userId = getUserIdFromKey(key);  
  4.         return new File(Environment.getUserSystemDirectory(userId),  
  5.                 SETTINGS_FILE_GLOBAL);  
  6.     } else if (isSystemSettingsKey(key)) {  
  7.         final int userId = getUserIdFromKey(key);  
  8.         return new File(Environment.getUserSystemDirectory(userId),  
  9.                 SETTINGS_FILE_SYSTEM);  
  10.     } else if (isSecureSettingsKey(key)) {  
  11.         final int userId = getUserIdFromKey(key);  
  12.         return new File(Environment.getUserSystemDirectory(userId),  
  13.                 SETTINGS_FILE_SECURE);  
  14.     } else {  
  15.         throw new IllegalArgumentException("Invalid settings key:" + key);  
  16.     }  
  17. }  
從getSettingsFile中可以看到SettingsProvider三個表global,system和secure的檔案,它們的路徑是相同的,通過Environment.getUserSystemDirectory確立

frameworks/base/core/java/android/os/Environment.java

[java] view plain copy
  1. public static File getUserSystemDirectory(int userId) {  
  2.     return new File(new File(getSystemSecureDirectory(), "users"), Integer.toString(userId));  
  3. }  
[java] view plain copy
  1. public static File getSystemSecureDirectory() {  
  2.     if (isEncryptedFilesystemEnabled()) { //加密檔案系統分支,預設是關閉的  
  3.         return new File(SECURE_DATA_DIRECTORY, "system");  
  4.     } else {  
  5.         return new File(DATA_DIRECTORY, "system");  
  6.     }  
  7. }  
[java] view plain copy
  1. private static final File DATA_DIRECTORY  
  2.         = getDirectory("ANDROID_DATA""/data");  
依據ANDROID_DATA環境變數獲取路徑,獲取不到的話就預設為/data。

獲取到DATA_DIRECTORY後,後續還要新增"/ " + "system" + "/" + "users" + "/" + userId的值

例如我測試的手機上是/data/system/users/0,該目錄的settings_global.xml,settings_secure.xml和settings_system.xml三個xml檔案就是SettingsProvider中的資料檔案。

相關文章