Home | History | Annotate | Download | only in metrics
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 //------------------------------------------------------------------------------
      6 // Description of the life cycle of a instance of MetricsService.
      7 //
      8 //  OVERVIEW
      9 //
     10 // A MetricsService instance is typically created at application startup.  It is
     11 // the central controller for the acquisition of log data, and the automatic
     12 // transmission of that log data to an external server.  Its major job is to
     13 // manage logs, grouping them for transmission, and transmitting them.  As part
     14 // of its grouping, MS finalizes logs by including some just-in-time gathered
     15 // memory statistics, snapshotting the current stats of numerous histograms,
     16 // closing the logs, translating to protocol buffer format, and compressing the
     17 // results for transmission.  Transmission includes submitting a compressed log
     18 // as data in a URL-post, and retransmitting (or retaining at process
     19 // termination) if the attempted transmission failed.  Retention across process
     20 // terminations is done using the the PrefServices facilities. The retained logs
     21 // (the ones that never got transmitted) are compressed and base64-encoded
     22 // before being persisted.
     23 //
     24 // Logs fall into one of two categories: "initial logs," and "ongoing logs."
     25 // There is at most one initial log sent for each complete run of the chromium
     26 // product (from startup, to browser shutdown).  An initial log is generally
     27 // transmitted some short time (1 minute?) after startup, and includes stats
     28 // such as recent crash info, the number and types of plugins, etc.  The
     29 // external server's response to the initial log conceptually tells this MS if
     30 // it should continue transmitting logs (during this session). The server
     31 // response can actually be much more detailed, and always includes (at a
     32 // minimum) how often additional ongoing logs should be sent.
     33 //
     34 // After the above initial log, a series of ongoing logs will be transmitted.
     35 // The first ongoing log actually begins to accumulate information stating when
     36 // the MS was first constructed.  Note that even though the initial log is
     37 // commonly sent a full minute after startup, the initial log does not include
     38 // much in the way of user stats.   The most common interlog period (delay)
     39 // is 30 minutes. That time period starts when the first user action causes a
     40 // logging event.  This means that if there is no user action, there may be long
     41 // periods without any (ongoing) log transmissions.  Ongoing logs typically
     42 // contain very detailed records of user activities (ex: opened tab, closed
     43 // tab, fetched URL, maximized window, etc.)  In addition, just before an
     44 // ongoing log is closed out, a call is made to gather memory statistics.  Those
     45 // memory statistics are deposited into a histogram, and the log finalization
     46 // code is then called.  In the finalization, a call to a Histogram server
     47 // acquires a list of all local histograms that have been flagged for upload
     48 // to the UMA server.  The finalization also acquires a the most recent number
     49 // of page loads, along with any counts of renderer or plugin crashes.
     50 //
     51 // When the browser shuts down, there will typically be a fragment of an ongoing
     52 // log that has not yet been transmitted.  At shutdown time, that fragment
     53 // is closed (including snapshotting histograms), and persisted, for
     54 // potential transmission during a future run of the product.
     55 //
     56 // There are two slightly abnormal shutdown conditions.  There is a
     57 // "disconnected scenario," and a "really fast startup and shutdown" scenario.
     58 // In the "never connected" situation, the user has (during the running of the
     59 // process) never established an internet connection.  As a result, attempts to
     60 // transmit the initial log have failed, and a lot(?) of data has accumulated in
     61 // the ongoing log (which didn't yet get closed, because there was never even a
     62 // contemplation of sending it).  There is also a kindred "lost connection"
     63 // situation, where a loss of connection prevented an ongoing log from being
     64 // transmitted, and a (still open) log was stuck accumulating a lot(?) of data,
     65 // while the earlier log retried its transmission.  In both of these
     66 // disconnected situations, two logs need to be, and are, persistently stored
     67 // for future transmission.
     68 //
     69 // The other unusual shutdown condition, termed "really fast startup and
     70 // shutdown," involves the deliberate user termination of the process before
     71 // the initial log is even formed or transmitted. In that situation, no logging
     72 // is done, but the historical crash statistics remain (unlogged) for inclusion
     73 // in a future run's initial log.  (i.e., we don't lose crash stats).
     74 //
     75 // With the above overview, we can now describe the state machine's various
     76 // stats, based on the State enum specified in the state_ member.  Those states
     77 // are:
     78 //
     79 //    INITIALIZED,            // Constructor was called.
     80 //    INIT_TASK_SCHEDULED,    // Waiting for deferred init tasks to complete.
     81 //    INIT_TASK_DONE,         // Waiting for timer to send initial log.
     82 //    INITIAL_LOG_READY,      // Initial log generated, and waiting for reply.
     83 //    SENDING_OLD_LOGS,       // Sending unsent logs from previous session.
     84 //    SENDING_CURRENT_LOGS,   // Sending standard current logs as they accrue.
     85 //
     86 // In more detail, we have:
     87 //
     88 //    INITIALIZED,            // Constructor was called.
     89 // The MS has been constructed, but has taken no actions to compose the
     90 // initial log.
     91 //
     92 //    INIT_TASK_SCHEDULED,    // Waiting for deferred init tasks to complete.
     93 // Typically about 30 seconds after startup, a task is sent to a second thread
     94 // (the file thread) to perform deferred (lower priority and slower)
     95 // initialization steps such as getting the list of plugins.  That task will
     96 // (when complete) make an async callback (via a Task) to indicate the
     97 // completion.
     98 //
     99 //    INIT_TASK_DONE,         // Waiting for timer to send initial log.
    100 // The callback has arrived, and it is now possible for an initial log to be
    101 // created.  This callback typically arrives back less than one second after
    102 // the deferred init task is dispatched.
    103 //
    104 //    INITIAL_LOG_READY,      // Initial log generated, and waiting for reply.
    105 // This state is entered only after an initial log has been composed, and
    106 // prepared for transmission.  It is also the case that any previously unsent
    107 // logs have been loaded into instance variables for possible transmission.
    108 //
    109 //    SENDING_OLD_LOGS,       // Sending unsent logs from previous session.
    110 // This state indicates that the initial log for this session has been
    111 // successfully sent and it is now time to send any logs that were
    112 // saved from previous sessions.  All such logs will be transmitted before
    113 // exiting this state, and proceeding with ongoing logs from the current session
    114 // (see next state).
    115 //
    116 //    SENDING_CURRENT_LOGS,   // Sending standard current logs as they accrue.
    117 // Current logs are being accumulated.  Typically every 20 minutes a log is
    118 // closed and finalized for transmission, at the same time as a new log is
    119 // started.
    120 //
    121 // The progression through the above states is simple, and sequential, in the
    122 // most common use cases.  States proceed from INITIAL to SENDING_CURRENT_LOGS,
    123 // and remain in the latter until shutdown.
    124 //
    125 // The one unusual case is when the user asks that we stop logging.  When that
    126 // happens, any staged (transmission in progress) log is persisted, and any log
    127 // that is currently accumulating is also finalized and persisted.  We then
    128 // regress back to the SEND_OLD_LOGS state in case the user enables log
    129 // recording again during this session.  This way anything we have persisted
    130 // will be sent automatically if/when we progress back to SENDING_CURRENT_LOG
    131 // state.
    132 //
    133 // Another similar case is on mobile, when the application is backgrounded and
    134 // then foregrounded again. Backgrounding created new "old" stored logs, so the
    135 // state drops back from SENDING_CURRENT_LOGS to SENDING_OLD_LOGS so those logs
    136 // will be sent.
    137 //
    138 // Also note that whenever we successfully send an old log, we mirror the list
    139 // of logs into the PrefService. This ensures that IF we crash, we won't start
    140 // up and retransmit our old logs again.
    141 //
    142 // Due to race conditions, it is always possible that a log file could be sent
    143 // twice.  For example, if a log file is sent, but not yet acknowledged by
    144 // the external server, and the user shuts down, then a copy of the log may be
    145 // saved for re-transmission.  These duplicates could be filtered out server
    146 // side, but are not expected to be a significant problem.
    147 //
    148 //
    149 //------------------------------------------------------------------------------
    150 
    151 #include "chrome/browser/metrics/metrics_service.h"
    152 
    153 #include <algorithm>
    154 
    155 #include "base/bind.h"
    156 #include "base/callback.h"
    157 #include "base/command_line.h"
    158 #include "base/guid.h"
    159 #include "base/md5.h"
    160 #include "base/metrics/histogram.h"
    161 #include "base/metrics/sparse_histogram.h"
    162 #include "base/metrics/statistics_recorder.h"
    163 #include "base/prefs/pref_registry_simple.h"
    164 #include "base/prefs/pref_service.h"
    165 #include "base/rand_util.h"
    166 #include "base/strings/string_number_conversions.h"
    167 #include "base/strings/utf_string_conversions.h"
    168 #include "base/threading/platform_thread.h"
    169 #include "base/threading/thread.h"
    170 #include "base/threading/thread_restrictions.h"
    171 #include "base/tracked_objects.h"
    172 #include "base/values.h"
    173 #include "chrome/browser/browser_process.h"
    174 #include "chrome/browser/chrome_notification_types.h"
    175 #include "chrome/browser/extensions/extension_service.h"
    176 #include "chrome/browser/extensions/process_map.h"
    177 #include "chrome/browser/io_thread.h"
    178 #include "chrome/browser/memory_details.h"
    179 #include "chrome/browser/metrics/compression_utils.h"
    180 #include "chrome/browser/metrics/gzipped_protobufs_field_trial.h"
    181 #include "chrome/browser/metrics/metrics_log.h"
    182 #include "chrome/browser/metrics/metrics_log_serializer.h"
    183 #include "chrome/browser/metrics/metrics_reporting_scheduler.h"
    184 #include "chrome/browser/metrics/time_ticks_experiment_win.h"
    185 #include "chrome/browser/metrics/tracking_synchronizer.h"
    186 #include "chrome/browser/net/http_pipelining_compatibility_client.h"
    187 #include "chrome/browser/net/network_stats.h"
    188 #include "chrome/browser/omnibox/omnibox_log.h"
    189 #include "chrome/browser/prefs/scoped_user_pref_update.h"
    190 #include "chrome/browser/profiles/profile.h"
    191 #include "chrome/browser/ui/browser_list.h"
    192 #include "chrome/browser/ui/browser_otr_state.h"
    193 #include "chrome/browser/ui/search/search_tab_helper.h"
    194 #include "chrome/common/child_process_logging.h"
    195 #include "chrome/common/chrome_result_codes.h"
    196 #include "chrome/common/chrome_switches.h"
    197 #include "chrome/common/metrics/caching_permuted_entropy_provider.h"
    198 #include "chrome/common/metrics/entropy_provider.h"
    199 #include "chrome/common/metrics/metrics_log_manager.h"
    200 #include "chrome/common/net/test_server_locations.h"
    201 #include "chrome/common/pref_names.h"
    202 #include "chrome/common/render_messages.h"
    203 #include "content/public/browser/child_process_data.h"
    204 #include "content/public/browser/histogram_fetcher.h"
    205 #include "content/public/browser/load_notification_details.h"
    206 #include "content/public/browser/notification_service.h"
    207 #include "content/public/browser/plugin_service.h"
    208 #include "content/public/browser/render_process_host.h"
    209 #include "content/public/browser/user_metrics.h"
    210 #include "content/public/browser/web_contents.h"
    211 #include "content/public/common/process_type.h"
    212 #include "content/public/common/webplugininfo.h"
    213 #include "net/base/load_flags.h"
    214 #include "net/url_request/url_fetcher.h"
    215 
    216 // TODO(port): port browser_distribution.h.
    217 #if !defined(OS_POSIX)
    218 #include "chrome/installer/util/browser_distribution.h"
    219 #endif
    220 
    221 #if defined(OS_CHROMEOS)
    222 #include "chrome/browser/chromeos/external_metrics.h"
    223 #include "chrome/browser/chromeos/system/statistics_provider.h"
    224 #endif
    225 
    226 #if defined(OS_WIN)
    227 #include <windows.h>  // Needed for STATUS_* codes
    228 #endif
    229 
    230 using base::Time;
    231 using content::BrowserThread;
    232 using content::ChildProcessData;
    233 using content::LoadNotificationDetails;
    234 using content::PluginService;
    235 
    236 namespace {
    237 
    238 // Check to see that we're being called on only one thread.
    239 bool IsSingleThreaded() {
    240   static base::PlatformThreadId thread_id = 0;
    241   if (!thread_id)
    242     thread_id = base::PlatformThread::CurrentId();
    243   return base::PlatformThread::CurrentId() == thread_id;
    244 }
    245 
    246 // The delay, in seconds, after starting recording before doing expensive
    247 // initialization work.
    248 #if defined(OS_ANDROID) || defined(OS_IOS)
    249 // On mobile devices, a significant portion of sessions last less than a minute.
    250 // Use a shorter timer on these platforms to avoid losing data.
    251 // TODO(dfalcantara): To avoid delaying startup, tighten up initialization so
    252 //                    that it occurs after the user gets their initial page.
    253 const int kInitializationDelaySeconds = 5;
    254 #else
    255 const int kInitializationDelaySeconds = 30;
    256 #endif
    257 
    258 // This specifies the amount of time to wait for all renderers to send their
    259 // data.
    260 const int kMaxHistogramGatheringWaitDuration = 60000;  // 60 seconds.
    261 
    262 // The maximum number of events in a log uploaded to the UMA server.
    263 const int kEventLimit = 2400;
    264 
    265 // If an upload fails, and the transmission was over this byte count, then we
    266 // will discard the log, and not try to retransmit it.  We also don't persist
    267 // the log to the prefs for transmission during the next chrome session if this
    268 // limit is exceeded.
    269 const size_t kUploadLogAvoidRetransmitSize = 50000;
    270 
    271 // Interval, in minutes, between state saves.
    272 const int kSaveStateIntervalMinutes = 5;
    273 
    274 enum ResponseStatus {
    275   UNKNOWN_FAILURE,
    276   SUCCESS,
    277   BAD_REQUEST,  // Invalid syntax or log too large.
    278   NO_RESPONSE,
    279   NUM_RESPONSE_STATUSES
    280 };
    281 
    282 ResponseStatus ResponseCodeToStatus(int response_code) {
    283   switch (response_code) {
    284     case 200:
    285       return SUCCESS;
    286     case 400:
    287       return BAD_REQUEST;
    288     case net::URLFetcher::RESPONSE_CODE_INVALID:
    289       return NO_RESPONSE;
    290     default:
    291       return UNKNOWN_FAILURE;
    292   }
    293 }
    294 
    295 // The argument used to generate a non-identifying entropy source. We want no
    296 // more than 13 bits of entropy, so use this max to return a number in the range
    297 // [0, 7999] as the entropy source (12.97 bits of entropy).
    298 const int kMaxLowEntropySize = 8000;
    299 
    300 // Default prefs value for prefs::kMetricsLowEntropySource to indicate that the
    301 // value has not yet been set.
    302 const int kLowEntropySourceNotSet = -1;
    303 
    304 // Generates a new non-identifying entropy source used to seed persistent
    305 // activities.
    306 int GenerateLowEntropySource() {
    307   return base::RandInt(0, kMaxLowEntropySize - 1);
    308 }
    309 
    310 // Converts an exit code into something that can be inserted into our
    311 // histograms (which expect non-negative numbers less than MAX_INT).
    312 int MapCrashExitCodeForHistogram(int exit_code) {
    313 #if defined(OS_WIN)
    314   // Since |abs(STATUS_GUARD_PAGE_VIOLATION) == MAX_INT| it causes problems in
    315   // histograms.cc. Solve this by remapping it to a smaller value, which
    316   // hopefully doesn't conflict with other codes.
    317   if (exit_code == STATUS_GUARD_PAGE_VIOLATION)
    318     return 0x1FCF7EC3;  // Randomly picked number.
    319 #endif
    320 
    321   return std::abs(exit_code);
    322 }
    323 
    324 void MarkAppCleanShutdownAndCommit() {
    325   PrefService* pref = g_browser_process->local_state();
    326   pref->SetBoolean(prefs::kStabilityExitedCleanly, true);
    327   // Start writing right away (write happens on a different thread).
    328   pref->CommitPendingWrite();
    329 }
    330 
    331 }  // namespace
    332 
    333 // static
    334 MetricsService::ShutdownCleanliness MetricsService::clean_shutdown_status_ =
    335     MetricsService::CLEANLY_SHUTDOWN;
    336 
    337 // This is used to quickly log stats from child process related notifications in
    338 // MetricsService::child_stats_buffer_.  The buffer's contents are transferred
    339 // out when Local State is periodically saved.  The information is then
    340 // reported to the UMA server on next launch.
    341 struct MetricsService::ChildProcessStats {
    342  public:
    343   explicit ChildProcessStats(int process_type)
    344       : process_launches(0),
    345         process_crashes(0),
    346         instances(0),
    347         loading_errors(0),
    348         process_type(process_type) {}
    349 
    350   // This constructor is only used by the map to return some default value for
    351   // an index for which no value has been assigned.
    352   ChildProcessStats()
    353       : process_launches(0),
    354         process_crashes(0),
    355         instances(0),
    356         loading_errors(0),
    357         process_type(content::PROCESS_TYPE_UNKNOWN) {}
    358 
    359   // The number of times that the given child process has been launched
    360   int process_launches;
    361 
    362   // The number of times that the given child process has crashed
    363   int process_crashes;
    364 
    365   // The number of instances of this child process that have been created.
    366   // An instance is a DOM object rendered by this child process during a page
    367   // load.
    368   int instances;
    369 
    370   // The number of times there was an error loading an instance of this child
    371   // process.
    372   int loading_errors;
    373 
    374   int process_type;
    375 };
    376 
    377 // Handles asynchronous fetching of memory details.
    378 // Will run the provided task after finished.
    379 class MetricsMemoryDetails : public MemoryDetails {
    380  public:
    381   explicit MetricsMemoryDetails(const base::Closure& callback)
    382       : callback_(callback) {}
    383 
    384   virtual void OnDetailsAvailable() OVERRIDE {
    385     base::MessageLoop::current()->PostTask(FROM_HERE, callback_);
    386   }
    387 
    388  private:
    389   virtual ~MetricsMemoryDetails() {}
    390 
    391   base::Closure callback_;
    392   DISALLOW_COPY_AND_ASSIGN(MetricsMemoryDetails);
    393 };
    394 
    395 // static
    396 void MetricsService::RegisterPrefs(PrefRegistrySimple* registry) {
    397   DCHECK(IsSingleThreaded());
    398   registry->RegisterStringPref(prefs::kMetricsClientID, std::string());
    399   registry->RegisterIntegerPref(prefs::kMetricsLowEntropySource,
    400                                 kLowEntropySourceNotSet);
    401   registry->RegisterInt64Pref(prefs::kMetricsClientIDTimestamp, 0);
    402   registry->RegisterInt64Pref(prefs::kStabilityLaunchTimeSec, 0);
    403   registry->RegisterInt64Pref(prefs::kStabilityLastTimestampSec, 0);
    404   registry->RegisterStringPref(prefs::kStabilityStatsVersion, std::string());
    405   registry->RegisterInt64Pref(prefs::kStabilityStatsBuildTime, 0);
    406   registry->RegisterBooleanPref(prefs::kStabilityExitedCleanly, true);
    407   registry->RegisterBooleanPref(prefs::kStabilitySessionEndCompleted, true);
    408   registry->RegisterIntegerPref(prefs::kMetricsSessionID, -1);
    409   registry->RegisterIntegerPref(prefs::kStabilityLaunchCount, 0);
    410   registry->RegisterIntegerPref(prefs::kStabilityCrashCount, 0);
    411   registry->RegisterIntegerPref(prefs::kStabilityIncompleteSessionEndCount, 0);
    412   registry->RegisterIntegerPref(prefs::kStabilityPageLoadCount, 0);
    413   registry->RegisterIntegerPref(prefs::kStabilityRendererCrashCount, 0);
    414   registry->RegisterIntegerPref(prefs::kStabilityExtensionRendererCrashCount,
    415                                 0);
    416   registry->RegisterIntegerPref(prefs::kStabilityRendererHangCount, 0);
    417   registry->RegisterIntegerPref(prefs::kStabilityChildProcessCrashCount, 0);
    418   registry->RegisterIntegerPref(prefs::kStabilityBreakpadRegistrationFail, 0);
    419   registry->RegisterIntegerPref(prefs::kStabilityBreakpadRegistrationSuccess,
    420                                 0);
    421   registry->RegisterIntegerPref(prefs::kStabilityDebuggerPresent, 0);
    422   registry->RegisterIntegerPref(prefs::kStabilityDebuggerNotPresent, 0);
    423 #if defined(OS_CHROMEOS)
    424   registry->RegisterIntegerPref(prefs::kStabilityOtherUserCrashCount, 0);
    425   registry->RegisterIntegerPref(prefs::kStabilityKernelCrashCount, 0);
    426   registry->RegisterIntegerPref(prefs::kStabilitySystemUncleanShutdownCount, 0);
    427 #endif  // OS_CHROMEOS
    428 
    429   registry->RegisterListPref(prefs::kMetricsInitialLogs);
    430   registry->RegisterListPref(prefs::kMetricsOngoingLogs);
    431 
    432   registry->RegisterInt64Pref(prefs::kInstallDate, 0);
    433   registry->RegisterInt64Pref(prefs::kUninstallMetricsPageLoadCount, 0);
    434   registry->RegisterInt64Pref(prefs::kUninstallLaunchCount, 0);
    435   registry->RegisterInt64Pref(prefs::kUninstallMetricsUptimeSec, 0);
    436   registry->RegisterInt64Pref(prefs::kUninstallLastLaunchTimeSec, 0);
    437   registry->RegisterInt64Pref(prefs::kUninstallLastObservedRunTimeSec, 0);
    438 }
    439 
    440 // static
    441 void MetricsService::DiscardOldStabilityStats(PrefService* local_state) {
    442   local_state->SetBoolean(prefs::kStabilityExitedCleanly, true);
    443   local_state->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
    444 
    445   local_state->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
    446   local_state->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0);
    447   local_state->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0);
    448   local_state->SetInteger(prefs::kStabilityDebuggerPresent, 0);
    449   local_state->SetInteger(prefs::kStabilityDebuggerNotPresent, 0);
    450 
    451   local_state->SetInteger(prefs::kStabilityLaunchCount, 0);
    452   local_state->SetInteger(prefs::kStabilityCrashCount, 0);
    453 
    454   local_state->SetInteger(prefs::kStabilityPageLoadCount, 0);
    455   local_state->SetInteger(prefs::kStabilityRendererCrashCount, 0);
    456   local_state->SetInteger(prefs::kStabilityRendererHangCount, 0);
    457 
    458   local_state->SetInt64(prefs::kStabilityLaunchTimeSec, 0);
    459   local_state->SetInt64(prefs::kStabilityLastTimestampSec, 0);
    460 
    461   local_state->ClearPref(prefs::kStabilityPluginStats);
    462 
    463   local_state->ClearPref(prefs::kMetricsInitialLogs);
    464   local_state->ClearPref(prefs::kMetricsOngoingLogs);
    465 }
    466 
    467 MetricsService::MetricsService()
    468     : recording_active_(false),
    469       reporting_active_(false),
    470       test_mode_active_(false),
    471       state_(INITIALIZED),
    472       low_entropy_source_(kLowEntropySourceNotSet),
    473       idle_since_last_transmission_(false),
    474       next_window_id_(0),
    475       self_ptr_factory_(this),
    476       state_saver_factory_(this),
    477       waiting_for_asynchronous_reporting_step_(false),
    478       entropy_source_returned_(LAST_ENTROPY_NONE) {
    479   DCHECK(IsSingleThreaded());
    480   InitializeMetricsState();
    481 
    482   base::Closure callback = base::Bind(&MetricsService::StartScheduledUpload,
    483                                       self_ptr_factory_.GetWeakPtr());
    484   scheduler_.reset(new MetricsReportingScheduler(callback));
    485   log_manager_.set_log_serializer(new MetricsLogSerializer());
    486   log_manager_.set_max_ongoing_log_store_size(kUploadLogAvoidRetransmitSize);
    487 
    488   BrowserChildProcessObserver::Add(this);
    489 }
    490 
    491 MetricsService::~MetricsService() {
    492   DisableRecording();
    493 
    494   BrowserChildProcessObserver::Remove(this);
    495 }
    496 
    497 void MetricsService::Start() {
    498   HandleIdleSinceLastTransmission(false);
    499   EnableRecording();
    500   EnableReporting();
    501 }
    502 
    503 void MetricsService::StartRecordingForTests() {
    504   test_mode_active_ = true;
    505   EnableRecording();
    506   DisableReporting();
    507 }
    508 
    509 void MetricsService::Stop() {
    510   HandleIdleSinceLastTransmission(false);
    511   DisableReporting();
    512   DisableRecording();
    513 }
    514 
    515 void MetricsService::EnableReporting() {
    516   if (reporting_active_)
    517     return;
    518   reporting_active_ = true;
    519   StartSchedulerIfNecessary();
    520 }
    521 
    522 void MetricsService::DisableReporting() {
    523   reporting_active_ = false;
    524 }
    525 
    526 std::string MetricsService::GetClientId() {
    527   return client_id_;
    528 }
    529 
    530 scoped_ptr<const base::FieldTrial::EntropyProvider>
    531     MetricsService::CreateEntropyProvider(bool reporting_will_be_enabled) {
    532   // For metrics reporting-enabled users, we combine the client ID and low
    533   // entropy source to get the final entropy source. Otherwise, only use the low
    534   // entropy source.
    535   // This has two useful properties:
    536   //  1) It makes the entropy source less identifiable for parties that do not
    537   //     know the low entropy source.
    538   //  2) It makes the final entropy source resettable.
    539   const int low_entropy_source_value = GetLowEntropySource();
    540   UMA_HISTOGRAM_SPARSE_SLOWLY("UMA.LowEntropySourceValue",
    541                               low_entropy_source_value);
    542   if (reporting_will_be_enabled) {
    543     if (entropy_source_returned_ == LAST_ENTROPY_NONE)
    544       entropy_source_returned_ = LAST_ENTROPY_HIGH;
    545     DCHECK_EQ(LAST_ENTROPY_HIGH, entropy_source_returned_);
    546     const std::string high_entropy_source =
    547         client_id_ + base::IntToString(low_entropy_source_value);
    548     return scoped_ptr<const base::FieldTrial::EntropyProvider>(
    549         new metrics::SHA1EntropyProvider(high_entropy_source));
    550   }
    551 
    552   if (entropy_source_returned_ == LAST_ENTROPY_NONE)
    553     entropy_source_returned_ = LAST_ENTROPY_LOW;
    554   DCHECK_EQ(LAST_ENTROPY_LOW, entropy_source_returned_);
    555 
    556 #if defined(OS_ANDROID) || defined(OS_IOS)
    557   return scoped_ptr<const base::FieldTrial::EntropyProvider>(
    558       new metrics::CachingPermutedEntropyProvider(
    559           g_browser_process->local_state(),
    560           low_entropy_source_value,
    561           kMaxLowEntropySize));
    562 #else
    563   return scoped_ptr<const base::FieldTrial::EntropyProvider>(
    564       new metrics::PermutedEntropyProvider(low_entropy_source_value,
    565                                            kMaxLowEntropySize));
    566 #endif
    567 }
    568 
    569 void MetricsService::ForceClientIdCreation() {
    570   if (!client_id_.empty())
    571     return;
    572   PrefService* pref = g_browser_process->local_state();
    573   client_id_ = pref->GetString(prefs::kMetricsClientID);
    574   if (!client_id_.empty())
    575     return;
    576 
    577   client_id_ = GenerateClientID();
    578   pref->SetString(prefs::kMetricsClientID, client_id_);
    579 
    580   // Might as well make a note of how long this ID has existed
    581   pref->SetString(prefs::kMetricsClientIDTimestamp,
    582                   base::Int64ToString(Time::Now().ToTimeT()));
    583 }
    584 
    585 void MetricsService::EnableRecording() {
    586   DCHECK(IsSingleThreaded());
    587 
    588   if (recording_active_)
    589     return;
    590   recording_active_ = true;
    591 
    592   ForceClientIdCreation();
    593   child_process_logging::SetClientId(client_id_);
    594   if (!log_manager_.current_log())
    595     OpenNewLog();
    596 
    597   SetUpNotifications(&registrar_, this);
    598   content::RemoveActionCallback(action_callback_);
    599   action_callback_ = base::Bind(&MetricsService::OnUserAction,
    600                                 base::Unretained(this));
    601   content::AddActionCallback(action_callback_);
    602 }
    603 
    604 void MetricsService::DisableRecording() {
    605   DCHECK(IsSingleThreaded());
    606 
    607   if (!recording_active_)
    608     return;
    609   recording_active_ = false;
    610 
    611   content::RemoveActionCallback(action_callback_);
    612   registrar_.RemoveAll();
    613   PushPendingLogsToPersistentStorage();
    614   DCHECK(!log_manager_.has_staged_log());
    615 }
    616 
    617 bool MetricsService::recording_active() const {
    618   DCHECK(IsSingleThreaded());
    619   return recording_active_;
    620 }
    621 
    622 bool MetricsService::reporting_active() const {
    623   DCHECK(IsSingleThreaded());
    624   return reporting_active_;
    625 }
    626 
    627 // static
    628 void MetricsService::SetUpNotifications(
    629     content::NotificationRegistrar* registrar,
    630     content::NotificationObserver* observer) {
    631   registrar->Add(observer, chrome::NOTIFICATION_BROWSER_OPENED,
    632                  content::NotificationService::AllBrowserContextsAndSources());
    633   registrar->Add(observer, chrome::NOTIFICATION_BROWSER_CLOSED,
    634                  content::NotificationService::AllSources());
    635   registrar->Add(observer, chrome::NOTIFICATION_TAB_PARENTED,
    636                  content::NotificationService::AllSources());
    637   registrar->Add(observer, chrome::NOTIFICATION_TAB_CLOSING,
    638                  content::NotificationService::AllSources());
    639   registrar->Add(observer, content::NOTIFICATION_LOAD_START,
    640                  content::NotificationService::AllSources());
    641   registrar->Add(observer, content::NOTIFICATION_LOAD_STOP,
    642                  content::NotificationService::AllSources());
    643   registrar->Add(observer, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
    644                  content::NotificationService::AllSources());
    645   registrar->Add(observer, content::NOTIFICATION_RENDERER_PROCESS_HANG,
    646                  content::NotificationService::AllSources());
    647   registrar->Add(observer, chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
    648                  content::NotificationService::AllSources());
    649 }
    650 
    651 void MetricsService::BrowserChildProcessHostConnected(
    652     const content::ChildProcessData& data) {
    653   GetChildProcessStats(data).process_launches++;
    654 }
    655 
    656 void MetricsService::BrowserChildProcessCrashed(
    657     const content::ChildProcessData& data) {
    658   GetChildProcessStats(data).process_crashes++;
    659   // Exclude plugin crashes from the count below because we report them via
    660   // a separate UMA metric.
    661   if (!IsPluginProcess(data.process_type))
    662     IncrementPrefValue(prefs::kStabilityChildProcessCrashCount);
    663 }
    664 
    665 void MetricsService::BrowserChildProcessInstanceCreated(
    666     const content::ChildProcessData& data) {
    667   GetChildProcessStats(data).instances++;
    668 }
    669 
    670 void MetricsService::Observe(int type,
    671                              const content::NotificationSource& source,
    672                              const content::NotificationDetails& details) {
    673   DCHECK(log_manager_.current_log());
    674   DCHECK(IsSingleThreaded());
    675 
    676   if (!CanLogNotification())
    677     return;
    678 
    679   switch (type) {
    680     case chrome::NOTIFICATION_BROWSER_OPENED:
    681     case chrome::NOTIFICATION_BROWSER_CLOSED:
    682     case chrome::NOTIFICATION_TAB_PARENTED:
    683     case chrome::NOTIFICATION_TAB_CLOSING:
    684     case content::NOTIFICATION_LOAD_STOP:
    685       // These notifications are currently used only to break out of idle mode.
    686       break;
    687 
    688     case content::NOTIFICATION_LOAD_START: {
    689       content::NavigationController* controller =
    690           content::Source<content::NavigationController>(source).ptr();
    691       content::WebContents* web_contents = controller->GetWebContents();
    692       LogLoadStarted(web_contents);
    693       break;
    694     }
    695 
    696     case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
    697         content::RenderProcessHost::RendererClosedDetails* process_details =
    698             content::Details<
    699                 content::RenderProcessHost::RendererClosedDetails>(
    700                     details).ptr();
    701         content::RenderProcessHost* host =
    702             content::Source<content::RenderProcessHost>(source).ptr();
    703         LogRendererCrash(
    704             host, process_details->status, process_details->exit_code);
    705       }
    706       break;
    707 
    708     case content::NOTIFICATION_RENDERER_PROCESS_HANG:
    709       LogRendererHang();
    710       break;
    711 
    712     case chrome::NOTIFICATION_OMNIBOX_OPENED_URL: {
    713       MetricsLog* current_log =
    714           static_cast<MetricsLog*>(log_manager_.current_log());
    715       DCHECK(current_log);
    716       current_log->RecordOmniboxOpenedURL(
    717           *content::Details<OmniboxLog>(details).ptr());
    718       break;
    719     }
    720 
    721     default:
    722       NOTREACHED();
    723       break;
    724   }
    725 
    726   HandleIdleSinceLastTransmission(false);
    727 }
    728 
    729 void MetricsService::HandleIdleSinceLastTransmission(bool in_idle) {
    730   // If there wasn't a lot of action, maybe the computer was asleep, in which
    731   // case, the log transmissions should have stopped.  Here we start them up
    732   // again.
    733   if (!in_idle && idle_since_last_transmission_)
    734     StartSchedulerIfNecessary();
    735   idle_since_last_transmission_ = in_idle;
    736 }
    737 
    738 void MetricsService::RecordStartOfSessionEnd() {
    739   LogCleanShutdown();
    740   RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted, false);
    741 }
    742 
    743 void MetricsService::RecordCompletedSessionEnd() {
    744   LogCleanShutdown();
    745   RecordBooleanPrefValue(prefs::kStabilitySessionEndCompleted, true);
    746 }
    747 
    748 #if defined(OS_ANDROID) || defined(OS_IOS)
    749 void MetricsService::OnAppEnterBackground() {
    750   scheduler_->Stop();
    751 
    752   MarkAppCleanShutdownAndCommit();
    753 
    754   // At this point, there's no way of knowing when the process will be
    755   // killed, so this has to be treated similar to a shutdown, closing and
    756   // persisting all logs. Unlinke a shutdown, the state is primed to be ready
    757   // to continue logging and uploading if the process does return.
    758   if (recording_active() && state_ >= INITIAL_LOG_READY) {
    759     PushPendingLogsToPersistentStorage();
    760     // Persisting logs closes the current log, so start recording a new log
    761     // immediately to capture any background work that might be done before the
    762     // process is killed.
    763     OpenNewLog();
    764   }
    765 }
    766 
    767 void MetricsService::OnAppEnterForeground() {
    768   PrefService* pref = g_browser_process->local_state();
    769   pref->SetBoolean(prefs::kStabilityExitedCleanly, false);
    770 
    771   StartSchedulerIfNecessary();
    772 }
    773 #else
    774 void MetricsService::LogNeedForCleanShutdown() {
    775   PrefService* pref = g_browser_process->local_state();
    776   pref->SetBoolean(prefs::kStabilityExitedCleanly, false);
    777   // Redundant setting to be sure we call for a clean shutdown.
    778   clean_shutdown_status_ = NEED_TO_SHUTDOWN;
    779 }
    780 #endif  // defined(OS_ANDROID) || defined(OS_IOS)
    781 
    782 void MetricsService::RecordBreakpadRegistration(bool success) {
    783   if (!success)
    784     IncrementPrefValue(prefs::kStabilityBreakpadRegistrationFail);
    785   else
    786     IncrementPrefValue(prefs::kStabilityBreakpadRegistrationSuccess);
    787 }
    788 
    789 void MetricsService::RecordBreakpadHasDebugger(bool has_debugger) {
    790   if (!has_debugger)
    791     IncrementPrefValue(prefs::kStabilityDebuggerNotPresent);
    792   else
    793     IncrementPrefValue(prefs::kStabilityDebuggerPresent);
    794 }
    795 
    796 //------------------------------------------------------------------------------
    797 // private methods
    798 //------------------------------------------------------------------------------
    799 
    800 
    801 //------------------------------------------------------------------------------
    802 // Initialization methods
    803 
    804 void MetricsService::InitializeMetricsState() {
    805 #if defined(OS_POSIX)
    806   network_stats_server_ = chrome_common_net::kEchoTestServerLocation;
    807   http_pipelining_test_server_ = chrome_common_net::kPipelineTestServerBaseUrl;
    808 #else
    809   BrowserDistribution* dist = BrowserDistribution::GetDistribution();
    810   network_stats_server_ = dist->GetNetworkStatsServer();
    811   http_pipelining_test_server_ = dist->GetHttpPipeliningTestServer();
    812 #endif
    813 
    814   PrefService* pref = g_browser_process->local_state();
    815   DCHECK(pref);
    816 
    817   if ((pref->GetInt64(prefs::kStabilityStatsBuildTime)
    818        != MetricsLog::GetBuildTime()) ||
    819       (pref->GetString(prefs::kStabilityStatsVersion)
    820        != MetricsLog::GetVersionString())) {
    821     // This is a new version, so we don't want to confuse the stats about the
    822     // old version with info that we upload.
    823     DiscardOldStabilityStats(pref);
    824     pref->SetString(prefs::kStabilityStatsVersion,
    825                     MetricsLog::GetVersionString());
    826     pref->SetInt64(prefs::kStabilityStatsBuildTime,
    827                    MetricsLog::GetBuildTime());
    828   }
    829 
    830   // Update session ID
    831   session_id_ = pref->GetInteger(prefs::kMetricsSessionID);
    832   ++session_id_;
    833   pref->SetInteger(prefs::kMetricsSessionID, session_id_);
    834 
    835   // Stability bookkeeping
    836   IncrementPrefValue(prefs::kStabilityLaunchCount);
    837 
    838   if (!pref->GetBoolean(prefs::kStabilityExitedCleanly)) {
    839     IncrementPrefValue(prefs::kStabilityCrashCount);
    840     // Reset flag, and wait until we call LogNeedForCleanShutdown() before
    841     // monitoring.
    842     pref->SetBoolean(prefs::kStabilityExitedCleanly, true);
    843   }
    844 
    845   if (!pref->GetBoolean(prefs::kStabilitySessionEndCompleted)) {
    846     IncrementPrefValue(prefs::kStabilityIncompleteSessionEndCount);
    847     // This is marked false when we get a WM_ENDSESSION.
    848     pref->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
    849   }
    850 
    851   // Initialize uptime counters.
    852   int64 startup_uptime = MetricsLog::GetIncrementalUptime(pref);
    853   DCHECK_EQ(0, startup_uptime);
    854   // For backwards compatibility, leave this intact in case Omaha is checking
    855   // them.  prefs::kStabilityLastTimestampSec may also be useless now.
    856   // TODO(jar): Delete these if they have no uses.
    857   pref->SetInt64(prefs::kStabilityLaunchTimeSec, Time::Now().ToTimeT());
    858 
    859   // Bookkeeping for the uninstall metrics.
    860   IncrementLongPrefsValue(prefs::kUninstallLaunchCount);
    861 
    862   // Get stats on use of command line.
    863   const CommandLine* command_line(CommandLine::ForCurrentProcess());
    864   size_t common_commands = 0;
    865   if (command_line->HasSwitch(switches::kUserDataDir)) {
    866     ++common_commands;
    867     UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineDatDirCount", 1);
    868   }
    869 
    870   if (command_line->HasSwitch(switches::kApp)) {
    871     ++common_commands;
    872     UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineAppModeCount", 1);
    873   }
    874 
    875   size_t switch_count = command_line->GetSwitches().size();
    876   UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineFlagCount", switch_count);
    877   UMA_HISTOGRAM_COUNTS_100("Chrome.CommandLineUncommonFlagCount",
    878                            switch_count - common_commands);
    879 
    880   // Kick off the process of saving the state (so the uptime numbers keep
    881   // getting updated) every n minutes.
    882   ScheduleNextStateSave();
    883 }
    884 
    885 // static
    886 void MetricsService::InitTaskGetHardwareClass(
    887     base::WeakPtr<MetricsService> self,
    888     base::MessageLoopProxy* target_loop) {
    889   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
    890 
    891   std::string hardware_class;
    892 #if defined(OS_CHROMEOS)
    893   chromeos::system::StatisticsProvider::GetInstance()->GetMachineStatistic(
    894       "hardware_class", &hardware_class);
    895 #endif  // OS_CHROMEOS
    896 
    897   target_loop->PostTask(FROM_HERE,
    898       base::Bind(&MetricsService::OnInitTaskGotHardwareClass,
    899           self, hardware_class));
    900 }
    901 
    902 void MetricsService::OnInitTaskGotHardwareClass(
    903     const std::string& hardware_class) {
    904   DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
    905   hardware_class_ = hardware_class;
    906 
    907 #if defined(ENABLE_PLUGINS)
    908   // Start the next part of the init task: loading plugin information.
    909   PluginService::GetInstance()->GetPlugins(
    910       base::Bind(&MetricsService::OnInitTaskGotPluginInfo,
    911           self_ptr_factory_.GetWeakPtr()));
    912 #else
    913   std::vector<content::WebPluginInfo> plugin_list_empty;
    914   OnInitTaskGotPluginInfo(plugin_list_empty);
    915 #endif  // defined(ENABLE_PLUGINS)
    916 }
    917 
    918 void MetricsService::OnInitTaskGotPluginInfo(
    919     const std::vector<content::WebPluginInfo>& plugins) {
    920   DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
    921   plugins_ = plugins;
    922 
    923   // Schedules a task on a blocking pool thread to gather Google Update
    924   // statistics (requires Registry reads).
    925   BrowserThread::PostBlockingPoolTask(
    926       FROM_HERE,
    927       base::Bind(&MetricsService::InitTaskGetGoogleUpdateData,
    928                  self_ptr_factory_.GetWeakPtr(),
    929                  base::MessageLoop::current()->message_loop_proxy()));
    930 }
    931 
    932 // static
    933 void MetricsService::InitTaskGetGoogleUpdateData(
    934     base::WeakPtr<MetricsService> self,
    935     base::MessageLoopProxy* target_loop) {
    936   GoogleUpdateMetrics google_update_metrics;
    937 
    938 #if defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
    939   const bool system_install = GoogleUpdateSettings::IsSystemInstall();
    940 
    941   google_update_metrics.is_system_install = system_install;
    942   google_update_metrics.last_started_au =
    943       GoogleUpdateSettings::GetGoogleUpdateLastStartedAU(system_install);
    944   google_update_metrics.last_checked =
    945       GoogleUpdateSettings::GetGoogleUpdateLastChecked(system_install);
    946   GoogleUpdateSettings::GetUpdateDetailForGoogleUpdate(
    947       system_install,
    948       &google_update_metrics.google_update_data);
    949   GoogleUpdateSettings::GetUpdateDetail(
    950       system_install,
    951       &google_update_metrics.product_data);
    952 #endif  // defined(OS_WIN) && defined(GOOGLE_CHROME_BUILD)
    953 
    954   target_loop->PostTask(FROM_HERE,
    955       base::Bind(&MetricsService::OnInitTaskGotGoogleUpdateData,
    956           self, google_update_metrics));
    957 }
    958 
    959 void MetricsService::OnInitTaskGotGoogleUpdateData(
    960     const GoogleUpdateMetrics& google_update_metrics) {
    961   DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
    962 
    963   google_update_metrics_ = google_update_metrics;
    964 
    965   // Start the next part of the init task: fetching performance data.  This will
    966   // call into |FinishedReceivingProfilerData()| when the task completes.
    967   chrome_browser_metrics::TrackingSynchronizer::FetchProfilerDataAsynchronously(
    968       self_ptr_factory_.GetWeakPtr());
    969 }
    970 
    971 void MetricsService::OnUserAction(const std::string& action) {
    972   if (!CanLogNotification())
    973     return;
    974 
    975   log_manager_.current_log()->RecordUserAction(action.c_str());
    976   HandleIdleSinceLastTransmission(false);
    977 }
    978 
    979 void MetricsService::ReceivedProfilerData(
    980     const tracked_objects::ProcessDataSnapshot& process_data,
    981     int process_type) {
    982   DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
    983 
    984   // Upon the first callback, create the initial log so that we can immediately
    985   // save the profiler data.
    986   if (!initial_log_.get())
    987     initial_log_.reset(new MetricsLog(client_id_, session_id_));
    988 
    989   initial_log_->RecordProfilerData(process_data, process_type);
    990 }
    991 
    992 void MetricsService::FinishedReceivingProfilerData() {
    993   DCHECK_EQ(INIT_TASK_SCHEDULED, state_);
    994     state_ = INIT_TASK_DONE;
    995 }
    996 
    997 int MetricsService::GetLowEntropySource() {
    998   // Note that the default value for the low entropy source and the default pref
    999   // value are both kLowEntropySourceNotSet, which is used to identify if the
   1000   // value has been set or not.
   1001   if (low_entropy_source_ != kLowEntropySourceNotSet)
   1002     return low_entropy_source_;
   1003 
   1004   PrefService* local_state = g_browser_process->local_state();
   1005   const CommandLine* command_line(CommandLine::ForCurrentProcess());
   1006   // Only try to load the value from prefs if the user did not request a reset.
   1007   // Otherwise, skip to generating a new value.
   1008   if (!command_line->HasSwitch(switches::kResetVariationState)) {
   1009     int value = local_state->GetInteger(prefs::kMetricsLowEntropySource);
   1010     // Old versions of the code would generate values in the range of [1, 8192],
   1011     // before the range was switched to [0, 8191] and then to [0, 7999]. Map
   1012     // 8192 to 0, so that the 0th bucket remains uniform, while re-generating
   1013     // the low entropy source for old values in the [8000, 8191] range.
   1014     if (value == 8192)
   1015       value = 0;
   1016     // If the value is outside the [0, kMaxLowEntropySize) range, re-generate
   1017     // it below.
   1018     if (value >= 0 && value < kMaxLowEntropySize) {
   1019       low_entropy_source_ = value;
   1020       UMA_HISTOGRAM_BOOLEAN("UMA.GeneratedLowEntropySource", false);
   1021       return low_entropy_source_;
   1022     }
   1023   }
   1024 
   1025   UMA_HISTOGRAM_BOOLEAN("UMA.GeneratedLowEntropySource", true);
   1026   low_entropy_source_ = GenerateLowEntropySource();
   1027   local_state->SetInteger(prefs::kMetricsLowEntropySource, low_entropy_source_);
   1028   metrics::CachingPermutedEntropyProvider::ClearCache(local_state);
   1029 
   1030   return low_entropy_source_;
   1031 }
   1032 
   1033 // static
   1034 std::string MetricsService::GenerateClientID() {
   1035   return base::GenerateGUID();
   1036 }
   1037 
   1038 //------------------------------------------------------------------------------
   1039 // State save methods
   1040 
   1041 void MetricsService::ScheduleNextStateSave() {
   1042   state_saver_factory_.InvalidateWeakPtrs();
   1043 
   1044   base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
   1045       base::Bind(&MetricsService::SaveLocalState,
   1046                  state_saver_factory_.GetWeakPtr()),
   1047       base::TimeDelta::FromMinutes(kSaveStateIntervalMinutes));
   1048 }
   1049 
   1050 void MetricsService::SaveLocalState() {
   1051   PrefService* pref = g_browser_process->local_state();
   1052   if (!pref) {
   1053     NOTREACHED();
   1054     return;
   1055   }
   1056 
   1057   RecordCurrentState(pref);
   1058 
   1059   // TODO(jar):110021 Does this run down the batteries????
   1060   ScheduleNextStateSave();
   1061 }
   1062 
   1063 
   1064 //------------------------------------------------------------------------------
   1065 // Recording control methods
   1066 
   1067 void MetricsService::OpenNewLog() {
   1068   DCHECK(!log_manager_.current_log());
   1069 
   1070   log_manager_.BeginLoggingWithLog(new MetricsLog(client_id_, session_id_),
   1071                                    MetricsLogManager::ONGOING_LOG);
   1072   if (state_ == INITIALIZED) {
   1073     // We only need to schedule that run once.
   1074     state_ = INIT_TASK_SCHEDULED;
   1075 
   1076     // Schedules a task on the file thread for execution of slower
   1077     // initialization steps (such as plugin list generation) necessary
   1078     // for sending the initial log.  This avoids blocking the main UI
   1079     // thread.
   1080     BrowserThread::PostDelayedTask(
   1081         BrowserThread::FILE,
   1082         FROM_HERE,
   1083         base::Bind(&MetricsService::InitTaskGetHardwareClass,
   1084             self_ptr_factory_.GetWeakPtr(),
   1085             base::MessageLoop::current()->message_loop_proxy()),
   1086         base::TimeDelta::FromSeconds(kInitializationDelaySeconds));
   1087   }
   1088 }
   1089 
   1090 void MetricsService::CloseCurrentLog() {
   1091   if (!log_manager_.current_log())
   1092     return;
   1093 
   1094   // TODO(jar): Integrate bounds on log recording more consistently, so that we
   1095   // can stop recording logs that are too big much sooner.
   1096   if (log_manager_.current_log()->num_events() > kEventLimit) {
   1097     UMA_HISTOGRAM_COUNTS("UMA.Discarded Log Events",
   1098                          log_manager_.current_log()->num_events());
   1099     log_manager_.DiscardCurrentLog();
   1100     OpenNewLog();  // Start trivial log to hold our histograms.
   1101   }
   1102 
   1103   // Adds to ongoing logs.
   1104   log_manager_.current_log()->set_hardware_class(hardware_class_);
   1105 
   1106   // Put incremental data (histogram deltas, and realtime stats deltas) at the
   1107   // end of all log transmissions (initial log handles this separately).
   1108   // RecordIncrementalStabilityElements only exists on the derived
   1109   // MetricsLog class.
   1110   MetricsLog* current_log =
   1111       static_cast<MetricsLog*>(log_manager_.current_log());
   1112   DCHECK(current_log);
   1113   current_log->RecordEnvironmentProto(plugins_, google_update_metrics_);
   1114   current_log->RecordIncrementalStabilityElements(plugins_);
   1115   RecordCurrentHistograms();
   1116 
   1117   log_manager_.FinishCurrentLog();
   1118 }
   1119 
   1120 void MetricsService::PushPendingLogsToPersistentStorage() {
   1121   if (state_ < INITIAL_LOG_READY)
   1122     return;  // We didn't and still don't have time to get plugin list etc.
   1123 
   1124   if (log_manager_.has_staged_log()) {
   1125     // We may race here, and send second copy of the log later.
   1126     MetricsLogManager::StoreType store_type;
   1127     if (current_fetch_.get())
   1128       store_type = MetricsLogManager::PROVISIONAL_STORE;
   1129     else
   1130       store_type = MetricsLogManager::NORMAL_STORE;
   1131     log_manager_.StoreStagedLogAsUnsent(store_type);
   1132   }
   1133   DCHECK(!log_manager_.has_staged_log());
   1134   CloseCurrentLog();
   1135   StoreUnsentLogs();
   1136 
   1137   // If there was a staged and/or current log, then there is now at least one
   1138   // log waiting to be uploaded.
   1139   if (log_manager_.has_unsent_logs())
   1140     state_ = SENDING_OLD_LOGS;
   1141 }
   1142 
   1143 //------------------------------------------------------------------------------
   1144 // Transmission of logs methods
   1145 
   1146 void MetricsService::StartSchedulerIfNecessary() {
   1147   // Never schedule cutting or uploading of logs in test mode.
   1148   if (test_mode_active_)
   1149     return;
   1150 
   1151   // Even if reporting is disabled, the scheduler is needed to trigger the
   1152   // creation of the initial log, which must be done in order for any logs to be
   1153   // persisted on shutdown or backgrounding.
   1154   if (recording_active() && (reporting_active() || state_ < INITIAL_LOG_READY))
   1155     scheduler_->Start();
   1156 }
   1157 
   1158 void MetricsService::StartScheduledUpload() {
   1159   // If we're getting no notifications, then the log won't have much in it, and
   1160   // it's possible the computer is about to go to sleep, so don't upload and
   1161   // stop the scheduler.
   1162   // If recording has been turned off, the scheduler doesn't need to run.
   1163   // If reporting is off, proceed if the initial log hasn't been created, since
   1164   // that has to happen in order for logs to be cut and stored when persisting.
   1165   // TODO(stuartmorgan): Call Stop() on the schedule when reporting and/or
   1166   // recording are turned off instead of letting it fire and then aborting.
   1167   if (idle_since_last_transmission_ ||
   1168       !recording_active() ||
   1169       (!reporting_active() && state_ >= INITIAL_LOG_READY)) {
   1170     scheduler_->Stop();
   1171     scheduler_->UploadCancelled();
   1172     return;
   1173   }
   1174 
   1175   // If the callback was to upload an old log, but there no longer is one,
   1176   // just report success back to the scheduler to begin the ongoing log
   1177   // callbacks.
   1178   // TODO(stuartmorgan): Consider removing the distinction between
   1179   // SENDING_OLD_LOGS and SENDING_CURRENT_LOGS to simplify the state machine
   1180   // now that the log upload flow is the same for both modes.
   1181   if (state_ == SENDING_OLD_LOGS && !log_manager_.has_unsent_logs()) {
   1182     state_ = SENDING_CURRENT_LOGS;
   1183     scheduler_->UploadFinished(true /* healthy */, false /* no unsent logs */);
   1184     return;
   1185   }
   1186   // If there are unsent logs, send the next one. If not, start the asynchronous
   1187   // process of finalizing the current log for upload.
   1188   if (state_ == SENDING_OLD_LOGS) {
   1189     DCHECK(log_manager_.has_unsent_logs());
   1190     log_manager_.StageNextLogForUpload();
   1191     SendStagedLog();
   1192   } else {
   1193     StartFinalLogInfoCollection();
   1194   }
   1195 }
   1196 
   1197 void MetricsService::StartFinalLogInfoCollection() {
   1198   // Begin the multi-step process of collecting memory usage histograms:
   1199   // First spawn a task to collect the memory details; when that task is
   1200   // finished, it will call OnMemoryDetailCollectionDone. That will in turn
   1201   // call HistogramSynchronization to collect histograms from all renderers and
   1202   // then call OnHistogramSynchronizationDone to continue processing.
   1203   DCHECK(!waiting_for_asynchronous_reporting_step_);
   1204   waiting_for_asynchronous_reporting_step_ = true;
   1205 
   1206   base::Closure callback =
   1207       base::Bind(&MetricsService::OnMemoryDetailCollectionDone,
   1208                  self_ptr_factory_.GetWeakPtr());
   1209 
   1210   scoped_refptr<MetricsMemoryDetails> details(
   1211       new MetricsMemoryDetails(callback));
   1212   details->StartFetch(MemoryDetails::UPDATE_USER_METRICS);
   1213 
   1214   // Collect WebCore cache information to put into a histogram.
   1215   for (content::RenderProcessHost::iterator i(
   1216           content::RenderProcessHost::AllHostsIterator());
   1217        !i.IsAtEnd(); i.Advance())
   1218     i.GetCurrentValue()->Send(new ChromeViewMsg_GetCacheResourceStats());
   1219 }
   1220 
   1221 void MetricsService::OnMemoryDetailCollectionDone() {
   1222   DCHECK(IsSingleThreaded());
   1223   // This function should only be called as the callback from an ansynchronous
   1224   // step.
   1225   DCHECK(waiting_for_asynchronous_reporting_step_);
   1226 
   1227   // Create a callback_task for OnHistogramSynchronizationDone.
   1228   base::Closure callback = base::Bind(
   1229       &MetricsService::OnHistogramSynchronizationDone,
   1230       self_ptr_factory_.GetWeakPtr());
   1231 
   1232   // Set up the callback to task to call after we receive histograms from all
   1233   // child processes. Wait time specifies how long to wait before absolutely
   1234   // calling us back on the task.
   1235   content::FetchHistogramsAsynchronously(
   1236       base::MessageLoop::current(), callback,
   1237       base::TimeDelta::FromMilliseconds(kMaxHistogramGatheringWaitDuration));
   1238 }
   1239 
   1240 void MetricsService::OnHistogramSynchronizationDone() {
   1241   DCHECK(IsSingleThreaded());
   1242   // This function should only be called as the callback from an ansynchronous
   1243   // step.
   1244   DCHECK(waiting_for_asynchronous_reporting_step_);
   1245 
   1246   waiting_for_asynchronous_reporting_step_ = false;
   1247   OnFinalLogInfoCollectionDone();
   1248 }
   1249 
   1250 void MetricsService::OnFinalLogInfoCollectionDone() {
   1251   // If somehow there is a fetch in progress, we return and hope things work
   1252   // out. The scheduler isn't informed since if this happens, the scheduler
   1253   // will get a response from the upload.
   1254   DCHECK(!current_fetch_.get());
   1255   if (current_fetch_.get())
   1256     return;
   1257 
   1258   // Abort if metrics were turned off during the final info gathering.
   1259   if (!recording_active()) {
   1260     scheduler_->Stop();
   1261     scheduler_->UploadCancelled();
   1262     return;
   1263   }
   1264 
   1265   StageNewLog();
   1266 
   1267   // If logs shouldn't be uploaded, stop here. It's important that this check
   1268   // be after StageNewLog(), otherwise the previous logs will never be loaded,
   1269   // and thus the open log won't be persisted.
   1270   // TODO(stuartmorgan): This is unnecessarily complicated; restructure loading
   1271   // of previous logs to not require running part of the upload logic.
   1272   // http://crbug.com/157337
   1273   if (!reporting_active()) {
   1274     scheduler_->Stop();
   1275     scheduler_->UploadCancelled();
   1276     return;
   1277   }
   1278 
   1279   SendStagedLog();
   1280 }
   1281 
   1282 void MetricsService::StageNewLog() {
   1283   if (log_manager_.has_staged_log())
   1284     return;
   1285 
   1286   switch (state_) {
   1287     case INITIALIZED:
   1288     case INIT_TASK_SCHEDULED:  // We should be further along by now.
   1289       NOTREACHED();
   1290       return;
   1291 
   1292     case INIT_TASK_DONE:
   1293       PrepareInitialLog();
   1294       DCHECK_EQ(INIT_TASK_DONE, state_);
   1295       log_manager_.LoadPersistedUnsentLogs();
   1296       state_ = INITIAL_LOG_READY;
   1297       break;
   1298 
   1299     case SENDING_OLD_LOGS:
   1300       NOTREACHED();  // Shouldn't be staging a new log during old log sending.
   1301       return;
   1302 
   1303     case SENDING_CURRENT_LOGS:
   1304       CloseCurrentLog();
   1305       OpenNewLog();
   1306       log_manager_.StageNextLogForUpload();
   1307       break;
   1308 
   1309     default:
   1310       NOTREACHED();
   1311       return;
   1312   }
   1313 
   1314   DCHECK(log_manager_.has_staged_log());
   1315 }
   1316 
   1317 void MetricsService::PrepareInitialLog() {
   1318   DCHECK_EQ(INIT_TASK_DONE, state_);
   1319 
   1320   DCHECK(initial_log_.get());
   1321   initial_log_->set_hardware_class(hardware_class_);
   1322   initial_log_->RecordEnvironment(plugins_, google_update_metrics_);
   1323 
   1324   // Histograms only get written to the current log, so make the new log current
   1325   // before writing them.
   1326   log_manager_.PauseCurrentLog();
   1327   log_manager_.BeginLoggingWithLog(initial_log_.release(),
   1328                                    MetricsLogManager::INITIAL_LOG);
   1329   RecordCurrentHistograms();
   1330   log_manager_.FinishCurrentLog();
   1331   log_manager_.ResumePausedLog();
   1332 
   1333   DCHECK(!log_manager_.has_staged_log());
   1334   log_manager_.StageNextLogForUpload();
   1335 }
   1336 
   1337 void MetricsService::StoreUnsentLogs() {
   1338   if (state_ < INITIAL_LOG_READY)
   1339     return;  // We never Recalled the prior unsent logs.
   1340 
   1341   log_manager_.PersistUnsentLogs();
   1342 }
   1343 
   1344 void MetricsService::SendStagedLog() {
   1345   DCHECK(log_manager_.has_staged_log());
   1346 
   1347   PrepareFetchWithStagedLog();
   1348 
   1349   bool upload_created = (current_fetch_.get() != NULL);
   1350   UMA_HISTOGRAM_BOOLEAN("UMA.UploadCreation", upload_created);
   1351   if (!upload_created) {
   1352     // Compression failed, and log discarded :-/.
   1353     // Skip this upload and hope things work out next time.
   1354     log_manager_.DiscardStagedLog();
   1355     scheduler_->UploadCancelled();
   1356     return;
   1357   }
   1358 
   1359   DCHECK(!waiting_for_asynchronous_reporting_step_);
   1360   waiting_for_asynchronous_reporting_step_ = true;
   1361 
   1362   current_fetch_->Start();
   1363 
   1364   HandleIdleSinceLastTransmission(true);
   1365 }
   1366 
   1367 void MetricsService::PrepareFetchWithStagedLog() {
   1368   DCHECK(log_manager_.has_staged_log());
   1369 
   1370   // Prepare the protobuf version.
   1371   DCHECK(!current_fetch_.get());
   1372   if (log_manager_.has_staged_log()) {
   1373     current_fetch_.reset(net::URLFetcher::Create(
   1374         GURL(kServerUrl), net::URLFetcher::POST, this));
   1375     current_fetch_->SetRequestContext(
   1376         g_browser_process->system_request_context());
   1377 
   1378     // Compress the protobufs 50% of the time. This can be used to see if
   1379     // compressed protobufs are being mishandled by machines between the
   1380     // client/server or monitoring programs/firewalls on the client.
   1381     bool gzip_protobuf_before_uploading =
   1382         metrics::ShouldGzipProtobufsBeforeUploading();
   1383     if (gzip_protobuf_before_uploading) {
   1384       std::string log_text = log_manager_.staged_log_text();
   1385       std::string compressed_log_text;
   1386       bool compression_successful = chrome::GzipCompress(log_text,
   1387                                                          &compressed_log_text);
   1388       DCHECK(compression_successful);
   1389       if (compression_successful) {
   1390         current_fetch_->SetUploadData(kMimeType, compressed_log_text);
   1391         // Tell the server that we're uploading gzipped protobufs.
   1392         current_fetch_->SetExtraRequestHeaders("content-encoding: gzip");
   1393         UMA_HISTOGRAM_PERCENTAGE(
   1394             "UMA.ProtoCompressionRatio",
   1395             100 * compressed_log_text.size() / log_text.size());
   1396         UMA_HISTOGRAM_CUSTOM_COUNTS(
   1397             "UMA.ProtoGzippedKBSaved",
   1398             (log_text.size() - compressed_log_text.size()) / 1024,
   1399             1, 2000, 50);
   1400       }
   1401     } else {
   1402       current_fetch_->SetUploadData(kMimeType, log_manager_.staged_log_text());
   1403     }
   1404     UMA_HISTOGRAM_BOOLEAN("UMA.ProtoGzipped",
   1405                           gzip_protobuf_before_uploading);
   1406 
   1407     // We already drop cookies server-side, but we might as well strip them out
   1408     // client-side as well.
   1409     current_fetch_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
   1410                                  net::LOAD_DO_NOT_SEND_COOKIES);
   1411   }
   1412 }
   1413 
   1414 void MetricsService::OnURLFetchComplete(const net::URLFetcher* source) {
   1415   DCHECK(waiting_for_asynchronous_reporting_step_);
   1416 
   1417   // We're not allowed to re-use the existing |URLFetcher|s, so free them here.
   1418   // Note however that |source| is aliased to the fetcher, so we should be
   1419   // careful not to delete it too early.
   1420   DCHECK_EQ(current_fetch_.get(), source);
   1421   scoped_ptr<net::URLFetcher> s(current_fetch_.Pass());
   1422 
   1423   int response_code = source->GetResponseCode();
   1424 
   1425   // Log a histogram to track response success vs. failure rates.
   1426   UMA_HISTOGRAM_ENUMERATION("UMA.UploadResponseStatus.Protobuf",
   1427                             ResponseCodeToStatus(response_code),
   1428                             NUM_RESPONSE_STATUSES);
   1429 
   1430   // If the upload was provisionally stored, drop it now that the upload is
   1431   // known to have gone through.
   1432   log_manager_.DiscardLastProvisionalStore();
   1433 
   1434   bool upload_succeeded = response_code == 200;
   1435 
   1436   // Provide boolean for error recovery (allow us to ignore response_code).
   1437   bool discard_log = false;
   1438   const size_t log_size = log_manager_.staged_log_text().length();
   1439   if (!upload_succeeded && log_size > kUploadLogAvoidRetransmitSize) {
   1440     UMA_HISTOGRAM_COUNTS("UMA.Large Rejected Log was Discarded",
   1441                          static_cast<int>(log_size));
   1442     discard_log = true;
   1443   } else if (response_code == 400) {
   1444     // Bad syntax.  Retransmission won't work.
   1445     discard_log = true;
   1446   }
   1447 
   1448   if (upload_succeeded || discard_log)
   1449     log_manager_.DiscardStagedLog();
   1450 
   1451   waiting_for_asynchronous_reporting_step_ = false;
   1452 
   1453   if (!log_manager_.has_staged_log()) {
   1454     switch (state_) {
   1455       case INITIAL_LOG_READY:
   1456         state_ = log_manager_.has_unsent_logs() ? SENDING_OLD_LOGS
   1457                                                 : SENDING_CURRENT_LOGS;
   1458         break;
   1459 
   1460       case SENDING_OLD_LOGS:
   1461         // Store the updated list to disk now that the removed log is uploaded.
   1462         StoreUnsentLogs();
   1463         if (!log_manager_.has_unsent_logs())
   1464           state_ = SENDING_CURRENT_LOGS;
   1465         break;
   1466 
   1467       case SENDING_CURRENT_LOGS:
   1468         break;
   1469 
   1470       default:
   1471         NOTREACHED();
   1472         break;
   1473     }
   1474 
   1475     if (log_manager_.has_unsent_logs())
   1476       DCHECK_LT(state_, SENDING_CURRENT_LOGS);
   1477   }
   1478 
   1479   // Error 400 indicates a problem with the log, not with the server, so
   1480   // don't consider that a sign that the server is in trouble.
   1481   bool server_is_healthy = upload_succeeded || response_code == 400;
   1482   scheduler_->UploadFinished(server_is_healthy, log_manager_.has_unsent_logs());
   1483 
   1484   // Collect network stats if UMA upload succeeded.
   1485   IOThread* io_thread = g_browser_process->io_thread();
   1486   if (server_is_healthy && io_thread) {
   1487     chrome_browser_net::CollectNetworkStats(network_stats_server_, io_thread);
   1488     chrome_browser_net::CollectPipeliningCapabilityStatsOnUIThread(
   1489         http_pipelining_test_server_, io_thread);
   1490 #if defined(OS_WIN)
   1491     chrome::CollectTimeTicksStats();
   1492 #endif
   1493   }
   1494 }
   1495 
   1496 void MetricsService::IncrementPrefValue(const char* path) {
   1497   PrefService* pref = g_browser_process->local_state();
   1498   DCHECK(pref);
   1499   int value = pref->GetInteger(path);
   1500   pref->SetInteger(path, value + 1);
   1501 }
   1502 
   1503 void MetricsService::IncrementLongPrefsValue(const char* path) {
   1504   PrefService* pref = g_browser_process->local_state();
   1505   DCHECK(pref);
   1506   int64 value = pref->GetInt64(path);
   1507   pref->SetInt64(path, value + 1);
   1508 }
   1509 
   1510 void MetricsService::LogLoadStarted(content::WebContents* web_contents) {
   1511   content::RecordAction(content::UserMetricsAction("PageLoad"));
   1512   HISTOGRAM_ENUMERATION("Chrome.UmaPageloadCounter", 1, 2);
   1513   IncrementPrefValue(prefs::kStabilityPageLoadCount);
   1514   IncrementLongPrefsValue(prefs::kUninstallMetricsPageLoadCount);
   1515   // We need to save the prefs, as page load count is a critical stat, and it
   1516   // might be lost due to a crash :-(.
   1517 }
   1518 
   1519 void MetricsService::LogRendererCrash(content::RenderProcessHost* host,
   1520                                       base::TerminationStatus status,
   1521                                       int exit_code) {
   1522   Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
   1523   ExtensionService* service = profile->GetExtensionService();
   1524   bool was_extension_process =
   1525       service && service->process_map()->Contains(host->GetID());
   1526   if (status == base::TERMINATION_STATUS_PROCESS_CRASHED ||
   1527       status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) {
   1528     if (was_extension_process) {
   1529       IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount);
   1530 
   1531       UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension",
   1532                                   MapCrashExitCodeForHistogram(exit_code));
   1533     } else {
   1534       IncrementPrefValue(prefs::kStabilityRendererCrashCount);
   1535 
   1536       UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer",
   1537                                   MapCrashExitCodeForHistogram(exit_code));
   1538     }
   1539 
   1540     UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildCrashes",
   1541                              was_extension_process ? 2 : 1);
   1542   } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) {
   1543     UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildKills",
   1544                              was_extension_process ? 2 : 1);
   1545   } else if (status == base::TERMINATION_STATUS_STILL_RUNNING) {
   1546     UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.DisconnectedAlive",
   1547                                was_extension_process ? 2 : 1);
   1548     }
   1549   }
   1550 
   1551 void MetricsService::LogRendererHang() {
   1552   IncrementPrefValue(prefs::kStabilityRendererHangCount);
   1553 }
   1554 
   1555 bool MetricsService::UmaMetricsProperlyShutdown() {
   1556   CHECK(clean_shutdown_status_ == CLEANLY_SHUTDOWN ||
   1557         clean_shutdown_status_ == NEED_TO_SHUTDOWN);
   1558   return clean_shutdown_status_ == CLEANLY_SHUTDOWN;
   1559 }
   1560 
   1561 void MetricsService::LogCleanShutdown() {
   1562   // Redundant hack to write pref ASAP.
   1563   MarkAppCleanShutdownAndCommit();
   1564 
   1565   // Redundant setting to assure that we always reset this value at shutdown
   1566   // (and that we don't use some alternate path, and not call LogCleanShutdown).
   1567   clean_shutdown_status_ = CLEANLY_SHUTDOWN;
   1568 
   1569   RecordBooleanPrefValue(prefs::kStabilityExitedCleanly, true);
   1570 }
   1571 
   1572 #if defined(OS_CHROMEOS)
   1573 void MetricsService::LogChromeOSCrash(const std::string &crash_type) {
   1574   if (crash_type == "user")
   1575     IncrementPrefValue(prefs::kStabilityOtherUserCrashCount);
   1576   else if (crash_type == "kernel")
   1577     IncrementPrefValue(prefs::kStabilityKernelCrashCount);
   1578   else if (crash_type == "uncleanshutdown")
   1579     IncrementPrefValue(prefs::kStabilitySystemUncleanShutdownCount);
   1580   else
   1581     NOTREACHED() << "Unexpected Chrome OS crash type " << crash_type;
   1582   // Wake up metrics logs sending if necessary now that new
   1583   // log data is available.
   1584   HandleIdleSinceLastTransmission(false);
   1585 }
   1586 #endif  // OS_CHROMEOS
   1587 
   1588 void MetricsService::LogPluginLoadingError(const base::FilePath& plugin_path) {
   1589   content::WebPluginInfo plugin;
   1590   bool success =
   1591       content::PluginService::GetInstance()->GetPluginInfoByPath(plugin_path,
   1592                                                                  &plugin);
   1593   DCHECK(success);
   1594   ChildProcessStats& stats = child_process_stats_buffer_[plugin.name];
   1595   // Initialize the type if this entry is new.
   1596   if (stats.process_type == content::PROCESS_TYPE_UNKNOWN) {
   1597     // The plug-in process might not actually of type PLUGIN (which means
   1598     // NPAPI), but we only care that it is *a* plug-in process.
   1599     stats.process_type = content::PROCESS_TYPE_PLUGIN;
   1600   } else {
   1601     DCHECK(IsPluginProcess(stats.process_type));
   1602   }
   1603   stats.loading_errors++;
   1604 }
   1605 
   1606 MetricsService::ChildProcessStats& MetricsService::GetChildProcessStats(
   1607     const content::ChildProcessData& data) {
   1608   const string16& child_name = data.name;
   1609   if (!ContainsKey(child_process_stats_buffer_, child_name)) {
   1610     child_process_stats_buffer_[child_name] =
   1611         ChildProcessStats(data.process_type);
   1612   }
   1613   return child_process_stats_buffer_[child_name];
   1614 }
   1615 
   1616 void MetricsService::RecordPluginChanges(PrefService* pref) {
   1617   ListPrefUpdate update(pref, prefs::kStabilityPluginStats);
   1618   ListValue* plugins = update.Get();
   1619   DCHECK(plugins);
   1620 
   1621   for (ListValue::iterator value_iter = plugins->begin();
   1622        value_iter != plugins->end(); ++value_iter) {
   1623     if (!(*value_iter)->IsType(Value::TYPE_DICTIONARY)) {
   1624       NOTREACHED();
   1625       continue;
   1626     }
   1627 
   1628     DictionaryValue* plugin_dict = static_cast<DictionaryValue*>(*value_iter);
   1629     std::string plugin_name;
   1630     plugin_dict->GetString(prefs::kStabilityPluginName, &plugin_name);
   1631     if (plugin_name.empty()) {
   1632       NOTREACHED();
   1633       continue;
   1634     }
   1635 
   1636     // TODO(viettrungluu): remove conversions
   1637     string16 name16 = UTF8ToUTF16(plugin_name);
   1638     if (child_process_stats_buffer_.find(name16) ==
   1639         child_process_stats_buffer_.end()) {
   1640       continue;
   1641     }
   1642 
   1643     ChildProcessStats stats = child_process_stats_buffer_[name16];
   1644     if (stats.process_launches) {
   1645       int launches = 0;
   1646       plugin_dict->GetInteger(prefs::kStabilityPluginLaunches, &launches);
   1647       launches += stats.process_launches;
   1648       plugin_dict->SetInteger(prefs::kStabilityPluginLaunches, launches);
   1649     }
   1650     if (stats.process_crashes) {
   1651       int crashes = 0;
   1652       plugin_dict->GetInteger(prefs::kStabilityPluginCrashes, &crashes);
   1653       crashes += stats.process_crashes;
   1654       plugin_dict->SetInteger(prefs::kStabilityPluginCrashes, crashes);
   1655     }
   1656     if (stats.instances) {
   1657       int instances = 0;
   1658       plugin_dict->GetInteger(prefs::kStabilityPluginInstances, &instances);
   1659       instances += stats.instances;
   1660       plugin_dict->SetInteger(prefs::kStabilityPluginInstances, instances);
   1661     }
   1662     if (stats.loading_errors) {
   1663       int loading_errors = 0;
   1664       plugin_dict->GetInteger(prefs::kStabilityPluginLoadingErrors,
   1665                               &loading_errors);
   1666       loading_errors += stats.loading_errors;
   1667       plugin_dict->SetInteger(prefs::kStabilityPluginLoadingErrors,
   1668                               loading_errors);
   1669     }
   1670 
   1671     child_process_stats_buffer_.erase(name16);
   1672   }
   1673 
   1674   // Now go through and add dictionaries for plugins that didn't already have
   1675   // reports in Local State.
   1676   for (std::map<string16, ChildProcessStats>::iterator cache_iter =
   1677            child_process_stats_buffer_.begin();
   1678        cache_iter != child_process_stats_buffer_.end(); ++cache_iter) {
   1679     ChildProcessStats stats = cache_iter->second;
   1680 
   1681     // Insert only plugins information into the plugins list.
   1682     if (!IsPluginProcess(stats.process_type))
   1683       continue;
   1684 
   1685     // TODO(viettrungluu): remove conversion
   1686     std::string plugin_name = UTF16ToUTF8(cache_iter->first);
   1687 
   1688     DictionaryValue* plugin_dict = new DictionaryValue;
   1689 
   1690     plugin_dict->SetString(prefs::kStabilityPluginName, plugin_name);
   1691     plugin_dict->SetInteger(prefs::kStabilityPluginLaunches,
   1692                             stats.process_launches);
   1693     plugin_dict->SetInteger(prefs::kStabilityPluginCrashes,
   1694                             stats.process_crashes);
   1695     plugin_dict->SetInteger(prefs::kStabilityPluginInstances,
   1696                             stats.instances);
   1697     plugin_dict->SetInteger(prefs::kStabilityPluginLoadingErrors,
   1698                             stats.loading_errors);
   1699     plugins->Append(plugin_dict);
   1700   }
   1701   child_process_stats_buffer_.clear();
   1702 }
   1703 
   1704 bool MetricsService::CanLogNotification() {
   1705   // We simply don't log anything to UMA if there is a single incognito
   1706   // session visible. The problem is that we always notify using the orginal
   1707   // profile in order to simplify notification processing.
   1708   return !chrome::IsOffTheRecordSessionActive();
   1709 }
   1710 
   1711 void MetricsService::RecordBooleanPrefValue(const char* path, bool value) {
   1712   DCHECK(IsSingleThreaded());
   1713 
   1714   PrefService* pref = g_browser_process->local_state();
   1715   DCHECK(pref);
   1716 
   1717   pref->SetBoolean(path, value);
   1718   RecordCurrentState(pref);
   1719 }
   1720 
   1721 void MetricsService::RecordCurrentState(PrefService* pref) {
   1722   pref->SetInt64(prefs::kStabilityLastTimestampSec, Time::Now().ToTimeT());
   1723 
   1724   RecordPluginChanges(pref);
   1725 }
   1726 
   1727 // static
   1728 bool MetricsService::IsPluginProcess(int process_type) {
   1729   return (process_type == content::PROCESS_TYPE_PLUGIN ||
   1730           process_type == content::PROCESS_TYPE_PPAPI_PLUGIN ||
   1731           process_type == content::PROCESS_TYPE_PPAPI_BROKER);
   1732 }
   1733 
   1734 #if defined(OS_CHROMEOS)
   1735 void MetricsService::StartExternalMetrics() {
   1736   external_metrics_ = new chromeos::ExternalMetrics;
   1737   external_metrics_->Start();
   1738 }
   1739 #endif
   1740 
   1741 // static
   1742 bool MetricsServiceHelper::IsMetricsReportingEnabled() {
   1743   bool result = false;
   1744   const PrefService* local_state = g_browser_process->local_state();
   1745   if (local_state) {
   1746     const PrefService::Preference* uma_pref =
   1747         local_state->FindPreference(prefs::kMetricsReportingEnabled);
   1748     if (uma_pref) {
   1749       bool success = uma_pref->GetValue()->GetAsBoolean(&result);
   1750       DCHECK(success);
   1751     }
   1752   }
   1753   return result;
   1754 }
   1755