summaryrefslogtreecommitdiff
path: root/chromium/components/module_installer
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2019-08-30 10:22:43 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2019-08-30 12:36:28 +0000
commit271a6c3487a14599023a9106329505597638d793 (patch)
treee040d58ffc86c1480b79ca8528020ca9ec919bf8 /chromium/components/module_installer
parent7b2ffa587235a47d4094787d72f38102089f402a (diff)
downloadqtwebengine-chromium-271a6c3487a14599023a9106329505597638d793.tar.gz
BASELINE: Update Chromium to 77.0.3865.59
Change-Id: I1e89a5f3b009a9519a6705102ad65c92fe736f21 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/components/module_installer')
-rw-r--r--chromium/components/module_installer/OWNERS1
-rw-r--r--chromium/components/module_installer/android/BUILD.gn13
-rw-r--r--chromium/components/module_installer/android/java/src-common/org/chromium/components/module_installer/Module.java16
-rw-r--r--chromium/components/module_installer/android/java/src-common/org/chromium/components/module_installer/ModuleInstaller.java63
-rw-r--r--chromium/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/FakeModuleInstallerBackend.java4
-rw-r--r--chromium/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/ModuleInstallerImpl.java (renamed from chromium/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/ModuleInstaller.java)107
-rw-r--r--chromium/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java6
-rw-r--r--chromium/components/module_installer/android/java/src-stub/org/chromium/components/module_installer/ModuleInstaller.java36
-rw-r--r--chromium/components/module_installer/android/java/src-stub/org/chromium/components/module_installer/ModuleInstallerImpl.java35
-rw-r--r--chromium/components/module_installer/android/java/src-test/org/chromium/components/module_installer/ModuleInstaller.java39
-rw-r--r--chromium/components/module_installer/android/javatests/src/org/chromium/components/module_installer/ModuleInstallerRule.java33
11 files changed, 202 insertions, 151 deletions
diff --git a/chromium/components/module_installer/OWNERS b/chromium/components/module_installer/OWNERS
index b18865e9e42..9fac46f8fb0 100644
--- a/chromium/components/module_installer/OWNERS
+++ b/chromium/components/module_installer/OWNERS
@@ -1,2 +1,3 @@
agrieve@chromium.org
tiborg@chromium.org
+# COMPONENT: Mobile>FeatureModules
diff --git a/chromium/components/module_installer/android/BUILD.gn b/chromium/components/module_installer/android/BUILD.gn
index e781862bd76..41d2ab4c02a 100644
--- a/chromium/components/module_installer/android/BUILD.gn
+++ b/chromium/components/module_installer/android/BUILD.gn
@@ -10,11 +10,12 @@ import("//build/config/android/rules.gni")
# build.
android_library("module_installer_java") {
java_files = [
- "java/src-stub/org/chromium/components/module_installer/ModuleInstaller.java",
+ "java/src-stub/org/chromium/components/module_installer/ModuleInstallerImpl.java",
+ "java/src-common/org/chromium/components/module_installer/ModuleInstaller.java",
"java/src-common/org/chromium/components/module_installer/OnModuleInstallFinishedListener.java",
"java/src-common/org/chromium/components/module_installer/Module.java",
]
- jar_excluded_patterns = [ "*/ModuleInstaller.class" ]
+ jar_excluded_patterns = [ "*/ModuleInstallerImpl.class" ]
deps = [
"//base:base_java",
]
@@ -24,7 +25,7 @@ android_library("module_installer_java") {
# Contains stub implementation to be used for builds not supporting modules
# (e.g. APKs).
android_library("module_installer_stub_java") {
- java_files = [ "java/src-stub/org/chromium/components/module_installer/ModuleInstaller.java" ]
+ java_files = [ "java/src-stub/org/chromium/components/module_installer/ModuleInstallerImpl.java" ]
deps = [
":module_installer_java",
"//base:base_java",
@@ -36,7 +37,7 @@ android_library("module_installer_stub_java") {
# bundles).
android_library("module_installer_impl_java") {
java_files = [
- "java/src-impl/org/chromium/components/module_installer/ModuleInstaller.java",
+ "java/src-impl/org/chromium/components/module_installer/ModuleInstallerImpl.java",
"java/src-impl/org/chromium/components/module_installer/ModuleInstallerBackend.java",
"java/src-impl/org/chromium/components/module_installer/FakeModuleInstallerBackend.java",
"java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java",
@@ -50,10 +51,12 @@ android_library("module_installer_impl_java") {
}
android_library("module_installer_test_java") {
- java_files = [ "java/src-test/org/chromium/components/module_installer/ModuleInstaller.java" ]
+ testonly = true
+ java_files = [ "javatests/src/org/chromium/components/module_installer/ModuleInstallerRule.java" ]
deps = [
":module_installer_java",
"//base:base_java",
+ "//third_party/junit",
]
jacoco_never_instrument = true
}
diff --git a/chromium/components/module_installer/android/java/src-common/org/chromium/components/module_installer/Module.java b/chromium/components/module_installer/android/java/src-common/org/chromium/components/module_installer/Module.java
index fd7a492f3a6..ccd6e5ab591 100644
--- a/chromium/components/module_installer/android/java/src-common/org/chromium/components/module_installer/Module.java
+++ b/chromium/components/module_installer/android/java/src-common/org/chromium/components/module_installer/Module.java
@@ -55,8 +55,8 @@ public class Module<T> {
if (mImpl != null) return true;
// Accessing classes in the module may cause its DEX file to be loaded. And on some devices
// that causes a read mode violation.
- try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
- ModuleInstaller.init();
+ try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) {
+ ModuleInstaller.getInstance().init();
Class.forName(mImplClassName);
return true;
} catch (ClassNotFoundException e) {
@@ -64,18 +64,18 @@ public class Module<T> {
}
}
- /** Requests install of the module. See {@link ModuleInstaller#install} for more details. */
+ /** Requests install of the module. See {@link ModuleInstallerImpl#install} for more details. */
public void install(OnModuleInstallFinishedListener onFinishedListener) {
assert !isInstalled();
- ModuleInstaller.install(mName, onFinishedListener);
+ ModuleInstaller.getInstance().install(mName, onFinishedListener);
}
/**
- * Requests deferred install of the module. See {@link ModuleInstaller#installDeferred} for
+ * Requests deferred install of the module. See {@link ModuleInstallerImpl#installDeferred} for
* more details.
*/
public void installDeferred() {
- ModuleInstaller.installDeferred(mName);
+ ModuleInstaller.getInstance().installDeferred(mName);
}
/**
@@ -85,10 +85,10 @@ public class Module<T> {
public T getImpl() {
assert isInstalled();
if (mImpl == null) {
- ModuleInstaller.init();
+ ModuleInstaller.getInstance().init();
// Accessing classes in the module may cause its DEX file to be loaded. And on some
// devices that causes a read mode violation.
- try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
+ try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) {
mImpl = mInterfaceClass.cast(Class.forName(mImplClassName).newInstance());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
| IllegalArgumentException e) {
diff --git a/chromium/components/module_installer/android/java/src-common/org/chromium/components/module_installer/ModuleInstaller.java b/chromium/components/module_installer/android/java/src-common/org/chromium/components/module_installer/ModuleInstaller.java
new file mode 100644
index 00000000000..b5083a5c6ac
--- /dev/null
+++ b/chromium/components/module_installer/android/java/src-common/org/chromium/components/module_installer/ModuleInstaller.java
@@ -0,0 +1,63 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.module_installer;
+
+import android.content.Context;
+
+import org.chromium.base.VisibleForTesting;
+
+/**
+ * This interface contains all the necessary methods to orchestrate the installation of dynamic
+ * feature modules (DFMs).
+ */
+public interface ModuleInstaller {
+ /** Returns the singleton instance from the correct implementation. */
+ static ModuleInstaller getInstance() {
+ return ModuleInstallerImpl.getInstance();
+ }
+
+ @VisibleForTesting
+ static void setInstanceForTesting(ModuleInstaller moduleInstaller) {
+ ModuleInstallerImpl.setInstanceForTesting(moduleInstaller);
+ }
+
+ /** Needs to be called before trying to access a module. */
+ default void init() {}
+
+ /**
+ * Needs to be called in attachBaseContext of the activities that want to have access to
+ * splits prior to application restart.
+ *
+ * For details, see:
+ * https://developer.android.com/reference/com/google/android/play/core/splitcompat/SplitCompat.html#install(android.content.Context)
+ */
+ default void initActivity(Context context) {}
+
+ /**
+ * Records via UMA all modules that have been requested and are currently installed. The intent
+ * is to measure the install penetration of each module.
+ */
+ default void recordModuleAvailability() {}
+
+ /** Writes fully installed and emulated modules to crash keys. */
+ default void updateCrashKeys() {}
+
+ /**
+ * Requests the install of a module. The install will be performed asynchronously.
+ *
+ * @param moduleName Name of the module as defined in GN.
+ * @param onFinishedListener Listener to be called once installation is finished.
+ */
+ default void install(String moduleName, OnModuleInstallFinishedListener onFinishedListener) {}
+
+ /**
+ * Asynchronously installs module in the background when on unmetered connection and charging.
+ * Install is best effort and may fail silently. Upon success, the module will only be available
+ * after Chrome restarts.
+ *
+ * @param moduleName Name of the module.
+ */
+ default void installDeferred(String moduleName) {}
+}
diff --git a/chromium/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/FakeModuleInstallerBackend.java b/chromium/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/FakeModuleInstallerBackend.java
index dae242dc9b5..9bc39a7b1bf 100644
--- a/chromium/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/FakeModuleInstallerBackend.java
+++ b/chromium/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/FakeModuleInstallerBackend.java
@@ -70,7 +70,7 @@ class FakeModuleInstallerBackend extends ModuleInstallerBackend {
private boolean installInternal(String moduleName) {
Context context = ContextUtils.getApplicationContext();
- int versionCode = BuildInfo.getInstance().versionCode;
+ long versionCode = BuildInfo.getInstance().versionCode;
// Get list of all files at path where SplitCompat looks for downloaded modules.
// May change in future releases of the Play Core SDK.
@@ -102,7 +102,7 @@ class FakeModuleInstallerBackend extends ModuleInstallerBackend {
if (srcModuleFileName.endsWith(".apk") && srcModuleFileName.startsWith(moduleName)) {
// Construct destination file corresponding to each source file.
File dstModuleFile = joinPaths(context.getFilesDir().getPath(), "splitcompat",
- Integer.toString(versionCode), "unverified-splits", srcModuleFileName);
+ Long.toString(versionCode), "unverified-splits", srcModuleFileName);
// NOTE: Need to give Chrome storage permission for this to work.
try {
diff --git a/chromium/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/ModuleInstaller.java b/chromium/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/ModuleInstallerImpl.java
index d01bc2c3abd..7e0b24c10ab 100644
--- a/chromium/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/ModuleInstaller.java
+++ b/chromium/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/ModuleInstallerImpl.java
@@ -18,6 +18,7 @@ import org.chromium.base.CommandLine;
import org.chromium.base.ContextUtils;
import org.chromium.base.StrictModeContext;
import org.chromium.base.ThreadUtils;
+import org.chromium.base.annotations.MainDex;
import org.chromium.components.crash.CrashKeyIndex;
import org.chromium.components.crash.CrashKeys;
@@ -30,53 +31,55 @@ import java.util.Set;
import java.util.TreeSet;
/** Installs dynamic feature modules (DFMs). */
-public class ModuleInstaller {
+@MainDex
+public class ModuleInstallerImpl implements ModuleInstaller {
/** Command line switch for activating the fake backend. */
private static final String FAKE_FEATURE_MODULE_INSTALL = "fake-feature-module-install";
- private static final Map<String, List<OnModuleInstallFinishedListener>> sModuleNameListenerMap =
+ private static ModuleInstaller sInstance = new ModuleInstallerImpl();
+ private static boolean sAppContextSplitCompatted;
+ private final Map<String, List<OnModuleInstallFinishedListener>> mModuleNameListenerMap =
new HashMap<>();
- private static ModuleInstallerBackend sBackend;
- private static boolean sSplitCompatted;
+ private ModuleInstallerBackend mBackend;
- /** Needs to be called before trying to access a module. */
- public static void init() {
- if (sSplitCompatted) return;
+ /** Returns the singleton instance. */
+ public static ModuleInstaller getInstance() {
+ return sInstance;
+ }
+
+ public static void setInstanceForTesting(ModuleInstaller moduleInstaller) {
+ sInstance = moduleInstaller;
+ }
+
+ @Override
+ public void init() {
+ if (sAppContextSplitCompatted) return;
// SplitCompat.install may copy modules into Chrome's internal folder or clean them up.
- try (StrictModeContext unused = StrictModeContext.allowDiskWrites()) {
+ try (StrictModeContext ignored = StrictModeContext.allowDiskWrites()) {
SplitCompat.install(ContextUtils.getApplicationContext());
- sSplitCompatted = true;
+ sAppContextSplitCompatted = true;
}
// SplitCompat.install may add emulated modules. Thus, update crash keys.
updateCrashKeys();
}
- /**
- * Needs to be called in attachBaseContext of the activities that want to have access to
- * splits prior to application restart.
- *
- * For details, see:
- * https://developer.android.com/reference/com/google/android/play/core/splitcompat/SplitCompat.html#install(android.content.Context)
- */
- public static void initActivity(Context context) {
+ @Override
+ public void initActivity(Context context) {
SplitCompat.install(context);
}
- /**
- * Records via UMA all modules that have been requested and are currently installed. The intent
- * is to measure the install penetration of each module.
- */
- public static void recordModuleAvailability() {
+ @Override
+ public void recordModuleAvailability() {
if (!CommandLine.getInstance().hasSwitch(FAKE_FEATURE_MODULE_INSTALL)) {
PlayCoreModuleInstallerBackend.recordModuleAvailability();
}
}
- /** Writes fully installed and emulated modules to crash keys. */
- public static void updateCrashKeys() {
+ @Override
+ public void updateCrashKeys() {
Context context = ContextUtils.getApplicationContext();
// Get modules that are fully installed as split APKs (excluding base which is always
- // intalled). Tree set to have ordered and, thus, deterministic results.
+ // installed). Tree set to have ordered and, thus, deterministic results.
Set<String> fullyInstalledModules = new TreeSet<>();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Split APKs are only supported on Android L+.
@@ -97,7 +100,7 @@ public class ModuleInstaller {
// emulation of later modules won't work. If splitcompat has not been called no modules are
// emulated. Therefore, use an empty set in that case.
Set<String> emulatedModules = new TreeSet<>();
- if (sSplitCompatted) {
+ if (sAppContextSplitCompatted) {
emulatedModules.addAll(
SplitInstallManagerFactory.create(context).getInstalledModules());
emulatedModules.removeAll(fullyInstalledModules);
@@ -109,21 +112,15 @@ public class ModuleInstaller {
CrashKeyIndex.EMULATED_MODULES, encodeCrashKeyValue(emulatedModules));
}
- /**
- * Requests the install of a module. The install will be performed asynchronously.
- *
- * @param moduleName Name of the module as defined in GN.
- * @param onFinishedListener Listener to be called once installation is finished.
- */
- public static void install(
- String moduleName, OnModuleInstallFinishedListener onFinishedListener) {
+ @Override
+ public void install(String moduleName, OnModuleInstallFinishedListener onFinishedListener) {
ThreadUtils.assertOnUiThread();
- if (!sModuleNameListenerMap.containsKey(moduleName)) {
- sModuleNameListenerMap.put(moduleName, new LinkedList<>());
+ if (!mModuleNameListenerMap.containsKey(moduleName)) {
+ mModuleNameListenerMap.put(moduleName, new LinkedList<>());
}
List<OnModuleInstallFinishedListener> onFinishedListeners =
- sModuleNameListenerMap.get(moduleName);
+ mModuleNameListenerMap.get(moduleName);
onFinishedListeners.add(onFinishedListener);
if (onFinishedListeners.size() > 1) {
// Request is already running.
@@ -132,56 +129,50 @@ public class ModuleInstaller {
getBackend().install(moduleName);
}
- /**
- * Asynchronously installs module in the background when on unmetered connection and charging.
- * Install is best effort and may fail silently. Upon success, the module will only be available
- * after Chrome restarts.
- *
- * @param moduleName Name of the module.
- */
- public static void installDeferred(String moduleName) {
+ @Override
+ public void installDeferred(String moduleName) {
ThreadUtils.assertOnUiThread();
getBackend().installDeferred(moduleName);
}
- private static void onFinished(boolean success, List<String> moduleNames) {
+ private void onFinished(boolean success, List<String> moduleNames) {
ThreadUtils.assertOnUiThread();
for (String moduleName : moduleNames) {
List<OnModuleInstallFinishedListener> onFinishedListeners =
- sModuleNameListenerMap.get(moduleName);
+ mModuleNameListenerMap.get(moduleName);
if (onFinishedListeners == null) continue;
for (OnModuleInstallFinishedListener listener : onFinishedListeners) {
listener.onFinished(success);
}
- sModuleNameListenerMap.remove(moduleName);
+ mModuleNameListenerMap.remove(moduleName);
}
- if (sModuleNameListenerMap.isEmpty()) {
- sBackend.close();
- sBackend = null;
+ if (mModuleNameListenerMap.isEmpty()) {
+ mBackend.close();
+ mBackend = null;
}
updateCrashKeys();
}
- private static ModuleInstallerBackend getBackend() {
- if (sBackend == null) {
- ModuleInstallerBackend.OnFinishedListener listener = ModuleInstaller::onFinished;
- sBackend = CommandLine.getInstance().hasSwitch(FAKE_FEATURE_MODULE_INSTALL)
+ private ModuleInstallerBackend getBackend() {
+ if (mBackend == null) {
+ ModuleInstallerBackend.OnFinishedListener listener = this::onFinished;
+ mBackend = CommandLine.getInstance().hasSwitch(FAKE_FEATURE_MODULE_INSTALL)
? new FakeModuleInstallerBackend(listener)
: new PlayCoreModuleInstallerBackend(listener);
}
- return sBackend;
+ return mBackend;
}
- private static String encodeCrashKeyValue(Set<String> moduleNames) {
+ private String encodeCrashKeyValue(Set<String> moduleNames) {
if (moduleNames.isEmpty()) return "<none>";
// Values with dots are interpreted as URLs. Some module names have dots in them. Make sure
// they don't get sanitized.
return TextUtils.join(",", moduleNames).replace('.', '$');
}
- private ModuleInstaller() {}
+ private ModuleInstallerImpl() {}
}
diff --git a/chromium/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java b/chromium/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java
index cee192c177d..b64387c4516 100644
--- a/chromium/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java
+++ b/chromium/components/module_installer/android/java/src-impl/org/chromium/components/module_installer/PlayCoreModuleInstallerBackend.java
@@ -20,7 +20,6 @@ import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
import org.chromium.base.metrics.CachedMetrics.EnumeratedHistogramSample;
import org.chromium.base.metrics.RecordHistogram;
-import org.chromium.components.module_installer.ModuleInstallerBackend.OnFinishedListener;
import java.util.Collections;
import java.util.HashMap;
@@ -93,7 +92,7 @@ import java.util.Set;
/** Records via UMA all modules that have been requested and are currently installed. */
public static void recordModuleAvailability() {
// MUST call init before creating a SplitInstallManager.
- ModuleInstaller.init();
+ ModuleInstaller.getInstance().init();
SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
Set<String> requestedModules = new HashSet<>();
requestedModules.addAll(
@@ -128,7 +127,7 @@ import java.util.Set;
public PlayCoreModuleInstallerBackend(OnFinishedListener listener) {
super(listener);
// MUST call init before creating a SplitInstallManager.
- ModuleInstaller.init();
+ ModuleInstaller.getInstance().init();
mManager = SplitInstallManagerFactory.create(ContextUtils.getApplicationContext());
mManager.registerListener(this);
}
@@ -179,6 +178,7 @@ import java.util.Set;
@Override
public void onStateUpdate(SplitInstallSessionState state) {
assert !mIsClosed;
+ Log.i(TAG, "Status for modules '%s' updated to %d", state.moduleNames(), state.status());
switch (state.status()) {
case SplitInstallSessionStatus.DOWNLOADING:
case SplitInstallSessionStatus.INSTALLING:
diff --git a/chromium/components/module_installer/android/java/src-stub/org/chromium/components/module_installer/ModuleInstaller.java b/chromium/components/module_installer/android/java/src-stub/org/chromium/components/module_installer/ModuleInstaller.java
deleted file mode 100644
index f88b9ca3486..00000000000
--- a/chromium/components/module_installer/android/java/src-stub/org/chromium/components/module_installer/ModuleInstaller.java
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.module_installer;
-
-import android.content.Context;
-
-import org.chromium.base.VisibleForTesting;
-
-/** Dummy fallback of ModuleInstaller for APK builds. */
-public class ModuleInstaller {
- public static void init() {}
-
- public static void initActivity(Context context) {}
-
- public static void recordModuleAvailability() {}
-
- public static void updateCrashKeys(){};
-
- public static void install(
- String moduleName, OnModuleInstallFinishedListener onFinishedListener) {
- throw new UnsupportedOperationException("Cannot install module if APK");
- }
-
- public static void installDeferred(String moduleName) {
- throw new UnsupportedOperationException("Cannot deferred install module if APK");
- }
-
- @VisibleForTesting
- public static boolean didRequestDeferred(String moduleName) {
- throw new UnsupportedOperationException();
- }
-
- private ModuleInstaller() {}
-}
diff --git a/chromium/components/module_installer/android/java/src-stub/org/chromium/components/module_installer/ModuleInstallerImpl.java b/chromium/components/module_installer/android/java/src-stub/org/chromium/components/module_installer/ModuleInstallerImpl.java
new file mode 100644
index 00000000000..25654c30cba
--- /dev/null
+++ b/chromium/components/module_installer/android/java/src-stub/org/chromium/components/module_installer/ModuleInstallerImpl.java
@@ -0,0 +1,35 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.module_installer;
+
+import org.chromium.base.annotations.MainDex;
+
+/** Dummy fallback of ModuleInstaller for APK builds. */
+@MainDex
+public class ModuleInstallerImpl implements ModuleInstaller {
+ /** A valid singleton instance is necessary for tests to swap it out. */
+ private static ModuleInstaller sInstance = new ModuleInstallerImpl();
+
+ /** Returns the singleton instance. */
+ public static ModuleInstaller getInstance() {
+ return sInstance;
+ }
+
+ public static void setInstanceForTesting(ModuleInstaller moduleInstaller) {
+ sInstance = moduleInstaller;
+ }
+
+ @Override
+ public void install(String moduleName, OnModuleInstallFinishedListener onFinishedListener) {
+ throw new UnsupportedOperationException("Cannot install module if APK");
+ }
+
+ @Override
+ public void installDeferred(String moduleName) {
+ throw new UnsupportedOperationException("Cannot deferred install module if APK");
+ }
+
+ private ModuleInstallerImpl() {}
+}
diff --git a/chromium/components/module_installer/android/java/src-test/org/chromium/components/module_installer/ModuleInstaller.java b/chromium/components/module_installer/android/java/src-test/org/chromium/components/module_installer/ModuleInstaller.java
deleted file mode 100644
index 02b8519a6b2..00000000000
--- a/chromium/components/module_installer/android/java/src-test/org/chromium/components/module_installer/ModuleInstaller.java
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.components.module_installer;
-
-import android.content.Context;
-
-import org.chromium.base.VisibleForTesting;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/** Mock ModuleInstaller for use in tests. */
-public class ModuleInstaller {
- private static Set<String> sModulesRequestedDeffered = new HashSet<>();
-
- public static void init() {}
-
- public static void initActivity(Context context) {}
-
- public static void recordModuleAvailability() {}
-
- public static void updateCrashKeys(){};
-
- public static void install(
- String moduleName, OnModuleInstallFinishedListener onFinishedListener) {}
-
- public static void installDeferred(String moduleName) {
- sModulesRequestedDeffered.add(moduleName);
- }
-
- @VisibleForTesting
- public static boolean didRequestDeferred(String moduleName) {
- return sModulesRequestedDeffered.contains(moduleName);
- }
-
- private ModuleInstaller() {}
-}
diff --git a/chromium/components/module_installer/android/javatests/src/org/chromium/components/module_installer/ModuleInstallerRule.java b/chromium/components/module_installer/android/javatests/src/org/chromium/components/module_installer/ModuleInstallerRule.java
new file mode 100644
index 00000000000..f9a9418f097
--- /dev/null
+++ b/chromium/components/module_installer/android/javatests/src/org/chromium/components/module_installer/ModuleInstallerRule.java
@@ -0,0 +1,33 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.module_installer;
+
+import org.junit.rules.ExternalResource;
+
+/**
+ * This rule allows the caller to specify their own {@link ModuleInstaller} for the duration of the
+ * test and resets it back to what it was before.
+ *
+ * TODO(wnwen): This should eventually become ModuleConfigRule.
+ */
+public class ModuleInstallerRule extends ExternalResource {
+ private ModuleInstaller mOldModuleInstaller;
+ private final ModuleInstaller mMockModuleInstaller;
+
+ public ModuleInstallerRule(ModuleInstaller mockModuleInstaller) {
+ mMockModuleInstaller = mockModuleInstaller;
+ }
+
+ @Override
+ protected void before() {
+ mOldModuleInstaller = ModuleInstaller.getInstance();
+ ModuleInstaller.setInstanceForTesting(mMockModuleInstaller);
+ }
+
+ @Override
+ protected void after() {
+ ModuleInstaller.setInstanceForTesting(mOldModuleInstaller);
+ }
+}