Bug 1499418 - Refactor and move Fennec's telemetry classes to geckoview/. r=jchen, a=RyanVM GECKOVIEW_64_RELBRANCH
authorEugen Sawin <esawin@mozilla.com>
Tue, 13 Nov 2018 15:29:21 +0100
branchGECKOVIEW_64_RELBRANCH
changeset 501452 26d700d8010a
parent 501451 348872e1c4fe
child 501458 f95d41399777
push id1869
push userryanvm@gmail.com
push dateTue, 04 Dec 2018 21:33:30 +0000
treeherdermozilla-release@26d700d8010a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjchen, RyanVM
bugs1499418
milestone64.0
Bug 1499418 - Refactor and move Fennec's telemetry classes to geckoview/. r=jchen, a=RyanVM
mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
mobile/android/base/java/org/mozilla/gecko/Telemetry.java
mobile/android/base/java/org/mozilla/gecko/TelemetryContract.java
mobile/android/geckoview/src/main/java/org/mozilla/gecko/TelemetryContract.java
mobile/android/geckoview/src/main/java/org/mozilla/gecko/TelemetryUtils.java
widget/android/Telemetry.h
widget/android/fennec/Telemetry.h
widget/android/nsAppShell.cpp
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -313,18 +313,18 @@ public abstract class GeckoApp extends G
                     // so just skip the tab and try the next one.
                 }
             }
         }
     };
 
     protected boolean mInitialized;
     protected boolean mWindowFocusInitialized;
-    private Telemetry.Timer mJavaUiStartupTimer;
-    private Telemetry.Timer mGeckoReadyStartupTimer;
+    private TelemetryUtils.Timer mJavaUiStartupTimer;
+    private TelemetryUtils.Timer mGeckoReadyStartupTimer;
 
     private String mPrivateBrowsingSession;
     private boolean mPrivateBrowsingSessionOutdated;
     private static final int MAX_PRIVATE_TABS_UPDATE_WAIT_MSEC = 500;
 
     private volatile HealthRecorder mHealthRecorder;
     private volatile Locale mLastLocale;
 
@@ -967,18 +967,18 @@ public abstract class GeckoApp extends G
             } else {
                 showSDKVersionError();
             }
             finish();
             return;
         }
 
         // The clock starts...now. Better hurry!
-        mJavaUiStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_JAVAUI");
-        mGeckoReadyStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_GECKOREADY");
+        mJavaUiStartupTimer = new TelemetryUtils.UptimeTimer("FENNEC_STARTUP_TIME_JAVAUI");
+        mGeckoReadyStartupTimer = new TelemetryUtils.UptimeTimer("FENNEC_STARTUP_TIME_GECKOREADY");
 
         final SafeIntent intent = new SafeIntent(getIntent());
 
         earlyStartJavaSampler(intent);
 
         // Workaround for <http://code.google.com/p/android/issues/detail?id=20915>.
         try {
             Class.forName("android.os.AsyncTask");
--- a/mobile/android/base/java/org/mozilla/gecko/Telemetry.java
+++ b/mobile/android/base/java/org/mozilla/gecko/Telemetry.java
@@ -8,219 +8,91 @@ package org.mozilla.gecko;
 import org.mozilla.gecko.annotation.RobocopTarget;
 import org.mozilla.gecko.annotation.WrapForJNI;
 import org.mozilla.gecko.TelemetryContract.Event;
 import org.mozilla.gecko.TelemetryContract.Method;
 import org.mozilla.gecko.TelemetryContract.Reason;
 import org.mozilla.gecko.TelemetryContract.Session;
 import org.mozilla.gecko.mma.MmaDelegate;
 
-import android.os.SystemClock;
 import android.util.Log;
 
 import static org.mozilla.gecko.mma.MmaDelegate.INTERACT_WITH_SEARCH_URL_AREA;
 import static org.mozilla.gecko.mma.MmaDelegate.OPENED_BOOKMARK;
 import static org.mozilla.gecko.mma.MmaDelegate.SAVED_BOOKMARK;
 import static org.mozilla.gecko.mma.MmaDelegate.SAVED_LOGIN_AND_PASSWORD;
 import static org.mozilla.gecko.mma.MmaDelegate.SCREENSHOT;
 
 
-/**
- * All telemetry times are relative to one of two clocks:
- *
- * * Real time since the device was booted, including deep sleep. Use this
- *   as a substitute for wall clock.
- * * Uptime since the device was booted, excluding deep sleep. Use this to
- *   avoid timing a user activity when their phone is in their pocket!
- *
- * The majority of methods in this class are defined in terms of real time.
- */
 @RobocopTarget
 public class Telemetry {
     private static final String LOGTAG = "Telemetry";
 
-    @WrapForJNI(stubName = "AddHistogram", dispatchTo = "gecko")
-    private static native void nativeAddHistogram(String name, int value);
-    @WrapForJNI(stubName = "AddKeyedHistogram", dispatchTo = "gecko")
-    private static native void nativeAddKeyedHistogram(String name, String key, int value);
-    @WrapForJNI(stubName = "StartUISession", dispatchTo = "gecko")
-    private static native void nativeStartUiSession(String name, long timestamp);
-    @WrapForJNI(stubName = "StopUISession", dispatchTo = "gecko")
-    private static native void nativeStopUiSession(String name, String reason, long timestamp);
-    @WrapForJNI(stubName = "AddUIEvent", dispatchTo = "gecko")
-    private static native void nativeAddUiEvent(String action, String method,
-                                                long timestamp, String extras);
-
-    public static long uptime() {
-        return SystemClock.uptimeMillis();
-    }
-
-    public static long realtime() {
-        return SystemClock.elapsedRealtime();
-    }
-
-    // Define new histograms in:
-    // toolkit/components/telemetry/Histograms.json
     public static void addToHistogram(String name, int value) {
-        if (GeckoThread.isRunning()) {
-            nativeAddHistogram(name, value);
-        } else {
-            GeckoThread.queueNativeCall(Telemetry.class, "nativeAddHistogram",
-                                        String.class, name, value);
-        }
+        TelemetryUtils.addToHistogram(name, value);
     }
 
     public static void addToKeyedHistogram(String name, String key, int value) {
-        if (GeckoThread.isRunning()) {
-            nativeAddKeyedHistogram(name, key, value);
-        } else {
-            GeckoThread.queueNativeCall(Telemetry.class, "nativeAddKeyedHistogram",
-                                        String.class, name, String.class, key, value);
-        }
-    }
-
-    public abstract static class Timer {
-        private final long mStartTime;
-        private final String mName;
-
-        private volatile boolean mHasFinished;
-        private volatile long mElapsed = -1;
-
-        protected abstract long now();
-
-        public Timer(String name) {
-            mName = name;
-            mStartTime = now();
-        }
-
-        public void cancel() {
-            mHasFinished = true;
-        }
-
-        public long getElapsed() {
-          return mElapsed;
-        }
-
-        public void stop() {
-            // Only the first stop counts.
-            if (mHasFinished) {
-                return;
-            }
-
-            mHasFinished = true;
-
-            final long elapsed = now() - mStartTime;
-            if (elapsed < 0) {
-                Log.e(LOGTAG, "Current time less than start time -- clock shenanigans?");
-                return;
-            }
-
-            mElapsed = elapsed;
-            if (elapsed > Integer.MAX_VALUE) {
-                Log.e(LOGTAG, "Duration of " + elapsed + "ms is too great to add to histogram.");
-                return;
-            }
-
-            addToHistogram(mName, (int) (elapsed));
-        }
-    }
-
-    public static class RealtimeTimer extends Timer {
-        public RealtimeTimer(String name) {
-            super(name);
-        }
-
-        @Override
-        protected long now() {
-            return Telemetry.realtime();
-        }
-    }
-
-    public static class UptimeTimer extends Timer {
-        public UptimeTimer(String name) {
-            super(name);
-        }
-
-        @Override
-        protected long now() {
-            return Telemetry.uptime();
-        }
+        TelemetryUtils.addToKeyedHistogram(name, key, value);
     }
 
     public static void startUISession(final Session session, final String sessionNameSuffix) {
-        final String sessionName = getSessionName(session, sessionNameSuffix);
-
-        Log.d(LOGTAG, "StartUISession: " + sessionName);
-        if (GeckoThread.isRunning()) {
-            nativeStartUiSession(sessionName, realtime());
-        } else {
-            GeckoThread.queueNativeCall(Telemetry.class, "nativeStartUiSession",
-                                        String.class, sessionName, realtime());
-        }
+        TelemetryUtils.startUISession(session, sessionNameSuffix);
     }
 
     public static void startUISession(final Session session) {
         startUISession(session, null);
     }
 
     public static void stopUISession(final Session session, final String sessionNameSuffix,
             final Reason reason) {
-        final String sessionName = getSessionName(session, sessionNameSuffix);
-
-        Log.d(LOGTAG, "StopUISession: " + sessionName + ", reason=" + reason);
-        if (GeckoThread.isRunning()) {
-            nativeStopUiSession(sessionName, reason.toString(), realtime());
-        } else {
-            GeckoThread.queueNativeCall(Telemetry.class, "nativeStopUiSession",
-                                        String.class, sessionName,
-                                        String.class, reason.toString(), realtime());
-        }
+        TelemetryUtils.stopUISession(session, sessionNameSuffix, reason);
     }
 
     public static void stopUISession(final Session session, final Reason reason) {
         stopUISession(session, null, reason);
     }
 
     public static void stopUISession(final Session session, final String sessionNameSuffix) {
         stopUISession(session, sessionNameSuffix, Reason.NONE);
     }
 
     public static void stopUISession(final Session session) {
         stopUISession(session, null, Reason.NONE);
     }
 
-    private static String getSessionName(final Session session, final String sessionNameSuffix) {
-        if (sessionNameSuffix != null) {
-            return session.toString() + ":" + sessionNameSuffix;
-        } else {
-            return session.toString();
-        }
+    public static void sendUIEvent(final Event event, final Method method, final long timestamp,
+            final String extras) {
+        sendUIEvent(event.toString(), method, timestamp, extras);
+    }
+
+    public static void sendUIEvent(final Event event, final Method method, final long timestamp) {
+        sendUIEvent(event, method, timestamp, null);
+    }
+
+    public static void sendUIEvent(final Event event, final Method method, final String extras) {
+        sendUIEvent(event, method, TelemetryUtils.realtime(), extras);
     }
 
-    /**
-     * @param method A non-null method (if null is desired, consider using Method.NONE)
-     */
+    public static void sendUIEvent(final Event event, final Method method) {
+        sendUIEvent(event, method, TelemetryUtils.realtime(), null);
+    }
+
+    public static void sendUIEvent(final Event event) {
+        sendUIEvent(event, Method.NONE, TelemetryUtils.realtime(), null);
+    }
+
+    public static void sendUIEvent(final Event event, final boolean eventStatus) {
+        final String eventName = event + ":" + eventStatus;
+        sendUIEvent(eventName, Method.NONE, TelemetryUtils.realtime(), null);
+    }
+
     private static void sendUIEvent(final String eventName, final Method method,
             final long timestamp, final String extras) {
-        if (method == null) {
-            throw new IllegalArgumentException("Expected non-null method - use Method.NONE?");
-        }
-
-        if (!AppConstants.RELEASE_OR_BETA) {
-            final String logString = "SendUIEvent: event = " + eventName + " method = " + method + " timestamp = " +
-                    timestamp + " extras = " + extras;
-            Log.d(LOGTAG, logString);
-        }
-        if (GeckoThread.isRunning()) {
-            nativeAddUiEvent(eventName, method.toString(), timestamp, extras);
-        } else {
-            GeckoThread.queueNativeCall(Telemetry.class, "nativeAddUiEvent",
-                                        String.class, eventName, String.class, method.toString(),
-                                        timestamp, String.class, extras);
-        }
+        TelemetryUtils.sendUIEvent(eventName, method, timestamp, extras);
         mappingMmaTracking(eventName, method, extras);
     }
 
     private static void mappingMmaTracking(String eventName, Method method, String extras) {
         if (eventName == null || method == null || extras == null) {
             return;
         }
         if (eventName.equalsIgnoreCase(Event.SAVE.toString()) && method == Method.MENU && extras.equals("bookmark")) {
@@ -230,43 +102,9 @@ public class Telemetry {
         } else if (eventName.equalsIgnoreCase(Event.SHOW.toString()) && method == Method.ACTIONBAR && extras.equals("urlbar-url")) {
             MmaDelegate.track(INTERACT_WITH_SEARCH_URL_AREA);
         } else if (eventName.equalsIgnoreCase(Event.SHARE.toString()) && method == Method.BUTTON && extras.equals("screenshot")) {
             MmaDelegate.track(SCREENSHOT);
         } else if (eventName.equalsIgnoreCase(Event.ACTION.toString()) && method == Method.DOORHANGER && extras.equals("login-positive")) {
             MmaDelegate.track(SAVED_LOGIN_AND_PASSWORD);
         }
     }
-
-    public static void sendUIEvent(final Event event, final Method method, final long timestamp,
-            final String extras) {
-        sendUIEvent(event.toString(), method, timestamp, extras);
-    }
-
-    public static void sendUIEvent(final Event event, final Method method, final long timestamp) {
-        sendUIEvent(event, method, timestamp, null);
-    }
-
-    public static void sendUIEvent(final Event event, final Method method, final String extras) {
-        sendUIEvent(event, method, realtime(), extras);
-    }
-
-    public static void sendUIEvent(final Event event, final Method method) {
-        sendUIEvent(event, method, realtime(), null);
-    }
-
-    public static void sendUIEvent(final Event event) {
-        sendUIEvent(event, Method.NONE, realtime(), null);
-    }
-
-    /**
-     * Sends a UIEvent with the given status appended to the event name.
-     *
-     * This method is a slight bend of the Telemetry framework so chances
-     * are that you don't want to use this: please think really hard before you do.
-     *
-     * Intended for use with data policy notifications.
-     */
-    public static void sendUIEvent(final Event event, final boolean eventStatus) {
-        final String eventName = event + ":" + eventStatus;
-        sendUIEvent(eventName, Method.NONE, realtime(), null);
-    }
 }
rename from mobile/android/base/java/org/mozilla/gecko/TelemetryContract.java
rename to mobile/android/geckoview/src/main/java/org/mozilla/gecko/TelemetryContract.java
new file mode 100644
--- /dev/null
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/TelemetryUtils.java
@@ -0,0 +1,247 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.gecko;
+
+import org.mozilla.gecko.annotation.WrapForJNI;
+import org.mozilla.gecko.TelemetryContract.Event;
+import org.mozilla.gecko.TelemetryContract.Method;
+import org.mozilla.gecko.TelemetryContract.Reason;
+import org.mozilla.gecko.TelemetryContract.Session;
+
+import android.os.SystemClock;
+import android.util.Log;
+
+/**
+ * All telemetry times are relative to one of two clocks:
+ *
+ * * Real time since the device was booted, including deep sleep. Use this
+ *   as a substitute for wall clock.
+ * * Uptime since the device was booted, excluding deep sleep. Use this to
+ *   avoid timing a user activity when their phone is in their pocket!
+ *
+ * The majority of methods in this class are defined in terms of real time.
+ */
+public class TelemetryUtils {
+
+    private static final boolean DEBUG = false;
+    private static final String LOGTAG = "TelemetryUtils";
+
+    @WrapForJNI(stubName = "AddHistogram", dispatchTo = "gecko")
+    private static native void nativeAddHistogram(String name, int value);
+    @WrapForJNI(stubName = "AddKeyedHistogram", dispatchTo = "gecko")
+    private static native void nativeAddKeyedHistogram(String name, String key, int value);
+
+    public static long uptime() {
+        return SystemClock.uptimeMillis();
+    }
+
+    public static long realtime() {
+        return SystemClock.elapsedRealtime();
+    }
+
+    // Define new histograms in:
+    // toolkit/components/telemetry/Histograms.json
+    public static void addToHistogram(String name, int value) {
+        if (GeckoThread.isRunning()) {
+            nativeAddHistogram(name, value);
+        } else {
+            GeckoThread.queueNativeCall(TelemetryUtils.class, "nativeAddHistogram",
+                                        String.class, name, value);
+        }
+    }
+
+    public static void addToKeyedHistogram(String name, String key, int value) {
+        if (GeckoThread.isRunning()) {
+            nativeAddKeyedHistogram(name, key, value);
+        } else {
+            GeckoThread.queueNativeCall(TelemetryUtils.class, "nativeAddKeyedHistogram",
+                                        String.class, name, String.class, key, value);
+        }
+    }
+
+    public abstract static class Timer {
+        private final long mStartTime;
+        private final String mName;
+
+        private volatile boolean mHasFinished;
+        private volatile long mElapsed = -1;
+
+        protected abstract long now();
+
+        public Timer(String name) {
+            mName = name;
+            mStartTime = now();
+        }
+
+        public void cancel() {
+            mHasFinished = true;
+        }
+
+        public long getElapsed() {
+          return mElapsed;
+        }
+
+        public void stop() {
+            // Only the first stop counts.
+            if (mHasFinished) {
+                return;
+            }
+
+            mHasFinished = true;
+
+            final long elapsed = now() - mStartTime;
+            if (elapsed < 0) {
+                Log.e(LOGTAG, "Current time less than start time -- clock shenanigans?");
+                return;
+            }
+
+            mElapsed = elapsed;
+            if (elapsed > Integer.MAX_VALUE) {
+                Log.e(LOGTAG, "Duration of " + elapsed + "ms is too great to add to histogram.");
+                return;
+            }
+
+            addToHistogram(mName, (int) (elapsed));
+        }
+    }
+
+    public static class RealtimeTimer extends Timer {
+        public RealtimeTimer(String name) {
+            super(name);
+        }
+
+        @Override
+        protected long now() {
+            return TelemetryUtils.realtime();
+        }
+    }
+
+    public static class UptimeTimer extends Timer {
+        public UptimeTimer(String name) {
+            super(name);
+        }
+
+        @Override
+        protected long now() {
+            return TelemetryUtils.uptime();
+        }
+    }
+
+    @WrapForJNI(stubName = "StartUISession", dispatchTo = "gecko")
+    private static native void nativeStartUiSession(String name, long timestamp);
+    @WrapForJNI(stubName = "StopUISession", dispatchTo = "gecko")
+    private static native void nativeStopUiSession(String name, String reason, long timestamp);
+    @WrapForJNI(stubName = "AddUIEvent", dispatchTo = "gecko")
+    private static native void nativeAddUiEvent(String action, String method,
+                                                long timestamp, String extras);
+
+    public static void startUISession(final Session session, final String sessionNameSuffix) {
+        final String sessionName = getSessionName(session, sessionNameSuffix);
+
+        Log.d(LOGTAG, "StartUISession: " + sessionName);
+        if (GeckoThread.isRunning()) {
+            nativeStartUiSession(sessionName, realtime());
+        } else {
+            GeckoThread.queueNativeCall(TelemetryUtils.class, "nativeStartUiSession",
+                                        String.class, sessionName, realtime());
+        }
+    }
+
+    public static void startUISession(final Session session) {
+        startUISession(session, null);
+    }
+
+    public static void stopUISession(final Session session, final String sessionNameSuffix,
+            final Reason reason) {
+        final String sessionName = getSessionName(session, sessionNameSuffix);
+
+        Log.d(LOGTAG, "StopUISession: " + sessionName + ", reason=" + reason);
+        if (GeckoThread.isRunning()) {
+            nativeStopUiSession(sessionName, reason.toString(), realtime());
+        } else {
+            GeckoThread.queueNativeCall(TelemetryUtils.class, "nativeStopUiSession",
+                                        String.class, sessionName,
+                                        String.class, reason.toString(), realtime());
+        }
+    }
+
+    public static void stopUISession(final Session session, final Reason reason) {
+        stopUISession(session, null, reason);
+    }
+
+    public static void stopUISession(final Session session, final String sessionNameSuffix) {
+        stopUISession(session, sessionNameSuffix, Reason.NONE);
+    }
+
+    public static void stopUISession(final Session session) {
+        stopUISession(session, null, Reason.NONE);
+    }
+
+    private static String getSessionName(final Session session, final String sessionNameSuffix) {
+        if (sessionNameSuffix != null) {
+            return session.toString() + ":" + sessionNameSuffix;
+        } else {
+            return session.toString();
+        }
+    }
+
+    /**
+     * @param method A non-null method (if null is desired, consider using Method.NONE)
+     */
+    /* package */ static void sendUIEvent(final String eventName, final Method method,
+            final long timestamp, final String extras) {
+        if (method == null) {
+            throw new IllegalArgumentException("Expected non-null method - use Method.NONE?");
+        }
+
+        if (DEBUG) {
+            final String logString = "SendUIEvent: event = " + eventName + " method = " + method + " timestamp = " +
+                    timestamp + " extras = " + extras;
+            Log.d(LOGTAG, logString);
+        }
+        if (GeckoThread.isRunning()) {
+            nativeAddUiEvent(eventName, method.toString(), timestamp, extras);
+        } else {
+            GeckoThread.queueNativeCall(TelemetryUtils.class, "nativeAddUiEvent",
+                                        String.class, eventName, String.class, method.toString(),
+                                        timestamp, String.class, extras);
+        }
+    }
+
+    public static void sendUIEvent(final Event event, final Method method, final long timestamp,
+            final String extras) {
+        sendUIEvent(event.toString(), method, timestamp, extras);
+    }
+
+    public static void sendUIEvent(final Event event, final Method method, final long timestamp) {
+        sendUIEvent(event, method, timestamp, null);
+    }
+
+    public static void sendUIEvent(final Event event, final Method method, final String extras) {
+        sendUIEvent(event, method, realtime(), extras);
+    }
+
+    public static void sendUIEvent(final Event event, final Method method) {
+        sendUIEvent(event, method, realtime(), null);
+    }
+
+    public static void sendUIEvent(final Event event) {
+        sendUIEvent(event, Method.NONE, realtime(), null);
+    }
+
+    /**
+     * Sends a UIEvent with the given status appended to the event name.
+     *
+     * This method is a slight bend of the Telemetry framework so chances
+     * are that you don't want to use this: please think really hard before you do.
+     *
+     * Intended for use with data policy notifications.
+     */
+    public static void sendUIEvent(final Event event, final boolean eventStatus) {
+        final String eventName = event + ":" + eventStatus;
+        sendUIEvent(eventName, Method.NONE, realtime(), null);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/widget/android/Telemetry.h
@@ -0,0 +1,100 @@
+/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; 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/. */
+
+#ifndef mozilla_widget_Telemetry_h__
+#define mozilla_widget_Telemetry_h__
+
+#include "FennecJNINatives.h"
+#include "nsAppShell.h"
+#include "nsIAndroidBridge.h"
+
+#include "mozilla/Telemetry.h"
+
+namespace mozilla {
+namespace widget {
+
+class Telemetry final
+    : public java::TelemetryUtils::Natives<Telemetry>
+{
+    Telemetry() = delete;
+
+    static already_AddRefed<nsIUITelemetryObserver>
+    GetObserver()
+    {
+        nsAppShell* const appShell = nsAppShell::Get();
+        if (!appShell) {
+            return nullptr;
+        }
+
+        nsCOMPtr<nsIAndroidBrowserApp> browserApp = appShell->GetBrowserApp();
+        nsCOMPtr<nsIUITelemetryObserver> obs;
+
+        if (!browserApp || NS_FAILED(browserApp->GetUITelemetryObserver(
+                getter_AddRefs(obs))) || !obs) {
+            return nullptr;
+        }
+
+        return obs.forget();
+    }
+
+public:
+    static void
+    AddHistogram(jni::String::Param aName, int32_t aValue)
+    {
+        MOZ_ASSERT(aName);
+        mozilla::Telemetry::Accumulate(aName->ToCString().get(), aValue);
+    }
+
+    static void
+    AddKeyedHistogram(jni::String::Param aName, jni::String::Param aKey,
+                      int32_t aValue)
+    {
+        MOZ_ASSERT(aName && aKey);
+        mozilla::Telemetry::Accumulate(aName->ToCString().get(),
+                                       aKey->ToCString(), aValue);
+    }
+
+    static void
+    StartUISession(jni::String::Param aName, int64_t aTimestamp)
+    {
+        MOZ_ASSERT(aName);
+        nsCOMPtr<nsIUITelemetryObserver> obs = GetObserver();
+        if (obs) {
+            obs->StartSession(aName->ToString().get(), aTimestamp);
+        }
+    }
+
+    static void
+    StopUISession(jni::String::Param aName, jni::String::Param aReason,
+                  int64_t aTimestamp)
+    {
+        MOZ_ASSERT(aName);
+        nsCOMPtr<nsIUITelemetryObserver> obs = GetObserver();
+        if (obs) {
+            obs->StopSession(aName->ToString().get(),
+                             aReason ? aReason->ToString().get() : nullptr,
+                             aTimestamp);
+        }
+    }
+
+    static void
+    AddUIEvent(jni::String::Param aAction, jni::String::Param aMethod,
+               int64_t aTimestamp, jni::String::Param aExtras)
+    {
+        MOZ_ASSERT(aAction);
+        nsCOMPtr<nsIUITelemetryObserver> obs = GetObserver();
+        if (obs) {
+            obs->AddEvent(aAction->ToString().get(),
+                          aMethod ? aMethod->ToString().get() : nullptr,
+                          aTimestamp,
+                          aExtras ? aExtras->ToString().get() : nullptr);
+        }
+    }
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // mozilla_widget_Telemetry_h__
deleted file mode 100644
--- a/widget/android/fennec/Telemetry.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; 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/. */
-
-#ifndef mozilla_widget_Telemetry_h__
-#define mozilla_widget_Telemetry_h__
-
-#include "FennecJNINatives.h"
-#include "nsAppShell.h"
-#include "nsIAndroidBridge.h"
-
-#include "mozilla/Telemetry.h"
-
-namespace mozilla {
-namespace widget {
-
-class Telemetry final
-    : public java::Telemetry::Natives<Telemetry>
-{
-    Telemetry() = delete;
-
-    static already_AddRefed<nsIUITelemetryObserver>
-    GetObserver()
-    {
-        nsAppShell* const appShell = nsAppShell::Get();
-        if (!appShell) {
-            return nullptr;
-        }
-
-        nsCOMPtr<nsIAndroidBrowserApp> browserApp = appShell->GetBrowserApp();
-        nsCOMPtr<nsIUITelemetryObserver> obs;
-
-        if (!browserApp || NS_FAILED(browserApp->GetUITelemetryObserver(
-                getter_AddRefs(obs))) || !obs) {
-            return nullptr;
-        }
-
-        return obs.forget();
-    }
-
-public:
-    static void
-    AddHistogram(jni::String::Param aName, int32_t aValue)
-    {
-        MOZ_ASSERT(aName);
-        mozilla::Telemetry::Accumulate(aName->ToCString().get(), aValue);
-    }
-
-    static void
-    AddKeyedHistogram(jni::String::Param aName, jni::String::Param aKey,
-                      int32_t aValue)
-    {
-        MOZ_ASSERT(aName && aKey);
-        mozilla::Telemetry::Accumulate(aName->ToCString().get(),
-                                       aKey->ToCString(), aValue);
-    }
-
-    static void
-    StartUISession(jni::String::Param aName, int64_t aTimestamp)
-    {
-        MOZ_ASSERT(aName);
-        nsCOMPtr<nsIUITelemetryObserver> obs = GetObserver();
-        if (obs) {
-            obs->StartSession(aName->ToString().get(), aTimestamp);
-        }
-    }
-
-    static void
-    StopUISession(jni::String::Param aName, jni::String::Param aReason,
-                  int64_t aTimestamp)
-    {
-        MOZ_ASSERT(aName);
-        nsCOMPtr<nsIUITelemetryObserver> obs = GetObserver();
-        if (obs) {
-            obs->StopSession(aName->ToString().get(),
-                             aReason ? aReason->ToString().get() : nullptr,
-                             aTimestamp);
-        }
-    }
-
-    static void
-    AddUIEvent(jni::String::Param aAction, jni::String::Param aMethod,
-               int64_t aTimestamp, jni::String::Param aExtras)
-    {
-        MOZ_ASSERT(aAction);
-        nsCOMPtr<nsIUITelemetryObserver> obs = GetObserver();
-        if (obs) {
-            obs->AddEvent(aAction->ToString().get(),
-                          aMethod ? aMethod->ToString().get() : nullptr,
-                          aTimestamp,
-                          aExtras ? aExtras->ToString().get() : nullptr);
-        }
-    }
-};
-
-} // namespace widget
-} // namespace mozilla
-
-#endif // mozilla_widget_Telemetry_h__
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -62,20 +62,20 @@
 #include "ANRReporter.h"
 #include "GeckoBatteryManager.h"
 #include "GeckoNetworkManager.h"
 #include "GeckoProcessManager.h"
 #include "GeckoScreenOrientation.h"
 #include "GeckoSystemStateListener.h"
 #include "GeckoVRManager.h"
 #include "PrefsHelper.h"
+#include "ScreenHelperAndroid.h"
+#include "Telemetry.h"
 #include "fennec/MemoryMonitor.h"
-#include "fennec/Telemetry.h"
 #include "fennec/ThumbnailHelper.h"
-#include "ScreenHelperAndroid.h"
 
 #ifdef DEBUG_ANDROID_EVENTS
 #define EVLOG(args...)  ALOG(args)
 #else
 #define EVLOG(args...) do { } while (0)
 #endif
 
 using namespace mozilla;
@@ -408,16 +408,17 @@ nsAppShell::nsAppShell()
 
     hal::Init();
 
     if (!XRE_IsParentProcess()) {
         if (jni::IsAvailable()) {
             GeckoThreadSupport::Init();
             GeckoAppShellSupport::Init();
             mozilla::GeckoSystemStateListener::Init();
+            mozilla::widget::Telemetry::Init();
 
             // Set the corresponding state in GeckoThread.
             java::GeckoThread::SetState(java::GeckoThread::State::RUNNING());
         }
         return;
     }
 
     if (jni::IsAvailable()) {
@@ -429,23 +430,23 @@ nsAppShell::nsAppShell()
         GeckoAppShellSupport::Init();
         GeckoThreadSupport::Init();
         mozilla::GeckoBatteryManager::Init();
         mozilla::GeckoNetworkManager::Init();
         mozilla::GeckoProcessManager::Init();
         mozilla::GeckoScreenOrientation::Init();
         mozilla::GeckoSystemStateListener::Init();
         mozilla::PrefsHelper::Init();
+        mozilla::widget::Telemetry::Init();
         nsWindow::InitNatives();
 
         if (jni::IsFennec()) {
             BrowserLocaleManagerSupport::Init();
             mozilla::ANRReporter::Init();
             mozilla::MemoryMonitor::Init();
-            mozilla::widget::Telemetry::Init();
             mozilla::ThumbnailHelper::Init();
         }
 
         java::GeckoThread::SetState(java::GeckoThread::State::JNI_READY());
 
         CreateAndroidUiThread();
     }