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