Bug 1109361 - Handle empty files when loading ProfileInformationCache. r=mcomella
authorRichard Newman <rnewman@mozilla.com>
Tue, 23 Dec 2014 14:28:46 -0800
changeset 221190 78614247a0b38e7e55e6e725f769a59eff71dba1
parent 221189 9b7ace6537733a86b1836469f3ce403eefd1a349
child 221191 8c93e281718e2ac8bdd01ba913ac26f2a84925cb
push id28013
push userphilringnalda@gmail.com
push dateWed, 24 Dec 2014 23:31:28 +0000
treeherdermozilla-central@38471b0310c9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcomella
bugs1109361
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1109361 - Handle empty files when loading ProfileInformationCache. r=mcomella
mobile/android/base/background/healthreport/ProfileInformationCache.java
mobile/android/tests/background/junit3/src/healthreport/MockProfileInformationCache.java
mobile/android/tests/background/junit3/src/healthreport/TestProfileInformationCache.java
--- a/mobile/android/base/background/healthreport/ProfileInformationCache.java
+++ b/mobile/android/base/background/healthreport/ProfileInformationCache.java
@@ -65,21 +65,25 @@ public class ProfileInformationCache imp
   //
   // We also track the OS locale here for the same reason -- we need to store
   // the default (OS) value before the locale-switching code takes effect!
   private volatile String osLocale = "";
   private volatile String appLocale = "";
 
   private volatile JSONObject addons = null;
 
-  public ProfileInformationCache(String profilePath) {
-    file = new File(profilePath + File.separator + CACHE_FILE);
+  protected ProfileInformationCache(final File f) {
+    file = f;
     Logger.pii(LOG_TAG, "Using " + file.getAbsolutePath() + " for profile information cache.");
   }
 
+  public ProfileInformationCache(final String profilePath) {
+    this(new File(profilePath + File.separator + CACHE_FILE));
+  }
+
   public synchronized void beginInitialization() {
     initialized = false;
     needsWrite = true;
   }
 
   public JSONObject toJSON() {
     JSONObject object = new JSONObject();
     try {
@@ -104,16 +108,21 @@ public class ProfileInformationCache imp
    * Attempt to restore this object from a JSON blob. If there is a version mismatch, there has
    * likely been an upgrade to the cache format. The cache can be reconstructed without data loss
    * so rather than migrating, we invalidate the cache by refusing to store the given JSONObject
    * and returning false.
    *
    * @return false if there's a version mismatch or an error, true on success.
    */
   private boolean fromJSON(JSONObject object) throws JSONException {
+    if (object == null) {
+      Logger.debug(LOG_TAG, "Can't load restore PIC from null JSON object.");
+      return false;
+    }
+
     int version = object.optInt("version", 1);
     switch (version) {
     case FORMAT_VERSION:
       blocklistEnabled = object.getBoolean("blocklist");
       telemetryEnabled = object.getBoolean("telemetry");
       isAcceptLangUserSet = object.getBoolean("isAcceptLangUserSet");
       profileCreationTime = object.getLong("profileCreated");
       addons = object.getJSONObject("addons");
@@ -125,19 +134,21 @@ public class ProfileInformationCache imp
       Logger.warn(LOG_TAG, "Unable to restore from version " + version + " PIC file: expecting " + FORMAT_VERSION);
       return false;
     }
   }
 
   protected JSONObject readFromFile() throws FileNotFoundException, JSONException {
     Scanner scanner = null;
     try {
-      scanner = new Scanner(file, "UTF-8");
-      final String contents = scanner.useDelimiter("\\A").next();
-      return new JSONObject(contents);
+      scanner = new Scanner(file, "UTF-8").useDelimiter("\\A");
+      if (!scanner.hasNext()) {
+        return null;
+      }
+      return new JSONObject(scanner.next());
     } finally {
       if (scanner != null) {
         scanner.close();
       }
     }
   }
 
   protected void writeToFile(JSONObject object) throws IOException {
--- a/mobile/android/tests/background/junit3/src/healthreport/MockProfileInformationCache.java
+++ b/mobile/android/tests/background/junit3/src/healthreport/MockProfileInformationCache.java
@@ -11,16 +11,20 @@ import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.background.healthreport.ProfileInformationCache;
 
 public class MockProfileInformationCache extends ProfileInformationCache {
   public MockProfileInformationCache(String profilePath) {
     super(profilePath);
   }
 
+  public MockProfileInformationCache(File mockFile) {
+      super(mockFile);
+  }
+
   public boolean isInitialized() {
     return this.initialized;
   }
   public boolean needsWrite() {
     return this.needsWrite;
   }
   public File getFile() {
     return this.file;
--- a/mobile/android/tests/background/junit3/src/healthreport/TestProfileInformationCache.java
+++ b/mobile/android/tests/background/junit3/src/healthreport/TestProfileInformationCache.java
@@ -7,16 +7,25 @@ import java.io.File;
 import java.io.IOException;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.background.helpers.FakeProfileTestCase;
 
 public class TestProfileInformationCache extends FakeProfileTestCase {
 
+  public final void testEmptyFile() throws Exception {
+    // createTempFile creates an empty file on disk.
+    final File emptyFile = File.createTempFile("empty", "pic", this.fakeProfileDirectory);
+    final MockProfileInformationCache cache = new MockProfileInformationCache(emptyFile);
+
+    // Should not throw.
+    assertNull(cache.readJSON());
+  }
+
   public final void testInitState() throws IOException {
     MockProfileInformationCache cache = new MockProfileInformationCache(this.fakeProfileDirectory.getAbsolutePath());
     assertFalse(cache.isInitialized());
     assertFalse(cache.needsWrite());
 
     try {
       cache.isBlocklistEnabled();
       fail("Should throw fetching isBlocklistEnabled.");