Android N SettingsProvider的数据保存

来源:互联网 发布:思归软件下载 编辑:程序博客网 时间:2024/05/16 00:58

Android M之前SettingProvider数据储存的位置在手机目录/data/data/com.Android.providers.settings/databases下

不过目前的Android版本虽然也有这个目录,其中却没有对应的文件在,本文是看下当前的数据到底存储在哪里。

代码在在frameworks/base/packages/SettingsProvider

插入流程分析

从插入代码为线索分析:

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

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  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
 在CODE上查看代码片派生到我的代码片
  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
 在CODE上查看代码片派生到我的代码片
  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
 在CODE上查看代码片派生到我的代码片
  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
 在CODE上查看代码片派生到我的代码片
  1. public boolean insertSettingLocked(String name, String value, String packageName) {  
  2.     ...  
  3.     updateMemoryUsagePerPackageLocked(packageName, oldValue, value);           
  4.     scheduleWriteIfNeededLocked();  
  5.     ...  
  6. }  

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. private void scheduleWriteIfNeededLocked() {  
  2.     if (!mDirty) {  
  3.         mDirty = true;  
  4.         writeStateAsyncLocked();  
  5.     }  
  6. }  
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  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
 在CODE上查看代码片派生到我的代码片
  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
 在CODE上查看代码片派生到我的代码片
  1. private final File mStatePersistFile;  
这个成员是xml的写入文件

在SettingsProvider中

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  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
 在CODE上查看代码片派生到我的代码片
  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
 在CODE上查看代码片派生到我的代码片
  1. public static File getUserSystemDirectory(int userId) {  
  2.     return new File(new File(getSystemSecureDirectory(), "users"), Integer.toString(userId));  
  3. }  
[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  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
 在CODE上查看代码片派生到我的代码片
  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中的数据文件。

0 0