blob: 18ee5fd2104b613f97737c4cec6454258c65e90d [file] [log] [blame]
// 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 com.google.android.play.core.splitinstall.SplitInstallManager;
import com.google.android.play.core.splitinstall.SplitInstallManagerFactory;
import com.google.android.play.core.splitinstall.SplitInstallRequest;
import com.google.android.play.core.splitinstall.SplitInstallSessionState;
import com.google.android.play.core.splitinstall.SplitInstallStateUpdatedListener;
import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus;
import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.components.module_installer.ModuleInstallerBackend.OnFinishedListener;
import java.util.Collections;
import java.util.List;
/**
* Backend that uses the Play Core SDK to download a module from Play and install it subsequently.
*/
/* package */ class PlayCoreModuleInstallerBackend
extends ModuleInstallerBackend implements SplitInstallStateUpdatedListener {
private static final String TAG = "PlayCoreModInBackend";
private final SplitInstallManager mManager;
private boolean mIsClosed;
// FeatureModuleInstallStatus defined in //tools/metrics/histograms/enums.xml.
// These values are persisted to logs. Entries should not be renumbered and numeric values
// should never be reused.
private static final int INSTALL_STATUS_SUCCESS = 0;
private static final int INSTALL_STATUS_FAILURE = 1;
private static final int INSTALL_STATUS_REQUEST_ERROR = 2;
private static final int INSTALL_STATUS_CANCELLATION = 3;
// Keep this one at the end and increment appropriately when adding new status.
private static final int INSTALL_STATUS_COUNT = 4;
public PlayCoreModuleInstallerBackend(OnFinishedListener listener) {
super(listener);
mManager = SplitInstallManagerFactory.create(ContextUtils.getApplicationContext());
mManager.registerListener(this);
}
@Override
public void install(String moduleName) {
assert !mIsClosed;
SplitInstallRequest request =
SplitInstallRequest.newBuilder().addModule(moduleName).build();
mManager.startInstall(request).addOnFailureListener(errorCode -> {
Log.e(TAG, "Failed to request module '%s': error code %s", moduleName, errorCode);
// If we reach this error condition |onStateUpdate| won't be called. Thus, call
// |onFinished| here.
finish(false, Collections.singletonList(moduleName), INSTALL_STATUS_REQUEST_ERROR);
});
}
@Override
public void installDeferred(String moduleName) {
assert !mIsClosed;
mManager.deferredInstall(Collections.singletonList(moduleName));
}
@Override
public void close() {
assert !mIsClosed;
mManager.unregisterListener(this);
mIsClosed = true;
}
@Override
public void onStateUpdate(SplitInstallSessionState state) {
assert !mIsClosed;
switch (state.status()) {
case SplitInstallSessionStatus.INSTALLED:
finish(true, state.moduleNames(), INSTALL_STATUS_SUCCESS);
break;
case SplitInstallSessionStatus.CANCELED:
case SplitInstallSessionStatus.FAILED:
Log.e(TAG, "Failed to install modules '%s': error code %s", state.moduleNames(),
state.status());
int status = state.status() == SplitInstallSessionStatus.CANCELED
? INSTALL_STATUS_CANCELLATION
: INSTALL_STATUS_FAILURE;
finish(false, state.moduleNames(), status);
break;
}
}
private void finish(boolean success, List<String> moduleNames, int eventId) {
for (String name : moduleNames) {
RecordHistogram.recordEnumeratedHistogram(
"Android.FeatureModules.InstallStatus." + name, eventId, INSTALL_STATUS_COUNT);
}
onFinished(success, moduleNames);
}
}