diff options
| author | 2023-08-21 15:38:30 -0700 | |
|---|---|---|
| committer | 2023-09-06 20:35:57 +0000 | |
| commit | a71de26cceebe9163cde1e772795cdd474d092cc (patch) | |
| tree | 99a62b83c47cfa92d359e7ef8f89601bfb2f3431 | |
| parent | eabdf5da43c5e4881b5ec0e30d8c8945c2bd42b6 (diff) | |
[SettingsProvider] clean up if a setting failed to be serialized
Previously, if a setting is partially serialized with an error, the code
doesn't clean it up but proceeds to the next setting. This can cause
parsing errors on the next reboot. This CL captures such error and
deletes the problematic setting before trying again to persist the rest
of the settings. This makes sure that the final file doesn't contain any
partially serialized settings.
BUG: 295555884
Test: manually forcing a setting write to parially fail
Merged-In: I13337d9cbd325c0b6f9e526b3dc44bd4d03e3bd0
Change-Id: I13337d9cbd325c0b6f9e526b3dc44bd4d03e3bd0
(cherry picked from commit 8d19951877566ed72f5380bb6c830984e7942445)
| -rw-r--r-- | packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java | 31 |
1 files changed, 23 insertions, 8 deletions
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index 73ead3c4d61f..ac65b20aefc0 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -845,6 +845,7 @@ final class SettingsState { private void doWriteState() { boolean wroteState = false; + String settingFailedToBePersisted = null; final int version; final ArrayMap<String, Setting> settings; final ArrayMap<String, String> namespaceBannedHashes; @@ -895,8 +896,14 @@ final class SettingsState { } } } catch (IOException ex) { - Slog.e(LOG_TAG, "[SKIPPED PERSISTING]" + setting.getName() + Slog.e(LOG_TAG, "[ABORT PERSISTING]" + setting.getName() + " due to error writing to disk", ex); + // A setting failed to be written. Abort the serialization to avoid leaving + // a partially serialized setting on disk, which can cause parsing errors. + // Note down the problematic setting, so that we can delete it before trying + // again to persist the rest of the settings. + settingFailedToBePersisted = setting.getName(); + throw ex; } } serializer.endTag(null, TAG_SETTINGS); @@ -922,14 +929,14 @@ final class SettingsState { Slog.i(LOG_TAG, "[PERSIST END]"); } } catch (Throwable t) { - Slog.wtf(LOG_TAG, "Failed to write settings, restoring backup", t); + Slog.wtf(LOG_TAG, "Failed to write settings, restoring old file", t); if (t instanceof IOException) { - if (DEBUG) { - // we failed to create a directory, so log the permissions and existence - // state for the settings file and directory - logSettingsDirectoryInformation(destination.getBaseFile()); - } if (t.getMessage().contains("Couldn't create directory")) { + if (DEBUG) { + // we failed to create a directory, so log the permissions and existence + // state for the settings file and directory + logSettingsDirectoryInformation(destination.getBaseFile()); + } // attempt to create the directory with Files.createDirectories, which // throws more informative errors than File.mkdirs. Path parentPath = destination.getBaseFile().getParentFile().toPath(); @@ -950,7 +957,15 @@ final class SettingsState { } } - if (wroteState) { + if (!wroteState) { + if (settingFailedToBePersisted != null) { + synchronized (mLock) { + // Delete the problematic setting. This will schedule a write as well. + deleteSettingLocked(settingFailedToBePersisted); + } + } + } else { + // success synchronized (mLock) { addHistoricalOperationLocked(HISTORICAL_OPERATION_PERSIST, null); } |