Bug 1258470 - Part 11b: Inline BrowserDB factory into GeckoApplication. draft
authorNick Alexander <nalexander@mozilla.com>
Tue, 21 Jun 2016 11:44:42 -0700
changeset 381004 8571679f000267c7dfafe93c0bb5f3b70adb5a51
parent 381003 9297f5de4fddd4d85f31b8a1dccc6be3be0a9496
child 381005 01323dc831f6b9a6fe02ba9bb0937c6a65235a5f
push id21383
push usernalexander@mozilla.com
push dateFri, 24 Jun 2016 00:16:43 +0000
bugs1258470
milestone50.0a1
Bug 1258470 - Part 11b: Inline BrowserDB factory into GeckoApplication. MozReview-Commit-ID: FRHk2aaDm8I
mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
mobile/android/base/java/org/mozilla/gecko/GeckoProfile.java
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
@@ -23,16 +23,17 @@ import org.mozilla.gecko.home.HomePanels
 import org.mozilla.gecko.lwt.LightweightTheme;
 import org.mozilla.gecko.mdns.MulticastDNSManager;
 import org.mozilla.gecko.util.Clipboard;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import java.io.File;
 import java.lang.reflect.Method;
+import java.util.concurrent.ConcurrentHashMap;
 
 public class GeckoApplication extends Application
     implements ContextGetter {
     private static final String LOG_TAG = "GeckoApplication";
 
     private static volatile GeckoApplication instance;
 
     private boolean mInBackground;
@@ -152,34 +153,16 @@ public class GeckoApplication extends Ap
         DownloadsIntegration.init();
         HomePanelsManager.getInstance().init(context);
 
         // This getInstance call will force initialization of the NotificationHelper, but does nothing with the result
         NotificationHelper.getInstance(context).init();
 
         MulticastDNSManager.getInstance(context).init();
 
-        // Make sure that all browser-ish applications default to the real LocalBrowserDB.
-        // GeckoView consumers use their own Application class, so this doesn't affect them.
-        //
-        // We need to do this before any access to the profile; it controls
-        // which database class is used.
-        //
-        // As such, this needs to occur before the GeckoView in GeckoApp is inflated -- i.e., in the
-        // GeckoApp constructor or earlier -- because GeckoView implicitly accesses the profile. This is earlier!
-        GeckoProfile.setBrowserDBFactory(new BrowserDB.Factory() {
-            @Override
-            public BrowserDB get(String profileName, File profileDir) {
-                // Note that we don't use the profile directory -- we
-                // send operations to the ContentProvider, which does
-                // its own thing.
-                return new LocalBrowserDB(profileName);
-            }
-        });
-
         GeckoService.register();
 
         super.onCreate();
     }
 
     public void onDelayedStartup() {
         if (AppConstants.MOZ_ANDROID_GCM) {
             // TODO: only run in main process.
@@ -213,13 +196,23 @@ public class GeckoApplication extends Ap
     public LightweightTheme getLightweightTheme() {
         return mLightweightTheme;
     }
 
     public void prepareLightweightTheme() {
         mLightweightTheme = new LightweightTheme(this);
     }
 
+    private static final ConcurrentHashMap<String, BrowserDB> sDBCache =
+            new ConcurrentHashMap<>(/* capacity */ 4, /* load factor */ 0.75f, /* concurrency */ 2);
+
     @RobocopTarget
     public static BrowserDB getDB(GeckoProfile profile) {
-        return profile.getDB();
+        final String profileName = profile.getName();
+        BrowserDB db = sDBCache.get(profileName);
+        if (db != null) {
+            return db;
+        }
+        db = new LocalBrowserDB(profileName);
+        sDBCache.put(profileName, db);
+        return db;
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoProfile.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoProfile.java
@@ -13,18 +13,16 @@ import android.text.TextUtils;
 import android.util.Log;
 
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
 import org.mozilla.gecko.GeckoProfileDirectories.NoSuchProfileException;
 import org.mozilla.gecko.annotation.RobocopTarget;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.db.StubBrowserDB;
 import org.mozilla.gecko.util.FileUtils;
 import org.mozilla.gecko.util.INIParser;
 import org.mozilla.gecko.util.INISection;
 import org.mozilla.gecko.util.IntentUtils;
 
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -81,18 +79,16 @@ public final class GeckoProfile {
             new ConcurrentHashMap<String, GeckoProfile>(
                     /* capacity */ 4, /* load factor */ 0.75f, /* concurrency */ 2);
     private static String sDefaultProfileName;
 
     private final String mName;
     private final File mMozillaDir;
     private final Context mApplicationContext;
 
-    private final BrowserDB mDB;
-
     /**
      * Access to this member should be synchronized to avoid
      * races during creation -- particularly between getDir and GeckoView#init.
      *
      * Not final because this is lazily computed.
      */
     private File mProfileDir;
 
@@ -153,17 +149,17 @@ public final class GeckoProfile {
         } catch (final NoMozillaDirectoryException e) {
             // If this failed, we're screwed.
             Log.wtf(LOGTAG, "Unable to get default profile name.", e);
             throw new RuntimeException(e);
         }
     }
 
     public static GeckoProfile get(Context context) {
-        return get(context, null, null, null);
+        return get(context, null, (File) null);
     }
 
     public static GeckoProfile get(Context context, String profileName) {
         if (profileName != null) {
             GeckoProfile profile = sProfileCache.get(profileName);
             if (profile != null)
                 return profile;
         }
@@ -177,41 +173,20 @@ public final class GeckoProfile {
             dir = new File(profilePath);
             if (!dir.exists() || !dir.isDirectory()) {
                 Log.w(LOGTAG, "requested profile directory missing: " + profilePath);
             }
         }
         return get(context, profileName, dir);
     }
 
-    // Extension hook.
-    private static volatile BrowserDB.Factory sDBFactory;
-    public static void setBrowserDBFactory(BrowserDB.Factory factory) {
-        sDBFactory = factory;
-    }
-
+    // Note that the profile cache respects only the profile name!
+    // If the directory changes, the returned GeckoProfile instance will be mutated.
     @RobocopTarget
     public static GeckoProfile get(Context context, String profileName, File profileDir) {
-        if (sDBFactory == null) {
-            // We do this so that GeckoView consumers don't need to know anything about BrowserDB.
-            // It's a bit of a broken abstraction, but very tightly coupled, so we work around it
-            // for now. We can't just have GeckoView set this, because then it would collide in
-            // Fennec's use of GeckoView.
-            // We should never see this in Fennec itself, because GeckoApplication sets the factory
-            // in onCreate.
-            Log.d(LOGTAG, "Defaulting to StubBrowserDB.");
-            sDBFactory = StubBrowserDB.getFactory();
-        }
-        return GeckoProfile.get(context, profileName, profileDir, sDBFactory);
-    }
-
-    // Note that the profile cache respects only the profile name!
-    // If the directory changes, the returned GeckoProfile instance will be mutated.
-    // If the factory differs, it will be *ignored*.
-    public static GeckoProfile get(Context context, String profileName, File profileDir, BrowserDB.Factory dbFactory) {
         if (context == null) {
             throw new IllegalArgumentException("context must be non-null");
         }
 
         // Null name? | Null dir? | Returned profile
         // ------------------------------------------
         //     Yes    |    Yes    | Active profile or default profile.
         //     No     |    Yes    | Profile with specified name at default dir.
@@ -246,17 +221,17 @@ public final class GeckoProfile {
         final boolean init = profileDir != null && profileDir.mkdirs();
 
         // Actually try to look up the profile.
         GeckoProfile profile = sProfileCache.get(profileName);
         GeckoProfile newProfile = null;
 
         if (profile == null) {
             try {
-                newProfile = new GeckoProfile(context, profileName, profileDir, dbFactory);
+                newProfile = new GeckoProfile(context, profileName, profileDir);
             } catch (NoMozillaDirectoryException e) {
                 // We're unable to do anything sane here.
                 throw new RuntimeException(e);
             }
 
             profile = sProfileCache.putIfAbsent(profileName, newProfile);
         }
 
@@ -326,53 +301,45 @@ public final class GeckoProfile {
 
         try {
             return profileDir.getCanonicalPath().equals(getGuestDir(context).getCanonicalPath());
         } catch (final IOException e) {
             return false;
         }
     }
 
-    private GeckoProfile(Context context, String profileName, File profileDir, BrowserDB.Factory dbFactory) throws NoMozillaDirectoryException {
+    private GeckoProfile(Context context, String profileName, File profileDir) throws NoMozillaDirectoryException {
         if (profileName == null) {
             throw new IllegalArgumentException("Unable to create GeckoProfile for empty profile name.");
         } else if (CUSTOM_PROFILE.equals(profileName) && profileDir == null) {
             throw new IllegalArgumentException("Custom profile must have a directory");
         }
 
         mApplicationContext = context.getApplicationContext();
         mName = profileName;
         mMozillaDir = GeckoProfileDirectories.getMozillaDirectory(context);
 
         mProfileDir = profileDir;
         if (profileDir != null && !profileDir.isDirectory()) {
             throw new IllegalArgumentException("Profile directory must exist if specified.");
         }
-
-        // N.B., mProfileDir can be null at this point.
-        mDB = dbFactory.get(profileName, mProfileDir);
     }
 
     public static boolean shouldUse(final Context context) {
         return GeckoSharedPrefs.forApp(context).getBoolean(GUEST_MODE_PREF, false);
     }
 
     public static void enter(final Context context) {
         GeckoSharedPrefs.forApp(context).edit().putBoolean(GUEST_MODE_PREF, true).commit();
     }
 
     public static void leave(final Context context) {
         GeckoSharedPrefs.forApp(context).edit().putBoolean(GUEST_MODE_PREF, false).commit();
     }
 
-    @RobocopTarget
-    public BrowserDB getDB() {
-        return mDB;
-    }
-
     private void setDir(File dir) {
         if (dir != null && dir.exists() && dir.isDirectory()) {
             synchronized (this) {
                 mProfileDir = dir;
                 mInGuestMode = null;
             }
         }
     }