blob: 1745c5ce3d6891034544705f85647f827a6df794 [file] [log] [blame]
// 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/metrics/chromeos_metrics_provider.h"
#include <string>
#include "base/bind.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
#include "chrome/browser/chromeos/multidevice_setup/multidevice_setup_client_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "chromeos/components/multidevice/remote_device_test_util.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "chromeos/login/login_state/login_state.h"
#include "chromeos/services/multidevice_setup/public/cpp/fake_multidevice_setup_client.h"
#include "chromeos/services/multidevice_setup/public/cpp/multidevice_setup_client_impl.h"
#include "chromeos/system/fake_statistics_provider.h"
#include "chromeos/system/statistics_provider.h"
#include "components/user_manager/scoped_user_manager.h"
#include "components/user_manager/user_manager.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
#include "device/bluetooth/dbus/bluez_dbus_manager.h"
#include "device/bluetooth/dbus/fake_bluetooth_adapter_client.h"
#include "device/bluetooth/dbus/fake_bluetooth_agent_manager_client.h"
#include "device/bluetooth/dbus/fake_bluetooth_device_client.h"
#include "device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.h"
#include "device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_client.h"
#include "device/bluetooth/dbus/fake_bluetooth_gatt_service_client.h"
#include "device/bluetooth/dbus/fake_bluetooth_input_client.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/metrics_proto/system_profile.pb.h"
using bluez::BluetoothAdapterClient;
using bluez::BluetoothAgentManagerClient;
using bluez::BluetoothDeviceClient;
using bluez::BluetoothGattCharacteristicClient;
using bluez::BluetoothGattDescriptorClient;
using bluez::BluetoothGattServiceClient;
using bluez::BluetoothInputClient;
using bluez::BluezDBusManager;
using bluez::BluezDBusManagerSetter;
using bluez::FakeBluetoothAdapterClient;
using bluez::FakeBluetoothAgentManagerClient;
using bluez::FakeBluetoothDeviceClient;
using bluez::FakeBluetoothGattCharacteristicClient;
using bluez::FakeBluetoothGattDescriptorClient;
using bluez::FakeBluetoothGattServiceClient;
using bluez::FakeBluetoothInputClient;
namespace {
class FakeMultiDeviceSetupClientImplFactory
: public chromeos::multidevice_setup::MultiDeviceSetupClientImpl::Factory {
public:
FakeMultiDeviceSetupClientImplFactory(
std::unique_ptr<chromeos::multidevice_setup::FakeMultiDeviceSetupClient>
fake_multidevice_setup_client)
: fake_multidevice_setup_client_(
std::move(fake_multidevice_setup_client)) {}
~FakeMultiDeviceSetupClientImplFactory() override = default;
// chromeos::multidevice_setup::MultiDeviceSetupClientImpl::Factory:
// NOTE: At most, one client should be created per-test.
std::unique_ptr<chromeos::multidevice_setup::MultiDeviceSetupClient>
BuildInstance(service_manager::Connector* connector) override {
EXPECT_TRUE(fake_multidevice_setup_client_);
return std::move(fake_multidevice_setup_client_);
}
private:
std::unique_ptr<chromeos::multidevice_setup::FakeMultiDeviceSetupClient>
fake_multidevice_setup_client_;
};
// Wrapper around ChromeOSMetricsProvider that initializes
// Bluetooth and hardware class in the constructor.
class TestChromeOSMetricsProvider : public ChromeOSMetricsProvider {
public:
TestChromeOSMetricsProvider()
: ChromeOSMetricsProvider(metrics::MetricsLogUploader::UMA) {
AsyncInit(base::Bind(&TestChromeOSMetricsProvider::GetIdleCallback,
base::Unretained(this)));
base::RunLoop().Run();
}
void GetIdleCallback() {
ASSERT_TRUE(base::RunLoop::IsRunningOnCurrentThread());
base::RunLoop::QuitCurrentWhenIdleDeprecated();
}
};
} // namespace
class ChromeOSMetricsProviderTest : public testing::Test {
public:
ChromeOSMetricsProviderTest() {}
protected:
void SetUp() override {
// Set up the fake Bluetooth environment,
std::unique_ptr<BluezDBusManagerSetter> bluez_dbus_setter =
BluezDBusManager::GetSetterForTesting();
bluez_dbus_setter->SetBluetoothAdapterClient(
std::unique_ptr<BluetoothAdapterClient>(
new FakeBluetoothAdapterClient));
bluez_dbus_setter->SetBluetoothDeviceClient(
std::unique_ptr<BluetoothDeviceClient>(new FakeBluetoothDeviceClient));
bluez_dbus_setter->SetBluetoothGattCharacteristicClient(
std::unique_ptr<BluetoothGattCharacteristicClient>(
new FakeBluetoothGattCharacteristicClient));
bluez_dbus_setter->SetBluetoothGattDescriptorClient(
std::unique_ptr<BluetoothGattDescriptorClient>(
new FakeBluetoothGattDescriptorClient));
bluez_dbus_setter->SetBluetoothGattServiceClient(
std::unique_ptr<BluetoothGattServiceClient>(
new FakeBluetoothGattServiceClient));
bluez_dbus_setter->SetBluetoothInputClient(
std::unique_ptr<BluetoothInputClient>(new FakeBluetoothInputClient));
bluez_dbus_setter->SetBluetoothAgentManagerClient(
std::unique_ptr<BluetoothAgentManagerClient>(
new FakeBluetoothAgentManagerClient));
// Set up a PowerManagerClient instance for PerfProvider.
chromeos::PowerManagerClient::InitializeFake();
// Grab pointers to members of the thread manager for easier testing.
fake_bluetooth_adapter_client_ = static_cast<FakeBluetoothAdapterClient*>(
BluezDBusManager::Get()->GetBluetoothAdapterClient());
fake_bluetooth_device_client_ = static_cast<FakeBluetoothDeviceClient*>(
BluezDBusManager::Get()->GetBluetoothDeviceClient());
chromeos::multidevice_setup::MultiDeviceSetupClientFactory::GetInstance()
->SetServiceIsNULLWhileTestingForTesting(false);
auto fake_multidevice_setup_client = std::make_unique<
chromeos::multidevice_setup::FakeMultiDeviceSetupClient>();
fake_multidevice_setup_client_ = fake_multidevice_setup_client.get();
fake_multidevice_setup_client_impl_factory_ =
std::make_unique<FakeMultiDeviceSetupClientImplFactory>(
std::move(fake_multidevice_setup_client));
chromeos::multidevice_setup::MultiDeviceSetupClientImpl::Factory::
SetInstanceForTesting(
fake_multidevice_setup_client_impl_factory_.get());
profile_manager_ = std::make_unique<TestingProfileManager>(
TestingBrowserProcess::GetGlobal());
ASSERT_TRUE(profile_manager_->SetUp());
TestingProfile* profile =
profile_manager_->CreateTestingProfile("test_name");
profile_manager_->UpdateLastUser(profile);
// Set statistic provider for hardware class tests.
chromeos::system::StatisticsProvider::SetTestProvider(
&fake_statistics_provider_);
// Initialize the login state trackers.
if (!chromeos::LoginState::IsInitialized())
chromeos::LoginState::Initialize();
}
void TearDown() override {
// Destroy the login state tracker if it was initialized.
chromeos::LoginState::Shutdown();
chromeos::PowerManagerClient::Shutdown();
chromeos::multidevice_setup::MultiDeviceSetupClientImpl::Factory::
SetInstanceForTesting(nullptr);
profile_manager_.reset();
}
protected:
FakeBluetoothAdapterClient* fake_bluetooth_adapter_client_;
FakeBluetoothDeviceClient* fake_bluetooth_device_client_;
chromeos::multidevice_setup::FakeMultiDeviceSetupClient*
fake_multidevice_setup_client_;
base::test::ScopedFeatureList scoped_feature_list_;
chromeos::system::ScopedFakeStatisticsProvider fake_statistics_provider_;
std::unique_ptr<TestingProfileManager> profile_manager_;
std::unique_ptr<FakeMultiDeviceSetupClientImplFactory>
fake_multidevice_setup_client_impl_factory_;
private:
content::TestBrowserThreadBundle thread_bundle_;
DISALLOW_COPY_AND_ASSIGN(ChromeOSMetricsProviderTest);
};
TEST_F(ChromeOSMetricsProviderTest, MultiProfileUserCount) {
const AccountId account_id1(AccountId::FromUserEmail("user1@example.com"));
const AccountId account_id2(AccountId::FromUserEmail("user2@example.com"));
const AccountId account_id3(AccountId::FromUserEmail("user3@example.com"));
// |scoped_enabler| takes over the lifetime of |user_manager|.
chromeos::FakeChromeUserManager* user_manager =
new chromeos::FakeChromeUserManager();
user_manager::ScopedUserManager scoped_enabler(
base::WrapUnique(user_manager));
user_manager->AddKioskAppUser(account_id1);
user_manager->AddKioskAppUser(account_id2);
user_manager->AddKioskAppUser(account_id3);
user_manager->LoginUser(account_id1);
user_manager->LoginUser(account_id3);
TestChromeOSMetricsProvider provider;
provider.OnDidCreateMetricsLog();
metrics::SystemProfileProto system_profile;
provider.ProvideSystemProfileMetrics(&system_profile);
EXPECT_EQ(2u, system_profile.multi_profile_user_count());
}
TEST_F(ChromeOSMetricsProviderTest, MultiProfileCountInvalidated) {
const AccountId account_id1(AccountId::FromUserEmail("user1@example.com"));
const AccountId account_id2(AccountId::FromUserEmail("user2@example.com"));
const AccountId account_id3(AccountId::FromUserEmail("user3@example.com"));
// |scoped_enabler| takes over the lifetime of |user_manager|.
chromeos::FakeChromeUserManager* user_manager =
new chromeos::FakeChromeUserManager();
user_manager::ScopedUserManager scoped_enabler(
base::WrapUnique(user_manager));
user_manager->AddKioskAppUser(account_id1);
user_manager->AddKioskAppUser(account_id2);
user_manager->AddKioskAppUser(account_id3);
user_manager->LoginUser(account_id1);
TestChromeOSMetricsProvider provider;
provider.OnDidCreateMetricsLog();
metrics::SystemProfileProto system_profile;
provider.ProvideSystemProfileMetrics(&system_profile);
EXPECT_EQ(1u, system_profile.multi_profile_user_count());
user_manager->LoginUser(account_id2);
provider.ProvideSystemProfileMetrics(&system_profile);
EXPECT_EQ(0u, system_profile.multi_profile_user_count());
}
TEST_F(ChromeOSMetricsProviderTest, BluetoothHardwareDisabled) {
TestChromeOSMetricsProvider provider;
provider.OnDidCreateMetricsLog();
metrics::SystemProfileProto system_profile;
provider.ProvideSystemProfileMetrics(&system_profile);
EXPECT_TRUE(system_profile.has_hardware());
EXPECT_TRUE(system_profile.hardware().has_bluetooth());
EXPECT_TRUE(system_profile.hardware().bluetooth().is_present());
EXPECT_FALSE(system_profile.hardware().bluetooth().is_enabled());
}
TEST_F(ChromeOSMetricsProviderTest, BluetoothHardwareEnabled) {
FakeBluetoothAdapterClient::Properties* properties =
fake_bluetooth_adapter_client_->GetProperties(
dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath));
properties->powered.ReplaceValue(true);
TestChromeOSMetricsProvider provider;
metrics::SystemProfileProto system_profile;
provider.ProvideSystemProfileMetrics(&system_profile);
EXPECT_TRUE(system_profile.has_hardware());
EXPECT_TRUE(system_profile.hardware().has_bluetooth());
EXPECT_TRUE(system_profile.hardware().bluetooth().is_present());
EXPECT_TRUE(system_profile.hardware().bluetooth().is_enabled());
}
TEST_F(ChromeOSMetricsProviderTest, BluetoothPairedDevices) {
// The fake bluetooth adapter class already claims to be paired with two
// device when initialized. Add a third and fourth fake device to it so we
// can test the cases where a device is not paired (LE device, generally)
// and a device that does not have Device ID information.
fake_bluetooth_device_client_->CreateDevice(
dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(FakeBluetoothDeviceClient::kRequestPinCodePath));
fake_bluetooth_device_client_->CreateDevice(
dbus::ObjectPath(FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(FakeBluetoothDeviceClient::kConfirmPasskeyPath));
FakeBluetoothDeviceClient::Properties* properties =
fake_bluetooth_device_client_->GetProperties(
dbus::ObjectPath(FakeBluetoothDeviceClient::kConfirmPasskeyPath));
properties->paired.ReplaceValue(true);
TestChromeOSMetricsProvider provider;
provider.OnDidCreateMetricsLog();
metrics::SystemProfileProto system_profile;
provider.ProvideSystemProfileMetrics(&system_profile);
ASSERT_TRUE(system_profile.has_hardware());
ASSERT_TRUE(system_profile.hardware().has_bluetooth());
// Only three of the devices should appear.
EXPECT_EQ(3, system_profile.hardware().bluetooth().paired_device_size());
typedef metrics::SystemProfileProto::Hardware::Bluetooth::PairedDevice
PairedDevice;
// As BluetoothAdapter keeps the device list without ordering,
// it's not appropriate to use fixed positional indices to index into the
// system_profile.hardware().bluetooth().paired_device list.
// Instead, directly find the two devices we're interested in.
PairedDevice device1;
PairedDevice device2;
for (int i = 0;
i < system_profile.hardware().bluetooth().paired_device_size(); ++i) {
const PairedDevice& device =
system_profile.hardware().bluetooth().paired_device(i);
if (device.bluetooth_class() ==
FakeBluetoothDeviceClient::kPairedDeviceClass &&
device.vendor_prefix() == 0x001122U) {
// Found the Paired Device object.
device1 = device;
} else if (device.bluetooth_class() ==
FakeBluetoothDeviceClient::kConfirmPasskeyClass) {
// Found the Confirm Passkey object.
device2 = device;
}
}
// The Paired Device object, complete with parsed Device ID information.
EXPECT_EQ(FakeBluetoothDeviceClient::kPairedDeviceClass,
device1.bluetooth_class());
EXPECT_EQ(PairedDevice::DEVICE_COMPUTER, device1.type());
EXPECT_EQ(0x001122U, device1.vendor_prefix());
EXPECT_EQ(PairedDevice::VENDOR_ID_USB, device1.vendor_id_source());
EXPECT_EQ(0x05ACU, device1.vendor_id());
EXPECT_EQ(0x030DU, device1.product_id());
EXPECT_EQ(0x0306U, device1.device_id());
// The Confirm Passkey object, this has no Device ID information.
EXPECT_EQ(FakeBluetoothDeviceClient::kConfirmPasskeyClass,
device2.bluetooth_class());
EXPECT_EQ(PairedDevice::DEVICE_PHONE, device2.type());
EXPECT_EQ(0x207D74U, device2.vendor_prefix());
EXPECT_EQ(PairedDevice::VENDOR_ID_UNKNOWN, device2.vendor_id_source());
}
TEST_F(ChromeOSMetricsProviderTest, NoLinkedAndroidPhone) {
fake_multidevice_setup_client_->SetHostStatusWithDevice(std::make_pair(
chromeos::multidevice_setup::mojom::HostStatus::kNoEligibleHosts,
base::nullopt /* host_device */));
TestChromeOSMetricsProvider provider;
metrics::SystemProfileProto system_profile;
provider.ProvideSystemProfileMetrics(&system_profile);
EXPECT_FALSE(system_profile.has_linked_android_phone_data());
}
TEST_F(ChromeOSMetricsProviderTest, HasLinkedAndroidPhoneAndEnabledFeatures) {
fake_multidevice_setup_client_->SetHostStatusWithDevice(std::make_pair(
chromeos::multidevice_setup::mojom::HostStatus::kHostVerified,
chromeos::multidevice::CreateRemoteDeviceRefForTest()));
fake_multidevice_setup_client_->SetFeatureState(
chromeos::multidevice_setup::mojom::Feature::kInstantTethering,
chromeos::multidevice_setup::mojom::FeatureState::kEnabledByUser);
fake_multidevice_setup_client_->SetFeatureState(
chromeos::multidevice_setup::mojom::Feature::kSmartLock,
chromeos::multidevice_setup::mojom::FeatureState::kEnabledByUser);
fake_multidevice_setup_client_->SetFeatureState(
chromeos::multidevice_setup::mojom::Feature::kMessages,
chromeos::multidevice_setup::mojom::FeatureState::kFurtherSetupRequired);
TestChromeOSMetricsProvider provider;
metrics::SystemProfileProto system_profile;
provider.ProvideSystemProfileMetrics(&system_profile);
EXPECT_TRUE(system_profile.has_linked_android_phone_data());
EXPECT_TRUE(
system_profile.linked_android_phone_data().has_phone_model_name_hash());
EXPECT_TRUE(system_profile.linked_android_phone_data()
.is_instant_tethering_enabled());
EXPECT_TRUE(
system_profile.linked_android_phone_data().is_smartlock_enabled());
EXPECT_FALSE(
system_profile.linked_android_phone_data().is_messages_enabled());
}
TEST_F(ChromeOSMetricsProviderTest, DisableUmaShortHwClass) {
const std::string expected_full_hw_class = "feature_disabled";
scoped_feature_list_.InitAndDisableFeature(features::kUmaShortHWClass);
fake_statistics_provider_.SetMachineStatistic("hardware_class",
expected_full_hw_class);
TestChromeOSMetricsProvider provider;
provider.OnDidCreateMetricsLog();
metrics::SystemProfileProto system_profile;
provider.ProvideSystemProfileMetrics(&system_profile);
ASSERT_TRUE(system_profile.has_hardware());
std::string proto_full_hw_class =
system_profile.hardware().full_hardware_class();
// If disabled, the two hardware classes should be equal to each other.
EXPECT_EQ(system_profile.hardware().hardware_class(), proto_full_hw_class);
EXPECT_EQ(expected_full_hw_class, proto_full_hw_class);
}
TEST_F(ChromeOSMetricsProviderTest, EnableUmaShortHwClass) {
const std::string expected_full_hw_class = "feature_enabled";
scoped_feature_list_.InitAndEnableFeature(features::kUmaShortHWClass);
fake_statistics_provider_.SetMachineStatistic("hardware_class",
expected_full_hw_class);
TestChromeOSMetricsProvider provider;
provider.OnDidCreateMetricsLog();
metrics::SystemProfileProto system_profile;
provider.ProvideSystemProfileMetrics(&system_profile);
ASSERT_TRUE(system_profile.has_hardware());
std::string proto_full_hw_class =
system_profile.hardware().full_hardware_class();
// If enabled, the two hardware strings should be different.
EXPECT_NE(system_profile.hardware().hardware_class(), proto_full_hw_class);
EXPECT_EQ(expected_full_hw_class, proto_full_hw_class);
}