Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4e920f70 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick
Browse files

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
parent e464fba4
Loading
Loading
Loading
Loading
+11 −0
Original line number Original line Diff line number Diff line
@@ -48156,6 +48156,17 @@
 visibility="public"
 visibility="public"
>
>
</field>
</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"
<field name="MODE_PRIVATE"
 type="int"
 type="int"
 transient="false"
 transient="false"
+7 −4
Original line number Original line Diff line number Diff line
@@ -554,10 +554,13 @@ class ContextImpl extends Context {
                return sp;
                return sp;
            }
            }
        }
        }
        if ((mode & Context.MODE_MULTI_PROCESS) != 0 ||
            getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) {
            // If somebody else (some other process) changed the prefs
            // If somebody else (some other process) changed the prefs
            // file behind our back, we reload it.  This has been the
            // file behind our back, we reload it.  This has been the
            // historical (if undocumented) behavior.
            // historical (if undocumented) behavior.
            sp.startReloadIfChangedUnexpectedly();
            sp.startReloadIfChangedUnexpectedly();
        }
        return sp;
        return sp;
    }
    }


+25 −1
Original line number Original line Diff line number Diff line
@@ -79,6 +79,25 @@ public abstract class Context {
     */
     */
    public static final int MODE_APPEND = 0x8000;
    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
     * Flag for {@link #bindService}: automatically create the service as long
     * as the binding exists.  Note that while this will create the service,
     * 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()).
     * editor (SharedPreferences.edit()) and then commit changes (Editor.commit()).
     * @param mode Operating mode.  Use 0 or {@link #MODE_PRIVATE} for the
     * @param mode Operating mode.  Use 0 or {@link #MODE_PRIVATE} for the
     * default operation, {@link #MODE_WORLD_READABLE}
     * 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
     * @return Returns the single SharedPreferences instance that can be used
     *         to retrieve and modify the preference values.
     *         to retrieve and modify the preference values.
@@ -326,6 +349,7 @@ public abstract class Context {
     * @see #MODE_PRIVATE
     * @see #MODE_PRIVATE
     * @see #MODE_WORLD_READABLE
     * @see #MODE_WORLD_READABLE
     * @see #MODE_WORLD_WRITEABLE
     * @see #MODE_WORLD_WRITEABLE
     * @see #MODE_MULTI_PROCESS
     */
     */
    public abstract SharedPreferences getSharedPreferences(String name,
    public abstract SharedPreferences getSharedPreferences(String name,
            int mode);
            int mode);
+6 −1
Original line number Original line Diff line number Diff line
@@ -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 
     * @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.
     * 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 */
    /** Regular expression for safe filenames: no spaces or metacharacters */
    private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+");
    private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+");
+67 −11
Original line number Original line Diff line number Diff line
@@ -669,25 +669,46 @@ public final class StrictMode {
        CloseGuard.setEnabled(enabled);
        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) {
        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) {
        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) {
        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) {
        public StrictModeCustomViolation(int policyMask, String name) {
            super(policyMask, DETECT_CUSTOM, name);
            super(policyMask, DETECT_CUSTOM, name);
        }
        }
@@ -1007,9 +1028,16 @@ public final class StrictMode {
            // thread, in "gather" mode.  In this case, the duration
            // thread, in "gather" mode.  In this case, the duration
            // of the violation is computed by the ultimate caller and
            // of the violation is computed by the ultimate caller and
            // its Looper, if any.
            // 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
            // TODO: if in gather mode, ignore Looper.myLooper() and always
            //       go into this immediate mode?
            //       go into this immediate mode?
            if (looper == null) {
            if (looper == null ||
                (info.policy & PENALTY_MASK) == PENALTY_DEATH) {
                info.durationMillis = -1;  // unknown (redundant, already set)
                info.durationMillis = -1;  // unknown (redundant, already set)
                handleViolation(info);
                handleViolation(info);
                return;
                return;
@@ -1179,13 +1207,16 @@ public final class StrictMode {
            }
            }


            if ((info.policy & PENALTY_DEATH) != 0) {
            if ((info.policy & PENALTY_DEATH) != 0) {
                System.err.println("StrictMode policy violation with POLICY_DEATH; shutting down.");
                executeDeathPenalty(info);
                Process.killProcess(Process.myPid());
                System.exit(10);
            }
            }
        }
        }
    }
    }


    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,
     * In the common case, as set by conditionallyEnableDebugLogging,
     * we're just dropboxing any violations but not showing a dialog,
     * we're just dropboxing any violations but not showing a dialog,
@@ -1596,6 +1627,31 @@ public final class StrictMode {
        ((AndroidBlockGuardPolicy) policy).onCustomSlowCall(name);
        ((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
     * Parcelable that gets sent in Binder call headers back to callers
     * to report violations that happened during a cross-process call.
     * to report violations that happened during a cross-process call.
Loading