blob: 1c8971aa001160df2d78471dbb4fa6c27b07c8ee [file] [log] [blame]
// Copyright 2020 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.chrome.browser.optimization_guide;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.ThreadUtils;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.components.optimization_guide.OptimizationGuideDecision;
import org.chromium.components.optimization_guide.proto.HintsProto.OptimizationType;
import org.chromium.components.optimization_guide.proto.ModelsProto.OptimizationTarget;
import org.chromium.components.optimization_guide.proto.PerformanceHintsMetadataProto.PerformanceHintsMetadata;
import org.chromium.content_public.browser.NavigationHandle;
import java.util.ArrayList;
import java.util.List;
/**
* Provides access to the optimization guide using the C++ OptimizationGuideKeyedService.
*
* An instance of this class must be created, used, and destroyed on the UI thread.
*/
@JNINamespace("optimization_guide::android")
public class OptimizationGuideBridge {
private long mNativeOptimizationGuideBridge;
/**
* Interface to implement to receive decisions from the optimization guide.
*/
public interface OptimizationGuideCallback {
void onOptimizationGuideDecision(
@OptimizationGuideDecision int decision, @Nullable OptimizationMetadata metadata);
}
/**
* Initializes the C++ side of this class, using the Optimization Guide Decider for the last
* used Profile.
*/
public OptimizationGuideBridge() {
ThreadUtils.assertOnUiThread();
mNativeOptimizationGuideBridge = OptimizationGuideBridgeJni.get().init();
}
@VisibleForTesting
protected OptimizationGuideBridge(long nativeOptimizationGuideBridge) {
mNativeOptimizationGuideBridge = nativeOptimizationGuideBridge;
}
/**
* Deletes the C++ side of this class. This must be called when this object is no longer needed.
*/
public void destroy() {
ThreadUtils.assertOnUiThread();
if (mNativeOptimizationGuideBridge != 0) {
OptimizationGuideBridgeJni.get().destroy(mNativeOptimizationGuideBridge);
mNativeOptimizationGuideBridge = 0;
}
}
/**
* Registers the optimization types and targets that intend to be queried
* during the session. It is expected for this to be called after the
* browser has been initialized.
*/
public void registerOptimizationTypesAndTargets(
@Nullable List<OptimizationType> optimizationTypes,
@Nullable List<OptimizationTarget> optimizationTargets) {
ThreadUtils.assertOnUiThread();
assert optimizationTypes != null || optimizationTargets != null;
if (mNativeOptimizationGuideBridge == 0) return;
if (optimizationTypes == null) {
optimizationTypes = new ArrayList<>();
}
int[] intOptimizationTypes = new int[optimizationTypes.size()];
for (int i = 0; i < optimizationTypes.size(); i++) {
intOptimizationTypes[i] = optimizationTypes.get(i).getNumber();
}
if (optimizationTargets == null) {
optimizationTargets = new ArrayList<>();
}
int[] intOptimizationTargets = new int[optimizationTargets.size()];
for (int i = 0; i < optimizationTargets.size(); i++) {
intOptimizationTargets[i] = optimizationTargets.get(i).getNumber();
}
OptimizationGuideBridgeJni.get().registerOptimizationTypesAndTargets(
mNativeOptimizationGuideBridge, intOptimizationTypes, intOptimizationTargets);
}
/**
* Invokes {@link callback} with the decision for the URL associated with {@link
* navigationHandle} and {@link optimizationType} when sufficient information has been
* collected to make a decision. This should only be called for main frame navigations.
*/
public void canApplyOptimization(NavigationHandle navigationHandle,
OptimizationType optimizationType, OptimizationGuideCallback callback) {
ThreadUtils.assertOnUiThread();
assert navigationHandle.isInMainFrame();
if (mNativeOptimizationGuideBridge == 0) {
callback.onOptimizationGuideDecision(OptimizationGuideDecision.FALSE, null);
return;
}
OptimizationGuideBridgeJni.get().canApplyOptimization(mNativeOptimizationGuideBridge,
navigationHandle.getUrl(), optimizationType.getNumber(), callback);
}
@CalledByNative
private static void onOptimizationGuideDecision(OptimizationGuideCallback callback,
@OptimizationGuideDecision int optimizationGuideDecision, Object optimizationMetadata) {
callback.onOptimizationGuideDecision(
optimizationGuideDecision, (OptimizationMetadata) optimizationMetadata);
}
@CalledByNative
private static OptimizationMetadata createOptimizationMetadataWithPerformanceHintsMetadata(
byte[] serializedPerformanceHintsMetadata) {
OptimizationMetadata optimizationMetadata = new OptimizationMetadata();
try {
optimizationMetadata.setPerformanceHintsMetadata(
PerformanceHintsMetadata.parseFrom(serializedPerformanceHintsMetadata));
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
return null;
}
return optimizationMetadata;
}
@NativeMethods
interface Natives {
long init();
void destroy(long nativeOptimizationGuideBridge);
void registerOptimizationTypesAndTargets(long nativeOptimizationGuideBridge,
int[] optimizationTypes, int[] optimizationTargets);
void canApplyOptimization(long nativeOptimizationGuideBridge, String url,
int optimizationType, OptimizationGuideCallback callback);
}
}