mobile/android/base/health/BrowserHealthReporter.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 package org.mozilla.gecko.health;
     8 import android.content.ContentProviderClient;
     9 import android.content.Context;
    10 import android.util.Log;
    12 import org.mozilla.gecko.GeckoAppShell;
    13 import org.mozilla.gecko.GeckoEvent;
    14 import org.mozilla.gecko.GeckoProfile;
    16 import org.mozilla.gecko.background.healthreport.EnvironmentBuilder;
    17 import org.mozilla.gecko.background.common.GlobalConstants;
    18 import org.mozilla.gecko.background.healthreport.HealthReportConstants;
    19 import org.mozilla.gecko.background.healthreport.HealthReportDatabaseStorage;
    20 import org.mozilla.gecko.background.healthreport.HealthReportGenerator;
    22 import org.mozilla.gecko.util.GeckoEventListener;
    23 import org.mozilla.gecko.util.ThreadUtils;
    25 import org.json.JSONException;
    26 import org.json.JSONObject;
    28 /**
    29  * BrowserHealthReporter is the browser's interface to the Firefox Health
    30  * Report report generator.
    31  *
    32  * Each instance registers Gecko event listeners, so keep a single instance
    33  * around for the life of the browser. Java callers should use this globally
    34  * available singleton.
    35  */
    36 public class BrowserHealthReporter implements GeckoEventListener {
    37     private static final String LOGTAG = "GeckoHealthRep";
    39     public static final String EVENT_REQUEST  = "HealthReport:Request";
    40     public static final String EVENT_RESPONSE = "HealthReport:Response";
    42     protected final Context context;
    44     public BrowserHealthReporter() {
    45         GeckoAppShell.registerEventListener(EVENT_REQUEST, this);
    47         context = GeckoAppShell.getContext();
    48         if (context == null) {
    49             throw new IllegalStateException("Null Gecko context");
    50         }
    51     }
    53     public void uninit() {
    54         GeckoAppShell.unregisterEventListener(EVENT_REQUEST, this);
    55     }
    57     /**
    58      * Generate a new Health Report.
    59      *
    60      * This method performs IO, so call it from a background thread.
    61      *
    62      * @param since timestamp of first day to report (milliseconds since epoch).
    63      * @param lastPingTime timestamp when last health report was uploaded
    64      *                     (milliseconds since epoch).
    65      * @param profilePath path of the profile to generate report for.
    66      * @throws JSONException if JSON generation fails.
    67      * @throws IllegalStateException if the environment does not allow to generate a report.
    68      * @return non-null report.
    69      */
    70     public JSONObject generateReport(long since, long lastPingTime, String profilePath) throws JSONException {
    71         // We abuse the life-cycle of an Android ContentProvider slightly by holding
    72         // onto a ContentProviderClient while we generate a payload. This keeps
    73         // our database storage alive, while also allowing us to share a database
    74         // connection with BrowserHealthRecorder and the uploader.
    75         // The ContentProvider owns all underlying Storage instances, so we don't
    76         // need to explicitly close them.
    77         ContentProviderClient client = EnvironmentBuilder.getContentProviderClient(context);
    78         if (client == null) {
    79             throw new IllegalStateException("Could not fetch Health Report content provider.");
    80         }
    82         try {
    83             // Storage instance is owned by HealthReportProvider, so we don't need
    84             // to close it.
    85             HealthReportDatabaseStorage storage = EnvironmentBuilder.getStorage(client, profilePath);
    86             if (storage == null) {
    87                 throw new IllegalStateException("No storage in Health Reporter.");
    88             }
    90             HealthReportGenerator generator = new HealthReportGenerator(storage);
    91             JSONObject report = generator.generateDocument(since, lastPingTime, profilePath);
    92             if (report == null) {
    93                 throw new IllegalStateException("Not enough profile information to generate report.");
    94             }
    95             return report;
    96         } finally {
    97             client.release();
    98         }
    99     }
   101     /**
   102      * Get last time a health report was successfully uploaded.
   103      *
   104      * This is read from shared preferences, so call it from a background
   105      * thread.  Bug 882182 tracks making this work with multiple profiles.
   106      *
   107      * @return milliseconds since the epoch, or 0 if never uploaded.
   108      */
   109     protected long getLastUploadLocalTime() {
   110         return context
   111             .getSharedPreferences(HealthReportConstants.PREFS_BRANCH, 0)
   112             .getLong(HealthReportConstants.PREF_LAST_UPLOAD_LOCAL_TIME, 0L);
   113     }
   115     /**
   116      * Generate a new Health Report for the current Gecko profile.
   117      *
   118      * This method performs IO, so call it from a background thread.
   119      *
   120      * @throws JSONException if JSON generation fails.
   121      * @throws IllegalStateException if the environment does not allow to generate a report.
   122      * @return non-null Health Report.
   123      */
   124     public JSONObject generateReport() throws JSONException {
   125         GeckoProfile profile = GeckoAppShell.getGeckoInterface().getProfile();
   126         String profilePath = profile.getDir().getAbsolutePath();
   128         long since = System.currentTimeMillis() - GlobalConstants.MILLISECONDS_PER_SIX_MONTHS;
   129         long lastPingTime = Math.max(getLastUploadLocalTime(), HealthReportConstants.EARLIEST_LAST_PING);
   131         return generateReport(since, lastPingTime, profilePath);
   132     }
   134     @Override
   135     public void handleMessage(String event, JSONObject message) {
   136         try {
   137             ThreadUtils.postToBackgroundThread(new Runnable() {
   138                 @Override
   139                 public void run() {
   140                     JSONObject report = null;
   141                     try {
   142                         report = generateReport(); // non-null if it returns.
   143                     } catch (Exception e) {
   144                         Log.e(LOGTAG, "Generating report failed; responding with empty report.", e);
   145                         report = new JSONObject();
   146                     }
   148                     GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(EVENT_RESPONSE, report.toString()));
   149                 }
   150            });
   151         } catch (Exception e) {
   152             Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
   153         }
   154     }
   155 }

mercurial