Loading core/java/android/app/ContextImpl.java +6 −45 Original line number Diff line number Diff line Loading @@ -532,10 +532,6 @@ class ContextImpl extends Context { throw new RuntimeException("Not supported in system context"); } static File makeBackupFile(File prefsFile) { return new File(prefsFile.getPath() + ".bak"); } public File getSharedPrefsFile(String name) { return makeFilename(getPreferencesDir(), name + ".xml"); } Loading @@ -543,54 +539,19 @@ class ContextImpl extends Context { @Override public SharedPreferences getSharedPreferences(String name, int mode) { SharedPreferencesImpl sp; File prefsFile; boolean needInitialLoad = false; synchronized (sSharedPrefs) { sp = sSharedPrefs.get(name); if (sp != null && !sp.hasFileChangedUnexpectedly()) { return sp; } prefsFile = getSharedPrefsFile(name); if (sp == null) { sp = new SharedPreferencesImpl(prefsFile, mode, null); File prefsFile = getSharedPrefsFile(name); sp = new SharedPreferencesImpl(prefsFile, mode); sSharedPrefs.put(name, sp); needInitialLoad = true; } } synchronized (sp) { if (needInitialLoad && sp.isLoaded()) { // lost the race to load; another thread handled it return sp; } File backup = makeBackupFile(prefsFile); if (backup.exists()) { prefsFile.delete(); backup.renameTo(prefsFile); } // Debugging if (prefsFile.exists() && !prefsFile.canRead()) { Log.w(TAG, "Attempt to read preferences file " + prefsFile + " without permission"); } Map map = null; FileStatus stat = new FileStatus(); if (FileUtils.getFileStatus(prefsFile.getPath(), stat) && prefsFile.canRead()) { try { FileInputStream str = new FileInputStream(prefsFile); 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); } } sp.replace(map, stat); } // If somebody else (some other process) changed the prefs // file behind our back, we reload it. This has been the // historical (if undocumented) behavior. sp.startReloadIfChangedUnexpectedly(); return sp; } Loading core/java/android/app/SharedPreferencesImpl.java +106 −26 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); } // Has this SharedPreferences ever had values assigned to it? boolean isLoaded() { private static File makeBackupFile(File prefsFile) { return new File(prefsFile.getPath() + ".bak"); } 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. Loading @@ -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); Loading @@ -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) { awaitLoadedLocked(); //noinspection unchecked return new HashMap<String, Object>(mMap); } Loading @@ -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; } Loading @@ -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; } Loading @@ -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; } Loading @@ -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(); } Loading Loading
core/java/android/app/ContextImpl.java +6 −45 Original line number Diff line number Diff line Loading @@ -532,10 +532,6 @@ class ContextImpl extends Context { throw new RuntimeException("Not supported in system context"); } static File makeBackupFile(File prefsFile) { return new File(prefsFile.getPath() + ".bak"); } public File getSharedPrefsFile(String name) { return makeFilename(getPreferencesDir(), name + ".xml"); } Loading @@ -543,54 +539,19 @@ class ContextImpl extends Context { @Override public SharedPreferences getSharedPreferences(String name, int mode) { SharedPreferencesImpl sp; File prefsFile; boolean needInitialLoad = false; synchronized (sSharedPrefs) { sp = sSharedPrefs.get(name); if (sp != null && !sp.hasFileChangedUnexpectedly()) { return sp; } prefsFile = getSharedPrefsFile(name); if (sp == null) { sp = new SharedPreferencesImpl(prefsFile, mode, null); File prefsFile = getSharedPrefsFile(name); sp = new SharedPreferencesImpl(prefsFile, mode); sSharedPrefs.put(name, sp); needInitialLoad = true; } } synchronized (sp) { if (needInitialLoad && sp.isLoaded()) { // lost the race to load; another thread handled it return sp; } File backup = makeBackupFile(prefsFile); if (backup.exists()) { prefsFile.delete(); backup.renameTo(prefsFile); } // Debugging if (prefsFile.exists() && !prefsFile.canRead()) { Log.w(TAG, "Attempt to read preferences file " + prefsFile + " without permission"); } Map map = null; FileStatus stat = new FileStatus(); if (FileUtils.getFileStatus(prefsFile.getPath(), stat) && prefsFile.canRead()) { try { FileInputStream str = new FileInputStream(prefsFile); 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); } } sp.replace(map, stat); } // If somebody else (some other process) changed the prefs // file behind our back, we reload it. This has been the // historical (if undocumented) behavior. sp.startReloadIfChangedUnexpectedly(); return sp; } Loading
core/java/android/app/SharedPreferencesImpl.java +106 −26 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); } // Has this SharedPreferences ever had values assigned to it? boolean isLoaded() { private static File makeBackupFile(File prefsFile) { return new File(prefsFile.getPath() + ".bak"); } 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. Loading @@ -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); Loading @@ -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) { awaitLoadedLocked(); //noinspection unchecked return new HashMap<String, Object>(mMap); } Loading @@ -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; } Loading @@ -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; } Loading @@ -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; } Loading @@ -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(); } Loading