Add presubmit to prevent SharedPreferences misuse.

BUG=599284

Review-Url: https://codereview.chromium.org/1993243002
Cr-Commit-Position: refs/heads/master@{#395881}
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 5fe8b53..0fb216c 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -25,6 +25,7 @@
     r"^chrome[\\\/]browser[\\\/]resources[\\\/]pdf[\\\/]index.js",
 )
 
+
 # The NetscapePlugIn library is excluded from pan-project as it will soon
 # be deleted together with the rest of the NPAPI and it's not worthwhile to
 # update the coding style until then.
@@ -32,10 +33,12 @@
     r"^content[\\\/]shell[\\\/]tools[\\\/]plugin[\\\/].*",
 )
 
+
 # Fragment of a regular expression that matches C++ and Objective-C++
 # implementation files.
 _IMPLEMENTATION_EXTENSIONS = r'\.(cc|cpp|cxx|mm)$'
 
+
 # Regular expression that matches code only used for test binaries
 # (best effort).
 _TEST_CODE_EXCLUDED_PATHS = (
@@ -55,6 +58,7 @@
     r'testing[\\\/]iossim[\\\/]iossim\.mm$',
 )
 
+
 _TEST_ONLY_WARNING = (
     'You might be calling functions intended only for testing from\n'
     'production code.  It is OK to ignore this warning if you know what\n'
@@ -67,6 +71,7 @@
     'collation (LC_COLLATE=C) and check\nhttps://google.github.io/styleguide/'
     'cppguide.html#Names_and_Order_of_Includes')
 
+
 _BANNED_OBJC_FUNCTIONS = (
     (
       'addTrackingRect:',
@@ -291,6 +296,7 @@
     ),
 )
 
+
 _IPC_ENUM_TRAITS_DEPRECATED = (
     'You are using IPC_ENUM_TRAITS() in your code. It has been deprecated.\n'
     'See http://www.chromium.org/Home/chromium-security/education/security-tips-for-ipc')
@@ -322,10 +328,12 @@
     'net/tools/testserver/testserver.pydeps',
 ]
 
+
 _GENERIC_PYDEPS_FILES = [
     'build/secondary/tools/swarming_client/isolate.pydeps',
 ]
 
+
 _ALL_PYDEPS_FILES = _ANDROID_SPECIFIC_PYDEPS_FILES + _GENERIC_PYDEPS_FILES
 
 
@@ -491,6 +499,7 @@
     'been modified and the associated histogram name has no match in either '
     '%s or the modifications of it:' % (histograms_xml_path),  problems)]
 
+
 def _CheckFlakyTestUsage(input_api, output_api):
   """Check that FlakyTest annotation is our own instead of the android one"""
   pattern = input_api.re.compile(r'import android.test.FlakyTest;')
@@ -506,6 +515,7 @@
       files)]
   return []
 
+
 def _CheckNoNewWStrings(input_api, output_api):
   """Checks to make sure we don't introduce use of wstrings."""
   problems = []
@@ -566,51 +576,42 @@
   warnings = []
   errors = []
 
+  def IsBlacklisted(affected_file, blacklist):
+    local_path = affected_file.LocalPath()
+    for item in blacklist:
+      if input_api.re.match(item, local_path):
+        return True
+    return False
+
+  def CheckForMatch(affected_file, line_num, line, func_name, message, error):
+    matched = False
+    if func_name[0:1] == '/':
+      regex = func_name[1:]
+      if input_api.re.search(regex, line):
+        matched = True
+    elif func_name in line:
+        matched = True
+    if matched:
+      problems = warnings;
+      if error:
+        problems = errors;
+      problems.append('    %s:%d:' % (affected_file.LocalPath(), line_num))
+      for message_line in message:
+        problems.append('      %s' % message_line)
+
   file_filter = lambda f: f.LocalPath().endswith(('.mm', '.m', '.h'))
   for f in input_api.AffectedFiles(file_filter=file_filter):
     for line_num, line in f.ChangedContents():
       for func_name, message, error in _BANNED_OBJC_FUNCTIONS:
-        matched = False
-        if func_name[0:1] == '/':
-          regex = func_name[1:]
-          if input_api.re.search(regex, line):
-            matched = True
-        elif func_name in line:
-            matched = True
-        if matched:
-          problems = warnings;
-          if error:
-            problems = errors;
-          problems.append('    %s:%d:' % (f.LocalPath(), line_num))
-          for message_line in message:
-            problems.append('      %s' % message_line)
+        CheckForMatch(f, line_num, line, func_name, message, error)
 
   file_filter = lambda f: f.LocalPath().endswith(('.cc', '.mm', '.h'))
   for f in input_api.AffectedFiles(file_filter=file_filter):
     for line_num, line in f.ChangedContents():
       for func_name, message, error, excluded_paths in _BANNED_CPP_FUNCTIONS:
-        def IsBlacklisted(affected_file, blacklist):
-          local_path = affected_file.LocalPath()
-          for item in blacklist:
-            if input_api.re.match(item, local_path):
-              return True
-          return False
         if IsBlacklisted(f, excluded_paths):
           continue
-        matched = False
-        if func_name[0:1] == '/':
-          regex = func_name[1:]
-          if input_api.re.search(regex, line):
-            matched = True
-        elif func_name in line:
-            matched = True
-        if matched:
-          problems = warnings;
-          if error:
-            problems = errors;
-          problems.append('    %s:%d:' % (f.LocalPath(), line_num))
-          for message_line in message:
-            problems.append('      %s' % message_line)
+        CheckForMatch(f, line_num, line, func_name, message, error)
 
   result = []
   if (warnings):
@@ -1862,6 +1863,7 @@
   results.extend(_CheckSingletonInHeaders(input_api, output_api))
   results.extend(_CheckNoDeprecatedCompiledResourcesGYP(input_api, output_api))
   results.extend(_CheckPydepsNeedsUpdating(input_api, output_api))
+  results.extend(_CheckJavaStyle(input_api, output_api))
 
   if any('PRESUBMIT.py' == f.LocalPath() for f in input_api.AffectedFiles()):
     results.extend(input_api.canned_checks.RunUnitTestsInDirectory(
@@ -2085,7 +2087,6 @@
   results = []
   results.extend(_CommonChecks(input_api, output_api))
   results.extend(_CheckValidHostsInDEPS(input_api, output_api))
-  results.extend(_CheckJavaStyle(input_api, output_api))
   results.extend(
       input_api.canned_checks.CheckGNFormatted(input_api, output_api))
   results.extend(_CheckUmaHistogramChanges(input_api, output_api))
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackupAgent.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackupAgent.java
index a95ec53..172cf787 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackupAgent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeBackupAgent.java
@@ -11,8 +11,8 @@
 import android.content.SharedPreferences;
 import android.os.Build;
 import android.os.ParcelFileDescriptor;
-import android.preference.PreferenceManager;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.chrome.browser.firstrun.FirstRunSignInProcessor;
 import org.chromium.chrome.browser.firstrun.FirstRunStatus;
@@ -62,8 +62,7 @@
 
     @Override
     public void onRestoreFinished() {
-        SharedPreferences sharedPrefs =
-                PreferenceManager.getDefaultSharedPreferences(ChromeBackupAgent.this);
+        SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences();
         Set<String> prefNames = sharedPrefs.getAll().keySet();
         // Save the user name for later restoration.
         String userName = sharedPrefs.getString(ChromeSigninController.SIGNED_IN_ACCOUNT_KEY, null);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeBackupIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeBackupIntegrationTest.java
index 11b8bfd..d90896a3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeBackupIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ChromeBackupIntegrationTest.java
@@ -9,9 +9,9 @@
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.os.Build;
-import android.preference.PreferenceManager;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.chrome.browser.firstrun.FirstRunSignInProcessor;
@@ -63,7 +63,7 @@
         Context targetContext = getInstrumentation().getTargetContext();
 
         // Fake having previously gone through FRE and signed in.
-        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(targetContext);
+        SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
         SharedPreferences.Editor preferenceEditor = prefs.edit();
         preferenceEditor.putBoolean(FirstRunStatus.FIRST_RUN_FLOW_COMPLETE, true);
         preferenceEditor.putBoolean(FirstRunSignInProcessor.FIRST_RUN_FLOW_SIGNIN_SETUP, true);
@@ -93,7 +93,7 @@
         Context targetContext = getInstrumentation().getTargetContext();
 
         // Fake having previously gone through FRE and signed in.
-        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(targetContext);
+        SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
         SharedPreferences.Editor preferenceEditor = prefs.edit();
         preferenceEditor.putBoolean(FirstRunStatus.FIRST_RUN_FLOW_COMPLETE, true);
         preferenceEditor.putBoolean(FirstRunSignInProcessor.FIRST_RUN_FLOW_SIGNIN_SETUP, true);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ChromeBackupAgentTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ChromeBackupAgentTest.java
index 20e1cb0..62853b63 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ChromeBackupAgentTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ChromeBackupAgentTest.java
@@ -9,9 +9,10 @@
 import static org.junit.Assert.assertThat;
 
 import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.Robolectric;
@@ -32,10 +33,14 @@
         }
     }
 
+    @Before
+    public void setUp() throws Exception {
+        ContextUtils.initApplicationContextForTests(Robolectric.application);
+    }
+
     @Test
     public void testOnRestoreFinished() {
-        SharedPreferences sharedPrefs =
-                PreferenceManager.getDefaultSharedPreferences(Robolectric.application);
+        SharedPreferences sharedPrefs = ContextUtils.getAppSharedPreferences();
         SharedPreferences.Editor editor = sharedPrefs.edit();
         editor.putBoolean("crash_dump_upload", false);
         editor.putString("google.services.username", "user1");
diff --git a/tools/android/checkstyle/chromium-style-5.0.xml b/tools/android/checkstyle/chromium-style-5.0.xml
index 6557f61..700f449a 100644
--- a/tools/android/checkstyle/chromium-style-5.0.xml
+++ b/tools/android/checkstyle/chromium-style-5.0.xml
@@ -7,6 +7,9 @@
 <module name="Checker">
   <property name="severity" value="warning"/>
   <property name="charset" value="UTF-8"/>
+  <module name="SuppressionFilter">
+    <property name="file" value="tools/android/checkstyle/suppressions.xml"/>
+  </module>
   <module name="TreeWalker">
     <module name="AvoidStarImport">
       <property name="severity" value="error"/>
@@ -208,6 +211,13 @@
       <property name="ignoreComments" value="true"/>
       <property name="message" value="Avoid android.app.AlertDialog; if possible, use android.support.v7.app.AlertDialog instead, which has a Material look on all devices. (Some parts of the codebase can’t depend on the support library, in which case android.app.AlertDialog is the only option)"/>
     </module>
+    <module name="RegexpSinglelineJava">
+      <property name="id" value="SharedPreferencesCheck"/>
+      <property name="severity" value="error"/>
+      <property name="format" value="getDefaultSharedPreferences"/>
+      <property name="ignoreComments" value="true"/>
+      <property name="message" value="Use ContextUtils.getAppSharedPreferences() instead to access app-wide SharedPreferences."/>
+    </module>
   </module>
 
   <!-- Non-TreeWalker modules -->
diff --git a/tools/android/checkstyle/suppressions.xml b/tools/android/checkstyle/suppressions.xml
new file mode 100644
index 0000000..850d7d4
--- /dev/null
+++ b/tools/android/checkstyle/suppressions.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE suppressions PUBLIC "-//Puppy Crawl//DTD Suppressions 1.1//EN" "http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
+
+<suppressions>
+  <suppress id="SharedPreferencesCheck" files="ContextUtils.java"/>
+</suppressions>