Merge "Add MODE_MULTI_PROCESS flag to Context.getSharedPreferences()"
diff --git a/api/current.xml b/api/current.xml
index df4b914..8ce9da4 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -48156,6 +48156,17 @@
visibility="public"
>
</field>
+<field name="MODE_MULTI_PROCESS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="MODE_PRIVATE"
type="int"
transient="false"
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 083612e..72f7286 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -554,10 +554,13 @@
return sp;
}
}
- // 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();
+ if ((mode & Context.MODE_MULTI_PROCESS) != 0 ||
+ getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) {
+ // 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;
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 277dc2f..b128d31 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -80,6 +80,25 @@
public static final int MODE_APPEND = 0x8000;
/**
+ * SharedPreference loading flag: when set, the file on disk will
+ * be checked for modification even if the shared preferences
+ * instance is already loaded in this process. This behavior is
+ * sometimes desired in cases where the application has multiple
+ * processes, all writing to the same SharedPreferences file.
+ * Generally there are better forms of communication between
+ * processes, though.
+ *
+ * <p>This was the legacy (but undocumented) behavior in and
+ * before Gingerbread (Android 2.3) and this flag is implied when
+ * targetting such releases. For applications targetting SDK
+ * versions <em>greater than</em> Android 2.3, this flag must be
+ * explicitly set if desired.
+ *
+ * @see #getSharedPreferences
+ */
+ public static final int MODE_MULTI_PROCESS = 0x0004;
+
+ /**
* Flag for {@link #bindService}: automatically create the service as long
* as the binding exists. Note that while this will create the service,
* its {@link android.app.Service#onStartCommand}
@@ -318,7 +337,11 @@
* editor (SharedPreferences.edit()) and then commit changes (Editor.commit()).
* @param mode Operating mode. Use 0 or {@link #MODE_PRIVATE} for the
* default operation, {@link #MODE_WORLD_READABLE}
- * and {@link #MODE_WORLD_WRITEABLE} to control permissions.
+ * and {@link #MODE_WORLD_WRITEABLE} to control permissions. The bit
+ * {@link #MODE_MULTI_PROCESS} can also be used if multiple processes
+ * are mutating the same SharedPreferences file. {@link #MODE_MULTI_PROCESS}
+ * is always on in apps targetting Gingerbread (Android 2.3) and below, and
+ * off by default in later versions.
*
* @return Returns the single SharedPreferences instance that can be used
* to retrieve and modify the preference values.
@@ -326,6 +349,7 @@
* @see #MODE_PRIVATE
* @see #MODE_WORLD_READABLE
* @see #MODE_WORLD_WRITEABLE
+ * @see #MODE_MULTI_PROCESS
*/
public abstract SharedPreferences getSharedPreferences(String name,
int mode);
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 9d50fd9..f56f6a9 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -76,7 +76,12 @@
* @return true if the file exists and false if it does not exist. If you do not have
* permission to stat the file, then this method will return false.
*/
- public static native boolean getFileStatus(String path, FileStatus status);
+ public static boolean getFileStatus(String path, FileStatus status) {
+ StrictMode.noteDiskRead();
+ return getFileStatusNative(path, status);
+ }
+
+ private static native boolean getFileStatusNative(String path, FileStatus status);
/** Regular expression for safe filenames: no spaces or metacharacters */
private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+");
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index b00b9c9..e314fce 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -669,25 +669,46 @@
CloseGuard.setEnabled(enabled);
}
- private static class StrictModeNetworkViolation extends BlockGuard.BlockGuardPolicyException {
+ /**
+ * @hide
+ */
+ public static class StrictModeViolation extends BlockGuard.BlockGuardPolicyException {
+ public StrictModeViolation(int policyState, int policyViolated, String message) {
+ super(policyState, policyViolated, message);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static class StrictModeNetworkViolation extends StrictModeViolation {
public StrictModeNetworkViolation(int policyMask) {
- super(policyMask, DETECT_NETWORK);
+ super(policyMask, DETECT_NETWORK, null);
}
}
- private static class StrictModeDiskReadViolation extends BlockGuard.BlockGuardPolicyException {
+ /**
+ * @hide
+ */
+ private static class StrictModeDiskReadViolation extends StrictModeViolation {
public StrictModeDiskReadViolation(int policyMask) {
- super(policyMask, DETECT_DISK_READ);
+ super(policyMask, DETECT_DISK_READ, null);
}
}
- private static class StrictModeDiskWriteViolation extends BlockGuard.BlockGuardPolicyException {
+ /**
+ * @hide
+ */
+ private static class StrictModeDiskWriteViolation extends StrictModeViolation {
public StrictModeDiskWriteViolation(int policyMask) {
- super(policyMask, DETECT_DISK_WRITE);
+ super(policyMask, DETECT_DISK_WRITE, null);
}
}
- private static class StrictModeCustomViolation extends BlockGuard.BlockGuardPolicyException {
+ /**
+ * @hide
+ */
+ private static class StrictModeCustomViolation extends StrictModeViolation {
public StrictModeCustomViolation(int policyMask, String name) {
super(policyMask, DETECT_CUSTOM, name);
}
@@ -1007,9 +1028,16 @@
// thread, in "gather" mode. In this case, the duration
// of the violation is computed by the ultimate caller and
// its Looper, if any.
+ //
+ // Also, as a special short-cut case when the only penalty
+ // bit is death, we die immediately, rather than timing
+ // the violation's duration. This makes it convenient to
+ // use in unit tests too, rather than waiting on a Looper.
+ //
// TODO: if in gather mode, ignore Looper.myLooper() and always
// go into this immediate mode?
- if (looper == null) {
+ if (looper == null ||
+ (info.policy & PENALTY_MASK) == PENALTY_DEATH) {
info.durationMillis = -1; // unknown (redundant, already set)
handleViolation(info);
return;
@@ -1179,13 +1207,16 @@
}
if ((info.policy & PENALTY_DEATH) != 0) {
- System.err.println("StrictMode policy violation with POLICY_DEATH; shutting down.");
- Process.killProcess(Process.myPid());
- System.exit(10);
+ executeDeathPenalty(info);
}
}
}
+ private static void executeDeathPenalty(ViolationInfo info) {
+ int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage);
+ throw new StrictModeViolation(info.policy, violationBit, null);
+ }
+
/**
* In the common case, as set by conditionallyEnableDebugLogging,
* we're just dropboxing any violations but not showing a dialog,
@@ -1597,6 +1628,31 @@
}
/**
+ * @hide
+ */
+ public static void noteDiskRead() {
+ BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
+ Log.d(TAG, "noteDiskRead; policy=" + policy);
+ if (!(policy instanceof AndroidBlockGuardPolicy)) {
+ // StrictMode not enabled.
+ return;
+ }
+ ((AndroidBlockGuardPolicy) policy).onReadFromDisk();
+ }
+
+ /**
+ * @hide
+ */
+ public static void noteDiskWrite() {
+ BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
+ if (!(policy instanceof AndroidBlockGuardPolicy)) {
+ // StrictMode not enabled.
+ return;
+ }
+ ((AndroidBlockGuardPolicy) policy).onWriteToDisk();
+ }
+
+ /**
* Parcelable that gets sent in Binder call headers back to callers
* to report violations that happened during a cross-process call.
*
diff --git a/core/jni/android_os_FileUtils.cpp b/core/jni/android_os_FileUtils.cpp
index d3faa2f..d8a3db3 100644
--- a/core/jni/android_os_FileUtils.cpp
+++ b/core/jni/android_os_FileUtils.cpp
@@ -177,7 +177,7 @@
{"getPermissions", "(Ljava/lang/String;[I)I", (void*)android_os_FileUtils_getPermissions},
{"setUMask", "(I)I", (void*)android_os_FileUtils_setUMask},
{"getFatVolumeId", "(Ljava/lang/String;)I", (void*)android_os_FileUtils_getFatVolumeId},
- {"getFileStatus", "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z", (void*)android_os_FileUtils_getFileStatus},
+ {"getFileStatusNative", "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z", (void*)android_os_FileUtils_getFileStatus},
};
static const char* const kFileUtilsPathName = "android/os/FileUtils";
@@ -211,4 +211,3 @@
}
}
-