M87 merge: Add FamilyUserMetricsProvider for family user types slicing
The FamilyUserMetricsProvider will filter the Family Experiences
team's metrics by family user type of interest. The categories
represent various combinations of supervised and EDU user types as
primary and secondary accounts.
(cherry picked from commit bb2e7e34be0a7fd5eb9d26a88e8fe57688bcb9e8)
[email protected],[email protected],[email protected]
Bug: 1103077
Change-Id: Icd87e553ed02278c77186b7b0ec5bd1a377f619c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2417451
Commit-Queue: Toby Huang <[email protected]>
Reviewed-by: Alexei Svitkine <[email protected]>
Reviewed-by: Xiyuan Xia <[email protected]>
Cr-Original-Commit-Position: refs/heads/master@{#814444}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2457747
Reviewed-by: Toby Huang <[email protected]>
Cr-Commit-Position: refs/branch-heads/4280@{#91}
Cr-Branched-From: ea420fb963f9658c9969b6513c56b8f47efa1a2a-refs/heads/master@{#812852}
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 181a67d4..7bab0f8 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4112,6 +4112,8 @@
"metrics/chromeos_metrics_provider.h",
"metrics/cros_healthd_metrics_provider.cc",
"metrics/cros_healthd_metrics_provider.h",
+ "metrics/family_user_metrics_provider.cc",
+ "metrics/family_user_metrics_provider.h",
"metrics/perf/collection_params.cc",
"metrics/perf/collection_params.h",
"metrics/perf/cpu_identity.cc",
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 54100df..277c25d 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -890,6 +890,8 @@
"child_accounts/event_based_status_reporting_service.h",
"child_accounts/event_based_status_reporting_service_factory.cc",
"child_accounts/event_based_status_reporting_service_factory.h",
+ "child_accounts/family_features.cc",
+ "child_accounts/family_features.h",
"child_accounts/family_user_metrics_service.cc",
"child_accounts/family_user_metrics_service.h",
"child_accounts/family_user_metrics_service_factory.cc",
diff --git a/chrome/browser/chromeos/child_accounts/family_features.cc b/chrome/browser/chromeos/child_accounts/family_features.cc
new file mode 100644
index 0000000..f0ab0eb
--- /dev/null
+++ b/chrome/browser/chromeos/child_accounts/family_features.cc
@@ -0,0 +1,12 @@
+// Copyright 2020 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/chromeos/child_accounts/family_features.h"
+
+namespace chromeos {
+
+const base::Feature kFamilyUserMetricsProvider{
+ "FamilyUserMetricsProvider", base::FEATURE_ENABLED_BY_DEFAULT};
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/child_accounts/family_features.h b/chrome/browser/chromeos/child_accounts/family_features.h
new file mode 100644
index 0000000..1d2c80c
--- /dev/null
+++ b/chrome/browser/chromeos/child_accounts/family_features.h
@@ -0,0 +1,19 @@
+// Copyright 2020 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_CHROMEOS_CHILD_ACCOUNTS_FAMILY_FEATURES_H_
+#define CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_FAMILY_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace chromeos {
+
+// Filters family user metrics into one of four types of family users.
+// TODO(crbug/1103077): If any of the buckets end up being too small, disable
+// this feature for privacy reasons.
+extern const base::Feature kFamilyUserMetricsProvider;
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_CHILD_ACCOUNTS_FAMILY_FEATURES_H_
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index 1e37620..8436c832 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -150,6 +150,7 @@
#include "chrome/browser/metrics/assistant_service_metrics_provider.h"
#include "chrome/browser/metrics/chromeos_metrics_provider.h"
#include "chrome/browser/metrics/cros_healthd_metrics_provider.h"
+#include "chrome/browser/metrics/family_user_metrics_provider.h"
#include "chrome/browser/signin/signin_status_metrics_provider_chromeos.h"
#include "components/metrics/structured/structured_metrics_provider.h"
#endif // defined(OS_CHROMEOS)
@@ -733,6 +734,9 @@
metrics_service_->RegisterMetricsProvider(
std::make_unique<AmbientModeMetricsProvider>());
+
+ metrics_service_->RegisterMetricsProvider(
+ std::make_unique<FamilyUserMetricsProvider>());
#endif // defined(OS_CHROMEOS)
#if !defined(OS_CHROMEOS)
diff --git a/chrome/browser/metrics/chrome_metrics_service_client_unittest.cc b/chrome/browser/metrics/chrome_metrics_service_client_unittest.cc
index 94a3df5..daf5fa3 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client_unittest.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client_unittest.cc
@@ -182,9 +182,9 @@
#if defined(OS_CHROMEOS)
// AmbientModeMetricsProvider, AssistantServiceMetricsProvider,
// CrosHealthdMetricsProvider, ChromeOSMetricsProvider,
- // SigninStatusMetricsProviderChromeOS, PrinterMetricsProvider, and
- // HashedLoggingMetricsProvider.
- expected_providers += 7;
+ // SigninStatusMetricsProviderChromeOS, PrinterMetricsProvider,
+ // HashedLoggingMetricsProvider, and FamilyUserMetricsProvider.
+ expected_providers += 8;
#endif // defined(OS_CHROMEOS)
#if !defined(OS_CHROMEOS)
diff --git a/chrome/browser/metrics/family_user_metrics_provider.cc b/chrome/browser/metrics/family_user_metrics_provider.cc
new file mode 100644
index 0000000..03adbdc
--- /dev/null
+++ b/chrome/browser/metrics/family_user_metrics_provider.cc
@@ -0,0 +1,91 @@
+// Copyright 2020 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/metrics/family_user_metrics_provider.h"
+
+#include "base/feature_list.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_process_platform_part.h"
+#include "chrome/browser/chromeos/child_accounts/family_features.h"
+#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
+#include "chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/policy/profile_policy_connector.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
+#include "components/policy/proto/device_management_backend.pb.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+#include "components/user_manager/user_manager.h"
+
+namespace {
+
+// Returns user's segment for metrics logging.
+enterprise_management::PolicyData::MetricsLogSegment GetMetricsLogSegment(
+ Profile* profile) {
+ const policy::UserCloudPolicyManagerChromeOS* user_cloud_policy_manager =
+ profile->GetUserCloudPolicyManagerChromeOS();
+ if (!user_cloud_policy_manager)
+ return enterprise_management::PolicyData::UNSPECIFIED;
+ const enterprise_management::PolicyData* policy =
+ user_cloud_policy_manager->core()->store()->policy();
+ if (!policy || !policy->has_metrics_log_segment())
+ return enterprise_management::PolicyData::UNSPECIFIED;
+ return policy->metrics_log_segment();
+}
+
+bool IsLoggedIn() {
+ return user_manager::UserManager::IsInitialized() &&
+ user_manager::UserManager::Get()->IsUserLoggedIn();
+}
+
+bool IsEnterpriseManaged() {
+ policy::BrowserPolicyConnectorChromeOS* connector =
+ g_browser_process->platform_part()->browser_policy_connector_chromeos();
+ return connector->IsEnterpriseManaged();
+}
+
+} // namespace
+
+// static
+const char FamilyUserMetricsProvider::kFamilyUserLogSegmentHistogramName[] =
+ "ChromeOS.FamilyUser.LogSegment";
+
+FamilyUserMetricsProvider::FamilyUserMetricsProvider() = default;
+
+FamilyUserMetricsProvider::~FamilyUserMetricsProvider() = default;
+
+void FamilyUserMetricsProvider::ProvideCurrentSessionData(
+ metrics::ChromeUserMetricsExtension* uma_proto_unused) {
+ if (!base::FeatureList::IsEnabled(chromeos::kFamilyUserMetricsProvider))
+ return;
+ if (!IsLoggedIn())
+ return;
+ Profile* profile = ProfileManager::GetPrimaryUserProfile();
+ DCHECK(profile);
+ DCHECK(chromeos::ProfileHelper::IsRegularProfile(profile));
+ signin::IdentityManager* identity_manager =
+ IdentityManagerFactory::GetForProfile(profile);
+ auto accounts_size = identity_manager->GetAccountsWithRefreshTokens().size();
+ DCHECK_GT(accounts_size, 0);
+
+ LogSegment log_segment = LogSegment::kOther;
+ if (profile->IsChild() && accounts_size == 1) {
+ log_segment = LogSegment::kSupervisedUser;
+ } else if (profile->IsChild() && accounts_size > 1) {
+ // If a supervised user has a secondary account, then the secondary
+ // account must be EDU.
+ log_segment = LogSegment::kSupervisedStudent;
+ } else if (!IsEnterpriseManaged() &&
+ GetMetricsLogSegment(profile) ==
+ enterprise_management::PolicyData::K12) {
+ DCHECK(profile->GetProfilePolicyConnector()->IsManaged());
+ // This is a K-12 EDU user on an unmanaged ChromeOS device.
+ log_segment = LogSegment::kStudentAtHome;
+ }
+ base::UmaHistogramEnumeration(kFamilyUserLogSegmentHistogramName,
+ log_segment);
+}
diff --git a/chrome/browser/metrics/family_user_metrics_provider.h b/chrome/browser/metrics/family_user_metrics_provider.h
new file mode 100644
index 0000000..8c5f182
--- /dev/null
+++ b/chrome/browser/metrics/family_user_metrics_provider.h
@@ -0,0 +1,55 @@
+// Copyright 2020 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_FAMILY_USER_METRICS_PROVIDER_H_
+#define CHROME_BROWSER_METRICS_FAMILY_USER_METRICS_PROVIDER_H_
+
+#include "components/metrics/metrics_provider.h"
+
+namespace metrics {
+class ChromeUserMetricsExtension;
+} // namespace metrics
+
+// Categorizes the current user into a family user type for UMA dashboard
+// filtering. This metrics provider is ChromeOS specific.
+class FamilyUserMetricsProvider : public metrics::MetricsProvider {
+ public:
+ // These enum values represent the current user's log segment for the Family
+ // Experiences team's metrics.
+ // These values are logged to UMA. Entries should not be renumbered and
+ // numeric values should never be reused. Please keep in sync with
+ // "FamilyUserLogSegment" in src/tools/metrics/histograms/enums.xml.
+ enum class LogSegment {
+ // User does not fall into any of the below categories.
+ kOther = 0,
+ // Supervised primary account with no secondary accounts.
+ kSupervisedUser = 1,
+ // Supervised primary account with EDU secondary account. If the primary
+ // account is supervised, then the secondary account must be EDU if one
+ // exists.
+ kSupervisedStudent = 2,
+ // K-12 EDU primary account on an unmanaged device, regardless of the
+ // secondary account.
+ kStudentAtHome = 3,
+ // Add future entries above this comment, in sync with
+ // "FamilyUserLogSegment" in src/tools/metrics/histograms/enums.xml.
+ // Update kMaxValue to the last value.
+ kMaxValue = kStudentAtHome
+ };
+
+ // Family user metrics log segment histogram name.
+ static const char kFamilyUserLogSegmentHistogramName[];
+
+ FamilyUserMetricsProvider();
+ ~FamilyUserMetricsProvider() override;
+ FamilyUserMetricsProvider(const FamilyUserMetricsProvider&) = delete;
+ FamilyUserMetricsProvider& operator=(const FamilyUserMetricsProvider&) =
+ delete;
+
+ // MetricsProvider:
+ void ProvideCurrentSessionData(
+ metrics::ChromeUserMetricsExtension* uma_proto_unused) override;
+};
+
+#endif // CHROME_BROWSER_METRICS_FAMILY_USER_METRICS_PROVIDER_H_
diff --git a/chrome/browser/metrics/family_user_metrics_provider_browsertest.cc b/chrome/browser/metrics/family_user_metrics_provider_browsertest.cc
new file mode 100644
index 0000000..a99f2c7
--- /dev/null
+++ b/chrome/browser/metrics/family_user_metrics_provider_browsertest.cc
@@ -0,0 +1,127 @@
+// Copyright 2020 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/metrics/family_user_metrics_provider.h"
+
+#include "base/optional.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "chrome/browser/chromeos/login/test/fake_gaia_mixin.h"
+#include "chrome/browser/chromeos/login/test/scoped_policy_update.h"
+#include "chrome/browser/chromeos/login/test/user_policy_mixin.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/supervised_user/logged_in_user_mixin.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/mixin_based_in_process_browser_test.h"
+#include "components/account_id/account_id.h"
+#include "components/signin/public/identity_manager/account_info.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+#include "components/signin/public/identity_manager/identity_test_utils.h"
+#include "content/public/test/browser_test.h"
+
+namespace {
+
+constexpr char kSecondaryEDUEmail[] = "[email protected]";
+
+// Returns the user type for the primary test account for logging in.
+chromeos::LoggedInUserMixin::LogInType GetPrimaryLogInType(
+ FamilyUserMetricsProvider::LogSegment log_segment) {
+ switch (log_segment) {
+ case FamilyUserMetricsProvider::LogSegment::kSupervisedUser:
+ case FamilyUserMetricsProvider::LogSegment::kSupervisedStudent:
+ return chromeos::LoggedInUserMixin::LogInType::kChild;
+ case FamilyUserMetricsProvider::LogSegment::kStudentAtHome:
+ case FamilyUserMetricsProvider::LogSegment::kOther:
+ return chromeos::LoggedInUserMixin::LogInType::kRegular;
+ }
+}
+
+// Returns the account id for the primary test account for logging in.
+base::Optional<AccountId> GetPrimaryAccountId(
+ FamilyUserMetricsProvider::LogSegment log_segment) {
+ if (log_segment == FamilyUserMetricsProvider::LogSegment::kStudentAtHome) {
+ // To distinguish K-12 EDU users from Enterprise users in ChromeOS, we use a
+ // PolicyData field. Fetching policy is skipped for obviously consumer
+ // users, who have an @gmail.com e-mail, for example (see comments in
+ // fake_gaia_mixin.h). Since we need policies for this test, we must use an
+ // e-mail address that has an enterprise domain. Of all the user categories,
+ // kStudentAtHome is the only one with an enterprise managed primary
+ // account.
+ return AccountId::FromUserEmailGaiaId(
+ chromeos::FakeGaiaMixin::kEnterpriseUser1,
+ chromeos::FakeGaiaMixin::kEnterpriseUser1GaiaId);
+ }
+ // Use the default FakeGaiaMixin::kFakeUserEmail consumer test account id.
+ return base::nullopt;
+}
+
+} // namespace
+
+class FamilyUserMetricsProviderTest
+ : public MixinBasedInProcessBrowserTest,
+ public testing::WithParamInterface<
+ FamilyUserMetricsProvider::LogSegment> {
+ public:
+ void SetUpInProcessBrowserTestFixture() override {
+ MixinBasedInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
+
+ const FamilyUserMetricsProvider::LogSegment log_segment = GetParam();
+ if (log_segment == FamilyUserMetricsProvider::LogSegment::kStudentAtHome) {
+ logged_in_user_mixin_.GetUserPolicyMixin()
+ ->RequestPolicyUpdate()
+ ->policy_data()
+ ->set_metrics_log_segment(enterprise_management::PolicyData::K12);
+ }
+ }
+
+ protected:
+ chromeos::LoggedInUserMixin logged_in_user_mixin_{
+ &mixin_host_, GetPrimaryLogInType(GetParam()), embedded_test_server(),
+ this,
+ /*should_launch_browser=*/true, GetPrimaryAccountId(GetParam()),
+ /*include_initial_user=*/true,
+ // Don't use LocalPolicyTestServer because it does not support customizing
+ // PolicyData.
+ // TODO(crbug/1112885): Use LocalPolicyTestServer when this is fixed.
+ /*use_local_policy_server=*/false};
+};
+
+IN_PROC_BROWSER_TEST_P(FamilyUserMetricsProviderTest, UserCategory) {
+ base::HistogramTester histogram_tester;
+ FamilyUserMetricsProvider provider;
+ // Simulate calling ProvideCurrentSessionData() prior to logging in.
+ // This call should return prematurely.
+ provider.ProvideCurrentSessionData(/*uma_proto_unused=*/nullptr);
+
+ logged_in_user_mixin_.LogInUser();
+
+ const FamilyUserMetricsProvider::LogSegment log_segment = GetParam();
+ if (log_segment ==
+ FamilyUserMetricsProvider::LogSegment::kSupervisedStudent) {
+ // Add a secondary EDU account.
+ Profile* profile = browser()->profile();
+ ASSERT_TRUE(profile);
+ signin::IdentityManager* identity_manager =
+ IdentityManagerFactory::GetForProfile(profile);
+ AccountInfo account_info =
+ signin::MakeAccountAvailable(identity_manager, kSecondaryEDUEmail);
+ EXPECT_TRUE(
+ identity_manager->HasAccountWithRefreshToken(account_info.account_id));
+ }
+
+ // Simulate calling ProvideCurrentSessionData() after logging in.
+ provider.ProvideCurrentSessionData(/*uma_proto_unused=*/nullptr);
+
+ histogram_tester.ExpectUniqueSample(
+ FamilyUserMetricsProvider::kFamilyUserLogSegmentHistogramName,
+ log_segment, 1);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ ,
+ FamilyUserMetricsProviderTest,
+ testing::Values(FamilyUserMetricsProvider::LogSegment::kSupervisedUser,
+ FamilyUserMetricsProvider::LogSegment::kSupervisedStudent,
+ FamilyUserMetricsProvider::LogSegment::kStudentAtHome,
+ FamilyUserMetricsProvider::LogSegment::kOther));
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 315e5dd2..ecfa05b 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2634,6 +2634,7 @@
"../browser/extensions/api/settings_private/settings_private_browsertest_chromeos.cc",
"../browser/extensions/api/vpn_provider/vpn_provider_apitest.cc",
"../browser/extensions/chromeos_component_extensions_browsertest.cc",
+ "../browser/metrics/family_user_metrics_provider_browsertest.cc",
"../browser/notifications/notification_platform_bridge_chromeos_browsertest.cc",
"../browser/resources/chromeos/zip_archiver/test/zip_archiver_jstest.cc",
"../browser/signin/chromeos_mirror_account_consistency_browsertest.cc",
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 02e96f0..226791d6 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -25503,10 +25503,10 @@
<enum name="FamilyUserLogSegment">
<summary>Filters family user metrics into categories of interest.</summary>
- <int value="0" label="Supervised User"/>
- <int value="1" label="Supervised Student"/>
- <int value="2" label="Student at Home"/>
- <int value="3" label="Other"/>
+ <int value="0" label="Other"/>
+ <int value="1" label="Supervised User"/>
+ <int value="2" label="Supervised Student"/>
+ <int value="3" label="Student at Home"/>
</enum>
<enum name="FaultTolerantHeap">
diff --git a/tools/metrics/histograms/histograms_xml/chrome/histograms.xml b/tools/metrics/histograms/histograms_xml/chrome/histograms.xml
index 8a99f37..595fae33 100644
--- a/tools/metrics/histograms/histograms_xml/chrome/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/chrome/histograms.xml
@@ -600,13 +600,14 @@
<owner>[email protected]</owner>
<owner>[email protected]</owner>
<summary>
- Categorizes the current user for the Family Experiences team's metrics. A
- Supervised User has a supervised primary account and no secondary accounts.
- A Supervised Student has a supervised primary account and one or more K-12
- EDU secondary accounts, which is the only available option for a secondary
- account in that scenario. A Student at Home has a K-12 EDU primary account
- on an unmanaged ChromeOS device, regardless of the secondary account. Other
- is for all other users that do not fall into any of the above categories.
+ Categorizes the current user for the Family Experiences team's metrics.
+ Other is for all other users that do not fall into any of the below
+ categories. A Supervised User has a supervised primary account and no
+ secondary accounts. A Supervised Student has a supervised primary account
+ and one or more EDU secondary accounts, which is the only available option
+ for a secondary account in that scenario. A Student at Home has a K-12 EDU
+ primary account on an unmanaged ChromeOS device, regardless of the secondary
+ account.
</summary>
</histogram>