diff options
author | Brad Fitzpatrick <bradfitz@android.com> | 2010-12-01 17:31:45 -0800 |
---|---|---|
committer | Brad Fitzpatrick <bradfitz@android.com> | 2010-12-07 10:50:36 -0800 |
commit | 4cd50b8d76e08d75df1a2e9d4902bcdc880bd1c1 (patch) | |
tree | 607d1b68b89a1fc95f1c386ad14f1f8cd6c034b2 /core/java/android/app/SharedPreferencesImpl.java | |
parent | 475593e249c53a8dc43f9cd43f528867c6a4074b (diff) | |
download | frameworks_base-4cd50b8d76e08d75df1a2e9d4902bcdc880bd1c1.zip frameworks_base-4cd50b8d76e08d75df1a2e9d4902bcdc880bd1c1.tar.gz frameworks_base-4cd50b8d76e08d75df1a2e9d4902bcdc880bd1c1.tar.bz2 |
Make getSharedPreference() async, blocking on first access.
Bug: 3177046
Change-Id: Ibc36a1e196afd39c4f9da513a2bf4ba9e2c72177
Diffstat (limited to 'core/java/android/app/SharedPreferencesImpl.java')
-rw-r--r-- | core/java/android/app/SharedPreferencesImpl.java | 132 |
1 files changed, 106 insertions, 26 deletions
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java index a807d3b..8aee65c 100644 --- a/core/java/android/app/SharedPreferencesImpl.java +++ b/core/java/android/app/SharedPreferencesImpl.java @@ -25,9 +25,12 @@ import android.util.Log; import com.google.android.collect.Maps; import com.android.internal.util.XmlUtils; +import dalvik.system.BlockGuard; + import org.xmlpull.v1.XmlPullParserException; import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; @@ -61,32 +64,88 @@ final class SharedPreferencesImpl implements SharedPreferences { private final Object mWritingToDiskLock = new Object(); private static final Object mContent = new Object(); - private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners; + private final WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners = + new WeakHashMap<OnSharedPreferenceChangeListener, Object>(); - SharedPreferencesImpl( - File file, int mode, Map initialContents) { + SharedPreferencesImpl(File file, int mode) { mFile = file; - mBackupFile = ContextImpl.makeBackupFile(file); + mBackupFile = makeBackupFile(file); mMode = mode; - mLoaded = initialContents != null; - mMap = initialContents != null ? initialContents : new HashMap<String, Object>(); + mLoaded = false; + mMap = null; + startLoadFromDisk(); + } + + private void startLoadFromDisk() { + synchronized (this) { + mLoaded = false; + } + new Thread("SharedPreferencesImpl-load") { + public void run() { + synchronized (SharedPreferencesImpl.this) { + loadFromDiskLocked(); + } + } + }.start(); + } + + private void loadFromDiskLocked() { + if (mLoaded) { + return; + } + if (mBackupFile.exists()) { + mFile.delete(); + mBackupFile.renameTo(mFile); + } + + // Debugging + if (mFile.exists() && !mFile.canRead()) { + Log.w(TAG, "Attempt to read preferences file " + mFile + " without permission"); + } + + Map map = null; FileStatus stat = new FileStatus(); - if (FileUtils.getFileStatus(file.getPath(), stat)) { + if (FileUtils.getFileStatus(mFile.getPath(), stat) && mFile.canRead()) { + try { + FileInputStream str = new FileInputStream(mFile); + map = XmlUtils.readMapXml(str); + str.close(); + } catch (XmlPullParserException e) { + Log.w(TAG, "getSharedPreferences", e); + } catch (FileNotFoundException e) { + Log.w(TAG, "getSharedPreferences", e); + } catch (IOException e) { + Log.w(TAG, "getSharedPreferences", e); + } + } + mLoaded = true; + if (map != null) { + mMap = map; mStatTimestamp = stat.mtime; + mStatSize = stat.size; + } else { + mMap = new HashMap<String, Object>(); } - mListeners = new WeakHashMap<OnSharedPreferenceChangeListener, Object>(); + notifyAll(); + } + + private static File makeBackupFile(File prefsFile) { + return new File(prefsFile.getPath() + ".bak"); } - // Has this SharedPreferences ever had values assigned to it? - boolean isLoaded() { + void startReloadIfChangedUnexpectedly() { synchronized (this) { - return mLoaded; + // TODO: wait for any pending writes to disk? + if (!hasFileChangedUnexpectedly()) { + return; + } + startLoadFromDisk(); } } // Has the file changed out from under us? i.e. writes that // we didn't instigate. - public boolean hasFileChangedUnexpectedly() { + private boolean hasFileChangedUnexpectedly() { synchronized (this) { if (mDiskWritesInFlight > 0) { // If we know we caused it, it's not unexpected. @@ -103,19 +162,6 @@ final class SharedPreferencesImpl implements SharedPreferences { } } - /*package*/ void replace(Map newContents, FileStatus stat) { - synchronized (this) { - mLoaded = true; - if (newContents != null) { - mMap = newContents; - } - if (stat != null) { - mStatTimestamp = stat.mtime; - mStatSize = stat.size; - } - } - } - public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) { synchronized(this) { mListeners.put(listener, mContent); @@ -128,8 +174,24 @@ final class SharedPreferencesImpl implements SharedPreferences { } } + private void awaitLoadedLocked() { + if (!mLoaded) { + // Raise an explicit StrictMode onReadFromDisk for this + // thread, since the real read will be in a different + // thread and otherwise ignored by StrictMode. + BlockGuard.getThreadPolicy().onReadFromDisk(); + } + while (!mLoaded) { + try { + wait(); + } catch (InterruptedException unused) { + } + } + } + public Map<String, ?> getAll() { - synchronized(this) { + synchronized (this) { + awaitLoadedLocked(); //noinspection unchecked return new HashMap<String, Object>(mMap); } @@ -137,6 +199,7 @@ final class SharedPreferencesImpl implements SharedPreferences { public String getString(String key, String defValue) { synchronized (this) { + awaitLoadedLocked(); String v = (String)mMap.get(key); return v != null ? v : defValue; } @@ -144,6 +207,7 @@ final class SharedPreferencesImpl implements SharedPreferences { public Set<String> getStringSet(String key, Set<String> defValues) { synchronized (this) { + awaitLoadedLocked(); Set<String> v = (Set<String>) mMap.get(key); return v != null ? v : defValues; } @@ -151,24 +215,28 @@ final class SharedPreferencesImpl implements SharedPreferences { public int getInt(String key, int defValue) { synchronized (this) { + awaitLoadedLocked(); Integer v = (Integer)mMap.get(key); return v != null ? v : defValue; } } public long getLong(String key, long defValue) { synchronized (this) { + awaitLoadedLocked(); Long v = (Long)mMap.get(key); return v != null ? v : defValue; } } public float getFloat(String key, float defValue) { synchronized (this) { + awaitLoadedLocked(); Float v = (Float)mMap.get(key); return v != null ? v : defValue; } } public boolean getBoolean(String key, boolean defValue) { synchronized (this) { + awaitLoadedLocked(); Boolean v = (Boolean)mMap.get(key); return v != null ? v : defValue; } @@ -176,11 +244,23 @@ final class SharedPreferencesImpl implements SharedPreferences { public boolean contains(String key) { synchronized (this) { + awaitLoadedLocked(); return mMap.containsKey(key); } } public Editor edit() { + // TODO: remove the need to call awaitLoadedLocked() when + // requesting an editor. will require some work on the + // Editor, but then we should be able to do: + // + // context.getSharedPreferences(..).edit().putString(..).apply() + // + // ... all without blocking. + synchronized (this) { + awaitLoadedLocked(); + } + return new EditorImpl(); } |