Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(252)

Unified Diff: ios/chrome/app/application_delegate/metrics_mediator.mm

Issue 2580363002: Upstream Chrome on iOS source code [1/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ios/chrome/app/application_delegate/metrics_mediator.mm
diff --git a/ios/chrome/app/application_delegate/metrics_mediator.mm b/ios/chrome/app/application_delegate/metrics_mediator.mm
new file mode 100644
index 0000000000000000000000000000000000000000..074ff8fc2a82c280642aff2138f4664520ca87f4
--- /dev/null
+++ b/ios/chrome/app/application_delegate/metrics_mediator.mm
@@ -0,0 +1,394 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/app/application_delegate/metrics_mediator.h"
+
+#include "base/ios/weak_nsobject.h"
+#include "base/mac/bind_objc_block.h"
+#include "base/metrics/user_metrics_action.h"
+#include "base/strings/sys_string_conversions.h"
+#include "components/crash/core/common/crash_keys.h"
+#include "components/metrics/metrics_pref_names.h"
+#include "components/metrics/metrics_service.h"
+#include "components/prefs/pref_service.h"
+#import "ios/chrome/app/application_delegate/startup_information.h"
+#include "ios/chrome/browser/application_context.h"
+#include "ios/chrome/browser/chrome_url_constants.h"
+#include "ios/chrome/browser/crash_report/breakpad_helper.h"
+#import "ios/chrome/browser/crash_report/crash_report_background_uploader.h"
+#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/metrics/first_user_action_recorder.h"
+#import "ios/chrome/browser/metrics/previous_session_info.h"
+#import "ios/chrome/browser/net/connection_type_observer_bridge.h"
+#include "ios/chrome/browser/pref_names.h"
+#import "ios/chrome/browser/tabs/tab.h"
+#import "ios/chrome/browser/tabs/tab_model.h"
+#import "ios/chrome/browser/ui/main/browser_view_information.h"
+#include "ios/chrome/common/app_group/app_group_metrics_mainapp.h"
+#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
+#include "ios/public/provider/chrome/browser/distribution/app_distribution_provider.h"
+#include "ios/web/public/web_thread.h"
+#include "url/gurl.h"
+
+namespace {
+// The amount of time (in seconds) between two background fetch calls.
+// TODO(crbug.com/496172): Re-enable background fetch.
+const NSTimeInterval kBackgroundFetchIntervalDelay =
+ UIApplicationBackgroundFetchIntervalNever;
+// The amount of time (in seconds) to wait for the user to start a new task.
+const NSTimeInterval kFirstUserActionTimeout = 30.0;
+} // namespace
+
+namespace metrics_mediator {
+NSString* const kAppEnteredBackgroundDateKey = @"kAppEnteredBackgroundDate";
+} // namespace metrics_mediator_constants
+
+using metrics_mediator::kAppEnteredBackgroundDateKey;
+
+@interface MetricsMediator ()<CRConnectionTypeObserverBridge> {
+ // Whether or not the crash reports present at startup have been processed to
+ // determine if the last app lifetime ended in an OOM crash.
+ BOOL _hasProcessedCrashReportsPresentAtStartup;
+
+ // Observer for the connection type. Contains a valid object only if the
+ // metrics setting is set to wifi-only.
+ std::unique_ptr<ConnectionTypeObserverBridge> connectionTypeObserverBridge_;
+}
+
+// Starts or stops metrics recording and/or uploading.
+- (void)setMetricsEnabled:(BOOL)enabled withUploading:(BOOL)allowUploading;
+// Sets variables needed by the app_group application to collect UMA data.
+// Process the pending logs produced by extensions.
+// Called on start (cold and warm) and UMA settings change to update the
+// collecting settings in extensions.
+- (void)setAppGroupMetricsEnabled:(BOOL)enabled;
+// Processes crash reports present at startup.
+- (void)processCrashReportsPresentAtStartup;
+// Starts or stops crash recording and/or uploading.
+- (void)setBreakpadEnabled:(BOOL)enabled withUploading:(BOOL)allowUploading;
+// Starts or stops watching for wwan events.
+- (void)setWatchWWANEnabled:(BOOL)enabled;
+// Enable/disable transmission of accumulated logs and crash reports (dumps).
+- (void)setReporting:(BOOL)enableReporting;
+// Enable/Disable uploading crash reports.
+- (void)setBreakpadUploadingEnabled:(BOOL)enableUploading;
+// Returns YES if the metrics are enabled and the reporting is wifi-only.
+- (BOOL)isMetricsReportingEnabledWifiOnly;
+// Update metrics prefs on a permission (opt-in/out) change. When opting out,
+// this clears various client ids. When opting in, this resets saving crash
+// prefs, so as not to trigger upload of various stale data.
+// Mirrors the function in metrics_reporting_state.cc.
+- (void)updateMetricsPrefsOnPermissionChange:(BOOL)enabled;
+// Logs the number of tabs with UMAHistogramCount100 and allows testing.
++ (void)recordNumTabAtStartup:(int)numTabs;
+// Logs the number of tabs with UMAHistogramCount100 and allows testing.
++ (void)recordNumTabAtResume:(int)numTabs;
+
+@end
+
+@implementation MetricsMediator
+
+#pragma mark - Public methods.
+
++ (void)logStartupDuration:(id<StartupInformation>)startupInformation {
+ if (![startupInformation isColdStart])
+ return;
+
+ base::TimeDelta startDuration =
+ base::TimeTicks::Now() - [startupInformation appLaunchTime];
+ if ([startupInformation startupParameters]) {
+ UMA_HISTOGRAM_TIMES("Startup.ColdStartWithExternalURLTime", startDuration);
+ } else {
+ UMA_HISTOGRAM_TIMES("Startup.ColdStartWithoutExternalURLTime",
+ startDuration);
+ }
+}
+
++ (void)logDateInUserDefaults {
+ [[NSUserDefaults standardUserDefaults]
+ setObject:[NSDate date]
+ forKey:metrics_mediator::kAppEnteredBackgroundDateKey];
+}
+
++ (void)logLaunchMetricsWithStartupInformation:
+ (id<StartupInformation>)startupInformation
+ browserViewInformation:
+ (id<BrowserViewInformation>)browserViewInformation {
+ int numTabs = static_cast<int>([[browserViewInformation mainTabModel] count]);
+ if (startupInformation.isColdStart) {
+ [self recordNumTabAtStartup:numTabs];
+ } else {
+ [self recordNumTabAtResume:numTabs];
+ }
+
+ if (UIAccessibilityIsVoiceOverRunning()) {
+ base::RecordAction(
+ base::UserMetricsAction("MobileVoiceOverActiveOnLaunch"));
+ }
+
+ // Create the first user action recorder and schedule a task to expire it
+ // after some timeout. If unable to determine the last time the app entered
+ // the background (i.e. either first run or restore after crash), don't bother
+ // recording the first user action since fresh start wouldn't be triggered.
+ NSDate* lastAppClose = [[NSUserDefaults standardUserDefaults]
+ objectForKey:kAppEnteredBackgroundDateKey];
+ if (lastAppClose) {
+ NSTimeInterval interval = -[lastAppClose timeIntervalSinceNow];
+ [startupInformation
+ activateFirstUserActionRecorderWithBackgroundTime:interval];
+ GURL ntpUrl = GURL(kChromeUINewTabURL);
+
+ Tab* currentTab = [[browserViewInformation currentTabModel] currentTab];
+ if (currentTab && [currentTab url] == ntpUrl) {
+ startupInformation.firstUserActionRecorder->RecordStartOnNTP();
+ [startupInformation resetFirstUserActionRecorder];
+ } else {
+ [startupInformation
+ expireFirstUserActionRecorderAfterDelay:kFirstUserActionTimeout];
+ }
+ // Remove the value so it's not reused if the app crashes.
+ [[NSUserDefaults standardUserDefaults]
+ removeObjectForKey:kAppEnteredBackgroundDateKey];
+ }
+}
+
+- (void)updateMetricsStateBasedOnPrefsUserTriggered:(BOOL)isUserTriggered {
+ BOOL optIn = [self areMetricsEnabled];
+ BOOL allowUploading = [self isUploadingEnabled];
+ BOOL wifiOnly = GetApplicationContext()->GetLocalState()->GetBoolean(
+ prefs::kMetricsReportingWifiOnly);
+
+ if (isUserTriggered)
+ [self updateMetricsPrefsOnPermissionChange:optIn];
+ [self setMetricsEnabled:optIn withUploading:allowUploading];
+ [self setBreakpadEnabled:optIn withUploading:allowUploading];
+ [self setWatchWWANEnabled:(optIn && wifiOnly)];
+}
+
+- (BOOL)areMetricsEnabled {
+// If this if-def changes, it needs to be changed in
+// IOSChromeMainParts::IsMetricsReportingEnabled and settings_egtest.mm.
+#if defined(GOOGLE_CHROME_BUILD)
+ BOOL optIn = GetApplicationContext()->GetLocalState()->GetBoolean(
+ metrics::prefs::kMetricsReportingEnabled);
+#else
+ // If a startup crash has been requested, then pretend that metrics have been
+ // enabled, so that the app will go into recovery mode.
+ BOOL optIn = experimental_flags::IsStartupCrashEnabled();
+#endif
+ return optIn;
+}
+
+- (BOOL)isUploadingEnabled {
+ BOOL optIn = [self areMetricsEnabled];
+ BOOL wifiOnly = GetApplicationContext()->GetLocalState()->GetBoolean(
+ prefs::kMetricsReportingWifiOnly);
+ BOOL allowUploading = optIn;
+ if (optIn && wifiOnly) {
+ BOOL usingWWAN = net::NetworkChangeNotifier::IsConnectionCellular(
+ net::NetworkChangeNotifier::GetConnectionType());
+ allowUploading = !usingWWAN;
+ }
+ return allowUploading;
+}
+
+#pragma mark - Internal methods.
+
+- (void)setMetricsEnabled:(BOOL)enabled withUploading:(BOOL)allowUploading {
+ metrics::MetricsService* metrics =
+ GetApplicationContext()->GetMetricsService();
+ DCHECK(metrics);
+ if (!metrics)
+ return;
+ if (enabled) {
+ [[UIApplication sharedApplication]
+ setMinimumBackgroundFetchInterval:kBackgroundFetchIntervalDelay];
+ if (!metrics->recording_active())
+ metrics->Start();
+
+ if (allowUploading)
+ metrics->EnableReporting();
+ else
+ metrics->DisableReporting();
+ } else {
+ if (metrics->recording_active())
+ metrics->Stop();
+ [[UIApplication sharedApplication]
+ setMinimumBackgroundFetchInterval:
+ UIApplicationBackgroundFetchIntervalNever];
+ }
+}
+
+- (void)setAppGroupMetricsEnabled:(BOOL)enabled {
+ metrics::MetricsService* metrics =
+ GetApplicationContext()->GetMetricsService();
+ if (enabled) {
+ PrefService* prefs = GetApplicationContext()->GetLocalState();
+ NSString* brandCode =
+ base::SysUTF8ToNSString(ios::GetChromeBrowserProvider()
+ ->GetAppDistributionProvider()
+ ->GetDistributionBrandCode());
+ app_group::main_app::EnableMetrics(
+ base::SysUTF8ToNSString(metrics->GetClientId()), brandCode,
+ prefs->GetInt64(metrics::prefs::kInstallDate),
+ prefs->GetInt64(metrics::prefs::kMetricsReportingEnabledTimestamp));
+ } else {
+ app_group::main_app::DisableMetrics();
+ }
+
+ // If metrics are enabled, process the logs. Otherwise, just delete them.
+ base::mac::ScopedBlock<app_group::ProceduralBlockWithData> callback;
+ if (enabled) {
+ callback.reset(
+ ^(NSData* log_content) {
+ std::string log(static_cast<const char*>([log_content bytes]),
+ static_cast<size_t>([log_content length]));
+ web::WebThread::PostTask(web::WebThread::UI, FROM_HERE,
+ base::BindBlock(^{
+ metrics->PushExternalLog(log);
+ }));
+ },
+ base::scoped_policy::RETAIN);
+ }
+
+ web::WebThread::PostTask(
+ web::WebThread::FILE, FROM_HERE,
+ base::Bind(&app_group::main_app::ProcessPendingLogs, callback));
+}
+
+- (void)processCrashReportsPresentAtStartup {
+ _hasProcessedCrashReportsPresentAtStartup = YES;
+
+ breakpad_helper::GetCrashReportCount(^(int crashReportCount) {
+ [[CrashReportBackgroundUploader sharedInstance]
+ setHasPendingCrashReportsToUploadAtStartup:(crashReportCount > 0)];
+ });
+}
+
+- (void)setBreakpadEnabled:(BOOL)enabled withUploading:(BOOL)allowUploading {
+ if (enabled) {
+ breakpad_helper::SetEnabled(true);
+
+ // Do some processing of the crash reports present at startup. Note that
+ // this processing must be done before uploading is enabled because once
+ // uploading starts the number of crash reports present will begin to
+ // decrease as they are uploaded. The ordering is ensured here because both
+ // the crash report processing and the upload enabling are handled by
+ // posting blocks to a single |dispath_queue_t| in BreakpadController.
+ if (!_hasProcessedCrashReportsPresentAtStartup && allowUploading) {
+ [self processCrashReportsPresentAtStartup];
+ }
+ [self setBreakpadUploadingEnabled:(![[PreviousSessionInfo sharedInstance]
+ isFirstSessionAfterUpgrade] &&
+ allowUploading)];
+ } else {
+ breakpad_helper::SetEnabled(false);
+ }
+}
+
+- (void)setWatchWWANEnabled:(BOOL)enabled {
+ if (!enabled) {
+ connectionTypeObserverBridge_.reset();
+ return;
+ }
+
+ if (!connectionTypeObserverBridge_) {
+ connectionTypeObserverBridge_.reset(new ConnectionTypeObserverBridge(self));
+ }
+}
+
+- (void)updateMetricsPrefsOnPermissionChange:(BOOL)enabled {
+ // TODO(crbug.com/635669): Consolidate with metrics_reporting_state.cc
+ // function.
+ metrics::MetricsService* metrics =
+ GetApplicationContext()->GetMetricsService();
+ DCHECK(metrics);
+ if (!metrics)
+ return;
+ if (enabled) {
+ // When a user opts in to the metrics reporting service, the previously
+ // collected data should be cleared to ensure that nothing is reported
+ // before a user opts in and all reported data is accurate.
+ if (!metrics->recording_active())
+ metrics->ClearSavedStabilityMetrics();
+ } else {
+ // Clear the client id pref when opting out.
+ // Note: Clearing client id will not affect the running state (e.g. field
+ // trial randomization), as the pref is only read on startup.
+ GetApplicationContext()->GetLocalState()->ClearPref(
+ metrics::prefs::kMetricsClientID);
+ GetApplicationContext()->GetLocalState()->ClearPref(
+ metrics::prefs::kMetricsReportingEnabledTimestamp);
+ crash_keys::ClearMetricsClientId();
+ }
+}
+
++ (void)disableReporting {
+ breakpad_helper::SetUploadingEnabled(false);
+ metrics::MetricsService* metrics =
+ GetApplicationContext()->GetMetricsService();
+ DCHECK(metrics);
+ metrics->DisableReporting();
+}
+
++ (void)applicationDidEnterBackground:(NSInteger)memoryWarningCount {
+ base::RecordAction(base::UserMetricsAction("MobileEnteredBackground"));
+ UMA_HISTOGRAM_COUNTS_100("MemoryWarning.OccurrencesPerSession",
+ memoryWarningCount);
+}
+
+#pragma mark - CRConnectionTypeObserverBridge implementation
+
+- (void)connectionTypeChanged:(net::NetworkChangeNotifier::ConnectionType)type {
+ BOOL wwanEnabled = net::NetworkChangeNotifier::IsConnectionCellular(type);
+ // Currently the MainController only cares about WWAN state for the metrics
+ // reporting preference. If it's disabled, or the wifi-only preference is
+ // not set, we don't care. In fact, we should not even be getting this call.
+ DCHECK([self isMetricsReportingEnabledWifiOnly]);
+ // |wwanEnabled| is true if a cellular connection such as EDGE or GPRS is
+ // used. Otherwise, either there is no connection available, or another link
+ // (such as WiFi) is used.
+ if (wwanEnabled) {
+ // If WWAN mode is on, wifi-only prefs should be disabled.
+ // For the crash reporter, we still want to record the crashes.
+ [self setBreakpadUploadingEnabled:NO];
+ [self setReporting:NO];
+ } else if ([self areMetricsEnabled]) {
+ // Double-check that the metrics reporting preference is enabled.
+ if (![[PreviousSessionInfo sharedInstance] isFirstSessionAfterUpgrade])
+ [self setBreakpadUploadingEnabled:YES];
+ [self setReporting:YES];
+ }
+}
+
+#pragma mark - interfaces methods
+
++ (void)recordNumTabAtStartup:(int)numTabs {
+ UMA_HISTOGRAM_COUNTS_100("Tabs.CountAtStartup", numTabs);
+}
+
++ (void)recordNumTabAtResume:(int)numTabs {
+ UMA_HISTOGRAM_COUNTS_100("Tabs.CountAtResume", numTabs);
+}
+
+- (void)setBreakpadUploadingEnabled:(BOOL)enableUploading {
+ breakpad_helper::SetUploadingEnabled(enableUploading);
+}
+
+- (void)setReporting:(BOOL)enableReporting {
+ if (enableReporting) {
+ GetApplicationContext()->GetMetricsService()->EnableReporting();
+ } else {
+ GetApplicationContext()->GetMetricsService()->DisableReporting();
+ }
+}
+
+- (BOOL)isMetricsReportingEnabledWifiOnly {
+ return GetApplicationContext()->GetLocalState()->GetBoolean(
+ metrics::prefs::kMetricsReportingEnabled) &&
+ GetApplicationContext()->GetLocalState()->GetBoolean(
+ prefs::kMetricsReportingWifiOnly);
+}
+
+@end
« no previous file with comments | « ios/chrome/app/application_delegate/metrics_mediator.h ('k') | ios/chrome/app/application_delegate/metrics_mediator_testing.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698