Only persist last Shared Preferences state

am: d15c4f1da5

Change-Id: I6431d4b7d07064eec5013d01b5bda76b1ed35e14
This commit is contained in:
Philip P. Moltmann
2017-01-13 01:09:03 +00:00
committed by android-build-merger

View File

@@ -26,6 +26,8 @@ import android.system.StructStat;
import android.util.Log;
import com.google.android.collect.Maps;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.XmlUtils;
import dalvik.system.BlockGuard;
@@ -72,6 +74,14 @@ final class SharedPreferencesImpl implements SharedPreferences {
private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners =
new WeakHashMap<OnSharedPreferenceChangeListener, Object>();
/** Current memory state (always increasing) */
@GuardedBy("this")
private long mCurrentMemoryStateGeneration;
/** Latest memory state that was committed to disk */
@GuardedBy("mWritingToDiskLock")
private long mDiskStateGeneration;
SharedPreferencesImpl(File file, int mode) {
mFile = file;
mBackupFile = makeBackupFile(file);
@@ -289,7 +299,7 @@ final class SharedPreferencesImpl implements SharedPreferences {
// Return value from EditorImpl#commitToMemory()
private static class MemoryCommitResult {
public boolean changesMade; // any keys different?
public long memoryStateGeneration;
public List<String> keysModified; // may be null
public Set<OnSharedPreferenceChangeListener> listeners; // may be null
public Map<?, ?> mapToWriteToDisk;
@@ -412,9 +422,11 @@ final class SharedPreferencesImpl implements SharedPreferences {
}
synchronized (this) {
boolean changesMade = false;
if (mClear) {
if (!mMap.isEmpty()) {
mcr.changesMade = true;
changesMade = true;
mMap.clear();
}
mClear = false;
@@ -441,13 +453,19 @@ final class SharedPreferencesImpl implements SharedPreferences {
mMap.put(k, v);
}
mcr.changesMade = true;
changesMade = true;
if (hasListeners) {
mcr.keysModified.add(k);
}
}
mModified.clear();
if (changesMade) {
mCurrentMemoryStateGeneration++;
}
mcr.memoryStateGeneration = mCurrentMemoryStateGeneration;
}
}
return mcr;
@@ -509,10 +527,12 @@ final class SharedPreferencesImpl implements SharedPreferences {
*/
private void enqueueDiskWrite(final MemoryCommitResult mcr,
final Runnable postWriteRunnable) {
final boolean isFromSyncCommit = (postWriteRunnable == null);
final Runnable writeToDiskRunnable = new Runnable() {
public void run() {
synchronized (mWritingToDiskLock) {
writeToFile(mcr);
writeToFile(mcr, isFromSyncCommit);
}
synchronized (SharedPreferencesImpl.this) {
mDiskWritesInFlight--;
@@ -523,8 +543,6 @@ final class SharedPreferencesImpl implements SharedPreferences {
}
};
final boolean isFromSyncCommit = (postWriteRunnable == null);
// Typical #commit() path with fewer allocations, doing a write on
// the current thread.
if (isFromSyncCommit) {
@@ -538,6 +556,10 @@ final class SharedPreferencesImpl implements SharedPreferences {
}
}
if (DEBUG) {
Log.d(TAG, "added " + mcr.memoryStateGeneration + " -> " + mFile.getName());
}
QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable);
}
@@ -565,17 +587,34 @@ final class SharedPreferencesImpl implements SharedPreferences {
}
// Note: must hold mWritingToDiskLock
private void writeToFile(MemoryCommitResult mcr) {
private void writeToFile(MemoryCommitResult mcr, boolean isFromSyncCommit) {
// Rename the current file so it may be used as a backup during the next read
if (mFile.exists()) {
if (!mcr.changesMade) {
// If the file already exists, but no changes were
// made to the underlying map, it's wasteful to
// re-write the file. Return as if we wrote it
// out.
boolean needsWrite = false;
if (isFromSyncCommit) {
// Only need to write if the disk state is older than this commit
if (mDiskStateGeneration < mcr.memoryStateGeneration) {
needsWrite = true;
}
} else {
synchronized (this) {
// No need to persist intermediate states. Just wait for the latest state to be
// persisted.
if (mCurrentMemoryStateGeneration == mcr.memoryStateGeneration) {
needsWrite = true;
}
}
}
if (!needsWrite) {
if (DEBUG) {
Log.d(TAG, "skipped " + mcr.memoryStateGeneration + " -> " + mFile.getName());
}
mcr.setDiskWriteResult(true);
return;
}
if (!mBackupFile.exists()) {
if (!mFile.renameTo(mBackupFile)) {
Log.e(TAG, "Couldn't rename file " + mFile
@@ -599,6 +638,11 @@ final class SharedPreferencesImpl implements SharedPreferences {
}
XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str);
FileUtils.sync(str);
if (DEBUG) {
Log.d(TAG, "wrote " + mcr.memoryStateGeneration + " -> " + mFile.getName());
}
str.close();
ContextImpl.setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
try {
@@ -612,7 +656,11 @@ final class SharedPreferencesImpl implements SharedPreferences {
}
// Writing was successful, delete the backup file if there is one.
mBackupFile.delete();
mDiskStateGeneration = mcr.memoryStateGeneration;
mcr.setDiskWriteResult(true);
return;
} catch (XmlPullParserException e) {
Log.w(TAG, "writeToFile: Got exception:", e);