From 3e4088f4b259243ebf41226375e4433db951b8f3 Mon Sep 17 00:00:00 2001 From: Daosheng Mu Date: Tue, 18 Sep 2018 11:00:28 -0700 Subject: [PATCH] Add telemetry for uri count and loading time. --- app/build.gradle | 2 +- .../org/mozilla/vrbrowser/SessionStore.java | 18 +++++ .../vrbrowser/telemetry/TelemetryWrapper.java | 66 ++++++++++++++++++- .../org/mozilla/vrbrowser/utils/UrlUtils.java | 33 ++++++++++ 4 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 app/src/common/shared/org/mozilla/vrbrowser/utils/UrlUtils.java diff --git a/app/build.gradle b/app/build.gradle index 6bc8111d53..8b5d95fbd8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -187,7 +187,7 @@ dependencies { svrImplementation fileTree(dir: "${project.rootDir}/third_party/svr/", include: ['*.jar']) implementation 'com.android.support:design:27.1.1' implementation 'com.google.vr:sdk-audio:1.170.0' - implementation "org.mozilla.components:telemetry:0.10" + implementation "org.mozilla.components:telemetry:0.23" implementation "com.github.mozilla:mozillaspeechlibrary:1.0.4" } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/SessionStore.java b/app/src/common/shared/org/mozilla/vrbrowser/SessionStore.java index c84674ded6..49d7dbf98f 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/SessionStore.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/SessionStore.java @@ -7,6 +7,7 @@ import android.content.Context; import android.graphics.Rect; +import android.os.SystemClock; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; @@ -16,6 +17,8 @@ import org.mozilla.gecko.GeckoAppShell; import org.mozilla.gecko.GeckoProfile; import org.mozilla.geckoview.*; +import org.mozilla.vrbrowser.telemetry.TelemetryWrapper; +import org.mozilla.vrbrowser.utils.UrlUtils; import java.io.File; import java.io.FileNotFoundException; @@ -45,6 +48,8 @@ public static SessionStore get() { private LinkedList mSessionChangeListeners; private LinkedList mTextInputListeners; private LinkedList mPromptListeners; + private final long MIN_LOAD_TIME = 40; + private long startLoadTime = 0; public interface SessionChangeListener { void onNewSession(GeckoSession aSession, int aId); @@ -156,6 +161,13 @@ public void dumpAllState(Integer sessionId) { dumpAllState(getSession(sessionId)); } + private boolean isLocalizedContent(@Nullable String url) { + return url != null && (url.equals("about:blank") + || url.equals(PRIVATE_BROWSING_URI) + || url.equals(HOME_WITHOUT_REGION_ORIGIN) + || url.equals(getHomeUri())); + } + private void dumpAllState(GeckoSession aSession) { for (GeckoSession.NavigationDelegate listener: mNavigationListeners) { dumpState(aSession, listener); @@ -823,6 +835,7 @@ public void onPageStart(GeckoSession aSession, String aUri) { return; } state.mIsLoading = true; + startLoadTime = SystemClock.elapsedRealtime(); for (GeckoSession.ProgressDelegate listener: mProgressListeners) { listener.onPageStart(aSession, aUri); } @@ -837,6 +850,11 @@ public void onPageStop(GeckoSession aSession, boolean b) { } state.mIsLoading = false; + long elapsedLoad = SystemClock.elapsedRealtime() - startLoadTime; + if (elapsedLoad > MIN_LOAD_TIME && !isLocalizedContent(state.mUri)) { + Log.i(LOGTAG, "Sent load to histogram"); + TelemetryWrapper.addLoadToHistogram(state.mUri, elapsedLoad); + } for (GeckoSession.ProgressDelegate listener: mProgressListeners) { listener.onPageStop(aSession, b); } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/telemetry/TelemetryWrapper.java b/app/src/common/shared/org/mozilla/vrbrowser/telemetry/TelemetryWrapper.java index c3407d6222..0d5ba256dc 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/telemetry/TelemetryWrapper.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/telemetry/TelemetryWrapper.java @@ -4,6 +4,8 @@ import android.content.res.Resources; import android.os.StrictMode; import android.support.annotation.UiThread; +import android.util.Log; + import org.mozilla.telemetry.Telemetry; import org.mozilla.telemetry.TelemetryHolder; import org.mozilla.telemetry.config.TelemetryConfiguration; @@ -19,31 +21,51 @@ import org.mozilla.vrbrowser.R; import org.mozilla.vrbrowser.SettingsStore; import org.mozilla.vrbrowser.search.SearchEngine; +import org.mozilla.vrbrowser.utils.UrlUtils; + +import java.net.URI; +import java.util.HashSet; +import static java.lang.Math.toIntExact; public class TelemetryWrapper { private final static String APP_NAME = "FirefoxReality"; + private final static String LOGTAG = "VRB"; + private final static int BUCKET_SIZE_MS = 100; + private final static int HISTOGRAM_MIN_INDEX = 0; + private final static int HISTOGRAM_SIZE = 200; + + private static HashSet domainMap = new HashSet(); + private static int[] histogram = new int[HISTOGRAM_SIZE]; + private static int numUri = 0; private class Category { private static final String ACTION = "action"; + private static final String HISTOGRAM = "histogram"; } private class Method { private static final String FOREGROUND = "foreground"; private static final String BACKGROUND = "background"; + private static final String OPEN = "open"; private static final String TYPE_URL = "type_url"; private static final String TYPE_QUERY = "type_query"; // TODO: Support "select_query" after providing search suggestion. private static final String VOICE_QUERY = "voice_query"; - } private class Object { private static final String APP = "app"; + private static final String BROWSER = "browser"; private static final String SEARCH_BAR = "search_bar"; private static final String VOICE_INPUT = "voice_input"; } + private class Extra { + private static final String TOTAL_URI_COUNT = "total_uri_count"; + private static final String UNIQUE_DOMAINS_COUNT = "unique_domains_count"; + } + // We should call this at the application initial stage. Instead, // it would be called when users turn on/off the setting of telemetry. // e.g., SettingsStore.getInstance(context).setTelemetryEnabled(); @@ -84,6 +106,29 @@ public static void start() { @UiThread public static void stop() { + TelemetryEvent histogramEvent = TelemetryEvent.create(Category.HISTOGRAM, Method.FOREGROUND, Object.BROWSER); + for (int bucketIndex = 0; bucketIndex < histogram.length; ++bucketIndex) { + histogramEvent.extra(Integer.toString(bucketIndex * BUCKET_SIZE_MS), Integer.toString(histogram[bucketIndex])); + } + histogramEvent.queue(); + + // Clear histogram array after queueing it + histogram = new int[HISTOGRAM_SIZE]; + + // We only upload the domain and URI counts to the probes without including + // users' URI info. + TelemetryEvent.create(Category.ACTION, Method.OPEN, Object.BROWSER).extra( + Extra.UNIQUE_DOMAINS_COUNT, + Integer.toString(domainMap.size()) + ).queue(); + domainMap.clear(); + + TelemetryEvent.create(Category.ACTION, Method.OPEN, Object.BROWSER).extra( + Extra.TOTAL_URI_COUNT, + Integer.toString(numUri) + ).queue(); + numUri = 0; + TelemetryEvent.create(Category.ACTION, Method.BACKGROUND, Object.APP).queue(); TelemetryHolder.get().recordSessionEnd(); @@ -129,5 +174,24 @@ private static void browseEvent() { // TODO: Working on autocomplete result. event.queue(); } + + @UiThread + public static void addLoadToHistogram(String uri, Long newLoadTime) { + domainMap.add(UrlUtils.stripCommonSubdomains(URI.create(uri).getHost())); + numUri++; + int histogramLoadIndex = toIntExact(newLoadTime / BUCKET_SIZE_MS); + + if (histogramLoadIndex > (HISTOGRAM_SIZE - 2)) { + histogramLoadIndex = HISTOGRAM_SIZE - 1; + } else if (histogramLoadIndex < HISTOGRAM_MIN_INDEX) { + histogramLoadIndex = HISTOGRAM_MIN_INDEX; + } + + if (histogramLoadIndex >= histogram.length) { + Log.e(LOGTAG, "the histogram size is overflow."); + histogramLoadIndex = histogram.length - 1; + } + histogram[histogramLoadIndex]++; + } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/utils/UrlUtils.java b/app/src/common/shared/org/mozilla/vrbrowser/utils/UrlUtils.java new file mode 100644 index 0000000000..94f277d606 --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/utils/UrlUtils.java @@ -0,0 +1,33 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.vrbrowser.utils; + +import android.support.annotation.Nullable; + + +// This class refers from mozilla-mobile/focus-android +public class UrlUtils { + + public static String stripCommonSubdomains(@Nullable String host) { + if (host == null) { + return null; + } + + // In contrast to desktop, we also strip mobile subdomains, + // since its unlikely users are intentionally typing them + int start = 0; + + if (host.startsWith("www.")) { + start = 4; + } else if (host.startsWith("mobile.")) { + start = 7; + } else if (host.startsWith("m.")) { + start = 2; + } + + return host.substring(start); + } +}