1// Copyright 2015 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#include "ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h"
6
7#import <UIKit/UIKit.h>
8
9#include <stdint.h>
10#include <utility>
11#include <vector>
12
13#include "base/base64.h"
14#include "base/bind.h"
15#include "base/callback.h"
16#include "base/check.h"
17#include "base/command_line.h"
18#include "base/files/file_path.h"
19#include "base/files/file_util.h"
20#include "base/metrics/histogram_functions.h"
21#include "base/metrics/histogram_macros.h"
22#include "base/metrics/persistent_histogram_allocator.h"
23#include "base/path_service.h"
24#include "base/process/process_metrics.h"
25#include "base/rand_util.h"
26#include "base/strings/string16.h"
27#include "base/task/post_task.h"
28#include "base/task/thread_pool.h"
29#include "base/threading/platform_thread.h"
30#include "components/crash/core/common/crash_keys.h"
31#include "components/history/core/browser/history_service.h"
32#include "components/keyed_service/core/service_access_type.h"
33#include "components/metrics/call_stack_profile_metrics_provider.h"
34#include "components/metrics/cpu_metrics_provider.h"
35#include "components/metrics/demographics/demographic_metrics_provider.h"
36#include "components/metrics/drive_metrics_provider.h"
37#include "components/metrics/entropy_state_provider.h"
38#include "components/metrics/field_trials_provider.h"
39#include "components/metrics/metrics_log_uploader.h"
40#include "components/metrics/metrics_pref_names.h"
41#include "components/metrics/metrics_reporting_default_state.h"
42#include "components/metrics/metrics_service.h"
43#include "components/metrics/metrics_state_manager.h"
44#include "components/metrics/net/cellular_logic_helper.h"
45#include "components/metrics/net/net_metrics_log_uploader.h"
46#include "components/metrics/net/network_metrics_provider.h"
47#include "components/metrics/persistent_histograms.h"
48#include "components/metrics/stability_metrics_helper.h"
49#include "components/metrics/ui/screen_info_metrics_provider.h"
50#include "components/metrics/url_constants.h"
51#include "components/metrics/version_utils.h"
52#include "components/omnibox/browser/omnibox_metrics_provider.h"
53#include "components/prefs/pref_registry_simple.h"
54#include "components/prefs/pref_service.h"
55#include "components/signin/core/browser/signin_status_metrics_provider.h"
56#include "components/sync/driver/sync_service.h"
57#include "components/sync_device_info/device_count_metrics_provider.h"
58#include "components/ukm/ukm_service.h"
59#include "components/variations/variations_associated_data.h"
60#include "components/version_info/version_info.h"
61#include "google_apis/google_api_keys.h"
62#include "ios/chrome/browser/application_context.h"
63#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
64#include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h"
65#include "ios/chrome/browser/chrome_paths.h"
66#include "ios/chrome/browser/google/google_brand.h"
67#include "ios/chrome/browser/history/history_service_factory.h"
68#import "ios/chrome/browser/main/browser.h"
69#import "ios/chrome/browser/main/browser_list.h"
70#import "ios/chrome/browser/main/browser_list_factory.h"
71#include "ios/chrome/browser/metrics/chrome_browser_state_client.h"
72#import "ios/chrome/browser/metrics/ios_chrome_default_browser_metrics_provider.h"
73#include "ios/chrome/browser/metrics/ios_chrome_stability_metrics_provider.h"
74#include "ios/chrome/browser/metrics/mobile_session_shutdown_metrics_provider.h"
75#include "ios/chrome/browser/signin/ios_chrome_signin_status_metrics_provider_delegate.h"
76#include "ios/chrome/browser/sync/device_info_sync_service_factory.h"
77#include "ios/chrome/browser/sync/profile_sync_service_factory.h"
78#include "ios/chrome/browser/tabs/tab_parenting_global_observer.h"
79#include "ios/chrome/browser/translate/translate_ranker_metrics_provider.h"
80#import "ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.h"
81#include "ios/chrome/browser/web_state_list/web_state_list.h"
82#include "ios/chrome/common/channel_info.h"
83#include "ios/web/public/thread/web_thread.h"
84#include "services/network/public/cpp/shared_url_loader_factory.h"
85
86#if !defined(__has_feature) || !__has_feature(objc_arc)
87#error "This file requires ARC support."
88#endif
89
90namespace {
91
92// Maximum amount of local storage for storing persistent histograms.
93const int kMaxHistogramStorageKiB = 50 << 10;  // 50 MiB
94
95void GetNetworkConnectionTrackerAsync(
96    base::OnceCallback<void(network::NetworkConnectionTracker*)> callback) {
97  std::move(callback).Run(
98      GetApplicationContext()->GetNetworkConnectionTracker());
99}
100
101std::unique_ptr<metrics::FileMetricsProvider> CreateFileMetricsProvider(
102    bool metrics_reporting_enabled) {
103  // Create an object to monitor files of metrics and include them in reports.
104  std::unique_ptr<metrics::FileMetricsProvider> file_metrics_provider(
105      new metrics::FileMetricsProvider(
106          GetApplicationContext()->GetLocalState()));
107
108  base::FilePath user_data_dir;
109  if (base::PathService::Get(ios::DIR_USER_DATA, &user_data_dir)) {
110    base::FilePath browser_metrics_upload_dir =
111        user_data_dir.AppendASCII(kBrowserMetricsName);
112    if (metrics_reporting_enabled) {
113      metrics::FileMetricsProvider::Params browser_metrics_params(
114          browser_metrics_upload_dir,
115          metrics::FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
116          metrics::FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE,
117          kBrowserMetricsName);
118      browser_metrics_params.max_dir_kib = kMaxHistogramStorageKiB;
119      browser_metrics_params.filter = base::BindRepeating(
120          &IOSChromeMetricsServiceClient::FilterBrowserMetricsFiles);
121      file_metrics_provider->RegisterSource(browser_metrics_params);
122    } else {
123      // When metrics reporting is not enabled, any existing files should be
124      // deleted in order to preserve user privacy.
125      base::ThreadPool::PostTask(
126          FROM_HERE,
127          {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
128           base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
129          base::BindOnce(base::GetDeletePathRecursivelyCallback(),
130                         std::move(browser_metrics_upload_dir)));
131    }
132  }
133  return file_metrics_provider;
134}
135
136}  // namespace
137
138// UKM suffix for field trial recording.
139const char kUKMFieldTrialSuffix[] = "UKM";
140
141IOSChromeMetricsServiceClient::IOSChromeMetricsServiceClient(
142    metrics::MetricsStateManager* state_manager)
143    : metrics_state_manager_(state_manager),
144      stability_metrics_provider_(nullptr),
145      weak_ptr_factory_(this) {
146  DCHECK(thread_checker_.CalledOnValidThread());
147  notification_listeners_active_ = RegisterForNotifications();
148}
149
150IOSChromeMetricsServiceClient::~IOSChromeMetricsServiceClient() {
151  DCHECK(thread_checker_.CalledOnValidThread());
152}
153
154// static
155std::unique_ptr<IOSChromeMetricsServiceClient>
156IOSChromeMetricsServiceClient::Create(
157    metrics::MetricsStateManager* state_manager) {
158  // Perform two-phase initialization so that |client->metrics_service_| only
159  // receives pointers to fully constructed objects.
160  std::unique_ptr<IOSChromeMetricsServiceClient> client(
161      new IOSChromeMetricsServiceClient(state_manager));
162  client->Initialize();
163
164  return client;
165}
166
167// static
168void IOSChromeMetricsServiceClient::RegisterPrefs(
169    PrefRegistrySimple* registry) {
170  metrics::MetricsService::RegisterPrefs(registry);
171  metrics::StabilityMetricsHelper::RegisterPrefs(registry);
172  metrics::FileMetricsProvider::RegisterSourcePrefs(registry,
173                                                    kBrowserMetricsName);
174  metrics::RegisterMetricsReportingStatePrefs(registry);
175  ukm::UkmService::RegisterPrefs(registry);
176}
177
178metrics::MetricsService* IOSChromeMetricsServiceClient::GetMetricsService() {
179  return metrics_service_.get();
180}
181
182ukm::UkmService* IOSChromeMetricsServiceClient::GetUkmService() {
183  return ukm_service_.get();
184}
185
186void IOSChromeMetricsServiceClient::SetMetricsClientId(
187    const std::string& client_id) {
188  crash_keys::SetMetricsClientIdFromGUID(client_id);
189}
190
191int32_t IOSChromeMetricsServiceClient::GetProduct() {
192  return metrics::ChromeUserMetricsExtension::CHROME;
193}
194
195std::string IOSChromeMetricsServiceClient::GetApplicationLocale() {
196  return GetApplicationContext()->GetApplicationLocale();
197}
198
199bool IOSChromeMetricsServiceClient::GetBrand(std::string* brand_code) {
200  return ios::google_brand::GetBrand(brand_code);
201}
202
203metrics::SystemProfileProto::Channel
204IOSChromeMetricsServiceClient::GetChannel() {
205  return metrics::AsProtobufChannel(::GetChannel());
206}
207
208std::string IOSChromeMetricsServiceClient::GetVersionString() {
209  return metrics::GetVersionString();
210}
211
212void IOSChromeMetricsServiceClient::CollectFinalMetricsForLog(
213    base::OnceClosure done_callback) {
214  DCHECK(thread_checker_.CalledOnValidThread());
215
216  collect_final_metrics_done_callback_ = std::move(done_callback);
217  CollectFinalHistograms();
218}
219
220std::unique_ptr<metrics::MetricsLogUploader>
221IOSChromeMetricsServiceClient::CreateUploader(
222    const GURL& server_url,
223    const GURL& insecure_server_url,
224    base::StringPiece mime_type,
225    metrics::MetricsLogUploader::MetricServiceType service_type,
226    const metrics::MetricsLogUploader::UploadCallback& on_upload_complete) {
227  return std::make_unique<metrics::NetMetricsLogUploader>(
228      GetApplicationContext()->GetSharedURLLoaderFactory(), server_url,
229      insecure_server_url, mime_type, service_type, on_upload_complete);
230}
231
232base::TimeDelta IOSChromeMetricsServiceClient::GetStandardUploadInterval() {
233  return metrics::GetUploadInterval(metrics::ShouldUseCellularUploadInterval());
234}
235
236void IOSChromeMetricsServiceClient::OnRendererProcessCrash() {
237  stability_metrics_provider_->LogRendererCrash();
238}
239
240void IOSChromeMetricsServiceClient::WebStateDidStartLoading(
241    web::WebState* web_state) {
242  metrics_service_->OnApplicationNotIdle();
243}
244
245void IOSChromeMetricsServiceClient::WebStateDidStopLoading(
246    web::WebState* web_state) {
247  metrics_service_->OnApplicationNotIdle();
248}
249
250void IOSChromeMetricsServiceClient::Initialize() {
251  PrefService* local_state = GetApplicationContext()->GetLocalState();
252  metrics_service_ = std::make_unique<metrics::MetricsService>(
253      metrics_state_manager_, this, local_state);
254  RegisterMetricsServiceProviders();
255
256  if (IsMetricsReportingForceEnabled() ||
257      base::FeatureList::IsEnabled(ukm::kUkmFeature)) {
258    ukm_service_ = std::make_unique<ukm::UkmService>(
259        local_state, this,
260        std::make_unique<metrics::DemographicMetricsProvider>(
261            std::make_unique<metrics::ChromeBrowserStateClient>(),
262            metrics::MetricsLogUploader::MetricServiceType::UKM));
263    RegisterUKMProviders();
264  }
265}
266
267void IOSChromeMetricsServiceClient::RegisterMetricsServiceProviders() {
268  PrefService* local_state = GetApplicationContext()->GetLocalState();
269
270  metrics_service_->RegisterMetricsProvider(
271      std::make_unique<metrics::NetworkMetricsProvider>(
272          base::BindRepeating(&GetNetworkConnectionTrackerAsync)));
273
274  metrics_service_->RegisterMetricsProvider(
275      std::make_unique<OmniboxMetricsProvider>());
276
277  auto stability_metrics_provider =
278      std::make_unique<IOSChromeStabilityMetricsProvider>(local_state);
279  stability_metrics_provider_ = stability_metrics_provider.get();
280  metrics_service_->RegisterMetricsProvider(
281      std::move(stability_metrics_provider));
282
283  metrics_service_->RegisterMetricsProvider(
284      std::make_unique<IOSChromeDefaultBrowserMetricsProvider>());
285
286  // NOTE: metrics_state_manager_->IsMetricsReportingEnabled() returns false
287  // during local testing. To test locally, modify
288  // MetricsServiceAccessor::IsMetricsReportingEnabled() to return true.
289  metrics_service_->RegisterMetricsProvider(CreateFileMetricsProvider(
290      metrics_state_manager_->IsMetricsReportingEnabled()));
291
292  metrics_service_->RegisterMetricsProvider(
293        std::make_unique<metrics::EntropyStateProvider>(local_state));
294
295  metrics_service_->RegisterMetricsProvider(
296      std::make_unique<metrics::ScreenInfoMetricsProvider>());
297
298  metrics_service_->RegisterMetricsProvider(
299      std::make_unique<metrics::DriveMetricsProvider>(ios::FILE_LOCAL_STATE));
300
301  metrics_service_->RegisterMetricsProvider(
302      std::make_unique<metrics::CallStackProfileMetricsProvider>());
303
304  metrics_service_->RegisterMetricsProvider(
305      SigninStatusMetricsProvider::CreateInstance(
306          std::make_unique<IOSChromeSigninStatusMetricsProviderDelegate>()));
307
308  metrics_service_->RegisterMetricsProvider(
309      std::make_unique<MobileSessionShutdownMetricsProvider>(
310          metrics_service_.get()));
311
312  metrics_service_->RegisterMetricsProvider(
313      std::make_unique<syncer::DeviceCountMetricsProvider>(base::BindRepeating(
314          &DeviceInfoSyncServiceFactory::GetAllDeviceInfoTrackers)));
315
316  metrics_service_->RegisterMetricsProvider(
317      std::make_unique<translate::TranslateRankerMetricsProvider>());
318
319  metrics_service_->RegisterMetricsProvider(
320      std::make_unique<metrics::DemographicMetricsProvider>(
321          std::make_unique<metrics::ChromeBrowserStateClient>(),
322          metrics::MetricsLogUploader::MetricServiceType::UMA));
323}
324
325void IOSChromeMetricsServiceClient::RegisterUKMProviders() {
326  ukm_service_->RegisterMetricsProvider(
327      std::make_unique<metrics::CPUMetricsProvider>());
328
329  ukm_service_->RegisterMetricsProvider(
330      std::make_unique<metrics::ScreenInfoMetricsProvider>());
331
332  // TODO(crbug.com/754877): Support synthetic trials for UKM.
333  ukm_service_->RegisterMetricsProvider(
334      std::make_unique<variations::FieldTrialsProvider>(nullptr,
335                                                        kUKMFieldTrialSuffix));
336}
337
338void IOSChromeMetricsServiceClient::CollectFinalHistograms() {
339  DCHECK(thread_checker_.CalledOnValidThread());
340
341  task_vm_info task_info_data;
342  mach_msg_type_number_t count = sizeof(task_vm_info) / sizeof(natural_t);
343  kern_return_t kr =
344      task_info(mach_task_self(), TASK_VM_INFO,
345                reinterpret_cast<task_info_t>(&task_info_data), &count);
346  if (kr == KERN_SUCCESS) {
347    base::UmaHistogramMemoryKB(
348        "Memory.Browser",
349        (task_info_data.resident_size - task_info_data.reusable) / 1024);
350    mach_vm_size_t footprint_mb = task_info_data.phys_footprint / 1024 / 1024;
351    base::UmaHistogramMemoryLargeMB("Memory.Browser.MemoryFootprint",
352                                    footprint_mb);
353
354    switch (UIApplication.sharedApplication.applicationState) {
355      case UIApplicationStateActive:
356        base::UmaHistogramMemoryLargeMB("Memory.Browser.MemoryFootprint.Active",
357                                        footprint_mb);
358        // According to Apple, apps on iPhone 6 and older devices get terminated
359        // by the OS if memory usage crosses 200MB watermark. Obviously this
360        // metric will not be recorded with true on iPhone 6 and older devices.
361        UMA_HISTOGRAM_BOOLEAN(
362            "Memory.Browser.MemoryFootprint.Active.Over200MBWatermark",
363            footprint_mb >= 200);
364        break;
365      case UIApplicationStateInactive:
366        base::UmaHistogramMemoryLargeMB(
367            "Memory.Browser.MemoryFootprint.Inactive", footprint_mb);
368        break;
369      case UIApplicationStateBackground:
370        base::UmaHistogramMemoryLargeMB(
371            "Memory.Browser.MemoryFootprint.Background", footprint_mb);
372        break;
373    }
374  }
375
376  std::vector<ChromeBrowserState*> loaded_browser_states =
377      GetApplicationContext()
378          ->GetChromeBrowserStateManager()
379          ->GetLoadedBrowserStates();
380
381  int open_tabs_count = 0;
382  for (ChromeBrowserState* browser_state : loaded_browser_states) {
383    // Iterate through regular Browser and OTR Browser to find the corresponding
384    // tab.
385    BrowserList* browser_list =
386        BrowserListFactory::GetForBrowserState(browser_state);
387    std::set<Browser*> regular_browsers = browser_list->AllRegularBrowsers();
388    std::set<Browser*> otr_browsers = browser_list->AllIncognitoBrowsers();
389
390    for (Browser* browser : regular_browsers) {
391      open_tabs_count += browser->GetWebStateList()->count();
392    }
393    for (Browser* browser : otr_browsers) {
394      open_tabs_count += browser->GetWebStateList()->count();
395    }
396  }
397  base::UmaHistogramCounts10000("Memory.Browser.MemoryFootprint.NumOpenTabs",
398                                open_tabs_count);
399  base::UmaHistogramCounts10000(
400      "Memory.Browser.MemoryFootprint.NumLiveOverscroll",
401      [OverscrollActionsController instanceCount]);
402
403  std::move(collect_final_metrics_done_callback_).Run();
404}
405
406bool IOSChromeMetricsServiceClient::RegisterForNotifications() {
407  tab_parented_subscription_ =
408      TabParentingGlobalObserver::GetInstance()->RegisterCallback(
409          base::BindRepeating(&IOSChromeMetricsServiceClient::OnTabParented,
410                              base::Unretained(this)));
411  omnibox_url_opened_subscription_ =
412      OmniboxEventGlobalTracker::GetInstance()->RegisterCallback(
413          base::BindRepeating(
414              &IOSChromeMetricsServiceClient::OnURLOpenedFromOmnibox,
415              base::Unretained(this)));
416
417  std::vector<ChromeBrowserState*> loaded_browser_states =
418      GetApplicationContext()
419          ->GetChromeBrowserStateManager()
420          ->GetLoadedBrowserStates();
421  bool all_profiles_succeeded = true;
422  for (ChromeBrowserState* browser_state : loaded_browser_states) {
423    if (!RegisterForBrowserStateEvents(browser_state)) {
424      all_profiles_succeeded = false;
425    }
426  }
427  return all_profiles_succeeded;
428}
429
430bool IOSChromeMetricsServiceClient::RegisterForBrowserStateEvents(
431    ChromeBrowserState* browser_state) {
432  history::HistoryService* history_service =
433      ios::HistoryServiceFactory::GetForBrowserState(
434          browser_state, ServiceAccessType::IMPLICIT_ACCESS);
435  ObserveServiceForDeletions(history_service);
436  syncer::SyncService* sync =
437      ProfileSyncServiceFactory::GetInstance()->GetForBrowserState(
438          browser_state);
439  StartObserving(sync, browser_state->GetPrefs());
440  return (history_service != nullptr && sync != nullptr);
441}
442
443void IOSChromeMetricsServiceClient::OnTabParented(web::WebState* web_state) {
444  metrics_service_->OnApplicationNotIdle();
445}
446
447void IOSChromeMetricsServiceClient::OnURLOpenedFromOmnibox(OmniboxLog* log) {
448  metrics_service_->OnApplicationNotIdle();
449}
450
451// static
452metrics::FileMetricsProvider::FilterAction
453IOSChromeMetricsServiceClient::FilterBrowserMetricsFiles(
454    const base::FilePath& path) {
455  // Do not process the file if it corresponds to the current process id.
456  base::ProcessId pid;
457  bool parse_success = base::GlobalHistogramAllocator::ParseFilePath(
458      path, nullptr, nullptr, &pid);
459  if (!parse_success)
460    return metrics::FileMetricsProvider::FILTER_PROCESS_FILE;
461  if (pid == base::GetCurrentProcId())
462    return metrics::FileMetricsProvider::FILTER_ACTIVE_THIS_PID;
463  // No need to test whether |pid| is a different active process. This isn't
464  // applicable to iOS because there cannot be two copies of Chrome running.
465  return metrics::FileMetricsProvider::FILTER_PROCESS_FILE;
466}
467
468metrics::EnableMetricsDefault
469IOSChromeMetricsServiceClient::GetMetricsReportingDefaultState() {
470  return metrics::GetMetricsReportingDefaultState(
471      GetApplicationContext()->GetLocalState());
472}
473
474void IOSChromeMetricsServiceClient::OnHistoryDeleted() {
475  if (ukm_service_)
476    ukm_service_->Purge();
477}
478
479void IOSChromeMetricsServiceClient::OnUkmAllowedStateChanged(bool must_purge) {
480  if (!ukm_service_)
481    return;
482  if (must_purge) {
483    ukm_service_->Purge();
484    ukm_service_->ResetClientState(ukm::ResetReason::kOnUkmAllowedStateChanged);
485  }
486  // Signal service manager to enable/disable UKM based on new state.
487  UpdateRunningServices();
488}
489
490void IOSChromeMetricsServiceClient::OnIncognitoWebStateAdded() {
491  // Signal service manager to enable/disable UKM based on new state.
492  UpdateRunningServices();
493}
494
495void IOSChromeMetricsServiceClient::OnIncognitoWebStateRemoved() {
496  // Signal service manager to enable/disable UKM based on new state.
497  UpdateRunningServices();
498}
499
500bool IOSChromeMetricsServiceClient::IsUkmAllowedForAllProfiles() {
501  return UkmConsentStateObserver::IsUkmAllowedForAllProfiles();
502}
503
504bool IOSChromeMetricsServiceClient::
505    AreNotificationListenersEnabledOnAllProfiles() {
506  return notification_listeners_active_;
507}
508
509std::string IOSChromeMetricsServiceClient::GetUploadSigningKey() {
510  std::string decoded_key;
511  base::Base64Decode(google_apis::GetMetricsKey(), &decoded_key);
512  return decoded_key;
513}
514