package org.chromium.chrome.browser.tabmodel;
+import android.os.SystemClock;
+
import org.chromium.base.CalledByNative;
import org.chromium.base.ObserverList;
import org.chromium.base.TraceEvent;
public abstract class TabModelBase implements TabModel {
private static final String TAG = "TabModelBase";
+ // TODO(dtrainor, simonb): Make these non-static so we don't break if we have multiple instances
+ // of chrome running. Also investigate how this affects document mode.
+ private static long sTabSwitchStartTime;
+ private static TabSelectionType sTabSelectionType;
+ private static boolean sTabSwitchLatencyMetricRequired;
+ private static boolean sPerceivedTabSwitchLatencyMetricLogged;
+
/**
* The main list of tabs. Note that when this changes, all pending closures must be committed
* via {@link #commitAllTabClosures()} as the indices are no longer valid. Also
return mModelDelegate.isSessionRestoreInProgress();
}
+ /**
+ * Register the start of tab switch latency timing. Called when setIndex() indicates a tab
+ * switch event.
+ * @param type The type of action that triggered the tab selection.
+ */
+ public static void startTabSwitchLatencyTiming(final TabSelectionType type) {
+ sTabSwitchStartTime = SystemClock.uptimeMillis();
+ sTabSelectionType = type;
+ sTabSwitchLatencyMetricRequired = false;
+ sPerceivedTabSwitchLatencyMetricLogged = false;
+ }
+
+ /**
+ * Should be called a visible {@link ChromeTab} gets a frame to render in the browser process.
+ * If we don't get this call, we ignore requests to
+ * {@link #flushActualTabSwitchLatencyMetric()}.
+ */
+ public static void setActualTabSwitchLatencyMetricRequired() {
+ if (sTabSwitchStartTime <= 0) return;
+ sTabSwitchLatencyMetricRequired = true;
+ }
+
+ /**
+ * Logs the perceived tab switching latency metric. This will automatically be logged if
+ * the actual metric is set and flushed.
+ */
+ public static void logPerceivedTabSwitchLatencyMetric() {
+ if (sTabSwitchStartTime <= 0 || sPerceivedTabSwitchLatencyMetricLogged) return;
+
+ flushTabSwitchLatencyMetric(true);
+ sPerceivedTabSwitchLatencyMetricLogged = true;
+ }
+
+ /**
+ * Flush the latency metric if called after the indication that a frame is ready.
+ */
+ public static void flushActualTabSwitchLatencyMetric() {
+ if (sTabSwitchStartTime <= 0 || !sTabSwitchLatencyMetricRequired) return;
+ logPerceivedTabSwitchLatencyMetric();
+ flushTabSwitchLatencyMetric(false);
+
+ sTabSwitchStartTime = 0;
+ sTabSwitchLatencyMetricRequired = false;
+ }
+
+ private static void flushTabSwitchLatencyMetric(boolean perceived) {
+ if (sTabSwitchStartTime <= 0) return;
+ final long ms = SystemClock.uptimeMillis() - sTabSwitchStartTime;
+ switch (sTabSelectionType) {
+ case FROM_CLOSE:
+ nativeLogFromCloseMetric(ms, perceived);
+ break;
+ case FROM_EXIT:
+ nativeLogFromExitMetric(ms, perceived);
+ break;
+ case FROM_NEW:
+ nativeLogFromNewMetric(ms, perceived);
+ break;
+ case FROM_USER:
+ nativeLogFromUserMetric(ms, perceived);
+ break;
+ }
+ }
+
private native long nativeInit(boolean isIncognito);
private native void nativeDestroy(long nativeTabModelBase);
private native void nativeBroadcastSessionRestoreComplete(long nativeTabModelBase);
private native Profile nativeGetProfileAndroid(long nativeTabModelBase);
private native void nativeTabAddedToModel(long nativeTabModelBase, Tab tab);
+ // Native methods for tab switch latency metrics.
+ private static native void nativeLogFromCloseMetric(long ms, boolean perceived);
+ private static native void nativeLogFromExitMetric(long ms, boolean perceived);
+ private static native void nativeLogFromNewMetric(long ms, boolean perceived);
+ private static native void nativeLogFromUserMetric(long ms, boolean perceived);
}