Bug 1123688 - Set BrowserDB factory in application startup, not only for GeckoApp subclasses. r=bnicholson

The issue: only by launching GeckoApp (or a subclass) did we specify what kind of DB we wanted. If we don't specify, we get a StubBrowserDB.

The search activity is not a GeckoApp, but it does implicitly access a profile.

The same is true for Sync: a background Sync would eventually cause the CP to touch GeckoProfile to get the profile directory.

Both of these avenues will poison the GeckoProfile cache, storing a profile with a database member that's a StubBrowserDB.

If you subsequently launched the browser you'd get that GeckoProfile instance from the profile cache. StubBrowserDB deliberately returns null for some queries -- such as getTopSites. That causes us to throw here.

The solution I chose: have *GeckoApplication* specify which kind of DB to use, and then have WebappImpl (the only subclass for which we want different behavior) override it.

GeckoView consumers remain unaffected, because they have their own Application class, and so the usual GeckoProfile fallback applies.
This commit is contained in:
Richard Newman 2015-01-22 20:23:38 -08:00
parent 3a59e47a0a
commit 32b1f4920e
5 changed files with 29 additions and 28 deletions

View File

@ -3270,20 +3270,6 @@ public class BrowserApp extends GeckoApp
return GeckoProfile.getDefaultProfileName(this);
}
// We want a real BrowserDB.
@Override
protected BrowserDB.Factory getBrowserDBFactory() {
return 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);
}
};
}
/**
* Launch UI that lets the user update Firefox.
*

View File

@ -127,14 +127,6 @@ public abstract class GeckoApp
SensorEventListener,
Tabs.OnTabsChangedListener {
protected GeckoApp() {
// We need to do this before any access to the profile; it controls
// which database class is used.
// We thus need to do this before our GeckoView is inflated, because
// GeckoView implicitly accesses the profile.
GeckoProfile.setBrowserDBFactory(getBrowserDBFactory());
}
private static final String LOGTAG = "GeckoApp";
private static final int ONE_DAY_MS = 1000*60*60*24;
@ -238,8 +230,6 @@ public abstract class GeckoApp
return GeckoSharedPrefs.forApp(this);
}
protected abstract BrowserDB.Factory getBrowserDBFactory();
@Override
public Activity getActivity() {
return this;

View File

@ -6,6 +6,7 @@ package org.mozilla.gecko;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.db.LocalBrowserDB;
import org.mozilla.gecko.home.HomePanelsManager;
import org.mozilla.gecko.lwt.LightweightTheme;
import org.mozilla.gecko.mozglue.GeckoLoader;
@ -19,6 +20,8 @@ import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.util.Log;
import java.io.File;
public class GeckoApplication extends Application
implements ContextGetter {
private static final String LOG_TAG = "GeckoApplication";
@ -128,6 +131,26 @@ public class GeckoApplication extends Application
// This getInstance call will force initialization of the NotificationHelper, but does nothing with the result
NotificationHelper.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.
// WebappImpl overrides this on creation.
//
// 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);
}
});
super.onCreate();
}

View File

@ -221,6 +221,8 @@ public final class GeckoProfile {
// 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();
}

View File

@ -14,6 +14,7 @@ import org.json.JSONObject;
import org.mozilla.gecko.GeckoApp;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.GeckoThread;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Tab;
@ -62,14 +63,13 @@ public class WebappImpl extends GeckoApp implements InstallCallback {
@Override
public boolean hasTabsSideBar() { return false; }
@Override
public BrowserDB.Factory getBrowserDBFactory() {
return new BrowserDB.Factory() {
public WebappImpl() {
GeckoProfile.setBrowserDBFactory(new BrowserDB.Factory() {
@Override
public BrowserDB get(String profileName, File profileDir) {
return new StubBrowserDB(profileName);
}
};
});
}
@Override