Bug 1460045 - Pass module enabled states through init-data; r?esawin
During session initialization, pass in the enabled state of all modules
through the init-data, and use that to enable modules if necessary. This
avoids a race condition where we enable modules too late on startup due
to event queuing.
MozReview-Commit-ID: I0rvq6UoOVh
--- a/mobile/android/chrome/geckoview/geckoview.js
+++ b/mobile/android/chrome/geckoview/geckoview.js
@@ -35,16 +35,17 @@ var ModuleManager = {
this._frozenSettings = Object.freeze(Object.assign({}, this._settings));
const self = this;
this._modules = new Map((function* () {
for (const module of aModules) {
yield [
module.name,
new ModuleInfo({
+ enabled: !!initData.modules[module.name],
manager: self,
...module,
}),
];
}
})());
WindowEventDispatcher.registerListener(this, [
@@ -98,19 +99,27 @@ var ModuleManager = {
const module = this._modules.get(aData.module);
if (module) {
module.enabled = aData.enabled;
}
break;
}
case "GeckoView:UpdateInitData": {
- // Replace all sett_onSettingsUpdateings during a transfer.
+ // Replace all settings during a transfer.
const initData = this._initData;
this._updateSettings(initData.settings);
+
+ // Update module enabled states.
+ for (const name in initData.modules) {
+ const module = this._modules.get(name);
+ if (module) {
+ module.enabled = initData.modules[name];
+ }
+ }
break;
}
case "GeckoView:UpdateSettings": {
this._updateSettings(aData);
break;
}
}
@@ -119,31 +128,34 @@ var ModuleManager = {
/**
* ModuleInfo is the structure used by ModuleManager to represent individual
* modules. It is responsible for loading the module JSM file if necessary,
* and it acts as the intermediary between ModuleManager and the module
* object that extends GeckoViewModule.
*/
class ModuleInfo {
- constructor({manager, name, resource}) {
+ constructor({enabled, manager, name, resource}) {
this._manager = manager;
this._name = name;
const scope = {};
const global = ChromeUtils.import(resource, scope);
const tag = name.replace("GeckoView", "GeckoView.");
GeckoViewUtils.initLogging(tag, global);
this._impl = new scope[name](this);
this._enabled = false;
+ // Only enable once we performed initialization.
+ this._enabledOnInit = enabled;
}
onInit() {
this._impl.onInit();
+ this.enabled = this._enabledOnInit;
}
get manager() {
return this._manager;
}
get name() {
return this._name;
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
@@ -737,18 +737,24 @@ public class GeckoSession extends LayerS
return mWindow != null;
}
/* package */ boolean isReady() {
return mNativeQueue.isReady();
}
private GeckoBundle createInitData() {
- final GeckoBundle initData = new GeckoBundle(1);
+ final GeckoBundle initData = new GeckoBundle(2);
initData.putBundle("settings", mSettings.toBundle());
+
+ final GeckoBundle modules = new GeckoBundle(mSessionHandlers.length);
+ for (final GeckoSessionHandler<?> handler : mSessionHandlers) {
+ modules.putBoolean(handler.getName(), handler.isEnabled());
+ }
+ initData.putBundle("modules", modules);
return initData;
}
/**
* Opens the session.
*
* Call this when you are ready to use a GeckoSession instance.
*
@@ -823,25 +829,16 @@ public class GeckoSession extends LayerS
onWindowChanged(WINDOW_CLOSE, /* inProgress */ false);
}
private void onWindowChanged(int change, boolean inProgress) {
if ((change == WINDOW_OPEN || change == WINDOW_TRANSFER_IN) && !inProgress) {
mTextInput.onWindowChanged(mWindow);
}
-
- if (change == WINDOW_CLOSE) {
- // Detach when window is closing, and reattach immediately after window is closed.
- // We reattach immediate after closing because we want any actions performed while the
- // session is closed to be properly queued, until the session is open again.
- for (final GeckoSessionHandler<?> handler : mSessionHandlers) {
- handler.setSessionIsReady(this, !inProgress);
- }
- }
}
/**
* Get the SessionTextInput instance for this session. May be called on any thread.
*
* @return SessionTextInput instance.
*/
public @NonNull SessionTextInput getTextInput() {
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSessionHandler.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSessionHandler.java
@@ -64,38 +64,42 @@ import android.util.Log;
unregister(session);
}
mDelegate = delegate;
if (!mAlwaysListen && settingNewDelegate) {
register(session);
}
+
+ // If session is not open, we will update module state during session opening.
+ if (!session.isOpen()) {
+ return;
+ }
+
+ final GeckoBundle msg = new GeckoBundle(2);
+ msg.putString("module", mModuleName);
+ msg.putBoolean("enabled", isEnabled());
+ session.getEventDispatcher().dispatch("GeckoView:UpdateModuleState", msg);
}
private void unregister(final GeckoSession session) {
- setSessionIsReady(session, /* ready */ false);
session.getEventDispatcher().unregisterUiThreadListener(this, mEvents);
}
private void register(final GeckoSession session) {
session.getEventDispatcher().registerUiThreadListener(this, mEvents);
- setSessionIsReady(session, /* ready */ true);
}
- public void setSessionIsReady(final GeckoSession session, final boolean ready) {
- // If not enabled, we don't need Gecko to register/unregister.
- if (!mAlwaysListen && mDelegate == null) {
- return;
- }
+ public String getName() {
+ return mModuleName;
+ }
- final GeckoBundle msg = new GeckoBundle(2);
- msg.putString("module", mModuleName);
- msg.putBoolean("enabled", ready);
- session.getEventDispatcher().dispatch("GeckoView:UpdateModuleState", msg);
+ public boolean isEnabled() {
+ return mDelegate != null;
}
@Override
public void handleMessage(final String event, final GeckoBundle message,
final EventCallback callback) {
if (DEBUG) {
Log.d(LOGTAG, mModuleName + " handleMessage: event = " + event);
}