Bug 960709 - Part 1: Factor out HealthRecorder interface. r=rnewman
authorMichael Comella <michael.l.comella@gmail.com>
Tue, 04 Feb 2014 19:41:29 -0800
changeset 166979 e4a442b68a435d9976e2b06dc12f78a7f5bd3177
parent 166978 f1156ec42c25e1a4b1fd684f7ee5c5d2eeaca39e
child 166980 52ed9fc26da5827fad1f9242907f6962cf51fcda
push id26157
push userryanvm@gmail.com
push dateWed, 05 Feb 2014 20:31:25 +0000
treeherdermozilla-central@bb4aa981b683 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrnewman
bugs960709
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 960709 - Part 1: Factor out HealthRecorder interface. r=rnewman
mobile/android/base/GeckoApp.java
mobile/android/base/health/BrowserHealthRecorder.java
mobile/android/base/health/HealthRecorder.java
mobile/android/base/health/SessionInformation.java
mobile/android/base/health/StubbedHealthRecorder.java
mobile/android/base/moz.build
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -12,17 +12,17 @@ import org.mozilla.gecko.gfx.BitmapUtils
 import org.mozilla.gecko.gfx.Layer;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.gfx.PluginLayer;
 import org.mozilla.gecko.prompts.PromptService;
 import org.mozilla.gecko.menu.GeckoMenu;
 import org.mozilla.gecko.menu.GeckoMenuInflater;
 import org.mozilla.gecko.menu.MenuPanel;
 import org.mozilla.gecko.health.BrowserHealthRecorder;
-import org.mozilla.gecko.health.BrowserHealthRecorder.SessionInformation;
+import org.mozilla.gecko.health.SessionInformation;
 import org.mozilla.gecko.preferences.GeckoPreferences;
 import org.mozilla.gecko.updater.UpdateService;
 import org.mozilla.gecko.updater.UpdateServiceHelper;
 import org.mozilla.gecko.util.ActivityResultHandler;
 import org.mozilla.gecko.util.EventDispatcher;
 import org.mozilla.gecko.util.GeckoEventListener;
 import org.mozilla.gecko.util.GeckoEventResponder;
 import org.mozilla.gecko.util.HardwareUtils;
--- a/mobile/android/base/health/BrowserHealthRecorder.java
+++ b/mobile/android/base/health/BrowserHealthRecorder.java
@@ -57,17 +57,17 @@ import java.util.concurrent.atomic.Atomi
  * Tell it when an environment attribute has changed: call {@link
  * #onAppLocaleChanged(String)} followed by {@link
  * #onEnvironmentChanged()}.
  *
  * Use it to record events: {@link #recordSearch(String, String)}.
  *
  * Shut it down when you're done being a browser: {@link #close()}.
  */
-public class BrowserHealthRecorder implements GeckoEventListener {
+public class BrowserHealthRecorder implements HealthRecorder, GeckoEventListener {
     private static final String LOG_TAG = "GeckoHealthRec";
     private static final String PREF_ACCEPT_LANG = "intl.accept_languages";
     private static final String PREF_BLOCKLIST_ENABLED = "extensions.blocklist.enabled";
     private static final String EVENT_SNAPSHOT = "HealthReport:Snapshot";
     private static final String EVENT_ADDONS_CHANGE = "Addons:Change";
     private static final String EVENT_ADDONS_UNINSTALLING = "Addons:Uninstalling";
     private static final String EVENT_PREF_CHANGE = "Pref:Change";
 
@@ -92,154 +92,39 @@ public class BrowserHealthRecorder imple
     private final AtomicBoolean orphanChecked = new AtomicBoolean(false);
     private volatile int env = -1;
 
     private ContentProviderClient client;
     private volatile HealthReportDatabaseStorage storage;
     private final ProfileInformationCache profileCache;
     private final EventDispatcher dispatcher;
 
-    public static class SessionInformation {
-        private static final String LOG_TAG = "GeckoSessInfo";
-
-        public static final String PREFS_SESSION_START = "sessionStart";
-
-        public final long wallStartTime;    // System wall clock.
-        public final long realStartTime;    // Realtime clock.
-
-        private final boolean wasOOM;
-        private final boolean wasStopped;
-
-        private volatile long timedGeckoStartup = -1;
-        private volatile long timedJavaStartup = -1;
-
-        // Current sessions don't (right now) care about wasOOM/wasStopped.
-        // Eventually we might want to lift that logic out of GeckoApp.
-        public SessionInformation(long wallTime, long realTime) {
-            this(wallTime, realTime, false, false);
-        }
-
-        // Previous sessions do...
-        public SessionInformation(long wallTime, long realTime, boolean wasOOM, boolean wasStopped) {
-            this.wallStartTime = wallTime;
-            this.realStartTime = realTime;
-            this.wasOOM = wasOOM;
-            this.wasStopped = wasStopped;
-        }
-
-        /**
-         * Initialize a new SessionInformation instance from the supplied prefs object.
-         *
-         * This includes retrieving OOM/crash data, as well as timings.
-         *
-         * If no wallStartTime was found, that implies that the previous
-         * session was correctly recorded, and an object with a zero
-         * wallStartTime is returned.
-         */
-        public static SessionInformation fromSharedPrefs(SharedPreferences prefs) {
-            boolean wasOOM = prefs.getBoolean(GeckoApp.PREFS_OOM_EXCEPTION, false);
-            boolean wasStopped = prefs.getBoolean(GeckoApp.PREFS_WAS_STOPPED, true);
-            long wallStartTime = prefs.getLong(PREFS_SESSION_START, 0L);
-            long realStartTime = 0L;
-            Log.d(LOG_TAG, "Building SessionInformation from prefs: " +
-                           wallStartTime + ", " + realStartTime + ", " +
-                           wasStopped + ", " + wasOOM);
-            return new SessionInformation(wallStartTime, realStartTime, wasOOM, wasStopped);
-        }
-
-        /**
-         * Initialize a new SessionInformation instance to 'split' the current
-         * session.
-         */
-        public static SessionInformation forRuntimeTransition() {
-            final boolean wasOOM = false;
-            final boolean wasStopped = true;
-            final long wallStartTime = System.currentTimeMillis();
-            final long realStartTime = android.os.SystemClock.elapsedRealtime();
-            Log.v(LOG_TAG, "Recording runtime session transition: " +
-                           wallStartTime + ", " + realStartTime);
-            return new SessionInformation(wallStartTime, realStartTime, wasOOM, wasStopped);
-        }
-
-        public boolean wasKilled() {
-            return wasOOM || !wasStopped;
-        }
-
-        /**
-         * Record the beginning of this session to SharedPreferences by
-         * recording our start time. If a session was already recorded, it is
-         * overwritten (there can only be one running session at a time). Does
-         * not commit the editor.
-         */
-        public void recordBegin(SharedPreferences.Editor editor) {
-            Log.d(LOG_TAG, "Recording start of session: " + this.wallStartTime);
-            editor.putLong(PREFS_SESSION_START, this.wallStartTime);
-        }
-
-        /**
-         * Record the completion of this session to SharedPreferences by
-         * deleting our start time. Does not commit the editor.
-         */
-        public void recordCompletion(SharedPreferences.Editor editor) {
-            Log.d(LOG_TAG, "Recording session done: " + this.wallStartTime);
-            editor.remove(PREFS_SESSION_START);
-        }
-
-        /**
-         * Return the JSON that we'll put in the DB for this session.
-         */
-        public JSONObject getCompletionJSON(String reason, long realEndTime) throws JSONException {
-            long durationSecs = (realEndTime - this.realStartTime) / 1000;
-            JSONObject out = new JSONObject();
-            out.put("r", reason);
-            out.put("d", durationSecs);
-            if (this.timedGeckoStartup > 0) {
-                out.put("sg", this.timedGeckoStartup);
-            }
-            if (this.timedJavaStartup > 0) {
-                out.put("sj", this.timedJavaStartup);
-            }
-            return out;
-        }
-
-        public JSONObject getCrashedJSON() throws JSONException {
-            JSONObject out = new JSONObject();
-            // We use ints here instead of booleans, because we're packing
-            // stuff into JSON, and saving bytes in the DB is a worthwhile
-            // goal.
-            out.put("oom", this.wasOOM ? 1 : 0);
-            out.put("stopped", this.wasStopped ? 1 : 0);
-            out.put("r", "A");
-            return out;
-        }
-    }
-
     // We track previousSession to avoid order-of-initialization confusion. We
     // accept it in the constructor, and process it after init.
     private final SessionInformation previousSession;
     private volatile SessionInformation session = null;
     public SessionInformation getCurrentSession() {
         return this.session;
     }
 
     public void setCurrentSession(SessionInformation session) {
         this.session = session;
     }
 
     public void recordGeckoStartupTime(long duration) {
         if (this.session == null) {
             return;
         }
-        this.session.timedGeckoStartup = duration;
+        this.session.setTimedGeckoStartup(duration);
     }
     public void recordJavaStartupTime(long duration) {
         if (this.session == null) {
             return;
         }
-        this.session.timedJavaStartup = duration;
+        this.session.setTimedJavaStartup(duration);
     }
 
     /**
      * Persist the opaque identifier for the current Firefox Health Report environment.
      * This changes in certain circumstances; be sure to use the current value when recording data.
      */
     private void setHealthEnvironment(final int env) {
         this.env = env;
@@ -1012,9 +897,8 @@ public class BrowserHealthRecorder imple
             // Future: record this exception in FHR's own error submitter.
         }
 
         // Track the end of this session in shared prefs, so it doesn't get
         // double-counted on next run.
         session.recordCompletion(editor);
     }
 }
-
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/health/HealthRecorder.java
@@ -0,0 +1,24 @@
+/* -*- 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.health;
+
+import android.content.SharedPreferences;
+
+/**
+ * HealthRecorder is an interface into the Firefox Health Report storage system.
+ */
+public interface HealthRecorder {
+    public void setCurrentSession(SessionInformation session);
+    public void recordSessionEnd(String reason, SharedPreferences.Editor editor);
+
+    public void recordGeckoStartupTime(long duration);
+    public void recordJavaStartupTime(long duration);
+
+    public void onAppLocaleChanged(String to);
+    public void onEnvironmentChanged(final boolean startNewSession, final String sessionEndReason);
+
+    public void close();
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/health/SessionInformation.java
@@ -0,0 +1,137 @@
+/* -*- 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.health;
+
+import android.content.SharedPreferences;
+import android.util.Log;
+
+import org.mozilla.gecko.GeckoApp;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class SessionInformation {
+    private static final String LOG_TAG = "GeckoSessInfo";
+
+    public static final String PREFS_SESSION_START = "sessionStart";
+
+    public final long wallStartTime;    // System wall clock.
+    public final long realStartTime;    // Realtime clock.
+
+    private final boolean wasOOM;
+    private final boolean wasStopped;
+
+    private volatile long timedGeckoStartup = -1;
+    private volatile long timedJavaStartup = -1;
+
+    // Current sessions don't (right now) care about wasOOM/wasStopped.
+    // Eventually we might want to lift that logic out of GeckoApp.
+    public SessionInformation(long wallTime, long realTime) {
+        this(wallTime, realTime, false, false);
+    }
+
+    // Previous sessions do...
+    public SessionInformation(long wallTime, long realTime, boolean wasOOM, boolean wasStopped) {
+        this.wallStartTime = wallTime;
+        this.realStartTime = realTime;
+        this.wasOOM = wasOOM;
+        this.wasStopped = wasStopped;
+    }
+
+    /**
+     * Initialize a new SessionInformation instance from the supplied prefs object.
+     *
+     * This includes retrieving OOM/crash data, as well as timings.
+     *
+     * If no wallStartTime was found, that implies that the previous
+     * session was correctly recorded, and an object with a zero
+     * wallStartTime is returned.
+     */
+    public static SessionInformation fromSharedPrefs(SharedPreferences prefs) {
+        boolean wasOOM = prefs.getBoolean(GeckoApp.PREFS_OOM_EXCEPTION, false);
+        boolean wasStopped = prefs.getBoolean(GeckoApp.PREFS_WAS_STOPPED, true);
+        long wallStartTime = prefs.getLong(PREFS_SESSION_START, 0L);
+        long realStartTime = 0L;
+        Log.d(LOG_TAG, "Building SessionInformation from prefs: " +
+                       wallStartTime + ", " + realStartTime + ", " +
+                       wasStopped + ", " + wasOOM);
+        return new SessionInformation(wallStartTime, realStartTime, wasOOM, wasStopped);
+    }
+
+    /**
+     * Initialize a new SessionInformation instance to 'split' the current
+     * session.
+     */
+    public static SessionInformation forRuntimeTransition() {
+        final boolean wasOOM = false;
+        final boolean wasStopped = true;
+        final long wallStartTime = System.currentTimeMillis();
+        final long realStartTime = android.os.SystemClock.elapsedRealtime();
+        Log.v(LOG_TAG, "Recording runtime session transition: " +
+                       wallStartTime + ", " + realStartTime);
+        return new SessionInformation(wallStartTime, realStartTime, wasOOM, wasStopped);
+    }
+
+    public boolean wasKilled() {
+        return wasOOM || !wasStopped;
+    }
+
+    /**
+     * Record the beginning of this session to SharedPreferences by
+     * recording our start time. If a session was already recorded, it is
+     * overwritten (there can only be one running session at a time). Does
+     * not commit the editor.
+     */
+    public void recordBegin(SharedPreferences.Editor editor) {
+        Log.d(LOG_TAG, "Recording start of session: " + this.wallStartTime);
+        editor.putLong(PREFS_SESSION_START, this.wallStartTime);
+    }
+
+    /**
+     * Record the completion of this session to SharedPreferences by
+     * deleting our start time. Does not commit the editor.
+     */
+    public void recordCompletion(SharedPreferences.Editor editor) {
+        Log.d(LOG_TAG, "Recording session done: " + this.wallStartTime);
+        editor.remove(PREFS_SESSION_START);
+    }
+
+    /**
+     * Return the JSON that we'll put in the DB for this session.
+     */
+    public JSONObject getCompletionJSON(String reason, long realEndTime) throws JSONException {
+        long durationSecs = (realEndTime - this.realStartTime) / 1000;
+        JSONObject out = new JSONObject();
+        out.put("r", reason);
+        out.put("d", durationSecs);
+        if (this.timedGeckoStartup > 0) {
+            out.put("sg", this.timedGeckoStartup);
+        }
+        if (this.timedJavaStartup > 0) {
+            out.put("sj", this.timedJavaStartup);
+        }
+        return out;
+    }
+
+    public JSONObject getCrashedJSON() throws JSONException {
+        JSONObject out = new JSONObject();
+        // We use ints here instead of booleans, because we're packing
+        // stuff into JSON, and saving bytes in the DB is a worthwhile
+        // goal.
+        out.put("oom", this.wasOOM ? 1 : 0);
+        out.put("stopped", this.wasStopped ? 1 : 0);
+        out.put("r", "A");
+        return out;
+    }
+
+    public void setTimedGeckoStartup(final long duration) {
+        timedGeckoStartup = duration;
+    }
+
+    public void setTimedJavaStartup(final long duration) {
+        timedJavaStartup = duration;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/health/StubbedHealthRecorder.java
@@ -0,0 +1,27 @@
+/* -*- 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.health;
+
+import android.content.SharedPreferences;
+
+/**
+ * StubbedHealthRecorder is an implementation of HealthRecorder that does (you guessed it!)
+ * nothing.
+ */
+public class StubbedHealthRecorder implements HealthRecorder {
+    public StubbedHealthRecorder() { }
+
+    public void setCurrentSession(SessionInformation session) { }
+    public void recordSessionEnd(String reason, SharedPreferences.Editor editor) { }
+
+    public void recordGeckoStartupTime(long duration) { }
+    public void recordJavaStartupTime(long duration) { }
+
+    public void onAppLocaleChanged(String to) { }
+    public void onEnvironmentChanged(final boolean startNewSession, final String sessionEndReason) { }
+
+    public void close() { }
+}
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -202,16 +202,19 @@ gbjar.sources += [
     'gfx/TextureReaper.java',
     'gfx/TileLayer.java',
     'gfx/TouchEventHandler.java',
     'gfx/ViewTransform.java',
     'gfx/VirtualLayer.java',
     'GlobalHistory.java',
     'health/BrowserHealthRecorder.java',
     'health/BrowserHealthReporter.java',
+    'health/HealthRecorder.java',
+    'health/SessionInformation.java',
+    'health/StubbedHealthRecorder.java',
     'home/BookmarkFolderView.java',
     'home/BookmarksListAdapter.java',
     'home/BookmarksListView.java',
     'home/BookmarksPanel.java',
     'home/BrowserSearch.java',
     'home/DynamicPanel.java',
     'home/FadedTextView.java',
     'home/FramePanelLayout.java',