1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/base/health/SessionInformation.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,137 @@ 1.4 +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +package org.mozilla.gecko.health; 1.10 + 1.11 +import android.content.SharedPreferences; 1.12 +import android.util.Log; 1.13 + 1.14 +import org.mozilla.gecko.GeckoApp; 1.15 + 1.16 +import org.json.JSONException; 1.17 +import org.json.JSONObject; 1.18 + 1.19 +public class SessionInformation { 1.20 + private static final String LOG_TAG = "GeckoSessInfo"; 1.21 + 1.22 + public static final String PREFS_SESSION_START = "sessionStart"; 1.23 + 1.24 + public final long wallStartTime; // System wall clock. 1.25 + public final long realStartTime; // Realtime clock. 1.26 + 1.27 + private final boolean wasOOM; 1.28 + private final boolean wasStopped; 1.29 + 1.30 + private volatile long timedGeckoStartup = -1; 1.31 + private volatile long timedJavaStartup = -1; 1.32 + 1.33 + // Current sessions don't (right now) care about wasOOM/wasStopped. 1.34 + // Eventually we might want to lift that logic out of GeckoApp. 1.35 + public SessionInformation(long wallTime, long realTime) { 1.36 + this(wallTime, realTime, false, false); 1.37 + } 1.38 + 1.39 + // Previous sessions do... 1.40 + public SessionInformation(long wallTime, long realTime, boolean wasOOM, boolean wasStopped) { 1.41 + this.wallStartTime = wallTime; 1.42 + this.realStartTime = realTime; 1.43 + this.wasOOM = wasOOM; 1.44 + this.wasStopped = wasStopped; 1.45 + } 1.46 + 1.47 + /** 1.48 + * Initialize a new SessionInformation instance from the supplied prefs object. 1.49 + * 1.50 + * This includes retrieving OOM/crash data, as well as timings. 1.51 + * 1.52 + * If no wallStartTime was found, that implies that the previous 1.53 + * session was correctly recorded, and an object with a zero 1.54 + * wallStartTime is returned. 1.55 + */ 1.56 + public static SessionInformation fromSharedPrefs(SharedPreferences prefs) { 1.57 + boolean wasOOM = prefs.getBoolean(GeckoApp.PREFS_OOM_EXCEPTION, false); 1.58 + boolean wasStopped = prefs.getBoolean(GeckoApp.PREFS_WAS_STOPPED, true); 1.59 + long wallStartTime = prefs.getLong(PREFS_SESSION_START, 0L); 1.60 + long realStartTime = 0L; 1.61 + Log.d(LOG_TAG, "Building SessionInformation from prefs: " + 1.62 + wallStartTime + ", " + realStartTime + ", " + 1.63 + wasStopped + ", " + wasOOM); 1.64 + return new SessionInformation(wallStartTime, realStartTime, wasOOM, wasStopped); 1.65 + } 1.66 + 1.67 + /** 1.68 + * Initialize a new SessionInformation instance to 'split' the current 1.69 + * session. 1.70 + */ 1.71 + public static SessionInformation forRuntimeTransition() { 1.72 + final boolean wasOOM = false; 1.73 + final boolean wasStopped = true; 1.74 + final long wallStartTime = System.currentTimeMillis(); 1.75 + final long realStartTime = android.os.SystemClock.elapsedRealtime(); 1.76 + Log.v(LOG_TAG, "Recording runtime session transition: " + 1.77 + wallStartTime + ", " + realStartTime); 1.78 + return new SessionInformation(wallStartTime, realStartTime, wasOOM, wasStopped); 1.79 + } 1.80 + 1.81 + public boolean wasKilled() { 1.82 + return wasOOM || !wasStopped; 1.83 + } 1.84 + 1.85 + /** 1.86 + * Record the beginning of this session to SharedPreferences by 1.87 + * recording our start time. If a session was already recorded, it is 1.88 + * overwritten (there can only be one running session at a time). Does 1.89 + * not commit the editor. 1.90 + */ 1.91 + public void recordBegin(SharedPreferences.Editor editor) { 1.92 + Log.d(LOG_TAG, "Recording start of session: " + this.wallStartTime); 1.93 + editor.putLong(PREFS_SESSION_START, this.wallStartTime); 1.94 + } 1.95 + 1.96 + /** 1.97 + * Record the completion of this session to SharedPreferences by 1.98 + * deleting our start time. Does not commit the editor. 1.99 + */ 1.100 + public void recordCompletion(SharedPreferences.Editor editor) { 1.101 + Log.d(LOG_TAG, "Recording session done: " + this.wallStartTime); 1.102 + editor.remove(PREFS_SESSION_START); 1.103 + } 1.104 + 1.105 + /** 1.106 + * Return the JSON that we'll put in the DB for this session. 1.107 + */ 1.108 + public JSONObject getCompletionJSON(String reason, long realEndTime) throws JSONException { 1.109 + long durationSecs = (realEndTime - this.realStartTime) / 1000; 1.110 + JSONObject out = new JSONObject(); 1.111 + out.put("r", reason); 1.112 + out.put("d", durationSecs); 1.113 + if (this.timedGeckoStartup > 0) { 1.114 + out.put("sg", this.timedGeckoStartup); 1.115 + } 1.116 + if (this.timedJavaStartup > 0) { 1.117 + out.put("sj", this.timedJavaStartup); 1.118 + } 1.119 + return out; 1.120 + } 1.121 + 1.122 + public JSONObject getCrashedJSON() throws JSONException { 1.123 + JSONObject out = new JSONObject(); 1.124 + // We use ints here instead of booleans, because we're packing 1.125 + // stuff into JSON, and saving bytes in the DB is a worthwhile 1.126 + // goal. 1.127 + out.put("oom", this.wasOOM ? 1 : 0); 1.128 + out.put("stopped", this.wasStopped ? 1 : 0); 1.129 + out.put("r", "A"); 1.130 + return out; 1.131 + } 1.132 + 1.133 + public void setTimedGeckoStartup(final long duration) { 1.134 + timedGeckoStartup = duration; 1.135 + } 1.136 + 1.137 + public void setTimedJavaStartup(final long duration) { 1.138 + timedJavaStartup = duration; 1.139 + } 1.140 +}