From 4e920f70f38d52d3a74c6a3133388a2e2cb6c175 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 14 Dec 2010 11:52:13 -0800 Subject: Add MODE_MULTI_PROCESS flag to Context.getSharedPreferences() Also, changes to make this testable with CTS: -- special PENALTY_DEATH StrictMode fast path that doesn't use the Looper idling to "time" the violation. Only used when death is the only violation, -- make PENALTY_DEATH throw a RuntimeException instead of killing its process with a signal. this means we can catch it in CTS tests, but it's also more consistent with PENALTY_NETWORK_DEATH in Honeycomb. -- make FileUtils.getFileStatus() invoke StrictMode, which isn't (yet?) aware of I/O in native code. so help it out. CTS test for MODE_MULTI_PROCESS is in I6154edab Change-Id: Icf93f9dfb0ece06b16781e4803dd2c17df3cf1b3 --- api/current.xml | 11 +++++ core/java/android/app/ContextImpl.java | 11 +++-- core/java/android/content/Context.java | 26 +++++++++++- core/java/android/os/FileUtils.java | 7 ++- core/java/android/os/StrictMode.java | 78 +++++++++++++++++++++++++++++----- core/jni/android_os_FileUtils.cpp | 3 +- 6 files changed, 117 insertions(+), 19 deletions(-) diff --git a/api/current.xml b/api/current.xml index df4b914b0b5d..8ce9da478e59 100644 --- a/api/current.xml +++ b/api/current.xml @@ -48156,6 +48156,17 @@ visibility="public" > + + 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 greater than 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, @@ -318,7 +337,11 @@ public abstract class Context { * 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 @@ public abstract class Context { * @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 9d50fd9bf123..f56f6a9937ac 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -76,7 +76,12 @@ public class FileUtils * @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 b00b9c9aef7e..e314fceeff8c 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -669,25 +669,46 @@ public final class StrictMode { 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 @@ public final class StrictMode { // 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 @@ public final class StrictMode { } 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, @@ -1596,6 +1627,31 @@ public final class StrictMode { ((AndroidBlockGuardPolicy) policy).onCustomSlowCall(name); } + /** + * @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 d3faa2fd98ed..d8a3db3b9305 100644 --- a/core/jni/android_os_FileUtils.cpp +++ b/core/jni/android_os_FileUtils.cpp @@ -177,7 +177,7 @@ static const JNINativeMethod methods[] = { {"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 @@ int register_android_os_FileUtils(JNIEnv* env) } } - -- cgit v1.2.3-59-g8ed1b