Commit 2a321de3 authored by bolian@chromium.org's avatar bolian@chromium.org

This is the separate change mentioned in comments of https://codereview.chromium.org/246553003/.

It emits NCN.NetworkOperatorMCCMNC_NewMetricsLog on new metric log creation with the network operator MCC_MNC code 

BUG=355604

Review URL: https://codereview.chromium.org/253203002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@269627 0039d316-1c4b-4281-b951-d872f2087c98
parent b0b1fbcd
// Copyright 2014 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.
#include "chrome/browser/chrome_browser_metrics_service_observer.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "net/base/network_change_notifier.h"
ChromeBrowserMetricsServiceObserver::ChromeBrowserMetricsServiceObserver() {
MetricsServiceHelper::AddMetricsServiceObserver(this);
}
ChromeBrowserMetricsServiceObserver::~ChromeBrowserMetricsServiceObserver() {
MetricsServiceHelper::RemoveMetricsServiceObserver(this);
}
void ChromeBrowserMetricsServiceObserver::OnDidCreateMetricsLog() {
net::NetworkChangeNotifier::LogOperatorCodeHistogram(
net::NetworkChangeNotifier::GetConnectionType());
}
// Copyright 2014 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.
#ifndef CHROME_BROWSER_CHROME_BROWSER_METRICS_SERVICE_OBSERVER_H_
#define CHROME_BROWSER_CHROME_BROWSER_METRICS_SERVICE_OBSERVER_H_
#include "chrome/browser/metrics/metrics_service_observer.h"
// ChromeBrowserMetricsServiceObserver receives notifications when the metrics
// service creates a new metrics log.
class ChromeBrowserMetricsServiceObserver : public MetricsServiceObserver {
public:
ChromeBrowserMetricsServiceObserver();
virtual ~ChromeBrowserMetricsServiceObserver();
// MetricsServiceObserver:
virtual void OnDidCreateMetricsLog() OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMetricsServiceObserver);
};
#endif // CHROME_BROWSER_CHROME_BROWSER_METRICS_SERVICE_OBSERVER_H_
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "chrome/browser/about_flags.h" #include "chrome/browser/about_flags.h"
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_browser_main.h" #include "chrome/browser/chrome_browser_main.h"
#include "chrome/browser/chrome_browser_metrics_service_observer.h"
#include "chrome/browser/pref_service_flags_storage.h" #include "chrome/browser/pref_service_flags_storage.h"
#include "chrome/browser/shell_integration.h" #include "chrome/browser/shell_integration.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
...@@ -154,6 +155,12 @@ void ChromeBrowserMainExtraPartsMetrics::PostBrowserStart() { ...@@ -154,6 +155,12 @@ void ChromeBrowserMainExtraPartsMetrics::PostBrowserStart() {
FROM_HERE, FROM_HERE,
base::Bind(&RecordStartupMetricsOnBlockingPool), base::Bind(&RecordStartupMetricsOnBlockingPool),
base::TimeDelta::FromSeconds(kStartupMetricsGatheringDelaySeconds)); base::TimeDelta::FromSeconds(kStartupMetricsGatheringDelaySeconds));
// Create the metrics log observer.
// We only need this for Android for now.
#if defined(ANDROID)
metrics_service_observer_.reset(new ChromeBrowserMetricsServiceObserver());
#endif
} }
namespace chrome { namespace chrome {
......
...@@ -7,9 +7,11 @@ ...@@ -7,9 +7,11 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/chrome_browser_main_extra_parts.h" #include "chrome/browser/chrome_browser_main_extra_parts.h"
class ChromeBrowserMainParts; class ChromeBrowserMainParts;
class ChromeBrowserMetricsServiceObserver;
namespace chrome { namespace chrome {
void AddMetricsExtraParts(ChromeBrowserMainParts* main_parts); void AddMetricsExtraParts(ChromeBrowserMainParts* main_parts);
...@@ -26,6 +28,9 @@ class ChromeBrowserMainExtraPartsMetrics : public ChromeBrowserMainExtraParts { ...@@ -26,6 +28,9 @@ class ChromeBrowserMainExtraPartsMetrics : public ChromeBrowserMainExtraParts {
virtual void PostBrowserStart() OVERRIDE; virtual void PostBrowserStart() OVERRIDE;
private: private:
// Observe and log histograms on new metric logs.
scoped_ptr<ChromeBrowserMetricsServiceObserver> metrics_service_observer_;
DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainExtraPartsMetrics); DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainExtraPartsMetrics);
}; };
......
...@@ -1040,6 +1040,7 @@ void MetricsService::ReceivedProfilerData( ...@@ -1040,6 +1040,7 @@ void MetricsService::ReceivedProfilerData(
initial_metrics_log_.reset( initial_metrics_log_.reset(
new MetricsLog(state_manager_->client_id(), session_id_, new MetricsLog(state_manager_->client_id(), session_id_,
MetricsLog::ONGOING_LOG)); MetricsLog::ONGOING_LOG));
NotifyOnDidCreateMetricsLog();
} }
initial_metrics_log_->RecordProfilerData(process_data, process_type); initial_metrics_log_->RecordProfilerData(process_data, process_type);
...@@ -1073,6 +1074,22 @@ void MetricsService::GetUptimes(PrefService* pref, ...@@ -1073,6 +1074,22 @@ void MetricsService::GetUptimes(PrefService* pref,
} }
} }
void MetricsService::AddObserver(MetricsServiceObserver* observer) {
DCHECK(thread_checker_.CalledOnValidThread());
observers_.AddObserver(observer);
}
void MetricsService::RemoveObserver(MetricsServiceObserver* observer) {
DCHECK(thread_checker_.CalledOnValidThread());
observers_.RemoveObserver(observer);
}
void MetricsService::NotifyOnDidCreateMetricsLog() {
DCHECK(thread_checker_.CalledOnValidThread());
FOR_EACH_OBSERVER(
MetricsServiceObserver, observers_, OnDidCreateMetricsLog());
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// State save methods // State save methods
...@@ -1108,6 +1125,7 @@ void MetricsService::OpenNewLog() { ...@@ -1108,6 +1125,7 @@ void MetricsService::OpenNewLog() {
log_manager_.BeginLoggingWithLog( log_manager_.BeginLoggingWithLog(
new MetricsLog(state_manager_->client_id(), session_id_, new MetricsLog(state_manager_->client_id(), session_id_,
MetricsLog::ONGOING_LOG)); MetricsLog::ONGOING_LOG));
NotifyOnDidCreateMetricsLog();
if (state_ == INITIALIZED) { if (state_ == INITIALIZED) {
// We only need to schedule that run once. // We only need to schedule that run once.
state_ = INIT_TASK_SCHEDULED; state_ = INIT_TASK_SCHEDULED;
...@@ -1405,6 +1423,10 @@ void MetricsService::PrepareInitialStabilityLog() { ...@@ -1405,6 +1423,10 @@ void MetricsService::PrepareInitialStabilityLog() {
scoped_ptr<MetricsLog> initial_stability_log( scoped_ptr<MetricsLog> initial_stability_log(
new MetricsLog(state_manager_->client_id(), session_id_, new MetricsLog(state_manager_->client_id(), session_id_,
MetricsLog::INITIAL_STABILITY_LOG)); MetricsLog::INITIAL_STABILITY_LOG));
// Do not call NotifyOnDidCreateMetricsLog here because the stability
// log describes stats from the _previous_ session.
if (!initial_stability_log->LoadSavedEnvironmentFromPrefs()) if (!initial_stability_log->LoadSavedEnvironmentFromPrefs())
return; return;
initial_stability_log->RecordStabilityMetrics(base::TimeDelta(), initial_stability_log->RecordStabilityMetrics(base::TimeDelta(),
...@@ -1934,3 +1956,17 @@ bool MetricsServiceHelper::IsCrashReportingEnabled() { ...@@ -1934,3 +1956,17 @@ bool MetricsServiceHelper::IsCrashReportingEnabled() {
return false; return false;
#endif #endif
} }
void MetricsServiceHelper::AddMetricsServiceObserver(
MetricsServiceObserver* observer) {
MetricsService* metrics_service = g_browser_process->metrics_service();
if (metrics_service)
metrics_service->AddObserver(observer);
}
void MetricsServiceHelper::RemoveMetricsServiceObserver(
MetricsServiceObserver* observer) {
MetricsService* metrics_service = g_browser_process->metrics_service();
if (metrics_service)
metrics_service->RemoveObserver(observer);
}
...@@ -18,9 +18,12 @@ ...@@ -18,9 +18,12 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/metrics/field_trial.h" #include "base/metrics/field_trial.h"
#include "base/metrics/user_metrics.h" #include "base/metrics/user_metrics.h"
#include "base/observer_list.h"
#include "base/process/kill.h" #include "base/process/kill.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "chrome/browser/metrics/metrics_log.h" #include "chrome/browser/metrics/metrics_log.h"
#include "chrome/browser/metrics/metrics_service_observer.h"
#include "chrome/browser/metrics/tracking_synchronizer_observer.h" #include "chrome/browser/metrics/tracking_synchronizer_observer.h"
#include "chrome/common/metrics/metrics_service_base.h" #include "chrome/common/metrics/metrics_service_base.h"
#include "chrome/installer/util/google_update_settings.h" #include "chrome/installer/util/google_update_settings.h"
...@@ -36,6 +39,7 @@ ...@@ -36,6 +39,7 @@
#include "chrome/browser/chromeos/external_metrics.h" #include "chrome/browser/chromeos/external_metrics.h"
#endif #endif
class ChromeBrowserMetricsServiceObserver;
class MetricsReportingScheduler; class MetricsReportingScheduler;
class PrefService; class PrefService;
class PrefRegistrySimple; class PrefRegistrySimple;
...@@ -364,6 +368,11 @@ class MetricsService ...@@ -364,6 +368,11 @@ class MetricsService
// Set up client ID, session ID, etc. // Set up client ID, session ID, etc.
void InitializeMetricsState(); void InitializeMetricsState();
// Registers/unregisters |observer| to receive MetricsLog notifications.
void AddObserver(MetricsServiceObserver* observer);
void RemoveObserver(MetricsServiceObserver* observer);
void NotifyOnDidCreateMetricsLog();
// Schedule the next save of LocalState information. This is called // Schedule the next save of LocalState information. This is called
// automatically by the task that performs each save to schedule the next one. // automatically by the task that performs each save to schedule the next one.
void ScheduleNextStateSave(); void ScheduleNextStateSave();
...@@ -585,7 +594,15 @@ class MetricsService ...@@ -585,7 +594,15 @@ class MetricsService
// Field trial groups that map to Chrome configuration states. // Field trial groups that map to Chrome configuration states.
SyntheticTrialGroups synthetic_trial_groups_; SyntheticTrialGroups synthetic_trial_groups_;
ObserverList<MetricsServiceObserver> observers_;
// Confirms single-threaded access to |observers_| in debug builds.
base::ThreadChecker thread_checker_;
friend class MetricsServiceHelper;
FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, IsPluginProcess); FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, IsPluginProcess);
FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, MetricsServiceObserver);
FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest,
PermutedEntropyCacheClearedWhenLowEntropyReset); PermutedEntropyCacheClearedWhenLowEntropyReset);
FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, RegisterSyntheticTrial); FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, RegisterSyntheticTrial);
...@@ -593,12 +610,13 @@ class MetricsService ...@@ -593,12 +610,13 @@ class MetricsService
DISALLOW_COPY_AND_ASSIGN(MetricsService); DISALLOW_COPY_AND_ASSIGN(MetricsService);
}; };
// This class limits and documents access to the IsMetricsReportingEnabled() and // This class limits and documents access to metrics service helper methods.
// IsCrashReportingEnabled() methods. Since these methods are private, each user // Since these methods are private, each user has to be explicitly declared
// has to be explicitly declared as a 'friend' below. // as a 'friend' below.
class MetricsServiceHelper { class MetricsServiceHelper {
private: private:
friend bool prerender::IsOmniboxEnabled(Profile* profile); friend bool prerender::IsOmniboxEnabled(Profile* profile);
friend class ::ChromeBrowserMetricsServiceObserver;
friend class ChromeRenderMessageFilter; friend class ChromeRenderMessageFilter;
friend class ::CrashesDOMHandler; friend class ::CrashesDOMHandler;
friend class extensions::ExtensionDownloader; friend class extensions::ExtensionDownloader;
...@@ -620,6 +638,11 @@ class MetricsServiceHelper { ...@@ -620,6 +638,11 @@ class MetricsServiceHelper {
// IsMetricsReportingEnabled for desktop Chrome. // IsMetricsReportingEnabled for desktop Chrome.
static bool IsCrashReportingEnabled(); static bool IsCrashReportingEnabled();
// Registers/unregisters |observer| to receive MetricsLog notifications
// from metrics service.
static void AddMetricsServiceObserver(MetricsServiceObserver* observer);
static void RemoveMetricsServiceObserver(MetricsServiceObserver* observer);
DISALLOW_IMPLICIT_CONSTRUCTORS(MetricsServiceHelper); DISALLOW_IMPLICIT_CONSTRUCTORS(MetricsServiceHelper);
}; };
......
// Copyright 2014 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.
#include "chrome/browser/chrome_browser_metrics_service_observer.h"
MetricsServiceObserver::MetricsServiceObserver() {
}
MetricsServiceObserver::~MetricsServiceObserver() {
}
// Copyright 2014 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.
#ifndef CHROME_BROWSER_METRICS_METRICS_SERVICE_OBSERVER_H_
#define CHROME_BROWSER_METRICS_METRICS_SERVICE_OBSERVER_H_
#include "base/macros.h"
// MetricsServiceObserver receives notifications from MetricsService.
// An observer must be added, removed, and notified on the same thread.
class MetricsServiceObserver {
public:
// Called when a new MetricsLog is created.
virtual void OnDidCreateMetricsLog() = 0;
protected:
MetricsServiceObserver();
virtual ~MetricsServiceObserver();
private:
DISALLOW_COPY_AND_ASSIGN(MetricsServiceObserver);
};
#endif // CHROME_BROWSER_METRICS_METRICS_SERVICE_OBSERVER_H_
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/threading/platform_thread.h" #include "base/threading/platform_thread.h"
#include "chrome/browser/metrics/metrics_service_observer.h"
#include "chrome/browser/metrics/metrics_state_manager.h" #include "chrome/browser/metrics/metrics_state_manager.h"
#include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
...@@ -145,6 +146,22 @@ class MetricsServiceTest : public testing::Test { ...@@ -145,6 +146,22 @@ class MetricsServiceTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(MetricsServiceTest); DISALLOW_COPY_AND_ASSIGN(MetricsServiceTest);
}; };
class TestMetricsServiceObserver : public MetricsServiceObserver {
public:
TestMetricsServiceObserver(): observed_(0) {}
virtual ~TestMetricsServiceObserver() {}
virtual void OnDidCreateMetricsLog() OVERRIDE {
++observed_;
}
int observed() const { return observed_; }
private:
int observed_;
DISALLOW_COPY_AND_ASSIGN(TestMetricsServiceObserver);
};
} // namespace } // namespace
TEST_F(MetricsServiceTest, IsPluginProcess) { TEST_F(MetricsServiceTest, IsPluginProcess) {
...@@ -313,3 +330,34 @@ TEST_F(MetricsServiceTest, CrashReportingEnabled) { ...@@ -313,3 +330,34 @@ TEST_F(MetricsServiceTest, CrashReportingEnabled) {
EXPECT_FALSE(MetricsServiceHelper::IsCrashReportingEnabled()); EXPECT_FALSE(MetricsServiceHelper::IsCrashReportingEnabled());
#endif // defined(GOOGLE_CHROME_BUILD) #endif // defined(GOOGLE_CHROME_BUILD)
} }
TEST_F(MetricsServiceTest, MetricsServiceObserver) {
MetricsService service(GetMetricsStateManager());
TestMetricsServiceObserver observer1;
TestMetricsServiceObserver observer2;
service.AddObserver(&observer1);
EXPECT_EQ(0, observer1.observed());
EXPECT_EQ(0, observer2.observed());
service.OpenNewLog();
EXPECT_EQ(1, observer1.observed());
EXPECT_EQ(0, observer2.observed());
service.log_manager_.FinishCurrentLog();
service.AddObserver(&observer2);
service.OpenNewLog();
EXPECT_EQ(2, observer1.observed());
EXPECT_EQ(1, observer2.observed());
service.log_manager_.FinishCurrentLog();
service.RemoveObserver(&observer1);
service.OpenNewLog();
EXPECT_EQ(2, observer1.observed());
EXPECT_EQ(2, observer2.observed());
service.log_manager_.FinishCurrentLog();
service.RemoveObserver(&observer2);
}
...@@ -402,6 +402,8 @@ ...@@ -402,6 +402,8 @@
'browser/chrome_browser_main_posix.h', 'browser/chrome_browser_main_posix.h',
'browser/chrome_browser_main_win.cc', 'browser/chrome_browser_main_win.cc',
'browser/chrome_browser_main_win.h', 'browser/chrome_browser_main_win.h',
'browser/chrome_browser_metrics_service_observer.cc',
'browser/chrome_browser_metrics_service_observer.h',
'browser/chrome_content_browser_client.cc', 'browser/chrome_content_browser_client.cc',
'browser/chrome_content_browser_client.h', 'browser/chrome_content_browser_client.h',
'browser/chrome_elf_init_win.cc', 'browser/chrome_elf_init_win.cc',
...@@ -1196,6 +1198,8 @@ ...@@ -1196,6 +1198,8 @@
'browser/metrics/metrics_reporting_scheduler.cc', 'browser/metrics/metrics_reporting_scheduler.cc',
'browser/metrics/metrics_reporting_scheduler.h', 'browser/metrics/metrics_reporting_scheduler.h',
'browser/metrics/metrics_service_android.cc', 'browser/metrics/metrics_service_android.cc',
'browser/metrics/metrics_service_observer.cc',
'browser/metrics/metrics_service_observer.h',
'browser/metrics/metrics_service.cc', 'browser/metrics/metrics_service.cc',
'browser/metrics/metrics_service.h', 'browser/metrics/metrics_service.h',
'browser/metrics/metrics_services_manager.cc', 'browser/metrics/metrics_services_manager.cc',
......
...@@ -235,22 +235,7 @@ class HistogramWatcher ...@@ -235,22 +235,7 @@ class HistogramWatcher
UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineChange", state_duration); UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineChange", state_duration);
} }
#if defined(OS_ANDROID) NetworkChangeNotifier::LogOperatorCodeHistogram(type);
// On a connection type change to 2/3/4G, log the network operator MCC/MNC.
// Log zero in other cases.
unsigned mcc_mnc = 0;
if (type == NetworkChangeNotifier::CONNECTION_2G ||
type == NetworkChangeNotifier::CONNECTION_3G ||
type == NetworkChangeNotifier::CONNECTION_4G) {
// Log zero if not perfectly converted.
if (!base::StringToUint(
net::android::GetTelephonyNetworkOperator(), &mcc_mnc)) {
mcc_mnc = 0;
}
}
UMA_HISTOGRAM_SPARSE_SLOWLY(
"NCN.NetworkOperatorMCCMNC_ConnectionChange", mcc_mnc);
#endif
UMA_HISTOGRAM_MEDIUM_TIMES( UMA_HISTOGRAM_MEDIUM_TIMES(
"NCN.IPAddressChangeToConnectionTypeChange", "NCN.IPAddressChangeToConnectionTypeChange",
...@@ -594,6 +579,25 @@ void NetworkChangeNotifier::ShutdownHistogramWatcher() { ...@@ -594,6 +579,25 @@ void NetworkChangeNotifier::ShutdownHistogramWatcher() {
g_network_change_notifier->histogram_watcher_.reset(); g_network_change_notifier->histogram_watcher_.reset();
} }
// static
void NetworkChangeNotifier::LogOperatorCodeHistogram(ConnectionType type) {
#if defined(OS_ANDROID)
// On a connection type change to 2/3/4G, log the network operator MCC/MNC.
// Log zero in other cases.
unsigned mcc_mnc = 0;
if (type == NetworkChangeNotifier::CONNECTION_2G ||
type == NetworkChangeNotifier::CONNECTION_3G ||
type == NetworkChangeNotifier::CONNECTION_4G) {
// Log zero if not perfectly converted.
if (!base::StringToUint(
net::android::GetTelephonyNetworkOperator(), &mcc_mnc)) {
mcc_mnc = 0;
}
}
UMA_HISTOGRAM_SPARSE_SLOWLY("NCN.NetworkOperatorMCCMNC", mcc_mnc);
#endif
}
#if defined(OS_LINUX) #if defined(OS_LINUX)
// static // static
const internal::AddressTrackerLinux* const internal::AddressTrackerLinux*
......
...@@ -232,6 +232,9 @@ class NET_EXPORT NetworkChangeNotifier { ...@@ -232,6 +232,9 @@ class NET_EXPORT NetworkChangeNotifier {
// should be called from the network thread to avoid race conditions. // should be called from the network thread to avoid race conditions.
static void ShutdownHistogramWatcher(); static void ShutdownHistogramWatcher();
// Log the |NCN.NetworkOperatorMCCMNC| histogram.
static void LogOperatorCodeHistogram(ConnectionType type);
// Allows a second NetworkChangeNotifier to be created for unit testing, so // Allows a second NetworkChangeNotifier to be created for unit testing, so
// the test suite can create a MockNetworkChangeNotifier, but platform // the test suite can create a MockNetworkChangeNotifier, but platform
// specific NetworkChangeNotifiers can also be created for testing. To use, // specific NetworkChangeNotifiers can also be created for testing. To use,
......
...@@ -10772,15 +10772,15 @@ Therefore, the affected-histogram name has to have at least one dot in it. ...@@ -10772,15 +10772,15 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<summary>The scheme of the URL for each main-frame navigation.</summary> <summary>The scheme of the URL for each main-frame navigation.</summary>
</histogram> </histogram>
<histogram name="NCN.NetworkOperatorMCCMNC_ConnectionChange"> <histogram name="NCN.NetworkOperatorMCCMNC">
<owner>bolian@chromium.org</owner> <owner>bolian@chromium.org</owner>
<owner>bengr@google.com</owner> <owner>bengr@google.com</owner>
<owner>marq@google.com</owner> <owner>marq@google.com</owner>
<summary> <summary>
The MCC (mobile country code) and MNC (mobile network code) of the network The MCC (mobile country code) and MNC (mobile network code) of the network
operator when the network connection is changed to a mobile network. Value operator when a new metrics log is created or when the network connection is
zero means the connection is changed to a non-mobile network or the operator changed. A value of zero means a non-mobile network or the operator code is
code is unknown. unknown.
</summary> </summary>
</histogram> </histogram>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment