| // Copyright 2016 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ash/arc/session/arc_session_manager.h" |
| |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <tuple> |
| #include <vector> |
| |
| #include "ash/components/arc/arc_features.h" |
| #include "ash/components/arc/arc_prefs.h" |
| #include "ash/components/arc/arc_util.h" |
| #include "ash/components/arc/session/arc_service_manager.h" |
| #include "ash/components/arc/session/arc_session_runner.h" |
| #include "ash/components/arc/test/arc_util_test_support.h" |
| #include "ash/components/arc/test/fake_arc_session.h" |
| #include "ash/constants/ash_features.h" |
| #include "ash/constants/ash_switches.h" |
| #include "base/check_op.h" |
| #include "base/command_line.h" |
| #include "base/files/file_path.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/functional/bind.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/notreached.h" |
| #include "base/observer_list.h" |
| #include "base/run_loop.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/test/bind.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/scoped_command_line.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/values.h" |
| #include "chrome/browser/ash/app_list/arc/arc_app_list_prefs.h" |
| #include "chrome/browser/ash/app_list/arc/arc_app_test.h" |
| #include "chrome/browser/ash/arc/arc_optin_uma.h" |
| #include "chrome/browser/ash/arc/arc_util.h" |
| #include "chrome/browser/ash/arc/optin/arc_terms_of_service_oobe_negotiator.h" |
| #include "chrome/browser/ash/arc/session/arc_play_store_enabled_preference_handler.h" |
| #include "chrome/browser/ash/arc/session/arc_provisioning_result.h" |
| #include "chrome/browser/ash/arc/session/arc_session_manager_observer.h" |
| #include "chrome/browser/ash/arc/test/arc_data_removed_waiter.h" |
| #include "chrome/browser/ash/arc/test/test_arc_session_manager.h" |
| #include "chrome/browser/ash/login/demo_mode/demo_setup_controller.h" |
| #include "chrome/browser/ash/login/oobe_screen.h" |
| #include "chrome/browser/ash/login/ui/fake_login_display_host.h" |
| #include "chrome/browser/ash/login/users/fake_chrome_user_manager.h" |
| #include "chrome/browser/ash/login/wizard_controller.h" |
| #include "chrome/browser/ash/policy/arc/fake_android_management_client.h" |
| #include "chrome/browser/ash/settings/device_settings_cache.h" |
| #include "chrome/browser/ash/settings/scoped_cros_settings_test_helper.h" |
| #include "chrome/browser/notifications/notification_display_service_tester.h" |
| #include "chrome/browser/policy/profile_policy_connector.h" |
| #include "chrome/browser/prefs/browser_prefs.h" |
| #include "chrome/browser/prefs/pref_service_syncable_util.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ui/ash/multi_user/multi_user_util.h" |
| #include "chrome/test/base/testing_browser_process.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "chromeos/ash/components/dbus/arc/arcvm_data_migrator_client.h" |
| #include "chromeos/ash/components/dbus/arc/fake_arcvm_data_migrator_client.h" |
| #include "chromeos/ash/components/dbus/concierge/concierge_client.h" |
| #include "chromeos/ash/components/dbus/resourced/fake_resourced_client.h" |
| #include "chromeos/ash/components/dbus/resourced/resourced_client.h" |
| #include "chromeos/ash/components/dbus/session_manager/session_manager_client.h" |
| #include "chromeos/ash/components/dbus/upstart/upstart_client.h" |
| #include "chromeos/ash/components/login/auth/auth_events_recorder.h" |
| #include "chromeos/ash/components/memory/swap_configuration.h" |
| #include "chromeos/dbus/power/power_manager_client.h" |
| #include "components/account_id/account_id.h" |
| #include "components/policy/proto/chrome_device_policy.pb.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/prefs/testing_pref_service.h" |
| #include "components/session_manager/core/session_manager.h" |
| #include "components/signin/public/identity_manager/identity_test_environment.h" |
| #include "components/sync/test/fake_sync_change_processor.h" |
| #include "components/sync_preferences/testing_pref_service_syncable.h" |
| #include "components/user_manager/known_user.h" |
| #include "components/user_manager/scoped_user_manager.h" |
| #include "components/user_manager/user_manager.h" |
| #include "components/user_manager/user_names.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "google_apis/gaia/gaia_constants.h" |
| #include "google_apis/gaia/gaia_urls.h" |
| #include "net/http/http_status_code.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| // TODO(b/254819616): Replace base::RunLoop().RunUntilIdle() with |
| // task_environment_.RunUntilIdle() or Run() & Quit() to make the tests less |
| // fragile. |
| |
| namespace arc { |
| |
| namespace { |
| |
| class ArcInitialStartHandler : public ArcSessionManagerObserver { |
| public: |
| explicit ArcInitialStartHandler(ArcSessionManager* session_manager) |
| : session_manager_(session_manager) { |
| session_manager->AddObserver(this); |
| } |
| |
| ArcInitialStartHandler(const ArcInitialStartHandler&) = delete; |
| ArcInitialStartHandler& operator=(const ArcInitialStartHandler&) = delete; |
| |
| ~ArcInitialStartHandler() override { session_manager_->RemoveObserver(this); } |
| |
| // ArcSessionManagerObserver: |
| void OnArcInitialStart() override { |
| DCHECK(!was_called_); |
| was_called_ = true; |
| } |
| |
| bool was_called() const { return was_called_; } |
| |
| private: |
| bool was_called_ = false; |
| |
| const raw_ptr<ArcSessionManager> session_manager_; |
| }; |
| |
| class FileExpansionObserver : public ArcSessionManagerObserver { |
| public: |
| FileExpansionObserver() = default; |
| ~FileExpansionObserver() override = default; |
| FileExpansionObserver(const FileExpansionObserver&) = delete; |
| FileExpansionObserver& operator=(const FileExpansionObserver&) = delete; |
| |
| const std::optional<bool>& property_files_expansion_result() const { |
| return property_files_expansion_result_; |
| } |
| |
| // ArcSessionManagerObserver: |
| void OnPropertyFilesExpanded(bool result) override { |
| property_files_expansion_result_ = result; |
| } |
| |
| private: |
| std::optional<bool> property_files_expansion_result_; |
| }; |
| |
| class ShowErrorObserver : public ArcSessionManagerObserver { |
| public: |
| ShowErrorObserver(const ShowErrorObserver&) = delete; |
| ShowErrorObserver& operator=(const ShowErrorObserver&) = delete; |
| |
| explicit ShowErrorObserver(ArcSessionManager* session_manager) |
| : session_manager_(session_manager) { |
| session_manager->AddObserver(this); |
| } |
| |
| ~ShowErrorObserver() override { session_manager_->RemoveObserver(this); } |
| |
| const std::optional<ArcSupportHost::ErrorInfo> error_info() const { |
| return error_info_; |
| } |
| |
| void OnArcErrorShowRequested(ArcSupportHost::ErrorInfo error_info) override { |
| error_info_ = error_info; |
| } |
| |
| private: |
| std::optional<ArcSupportHost::ErrorInfo> error_info_; |
| const raw_ptr<ArcSessionManager> session_manager_; |
| }; |
| |
| class ArcSessionManagerInLoginScreenTest : public testing::Test { |
| public: |
| ArcSessionManagerInLoginScreenTest() |
| : fake_user_manager_(std::make_unique<ash::FakeChromeUserManager>()) { |
| ash::ConciergeClient::InitializeFake(/*fake_cicerone_client=*/nullptr); |
| ash::SessionManagerClient::InitializeFakeInMemory(); |
| |
| ArcSessionManager::SetUiEnabledForTesting(false); |
| SetArcBlockedDueToIncompatibleFileSystemForTesting(false); |
| |
| arc_service_manager_ = std::make_unique<ArcServiceManager>(); |
| arc_session_manager_ = |
| CreateTestArcSessionManager(std::make_unique<ArcSessionRunner>( |
| base::BindRepeating(FakeArcSession::Create))); |
| } |
| |
| ArcSessionManagerInLoginScreenTest( |
| const ArcSessionManagerInLoginScreenTest&) = delete; |
| ArcSessionManagerInLoginScreenTest& operator=( |
| const ArcSessionManagerInLoginScreenTest&) = delete; |
| |
| ~ArcSessionManagerInLoginScreenTest() override { |
| arc_session_manager_->Shutdown(); |
| arc_session_manager_.reset(); |
| arc_service_manager_.reset(); |
| ash::SessionManagerClient::Shutdown(); |
| ash::ConciergeClient::Shutdown(); |
| } |
| |
| protected: |
| ArcSessionManager* arc_session_manager() { |
| return arc_session_manager_.get(); |
| } |
| |
| FakeArcSession* arc_session() { |
| return static_cast<FakeArcSession*>( |
| arc_session_manager_->GetArcSessionRunnerForTesting() |
| ->GetArcSessionForTesting()); |
| } |
| |
| private: |
| content::BrowserTaskEnvironment task_environment_; |
| std::unique_ptr<ArcServiceManager> arc_service_manager_; |
| std::unique_ptr<ArcSessionManager> arc_session_manager_; |
| user_manager::TypedScopedUserManager<ash::FakeChromeUserManager> |
| fake_user_manager_; |
| }; |
| |
| // We expect mini instance starts to run if EmitLoginPromptVisible signal is |
| // emitted. |
| TEST_F(ArcSessionManagerInLoginScreenTest, EmitLoginPromptVisible) { |
| EXPECT_FALSE(arc_session()); |
| |
| SetArcAvailableCommandLineForTesting(base::CommandLine::ForCurrentProcess()); |
| |
| ash::SessionManagerClient::Get()->EmitLoginPromptVisible(); |
| ASSERT_TRUE(arc_session()); |
| EXPECT_FALSE(arc_session()->is_running()); |
| EXPECT_EQ(ArcSessionManager::State::NOT_INITIALIZED, |
| arc_session_manager()->state()); |
| } |
| |
| // We expect mini instance does not start on EmitLoginPromptVisible when ARC |
| // is not available. |
| TEST_F(ArcSessionManagerInLoginScreenTest, EmitLoginPromptVisible_NoOp) { |
| EXPECT_FALSE(arc_session()); |
| |
| ash::SessionManagerClient::Get()->EmitLoginPromptVisible(); |
| EXPECT_FALSE(arc_session()); |
| EXPECT_EQ(ArcSessionManager::State::NOT_INITIALIZED, |
| arc_session_manager()->state()); |
| } |
| |
| // We expect mini instance is not started in manual mode. |
| TEST_F(ArcSessionManagerInLoginScreenTest, EmitLoginPromptVisibleManualStart) { |
| EXPECT_FALSE(arc_session()); |
| |
| SetArcAvailableCommandLineForTesting(base::CommandLine::ForCurrentProcess()); |
| base::test::ScopedCommandLine command_line; |
| command_line.GetProcessCommandLine()->AppendSwitchASCII("arc-start-mode", |
| "manual"); |
| |
| ash::SessionManagerClient::Get()->EmitLoginPromptVisible(); |
| EXPECT_FALSE(arc_session()); |
| EXPECT_EQ(ArcSessionManager::State::NOT_INITIALIZED, |
| arc_session_manager()->state()); |
| } |
| |
| // We expect that StopMiniArcIfNecessary stops mini-ARC when it is running. |
| TEST_F(ArcSessionManagerInLoginScreenTest, StopMiniArcIfNecessary) { |
| EXPECT_FALSE(arc_session()); |
| |
| SetArcAvailableCommandLineForTesting(base::CommandLine::ForCurrentProcess()); |
| |
| ash::SessionManagerClient::Get()->EmitLoginPromptVisible(); |
| EXPECT_TRUE(arc_session()); |
| |
| arc_session_manager()->StopMiniArcIfNecessary(); |
| EXPECT_FALSE(arc_session()); |
| } |
| |
| class ArcSessionManagerTestBase : public testing::Test { |
| public: |
| ArcSessionManagerTestBase() |
| : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP, |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME), |
| fake_user_manager_(std::make_unique<ash::FakeChromeUserManager>()) { |
| TestingBrowserProcess::GetGlobal()->SetLocalState(&test_local_state_); |
| RegisterLocalState(test_local_state_.registry()); |
| auth_events_recorder_ = ash::AuthEventsRecorder::CreateForTesting(); |
| } |
| |
| ArcSessionManagerTestBase(const ArcSessionManagerTestBase&) = delete; |
| ArcSessionManagerTestBase& operator=(const ArcSessionManagerTestBase&) = |
| delete; |
| |
| ~ArcSessionManagerTestBase() override { |
| TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr); |
| } |
| |
| void SetUp() override { |
| ash::ArcVmDataMigratorClient::InitializeFake(); |
| ash::ConciergeClient::InitializeFake(/*fake_cicerone_client=*/nullptr); |
| chromeos::PowerManagerClient::InitializeFake(); |
| ash::SessionManagerClient::InitializeFakeInMemory(); |
| ash::UpstartClient::InitializeFake(); |
| |
| SetArcAvailableCommandLineForTesting( |
| base::CommandLine::ForCurrentProcess()); |
| ArcSessionManager::SetUiEnabledForTesting(false); |
| SetArcBlockedDueToIncompatibleFileSystemForTesting(false); |
| |
| arc_service_manager_ = std::make_unique<ArcServiceManager>(); |
| arc_session_manager_ = |
| CreateTestArcSessionManager(std::make_unique<ArcSessionRunner>( |
| base::BindRepeating(FakeArcSession::Create))); |
| |
| EXPECT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| TestingProfile::Builder profile_builder; |
| profile_builder.SetProfileName("user@example.com"); |
| profile_builder.SetPath(temp_dir_.GetPath().AppendASCII("TestArcProfile")); |
| |
| profile_ = profile_builder.Build(); |
| StartPreferenceSyncing(); |
| |
| ASSERT_FALSE(arc_session_manager_->enable_requested()); |
| } |
| |
| void TearDown() override { |
| arc_session_manager_->Shutdown(); |
| profile_.reset(); |
| arc_session_manager_.reset(); |
| arc_service_manager_.reset(); |
| ash::UpstartClient::Shutdown(); |
| ash::SessionManagerClient::Shutdown(); |
| chromeos::PowerManagerClient::Shutdown(); |
| ash::ConciergeClient::Shutdown(); |
| ash::ArcVmDataMigratorClient::Shutdown(); |
| } |
| |
| ash::FakeChromeUserManager* GetFakeUserManager() const { |
| return fake_user_manager_.Get(); |
| } |
| |
| protected: |
| content::BrowserTaskEnvironment& task_environment() { |
| return task_environment_; |
| } |
| |
| TestingProfile* profile() { return profile_.get(); } |
| |
| ArcSessionManager* arc_session_manager() { |
| return arc_session_manager_.get(); |
| } |
| |
| bool WaitForDataRemoved(ArcSessionManager::State expected_state) { |
| if (arc_session_manager()->state() != |
| ArcSessionManager::State::REMOVING_DATA_DIR) { |
| return false; |
| } |
| |
| base::RunLoop().RunUntilIdle(); |
| if (arc_session_manager()->state() != expected_state) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| private: |
| void StartPreferenceSyncing() const { |
| PrefServiceSyncableFromProfile(profile_.get()) |
| ->GetSyncableService(syncer::PREFERENCES) |
| ->MergeDataAndStartSyncing( |
| syncer::PREFERENCES, syncer::SyncDataList(), |
| std::make_unique<syncer::FakeSyncChangeProcessor>()); |
| } |
| |
| content::BrowserTaskEnvironment task_environment_; |
| user_manager::TypedScopedUserManager<ash::FakeChromeUserManager> |
| fake_user_manager_; |
| session_manager::SessionManager session_manager_; |
| std::unique_ptr<TestingProfile> profile_; |
| std::unique_ptr<ArcServiceManager> arc_service_manager_; |
| std::unique_ptr<ArcSessionManager> arc_session_manager_; |
| base::ScopedTempDir temp_dir_; |
| TestingPrefServiceSimple test_local_state_; |
| std::unique_ptr<ash::AuthEventsRecorder> auth_events_recorder_; |
| }; |
| |
| class ArcSessionManagerTest : public ArcSessionManagerTestBase { |
| public: |
| ArcSessionManagerTest() = default; |
| |
| ArcSessionManagerTest(const ArcSessionManagerTest&) = delete; |
| ArcSessionManagerTest& operator=(const ArcSessionManagerTest&) = delete; |
| |
| void SetUp() override { |
| ArcSessionManagerTestBase::SetUp(); |
| |
| const AccountId account_id(AccountId::FromUserEmailGaiaId( |
| profile()->GetProfileUserName(), "1234567890")); |
| GetFakeUserManager()->AddUser(account_id); |
| GetFakeUserManager()->LoginUser(account_id); |
| resourced_client_ = ash::ResourcedClient::InitializeFake(); |
| |
| ASSERT_EQ(ArcSessionManager::State::NOT_INITIALIZED, |
| arc_session_manager()->state()); |
| } |
| |
| void TearDown() override { |
| resourced_client_ = nullptr; |
| ash::ResourcedClient::Shutdown(); |
| ArcSessionManagerTestBase::TearDown(); |
| } |
| |
| protected: |
| raw_ptr<ash::FakeResourcedClient> resourced_client_ = nullptr; |
| }; |
| |
| TEST_F(ArcSessionManagerTest, BaseWorkflow) { |
| EXPECT_TRUE(arc_session_manager()->sign_in_start_time().is_null()); |
| EXPECT_TRUE(arc_session_manager()->pre_start_time().is_null()); |
| EXPECT_TRUE(arc_session_manager()->start_time().is_null()); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| // By default ARC is not enabled. |
| EXPECT_EQ(ArcSessionManager::State::STOPPED, arc_session_manager()->state()); |
| EXPECT_TRUE(arc_session_manager()->pre_start_time().is_null()); |
| EXPECT_TRUE(arc_session_manager()->start_time().is_null()); |
| |
| const base::TimeTicks enabled_time = base::TimeTicks::Now(); |
| |
| // Enables ARC. First time, ToS negotiation should start. |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| const base::TimeTicks after_enabled_time = base::TimeTicks::Now(); |
| |
| const base::TimeTicks pre_start_time = |
| arc_session_manager()->pre_start_time(); |
| EXPECT_FALSE(pre_start_time.is_null()); |
| EXPECT_GE(pre_start_time, enabled_time); |
| EXPECT_GE(after_enabled_time, pre_start_time); |
| EXPECT_TRUE(arc_session_manager()->start_time().is_null()); |
| |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| |
| const base::TimeTicks start_time = arc_session_manager()->start_time(); |
| EXPECT_FALSE(arc_session_manager()->sign_in_start_time().is_null()); |
| EXPECT_EQ(pre_start_time, arc_session_manager()->pre_start_time()); |
| EXPECT_FALSE(start_time.is_null()); |
| EXPECT_GE(start_time, after_enabled_time); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| arc_session_manager()->Shutdown(); |
| |
| EXPECT_TRUE(arc_session_manager()->pre_start_time().is_null()); |
| EXPECT_TRUE(arc_session_manager()->start_time().is_null()); |
| } |
| |
| TEST_F(ArcSessionManagerTest, SignedInWorkflow) { |
| session_manager::SessionManager::Get() |
| ->HandleUserSessionStartUpTaskCompleted(); |
| |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| prefs->SetBoolean(prefs::kArcSignedIn, true); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| // By default ARC is not enabled. |
| EXPECT_EQ(ArcSessionManager::State::STOPPED, arc_session_manager()->state()); |
| |
| // When signed-in, enabling ARC results in the ACTIVE state. |
| arc_session_manager()->RequestEnable(); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| } |
| |
| TEST_F(ArcSessionManagerTest, SignedInWorkflowWithArcOnDemand) { |
| // Enable ARC on Demand feature. |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature(kArcOnDemandFeature); |
| // ARC on Demand is enabled only for managed users. |
| profile()->GetProfilePolicyConnector()->OverrideIsManagedForTesting(true); |
| // ARC on Demand is enabled only on ARCVM. |
| base::CommandLine::ForCurrentProcess()->AppendSwitch( |
| ash::switches::kEnableArcVm); |
| |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| prefs->SetBoolean(prefs::kArcSignedIn, true); |
| prefs->SetBoolean(prefs::kArcPackagesIsUpToDate, true); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| // By default ARC is not enabled. |
| EXPECT_EQ(ArcSessionManager::State::STOPPED, arc_session_manager()->state()); |
| ASSERT_FALSE(arc_session_manager()->IsActivationDelayed()); |
| |
| // When signed-in, enabling ARC results in the READY state. |
| arc_session_manager()->RequestEnable(); |
| ASSERT_EQ(ArcSessionManager::State::READY, arc_session_manager()->state()); |
| ASSERT_TRUE(arc_session_manager()->IsActivationDelayed()); |
| |
| // ARC starts after calling AllowActivation(). |
| arc_session_manager()->AllowActivation( |
| ArcSessionManager::AllowActivationReason::kUserLaunchAction); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| } |
| |
| TEST_F(ArcSessionManagerTest, SignedInWorkflowWithDeferringArcActivation) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| kDeferArcActivationUntilUserSessionStartUpTaskCompletion); |
| |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| prefs->SetBoolean(prefs::kArcSignedIn, true); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| base::HistogramTester histogram_tester; |
| |
| // By default ARC is not enabled. |
| EXPECT_EQ(ArcSessionManager::State::STOPPED, arc_session_manager()->state()); |
| ASSERT_FALSE(arc_session_manager()->IsActivationDelayed()); |
| |
| // Enabling ARC, does not yet activate ARC. |
| arc_session_manager()->RequestEnable(); |
| ASSERT_EQ(ArcSessionManager::State::READY, arc_session_manager()->state()); |
| |
| histogram_tester.ExpectUniqueSample("Arc.DeferActivation.Category", 0, 1); |
| |
| // No history is updated yet. |
| ASSERT_TRUE( |
| prefs->GetList(prefs::kArcFirstActivationDuringUserSessionStartUpHistory) |
| .empty()); |
| |
| // Emulate session start up task completion. |
| arc_session_manager()->OnUserSessionStartUpTaskCompleted(); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| histogram_tester.ExpectUniqueSample("Arc.DeferActivation.Result", 0, 1); |
| histogram_tester.ExpectTotalCount( |
| "Arc.DeferActivation.Deferred.Success.ElapsedTime", 1); |
| |
| // Making sure activation is recorded. |
| auto& history = |
| prefs->GetList(prefs::kArcFirstActivationDuringUserSessionStartUpHistory); |
| ASSERT_EQ(1u, history.size()); |
| EXPECT_EQ(history.front(), base::Value(false)); |
| |
| histogram_tester.ExpectUniqueSample("Arc.DeferActivation.Result", 0, 1); |
| histogram_tester.ExpectTotalCount( |
| "Arc.DeferActivation.Deferred.Success.ElapsedTime", 1); |
| } |
| |
| TEST_F(ArcSessionManagerTest, |
| SignedInWorkflowWithDeferringArcActivationActivatedSoon) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| kDeferArcActivationUntilUserSessionStartUpTaskCompletion); |
| |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| prefs->SetBoolean(prefs::kArcSignedIn, true); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| base::HistogramTester histogram_tester; |
| |
| // By default ARC is not enabled. |
| EXPECT_EQ(ArcSessionManager::State::STOPPED, arc_session_manager()->state()); |
| ASSERT_FALSE(arc_session_manager()->IsActivationDelayed()); |
| |
| // Enabling ARC, does not yet activate ARC. |
| arc_session_manager()->RequestEnable(); |
| ASSERT_EQ(ArcSessionManager::State::READY, arc_session_manager()->state()); |
| |
| histogram_tester.ExpectUniqueSample("Arc.DeferActivation.Category", 0, 1); |
| |
| // No history is updated yet. |
| ASSERT_TRUE( |
| prefs->GetList(prefs::kArcFirstActivationDuringUserSessionStartUpHistory) |
| .empty()); |
| |
| // Activate by some external event. |
| arc_session_manager()->AllowActivation( |
| ArcSessionManager::AllowActivationReason::kUserLaunchAction); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| histogram_tester.ExpectUniqueSample("Arc.DeferActivation.Result", 1, 1); |
| histogram_tester.ExpectUniqueSample( |
| "Arc.DeferActivation.Deferred.Failure.Reason", 4, 1); |
| histogram_tester.ExpectTotalCount( |
| "Arc.DeferActivation.Deferred.Failure.ElapsedTime", 1); |
| |
| // Making sure activation is recorded. |
| auto& history = |
| prefs->GetList(prefs::kArcFirstActivationDuringUserSessionStartUpHistory); |
| ASSERT_EQ(1u, history.size()); |
| EXPECT_EQ(history.front(), base::Value(true)); |
| |
| // Emulate session start up task completion. |
| arc_session_manager()->OnUserSessionStartUpTaskCompleted(); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| // No more history is recorded, since it is one for each user session. |
| EXPECT_EQ(1u, history.size()); |
| histogram_tester.ExpectUniqueSample("Arc.DeferActivation.Result", 1, 1); |
| histogram_tester.ExpectTotalCount( |
| "Arc.DeferActivation.Deferred.Failure.ElapsedTime", 1); |
| } |
| |
| TEST_F(ArcSessionManagerTest, |
| SignedInWorkflowWithDeferringArcActivationForUsersAggressivelyUsingArc) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| kDeferArcActivationUntilUserSessionStartUpTaskCompletion); |
| // TODO(b/326065955): Remove the magic number. |
| constexpr size_t kHistoryThreshold = 3; |
| |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| prefs->SetBoolean(prefs::kArcSignedIn, true); |
| { |
| // Emulate the situation that ARC is activated during user session start up |
| // in recent three sessions, which exceeds the threshold. |
| base::Value::List history; |
| for (size_t i = 0; i < kHistoryThreshold; ++i) { |
| history.Append(base::Value(true)); |
| } |
| prefs->SetList(prefs::kArcFirstActivationDuringUserSessionStartUpHistory, |
| std::move(history)); |
| } |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| base::HistogramTester histogram_tester; |
| |
| // By default ARC is not enabled. |
| EXPECT_EQ(ArcSessionManager::State::STOPPED, arc_session_manager()->state()); |
| ASSERT_FALSE(arc_session_manager()->IsActivationDelayed()); |
| |
| // Enabling ARC immediately activates. |
| arc_session_manager()->RequestEnable(); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| histogram_tester.ExpectUniqueSample("Arc.DeferActivation.Category", 1, 1); |
| |
| // No history is updated yet, even if the activation is done immediately. |
| ASSERT_EQ( |
| kHistoryThreshold, |
| prefs->GetList(prefs::kArcFirstActivationDuringUserSessionStartUpHistory) |
| .size()); |
| |
| // Emulate session start up task completion. |
| arc_session_manager()->OnUserSessionStartUpTaskCompleted(); |
| |
| // Making sure activation is recorded. |
| auto& history = |
| prefs->GetList(prefs::kArcFirstActivationDuringUserSessionStartUpHistory); |
| ASSERT_EQ(kHistoryThreshold + 1u, history.size()); |
| EXPECT_EQ(history.back(), base::Value(false)); |
| |
| histogram_tester.ExpectUniqueSample("Arc.DeferActivation.Result", 3, 1); |
| histogram_tester.ExpectTotalCount( |
| "Arc.DeferActivation.NotDeferred.Failure.ElapsedTime", 1); |
| } |
| |
| TEST_F(ArcSessionManagerTest, |
| SignedInWorkflowWithDeferringArcActivationAlreadyActivated) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature( |
| kDeferArcActivationUntilUserSessionStartUpTaskCompletion); |
| |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| prefs->SetBoolean(prefs::kArcSignedIn, true); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| arc_session_manager()->AllowActivation( |
| ArcSessionManager::AllowActivationReason::kUserLaunchAction); |
| |
| // By default ARC is not enabled. |
| EXPECT_EQ(ArcSessionManager::State::STOPPED, arc_session_manager()->state()); |
| ASSERT_FALSE(arc_session_manager()->IsActivationDelayed()); |
| |
| // Enabling ARC immediately activates it. |
| arc_session_manager()->RequestEnable(); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| } |
| |
| TEST_F(ArcSessionManagerTest, SignedInWorkflow_ActivationIsAlreadyAllowed) { |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| prefs->SetBoolean(prefs::kArcSignedIn, true); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| // By default ARC is not enabled. |
| EXPECT_EQ(ArcSessionManager::State::STOPPED, arc_session_manager()->state()); |
| |
| // When signed-in, enabling ARC results in the ACTIVE state if |
| // AllowActivation() is called beforehand. |
| arc_session_manager()->AllowActivation( |
| ArcSessionManager::AllowActivationReason::kImmediateActivation); |
| arc_session_manager()->RequestEnable(); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| } |
| |
| // Tests that tying to enable ARC++ with an incompatible file system fails and |
| // shows the user a notification to that effect. |
| TEST_F(ArcSessionManagerTest, MigrationGuideNotification) { |
| ArcSessionManager::SetUiEnabledForTesting(true); |
| ArcSessionManager::EnableCheckAndroidManagementForTesting(false); |
| SetArcBlockedDueToIncompatibleFileSystemForTesting(true); |
| |
| NotificationDisplayServiceTester notification_service(profile()); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(ArcSessionManager::State::STOPPED, arc_session_manager()->state()); |
| auto notifications = notification_service.GetDisplayedNotificationsForType( |
| NotificationHandler::Type::TRANSIENT); |
| ASSERT_EQ(1U, notifications.size()); |
| EXPECT_EQ("arc_fs_migration/suggest", notifications[0].id()); |
| } |
| |
| // Tests that OnArcInitialStart is called after the successful ARC provisioning |
| // on the first start after OptIn. |
| TEST_F(ArcSessionManagerTest, ArcInitialStartFirstProvisioning) { |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| ArcInitialStartHandler start_handler(arc_session_manager()); |
| EXPECT_FALSE(start_handler.was_called()); |
| |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(start_handler.was_called()); |
| |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| |
| EXPECT_FALSE(start_handler.was_called()); |
| |
| arc::mojom::ArcSignInResultPtr result = |
| arc::mojom::ArcSignInResult::NewSuccess( |
| arc::mojom::ArcSignInSuccess::SUCCESS); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| |
| EXPECT_TRUE(start_handler.was_called()); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| // Tests that OnArcInitialStart is not called after the successful ARC |
| // provisioning on the second and next starts after OptIn. |
| TEST_F(ArcSessionManagerTest, ArcInitialStartNextProvisioning) { |
| // Set up the situation that provisioning is successfully done in the |
| // previous session. In this case initial start callback is not called. |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| prefs->SetBoolean(prefs::kArcSignedIn, true); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| ArcInitialStartHandler start_handler(arc_session_manager()); |
| |
| arc_session_manager()->RequestEnable(); |
| arc::mojom::ArcSignInResultPtr result = |
| arc::mojom::ArcSignInResult::NewSuccess( |
| arc::mojom::ArcSignInSuccess::SUCCESS); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| |
| EXPECT_FALSE(start_handler.was_called()); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, IncompatibleFileSystemBlocksTermsOfService) { |
| SetArcBlockedDueToIncompatibleFileSystemForTesting(true); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| // Enables ARC first time. ToS negotiation should NOT happen. |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(ArcSessionManager::State::STOPPED, arc_session_manager()->state()); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, IncompatibleFileSystemBlocksArcStart) { |
| SetArcBlockedDueToIncompatibleFileSystemForTesting(true); |
| |
| // Set up the situation that provisioning is successfully done in the |
| // previous session. |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| prefs->SetBoolean(prefs::kArcSignedIn, true); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| // Enables ARC second time. ARC should NOT start. |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(ArcSessionManager::State::STOPPED, arc_session_manager()->state()); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, CancelFetchingDisablesArc) { |
| SetArcPlayStoreEnabledForProfile(profile(), true); |
| |
| // Starts ARC. |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| |
| // Emulate to cancel the ToS UI (e.g. closing the window). |
| arc_session_manager()->CancelAuthCode(); |
| |
| // Google Play Store enabled preference should be set to false, too. |
| EXPECT_FALSE(IsArcPlayStoreEnabledForProfile(profile())); |
| |
| // Emulate the preference handling. |
| arc_session_manager()->RequestDisableWithArcDataRemoval(); |
| |
| // Wait until data is removed. |
| ASSERT_TRUE(WaitForDataRemoved(ArcSessionManager::State::STOPPED)); |
| |
| // Correctly stop service. |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, CloseUIKeepsArcEnabled) { |
| // Starts ARC. |
| SetArcPlayStoreEnabledForProfile(profile(), true); |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| // When ARC is properly started, closing UI should be no-op. |
| arc_session_manager()->CancelAuthCode(); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| EXPECT_TRUE(IsArcPlayStoreEnabledForProfile(profile())); |
| |
| // Correctly stop service. |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, Provisioning_Success) { |
| PrefService* const prefs = profile()->GetPrefs(); |
| |
| EXPECT_TRUE(arc_session_manager()->sign_in_start_time().is_null()); |
| EXPECT_TRUE(arc_session_manager()->pre_start_time().is_null()); |
| EXPECT_TRUE(arc_session_manager()->start_time().is_null()); |
| EXPECT_FALSE(arc_session_manager()->IsPlaystoreLaunchRequestedForTesting()); |
| |
| ASSERT_FALSE(prefs->GetBoolean(prefs::kArcSignedIn)); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| ASSERT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| |
| // Emulate to accept the terms of service. |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| EXPECT_FALSE(arc_session_manager()->sign_in_start_time().is_null()); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| // Here, provisioning is not yet completed, so kArcSignedIn should be false. |
| EXPECT_FALSE(prefs->GetBoolean(prefs::kArcSignedIn)); |
| EXPECT_FALSE(arc_session_manager()->pre_start_time().is_null()); |
| EXPECT_FALSE(arc_session_manager()->start_time().is_null()); |
| EXPECT_FALSE(arc_session_manager()->IsPlaystoreLaunchRequestedForTesting()); |
| |
| // Emulate successful provisioning. |
| arc::mojom::ArcSignInResultPtr result = |
| arc::mojom::ArcSignInResult::NewSuccess( |
| arc::mojom::ArcSignInSuccess::SUCCESS); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| |
| EXPECT_TRUE(prefs->GetBoolean(prefs::kArcSignedIn)); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| EXPECT_TRUE(arc_session_manager()->IsPlaystoreLaunchRequestedForTesting()); |
| } |
| |
| TEST_F(ArcSessionManagerTest, Provisioning_SigninErrorMetric) { |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| |
| base::HistogramTester histogram_tester; |
| |
| arc::mojom::ArcSignInResultPtr result = arc::mojom::ArcSignInResult::NewError( |
| arc::mojom::ArcSignInError::NewSignInError( |
| arc::mojom::GMSSignInError::GMS_SIGN_IN_NETWORK_ERROR)); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| |
| histogram_tester.ExpectUniqueSample("Arc.Provisioning.SigninResult.Unmanaged", |
| 2 /*kNetworkError*/, 1); |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, Provisioning_DpcErrorMetric) { |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| |
| base::HistogramTester histogram_tester; |
| |
| arc::mojom::ArcSignInResultPtr result = arc::mojom::ArcSignInResult::NewError( |
| arc::mojom::ArcSignInError::NewCloudProvisionFlowError( |
| arc::mojom::CloudProvisionFlowError::ERROR_ADD_ACCOUNT_FAILED)); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| |
| histogram_tester.ExpectUniqueSample("Arc.Provisioning.DpcResult.Unmanaged", |
| 3 /*kAccountAddFail*/, 1); |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, Provisioning_CheckinErrorMetric) { |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| |
| base::HistogramTester histogram_tester; |
| |
| arc::mojom::ArcSignInResultPtr result = arc::mojom::ArcSignInResult::NewError( |
| arc::mojom::ArcSignInError::NewCheckInError( |
| arc::mojom::GMSCheckInError::GMS_CHECK_IN_TIMEOUT)); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| |
| histogram_tester.ExpectUniqueSample( |
| "Arc.Provisioning.CheckinResult.Unmanaged", 2 /*kTimeout*/, 1); |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, Provisioning_SuccessMetric_Unmanaged) { |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| |
| base::HistogramTester histogram_tester; |
| |
| arc::mojom::ArcSignInResultPtr result = |
| arc::mojom::ArcSignInResult::NewSuccess( |
| arc::mojom::ArcSignInSuccess::SUCCESS); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| |
| histogram_tester.ExpectUniqueSample("Arc.Provisioning.SigninResult.Unmanaged", |
| 0, 1); |
| histogram_tester.ExpectUniqueSample( |
| "Arc.Provisioning.CheckinResult.Unmanaged", 0, 1); |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, Provisioning_SuccessMetric_Managed) { |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| profile()->GetProfilePolicyConnector()->OverrideIsManagedForTesting(true); |
| |
| base::HistogramTester histogram_tester; |
| |
| arc::mojom::ArcSignInResultPtr result = |
| arc::mojom::ArcSignInResult::NewSuccess( |
| arc::mojom::ArcSignInSuccess::SUCCESS); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| |
| histogram_tester.ExpectUniqueSample("Arc.Provisioning.DpcResult.Managed", 0, |
| 1); |
| histogram_tester.ExpectUniqueSample("Arc.Provisioning.CheckinResult.Managed", |
| 0, 1); |
| arc_session_manager()->Shutdown(); |
| } |
| |
| // Verifies that Play Store shown is suppressed on restart when required. |
| TEST_F(ArcSessionManagerTest, PlayStoreSuppressed) { |
| // Set up the situation that terms were accepted in the previous session. |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| // Set the flag indicating that the provisioning was initiated from OOBE in |
| // the previous session. |
| prefs->SetBoolean(prefs::kArcProvisioningInitiatedFromOobe, true); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| arc_session_manager()->StartArcForTesting(); |
| |
| // Second start, no fetching code is expected. |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| EXPECT_FALSE(arc_session_manager()->IsPlaystoreLaunchRequestedForTesting()); |
| arc::mojom::ArcSignInResultPtr result = |
| arc::mojom::ArcSignInResult::NewSuccess( |
| arc::mojom::ArcSignInSuccess::SUCCESS); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| |
| // Completing the provisioning resets this flag. |
| EXPECT_FALSE(prefs->GetBoolean(prefs::kArcProvisioningInitiatedFromOobe)); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| // |prefs::kArcProvisioningInitiatedFromOobe| flag prevents opening the |
| // Play Store. |
| EXPECT_FALSE(arc_session_manager()->IsPlaystoreLaunchRequestedForTesting()); |
| |
| // Correctly stop service. |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, InitiatedFromOobeIsResetOnOptOut) { |
| // Set up the situation that terms were accepted in the previous session. |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| // Set the flag indicating that the provisioning was initiated from OOBE in |
| // the previous session. |
| prefs->SetBoolean(prefs::kArcProvisioningInitiatedFromOobe, true); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| EXPECT_TRUE(prefs->GetBoolean(prefs::kArcProvisioningInitiatedFromOobe)); |
| // Disabling ARC resets suppress state |
| arc_session_manager()->RequestDisable(); |
| EXPECT_FALSE(prefs->GetBoolean(prefs::kArcProvisioningInitiatedFromOobe)); |
| |
| // Correctly stop service. |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, Provisioning_Restart) { |
| // Set up the situation that provisioning is successfully done in the |
| // previous session. |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| prefs->SetBoolean(prefs::kArcSignedIn, true); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->AllowActivation( |
| ArcSessionManager::AllowActivationReason::kImmediateActivation); |
| arc_session_manager()->RequestEnable(); |
| |
| // Second start, no fetching code is expected. |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| // Report failure. |
| arc::mojom::ArcSignInResultPtr result = arc::mojom::ArcSignInResult::NewError( |
| arc::mojom::ArcSignInError::NewSignInError( |
| arc::mojom::GMSSignInError::GMS_SIGN_IN_NETWORK_ERROR)); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| |
| // On error, UI to send feedback is showing. In that case, |
| // the ARC is still necessary to run on background for gathering the logs. |
| EXPECT_TRUE(prefs->GetBoolean(prefs::kArcSignedIn)); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| // Correctly stop service. |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, RemoveDataDir) { |
| // Emulate the situation where the initial Google Play Store enabled |
| // preference is false for managed user, i.e., data dir is being removed at |
| // beginning. |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestArcDataRemoval(); |
| EXPECT_TRUE( |
| profile()->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)); |
| EXPECT_EQ(ArcSessionManager::State::REMOVING_DATA_DIR, |
| arc_session_manager()->state()); |
| |
| // Enable ARC. Data is removed asyncronously. At this moment session manager |
| // should be in REMOVING_DATA_DIR state. |
| arc_session_manager()->RequestEnable(); |
| EXPECT_TRUE( |
| profile()->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)); |
| EXPECT_EQ(ArcSessionManager::State::REMOVING_DATA_DIR, |
| arc_session_manager()->state()); |
| // Wait until data is removed. |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_FALSE( |
| profile()->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)); |
| EXPECT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| // Request to remove data and stop session manager. |
| arc_session_manager()->RequestArcDataRemoval(); |
| ASSERT_TRUE( |
| profile()->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| arc_session_manager()->Shutdown(); |
| base::RunLoop().RunUntilIdle(); |
| // Request should persist. |
| ASSERT_TRUE( |
| profile()->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)); |
| } |
| |
| TEST_F(ArcSessionManagerTest, RemoveDataDir_Restart) { |
| // Emulate second sign-in. Data should be removed first and ARC started after. |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcDataRemoveRequested, true); |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| EXPECT_TRUE( |
| profile()->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)); |
| ASSERT_TRUE( |
| WaitForDataRemoved(ArcSessionManager::State::CHECKING_REQUIREMENTS)); |
| EXPECT_FALSE( |
| profile()->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, ArcVmDataMigrationInProgress_RequestEnable) { |
| int restart_count = 0; |
| // Replace chrome::AttemptRestart() for testing. |
| arc_session_manager()->SetAttemptRestartCallbackForTesting( |
| base::BindLambdaForTesting([&restart_count]() { ++restart_count; })); |
| |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| prefs->SetBoolean(prefs::kArcSignedIn, true); |
| SetArcVmDataMigrationStatus(prefs, ArcVmDataMigrationStatus::kStarted); |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature(kEnableArcVmDataMigration); |
| |
| EXPECT_EQ(prefs->GetInteger(prefs::kArcVmDataMigrationAutoResumeCount), 0); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(prefs->GetInteger(prefs::kArcVmDataMigrationAutoResumeCount), 1); |
| EXPECT_EQ(restart_count, 1); |
| |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(arc_session_manager()->state(), ArcSessionManager::State::STOPPED); |
| EXPECT_EQ(prefs->GetInteger(prefs::kArcVmDataMigrationAutoResumeCount), 1); |
| EXPECT_EQ(restart_count, 1); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, |
| ArcVmDataMigrationInProgress_RequestArcDataRemoval) { |
| int restart_count = 0; |
| // Replace chrome::AttemptRestart() for testing. |
| arc_session_manager()->SetAttemptRestartCallbackForTesting( |
| base::BindLambdaForTesting([&restart_count]() { ++restart_count; })); |
| |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| prefs->SetBoolean(prefs::kArcSignedIn, true); |
| SetArcVmDataMigrationStatus(prefs, ArcVmDataMigrationStatus::kStarted); |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature(kEnableArcVmDataMigration); |
| |
| EXPECT_EQ(prefs->GetInteger(prefs::kArcVmDataMigrationAutoResumeCount), 0); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(prefs->GetInteger(prefs::kArcVmDataMigrationAutoResumeCount), 1); |
| EXPECT_EQ(restart_count, 1); |
| |
| arc_session_manager()->RequestArcDataRemoval(); |
| base::RunLoop().RunUntilIdle(); |
| // /data removal request should persist, i.e., /data should not be removed. |
| EXPECT_TRUE(prefs->GetBoolean(prefs::kArcDataRemoveRequested)); |
| EXPECT_EQ(arc_session_manager()->state(), ArcSessionManager::State::STOPPED); |
| EXPECT_EQ(prefs->GetInteger(prefs::kArcVmDataMigrationAutoResumeCount), 1); |
| EXPECT_EQ(restart_count, 1); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, ArcVmDataMigration_MaxAutoResumeCountReached) { |
| int restart_count = 0; |
| // Replace chrome::AttemptRestart() for testing. |
| arc_session_manager()->SetAttemptRestartCallbackForTesting( |
| base::BindLambdaForTesting([&restart_count]() { ++restart_count; })); |
| |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| prefs->SetBoolean(prefs::kArcSignedIn, true); |
| SetArcVmDataMigrationStatus(prefs, ArcVmDataMigrationStatus::kStarted); |
| prefs->SetInteger(prefs::kArcVmDataMigrationAutoResumeCount, |
| kArcVmDataMigrationMaxAutoResumeCount); |
| |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature(kEnableArcVmDataMigration); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(prefs->GetInteger(prefs::kArcVmDataMigrationAutoResumeCount), |
| kArcVmDataMigrationMaxAutoResumeCount + 1); |
| |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| // ARC should be blocked and auto-resume should not be triggered. |
| EXPECT_EQ(arc_session_manager()->state(), ArcSessionManager::State::STOPPED); |
| EXPECT_EQ(restart_count, 0); |
| EXPECT_EQ(prefs->GetInteger(prefs::kArcVmDataMigrationAutoResumeCount), |
| kArcVmDataMigrationMaxAutoResumeCount + 1); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, ArcVmDataMigrationNecessityChecker_Necessary) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature(kEnableArcVmDataMigration); |
| SetArcVmDataMigrationStatus(profile()->GetPrefs(), |
| ArcVmDataMigrationStatus::kUnnotified); |
| ash::FakeArcVmDataMigratorClient::Get()->set_has_data_to_migrate(true); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(arc_session_manager() |
| ->GetArcSessionRunnerForTesting() |
| ->use_virtio_blk_data()); |
| EXPECT_EQ(GetArcVmDataMigrationStatus(profile()->GetPrefs()), |
| ArcVmDataMigrationStatus::kUnnotified); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, ArcVmDataMigrationNecessityChecker_Unnecessary) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature(kEnableArcVmDataMigration); |
| SetArcVmDataMigrationStatus(profile()->GetPrefs(), |
| ArcVmDataMigrationStatus::kUnnotified); |
| ash::FakeArcVmDataMigratorClient::Get()->set_has_data_to_migrate(false); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE(arc_session_manager() |
| ->GetArcSessionRunnerForTesting() |
| ->use_virtio_blk_data()); |
| EXPECT_EQ(GetArcVmDataMigrationStatus(profile()->GetPrefs()), |
| ArcVmDataMigrationStatus::kFinished); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, ArcVmDataMigrationNecessityChecker_Undetermined) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitAndEnableFeature(kEnableArcVmDataMigration); |
| SetArcVmDataMigrationStatus(profile()->GetPrefs(), |
| ArcVmDataMigrationStatus::kUnnotified); |
| ash::FakeArcVmDataMigratorClient::Get()->set_has_data_to_migrate( |
| std::nullopt); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_FALSE(arc_session_manager() |
| ->GetArcSessionRunnerForTesting() |
| ->use_virtio_blk_data()); |
| EXPECT_EQ(GetArcVmDataMigrationStatus(profile()->GetPrefs()), |
| ArcVmDataMigrationStatus::kUnnotified); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, RegularToChildTransition) { |
| // Emulate the situation where a regular user has transitioned to a child |
| // account. |
| profile()->GetPrefs()->SetInteger( |
| prefs::kArcManagementTransition, |
| static_cast<int>(ArcManagementTransition::REGULAR_TO_CHILD)); |
| base::test::ScopedFeatureList feature_list; |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| EXPECT_FALSE( |
| profile()->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)); |
| EXPECT_EQ(static_cast<int>(ArcManagementTransition::REGULAR_TO_CHILD), |
| profile()->GetPrefs()->GetInteger(prefs::kArcManagementTransition)); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, SetArcSignedIn) { |
| session_manager::SessionManager::Get() |
| ->HandleUserSessionStartUpTaskCompleted(); |
| |
| PrefService* const prefs = profile()->GetPrefs(); |
| ASSERT_TRUE(prefs); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| prefs->SetBoolean(prefs::kArcSignedIn, true); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| // By default ARC is not enabled. |
| EXPECT_EQ(ArcSessionManager::State::STOPPED, arc_session_manager()->state()); |
| |
| // When signed-in, enabling ARC results in the ACTIVE state. |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| EXPECT_TRUE(prefs->GetBoolean(prefs::kArcSignedIn)); |
| EXPECT_TRUE( |
| arc_session_manager()->GetArcSessionRunnerForTesting()->arc_signed_in()); |
| EXPECT_TRUE(arc_session_manager()->skipped_terms_of_service_negotiation()); |
| |
| // Correctly stop service. |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, ClearArcSignedIn) { |
| // Start ARC. |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| |
| // Disable ARC. |
| arc_session_manager()->RequestDisable(); |
| |
| PrefService* const prefs = profile()->GetPrefs(); |
| ASSERT_TRUE(prefs); |
| EXPECT_FALSE(prefs->GetBoolean(prefs::kArcSignedIn)); |
| EXPECT_FALSE( |
| arc_session_manager()->GetArcSessionRunnerForTesting()->arc_signed_in()); |
| EXPECT_FALSE(arc_session_manager()->skipped_terms_of_service_negotiation()); |
| |
| // Correctly stop service. |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, ClearArcTransitionOnShutdown) { |
| profile()->GetPrefs()->SetInteger( |
| prefs::kArcManagementTransition, |
| static_cast<int>(ArcManagementTransition::NO_TRANSITION)); |
| |
| // Initialize ARC. |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| arc::mojom::ArcSignInResultPtr result = |
| arc::mojom::ArcSignInResult::NewSuccess( |
| arc::mojom::ArcSignInSuccess::SUCCESS); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| |
| EXPECT_EQ(static_cast<int>(ArcManagementTransition::NO_TRANSITION), |
| profile()->GetPrefs()->GetInteger(prefs::kArcManagementTransition)); |
| |
| // Child started graduation. |
| profile()->GetPrefs()->SetInteger( |
| prefs::kArcManagementTransition, |
| static_cast<int>(ArcManagementTransition::CHILD_TO_REGULAR)); |
| // Simulate ARC shutdown. |
| arc_session_manager()->RequestDisableWithArcDataRemoval(); |
| EXPECT_EQ(static_cast<int>(ArcManagementTransition::NO_TRANSITION), |
| profile()->GetPrefs()->GetInteger(prefs::kArcManagementTransition)); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, ClearArcTransitionOnArcDataRemoval) { |
| EXPECT_EQ(ArcManagementTransition::NO_TRANSITION, |
| arc::GetManagementTransition(profile())); |
| |
| // Initialize ARC. |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| arc::mojom::ArcSignInResultPtr result = |
| arc::mojom::ArcSignInResult::NewSuccess( |
| arc::mojom::ArcSignInSuccess::SUCCESS); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| |
| EXPECT_EQ(ArcManagementTransition::NO_TRANSITION, |
| arc::GetManagementTransition(profile())); |
| |
| // Child started graduation. |
| profile()->GetPrefs()->SetInteger( |
| prefs::kArcManagementTransition, |
| static_cast<int>(ArcManagementTransition::CHILD_TO_REGULAR)); |
| |
| arc_session_manager()->RequestArcDataRemoval(); |
| EXPECT_EQ(ArcManagementTransition::NO_TRANSITION, |
| arc::GetManagementTransition(profile())); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, IgnoreSecondErrorReporting) { |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| // Report some failure that does not stop the bridge. |
| arc::mojom::ArcSignInResultPtr result = arc::mojom::ArcSignInResult::NewError( |
| arc::mojom::ArcSignInError::NewSignInError( |
| arc::mojom::GMSSignInError::GMS_SIGN_IN_FAILED)); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| // Try to send another error that stops the bridge if sent first. It should |
| // be ignored. |
| result = arc::mojom::ArcSignInResult::NewError( |
| arc::mojom::ArcSignInError::NewGeneralError( |
| arc::mojom::GeneralSignInError::CHROME_SERVER_COMMUNICATION_ERROR)); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| // Test case when skipped ToS flag is not set during the ARC boot. |
| TEST_F(ArcSessionManagerTest, SkippedTermsOfServiceNegotiationFalse) { |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| // On initial start skipped ToS flag is not set. |
| EXPECT_FALSE(arc_session_manager()->skipped_terms_of_service_negotiation()); |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_FALSE(arc_session_manager()->skipped_terms_of_service_negotiation()); |
| ASSERT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| arc::mojom::ArcSignInResultPtr result = |
| arc::mojom::ArcSignInResult::NewSuccess( |
| arc::mojom::ArcSignInSuccess::SUCCESS); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| EXPECT_FALSE(arc_session_manager()->skipped_terms_of_service_negotiation()); |
| arc_session_manager()->Shutdown(); |
| EXPECT_FALSE(arc_session_manager()->skipped_terms_of_service_negotiation()); |
| } |
| |
| // Test case when skipped ToS flag is set during the ARC boot. |
| // Preconditions are: ToS accepted and ARC was signed in. |
| TEST_F(ArcSessionManagerTest, SkippedTermsOfServiceNegotiationTrue) { |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| prefs->SetBoolean(prefs::kArcSignedIn, true); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| EXPECT_FALSE(arc_session_manager()->skipped_terms_of_service_negotiation()); |
| arc_session_manager()->AllowActivation( |
| ArcSessionManager::AllowActivationReason::kImmediateActivation); |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_TRUE(arc_session_manager()->skipped_terms_of_service_negotiation()); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| // Disabling ARC turns skipped ToS flag off. |
| arc_session_manager()->RequestDisable(); |
| EXPECT_FALSE(arc_session_manager()->skipped_terms_of_service_negotiation()); |
| arc_session_manager()->Shutdown(); |
| } |
| |
| // Test case when skipped ToS flag is preserved during the internal ARC restart. |
| TEST_F(ArcSessionManagerTest, |
| SkippedTermsOfServiceNegotiationOnInternalRestart) { |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->AllowActivation( |
| ArcSessionManager::AllowActivationReason::kImmediateActivation); |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| arc::mojom::ArcSignInResultPtr result = |
| arc::mojom::ArcSignInResult::NewSuccess( |
| arc::mojom::ArcSignInSuccess::SUCCESS); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| |
| EXPECT_FALSE(arc_session_manager()->skipped_terms_of_service_negotiation()); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| EXPECT_FALSE(arc_session_manager()->skipped_terms_of_service_negotiation()); |
| |
| // Simulate internal restart. |
| arc_session_manager()->StopAndEnableArc(); |
| // Fake ARC session implementation synchronously calls stop callback and |
| // session manager should be reactivated at this moment. |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| // Skipped ToS flag should be preserved. |
| EXPECT_FALSE(arc_session_manager()->skipped_terms_of_service_negotiation()); |
| arc_session_manager()->Shutdown(); |
| } |
| |
| // In case of the next start ArcSessionManager should go through remove data |
| // folder phase before negotiating terms of service. |
| TEST_F(ArcSessionManagerTest, DataCleanUpOnFirstStart) { |
| session_manager::SessionManager::Get() |
| ->HandleUserSessionStartUpTaskCompleted(); |
| |
| base::test::ScopedCommandLine command_line; |
| command_line.GetProcessCommandLine()->AppendSwitch( |
| ash::switches::kArcDataCleanupOnStart); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| ArcPlayStoreEnabledPreferenceHandler handler(profile(), |
| arc_session_manager()); |
| handler.Start(); |
| |
| EXPECT_EQ(ArcSessionManager::State::REMOVING_DATA_DIR, |
| arc_session_manager()->state()); |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_EQ(ArcSessionManager::State::STOPPED, arc_session_manager()->state()); |
| |
| profile()->GetPrefs()->SetBoolean(prefs::kArcEnabled, true); |
| |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| // In case of the next start ArcSessionManager should go through remove data |
| // folder phase before activating. |
| TEST_F(ArcSessionManagerTest, DataCleanUpOnNextStart) { |
| session_manager::SessionManager::Get() |
| ->HandleUserSessionStartUpTaskCompleted(); |
| |
| base::test::ScopedCommandLine command_line; |
| command_line.GetProcessCommandLine()->AppendSwitch( |
| ash::switches::kArcDataCleanupOnStart); |
| |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcTermsAccepted, true); |
| prefs->SetBoolean(prefs::kArcSignedIn, true); |
| prefs->SetBoolean(prefs::kArcEnabled, true); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| ArcPlayStoreEnabledPreferenceHandler handler(profile(), |
| arc_session_manager()); |
| handler.Start(); |
| |
| EXPECT_EQ(ArcSessionManager::State::REMOVING_DATA_DIR, |
| arc_session_manager()->state()); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| EXPECT_TRUE(arc_session_manager()->skipped_terms_of_service_negotiation()); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, RequestDisableDoesNotRemoveData) { |
| // Start ARC. |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| |
| // Disable ARC. |
| arc_session_manager()->RequestDisable(); |
| |
| // Data removal is not requested. |
| EXPECT_FALSE( |
| profile()->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)); |
| |
| // Correctly stop service. |
| arc_session_manager()->Shutdown(); |
| } |
| |
| TEST_F(ArcSessionManagerTest, RequestDisableWithArcDataRemoval) { |
| // Start ARC. |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| |
| // Disable ARC and remove ARC data. |
| arc_session_manager()->RequestDisableWithArcDataRemoval(); |
| |
| // Data removal is requested. |
| EXPECT_TRUE( |
| profile()->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)); |
| |
| // Correctly stop service. |
| arc_session_manager()->Shutdown(); |
| } |
| |
| class ArcSessionManagerArcAlwaysStartTest : public ArcSessionManagerTest { |
| public: |
| ArcSessionManagerArcAlwaysStartTest() = default; |
| |
| ArcSessionManagerArcAlwaysStartTest( |
| const ArcSessionManagerArcAlwaysStartTest&) = delete; |
| ArcSessionManagerArcAlwaysStartTest& operator=( |
| const ArcSessionManagerArcAlwaysStartTest&) = delete; |
| |
| void SetUp() override { |
| SetArcAlwaysStartWithoutPlayStoreForTesting(); |
| ArcSessionManagerTest::SetUp(); |
| } |
| }; |
| |
| ArcProvisioningResult CreateProvisioningResult( |
| const absl::variant<arc::mojom::GeneralSignInError, |
| arc::mojom::GMSSignInError, |
| arc::mojom::GMSCheckInError, |
| arc::mojom::CloudProvisionFlowError, |
| ArcStopReason, |
| ChromeProvisioningTimeout>& error) { |
| if (absl::holds_alternative<arc::mojom::GeneralSignInError>(error)) { |
| return ArcProvisioningResult(arc::mojom::ArcSignInResult::NewError( |
| arc::mojom::ArcSignInError::NewGeneralError( |
| absl::get<arc::mojom::GeneralSignInError>(error)))); |
| } |
| |
| if (absl::holds_alternative<arc::mojom::GMSSignInError>(error)) { |
| return ArcProvisioningResult(arc::mojom::ArcSignInResult::NewError( |
| arc::mojom::ArcSignInError::NewSignInError( |
| absl::get<arc::mojom::GMSSignInError>(error)))); |
| } |
| |
| if (absl::holds_alternative<arc::mojom::GMSCheckInError>(error)) { |
| return ArcProvisioningResult(arc::mojom::ArcSignInResult::NewError( |
| arc::mojom::ArcSignInError::NewCheckInError( |
| absl::get<arc::mojom::GMSCheckInError>(error)))); |
| } |
| |
| if (absl::holds_alternative<arc::mojom::CloudProvisionFlowError>(error)) { |
| return ArcProvisioningResult(arc::mojom::ArcSignInResult::NewError( |
| arc::mojom::ArcSignInError::NewCloudProvisionFlowError( |
| absl::get<arc::mojom::CloudProvisionFlowError>(error)))); |
| } |
| |
| if (absl::holds_alternative<ArcStopReason>(error)) { |
| return ArcProvisioningResult(absl::get<ArcStopReason>(error)); |
| } |
| |
| return ArcProvisioningResult(ChromeProvisioningTimeout{}); |
| } |
| |
| struct ProvisioningErrorDisplayTestParam { |
| // The reason for arc instance stopping. |
| absl::variant<arc::mojom::GeneralSignInError, |
| arc::mojom::GMSSignInError, |
| arc::mojom::GMSCheckInError, |
| arc::mojom::CloudProvisionFlowError, |
| ArcStopReason, |
| ChromeProvisioningTimeout> |
| error; |
| |
| // The error sent to arc support host. |
| ArcSupportHost::Error message; |
| |
| // The error code sent to arc support host. |
| std::optional<int> arg; |
| }; |
| |
| constexpr ProvisioningErrorDisplayTestParam |
| kProvisioningErrorDisplayTestCases[] = { |
| {ArcStopReason::GENERIC_BOOT_FAILURE, |
| ArcSupportHost::Error::SIGN_IN_UNKNOWN_ERROR, 8 /*ARC_STOPPED*/}, |
| {ArcStopReason::LOW_DISK_SPACE, |
| ArcSupportHost::Error::LOW_DISK_SPACE_ERROR, |
| {}}, |
| {ArcStopReason::CRASH, ArcSupportHost::Error::SIGN_IN_UNKNOWN_ERROR, |
| 8 /*ARC_STOPPED*/}, |
| {arc::mojom::GMSSignInError::GMS_SIGN_IN_NETWORK_ERROR, |
| ArcSupportHost::Error::SIGN_IN_NETWORK_ERROR, |
| 1 /*GMS_SIGN_IN_NETWORK_ERROR*/}, |
| {arc::mojom::GMSSignInError::GMS_SIGN_IN_TIMEOUT, |
| ArcSupportHost::Error::SIGN_IN_GMS_SIGNIN_ERROR, |
| 5 /*GMS_SIGN_IN_TIMEOUT*/}, |
| {arc::mojom::GMSCheckInError::GMS_CHECK_IN_TIMEOUT, |
| ArcSupportHost::Error::SIGN_IN_GMS_CHECKIN_ERROR, |
| 2 /*GMS_CHECK_IN_TIMEOUT*/}}; |
| |
| class ProvisioningErrorDisplayTest |
| : public ArcSessionManagerTest, |
| public testing::WithParamInterface<ProvisioningErrorDisplayTestParam> { |
| void SetUp() override { |
| ArcSessionManagerTest::SetUp(); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| } |
| |
| void TearDown() override { |
| arc_session_manager()->Shutdown(); |
| ArcSessionManagerTest::TearDown(); |
| } |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| ProvisioningErrorDisplayTest, |
| ::testing::ValuesIn(kProvisioningErrorDisplayTestCases)); |
| |
| TEST_P(ProvisioningErrorDisplayTest, ArcStopped) { |
| ShowErrorObserver observer(arc_session_manager()); |
| |
| ArcProvisioningResult result = CreateProvisioningResult(GetParam().error); |
| arc_session_manager()->OnProvisioningFinished(result); |
| |
| ASSERT_TRUE(observer.error_info()); |
| EXPECT_EQ(GetParam().message, observer.error_info().value().error); |
| EXPECT_EQ(GetParam().arg, observer.error_info().value().arg); |
| } |
| |
| TEST_F(ArcSessionManagerArcAlwaysStartTest, BaseWorkflow) { |
| // TODO(victorhsieh): Consider also tracking sign-in activity, which is |
| // initiated from the Android side. |
| EXPECT_TRUE(arc_session_manager()->pre_start_time().is_null()); |
| EXPECT_TRUE(arc_session_manager()->start_time().is_null()); |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| // By default ARC is not enabled. |
| EXPECT_EQ(ArcSessionManager::State::STOPPED, arc_session_manager()->state()); |
| |
| // When ARC is always started, ArcSessionManager should always be in ACTIVE |
| // state. |
| arc_session_manager()->RequestEnable(); |
| base::RunLoop().RunUntilIdle(); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| EXPECT_FALSE(arc_session_manager()->pre_start_time().is_null()); |
| EXPECT_FALSE(arc_session_manager()->start_time().is_null()); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| class ArcSessionManagerPolicyTest |
| : public ArcSessionManagerTestBase, |
| public testing::WithParamInterface<std::tuple<bool, bool, int, int>> { |
| public: |
| void SetUp() override { |
| ArcSessionManagerTestBase::SetUp(); |
| AccountId account_id; |
| account_id = AccountId(AccountId::FromUserEmailGaiaId( |
| profile()->GetProfileUserName(), "1234567890")); |
| GetFakeUserManager()->AddUser(account_id); |
| GetFakeUserManager()->LoginUser(account_id); |
| // Mocks OOBE environment so that IsArcOobeOptInActive() returns true. |
| if (is_oobe_optin()) { |
| CreateLoginDisplayHost(); |
| } |
| } |
| |
| void TearDown() override { |
| if (is_oobe_optin()) { |
| fake_login_display_host_.reset(); |
| TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr); |
| } |
| ArcSessionManagerTestBase::TearDown(); |
| } |
| |
| bool arc_enabled_pref_managed() const { return std::get<0>(GetParam()); } |
| |
| bool is_oobe_optin() const { return std::get<1>(GetParam()); } |
| |
| base::Value backup_restore_pref_value() const { |
| switch (std::get<2>(GetParam())) { |
| case 0: |
| return base::Value(); |
| case 1: |
| return base::Value(false); |
| case 2: |
| return base::Value(true); |
| } |
| NOTREACHED_IN_MIGRATION(); |
| return base::Value(); |
| } |
| |
| base::Value location_service_pref_value() const { |
| switch (std::get<3>(GetParam())) { |
| case 0: |
| return base::Value(); |
| case 1: |
| return base::Value(false); |
| case 2: |
| return base::Value(true); |
| } |
| NOTREACHED_IN_MIGRATION(); |
| return base::Value(); |
| } |
| |
| private: |
| void CreateLoginDisplayHost() { |
| fake_login_display_host_ = std::make_unique<ash::FakeLoginDisplayHost>(); |
| } |
| |
| std::unique_ptr<ash::FakeLoginDisplayHost> fake_login_display_host_; |
| }; |
| |
| TEST_P(ArcSessionManagerPolicyTest, SkippingTerms) { |
| sync_preferences::TestingPrefServiceSyncable* const prefs = |
| profile()->GetTestingPrefService(); |
| |
| // Backup-restore and location-service prefs are off by default. |
| EXPECT_FALSE(prefs->GetBoolean(prefs::kArcSignedIn)); |
| EXPECT_FALSE(prefs->GetBoolean(prefs::kArcTermsAccepted)); |
| |
| // Enable ARC through user pref or by policy, according to the test parameter. |
| if (arc_enabled_pref_managed()) { |
| prefs->SetManagedPref(prefs::kArcEnabled, |
| std::make_unique<base::Value>(true)); |
| } else { |
| prefs->SetBoolean(prefs::kArcEnabled, true); |
| } |
| EXPECT_TRUE(IsArcPlayStoreEnabledForProfile(profile())); |
| |
| // Assign test values to the prefs. |
| if (backup_restore_pref_value().is_bool()) { |
| prefs->SetManagedPref( |
| prefs::kArcBackupRestoreEnabled, |
| base::Value::ToUniquePtrValue(backup_restore_pref_value().Clone())); |
| } |
| if (location_service_pref_value().is_bool()) { |
| prefs->SetManagedPref( |
| prefs::kArcLocationServiceEnabled, |
| base::Value::ToUniquePtrValue(location_service_pref_value().Clone())); |
| } |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| |
| // Terms of Service are skipped if ARC is enabled by policy AND (both policies |
| // are managed OR if ARC is in session opt-in). |
| const bool backup_managed = backup_restore_pref_value().is_bool(); |
| const bool location_managed = location_service_pref_value().is_bool(); |
| const bool is_arc_oobe_optin = is_oobe_optin(); |
| const bool expected_terms_skipping = |
| arc_enabled_pref_managed() && |
| ((backup_managed && location_managed) || !is_arc_oobe_optin); |
| EXPECT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| EXPECT_EQ(IsArcOobeOptInActive(), is_arc_oobe_optin); |
| |
| // Complete provisioning if it's not done yet. |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| arc::mojom::ArcSignInResultPtr result = |
| arc::mojom::ArcSignInResult::NewSuccess( |
| arc::mojom::ArcSignInSuccess::SUCCESS); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| |
| // Play Store app is launched unless the Terms screen was suppressed or Tos is |
| // accepted during OOBE. |
| EXPECT_NE(expected_terms_skipping || is_arc_oobe_optin, |
| arc_session_manager()->IsPlaystoreLaunchRequestedForTesting()); |
| |
| // In case Tos is skipped, B&R and GLS should not be set if not managed. |
| if (expected_terms_skipping) { |
| if (!backup_managed) { |
| EXPECT_FALSE(prefs->GetBoolean(prefs::kArcBackupRestoreEnabled)); |
| } |
| if (!location_managed) { |
| EXPECT_FALSE(prefs->GetBoolean(prefs::kArcLocationServiceEnabled)); |
| } |
| } |
| |
| // Managed values for the prefs are unset. |
| prefs->RemoveManagedPref(prefs::kArcBackupRestoreEnabled); |
| prefs->RemoveManagedPref(prefs::kArcLocationServiceEnabled); |
| |
| // The ARC state is preserved. The prefs return to the default false values. |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| EXPECT_FALSE(prefs->GetBoolean(prefs::kArcBackupRestoreEnabled)); |
| EXPECT_FALSE(prefs->GetBoolean(prefs::kArcLocationServiceEnabled)); |
| |
| // Stop ARC and shutdown the service. |
| prefs->RemoveManagedPref(prefs::kArcEnabled); |
| WaitForDataRemoved(ArcSessionManager::State::STOPPED); |
| arc_session_manager()->Shutdown(); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| ArcSessionManagerPolicyTest, |
| // testing::Values is incompatible with move-only types, hence ints are used |
| // as a proxy for base::Value. |
| testing::Combine(testing::Bool() /* arc_enabled_pref_managed */, |
| testing::Bool() /* is_oobe_optin */, |
| /* backup_restore_pref_value */ |
| testing::Values(0, // base::Value() |
| 1, // base::Value(false) |
| 2), // base::Value(true) |
| /* location_service_pref_value */ |
| testing::Values(0, // base::Value() |
| 1, // base::Value(false) |
| 2))); // base::Value(true) |
| |
| class ArcSessionManagerPublicSessionTest : public ArcSessionManagerTestBase { |
| public: |
| ArcSessionManagerPublicSessionTest() = default; |
| |
| ArcSessionManagerPublicSessionTest( |
| const ArcSessionManagerPublicSessionTest&) = delete; |
| ArcSessionManagerPublicSessionTest& operator=( |
| const ArcSessionManagerPublicSessionTest&) = delete; |
| |
| void SetUp() override { |
| ArcSessionManagerTestBase::SetUp(); |
| const AccountId account_id( |
| AccountId::FromUserEmail(profile()->GetProfileUserName())); |
| GetFakeUserManager()->AddPublicAccountUser(account_id); |
| GetFakeUserManager()->LoginUser(account_id); |
| } |
| }; |
| |
| TEST_F(ArcSessionManagerPublicSessionTest, AuthFailure) { |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| // Replace chrome::AttemptUserExit() for testing. |
| // At the end of test, leave the dangling pointer |terminated|, |
| // assuming the callback is never invoked in OnProvisioningFinished() |
| // and not invoked then, including TearDown(). |
| bool terminated = false; |
| arc_session_manager()->SetAttemptUserExitCallbackForTesting( |
| base::BindRepeating([](bool* terminated) { *terminated = true; }, |
| &terminated)); |
| |
| arc::mojom::ArcSignInResultPtr result = arc::mojom::ArcSignInResult::NewError( |
| arc::mojom::ArcSignInError::NewGeneralError( |
| arc::mojom::GeneralSignInError::CHROME_SERVER_COMMUNICATION_ERROR)); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| EXPECT_FALSE(terminated); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| } |
| |
| class ArcSessionOobeOptInNegotiatorTest |
| : public ArcSessionManagerTest, |
| public testing::WithParamInterface<bool> { |
| public: |
| ArcSessionOobeOptInNegotiatorTest() = default; |
| ArcSessionOobeOptInNegotiatorTest(const ArcSessionOobeOptInNegotiatorTest&) = |
| delete; |
| ArcSessionOobeOptInNegotiatorTest& operator=( |
| const ArcSessionOobeOptInNegotiatorTest&) = delete; |
| |
| void SetUp() override { |
| ArcSessionManagerTest::SetUp(); |
| |
| ArcSessionManager::SetArcTermsOfServiceOobeNegotiatorEnabledForTesting( |
| true); |
| |
| CreateLoginDisplayHost(); |
| login_display_host()->StartWizard(ash::OobeScreenId("fake")); |
| |
| std::unique_ptr<ash::ConsolidatedConsentScreen> |
| fake_consolidated_consent_screen = |
| std::make_unique<ash::ConsolidatedConsentScreen>( |
| std::make_unique<ash::ConsolidatedConsentScreenHandler>() |
| ->AsWeakPtr(), |
| base::DoNothing()); |
| login_display_host() |
| ->GetWizardController() |
| ->screen_manager() |
| ->SetScreenForTesting(std::move(fake_consolidated_consent_screen)); |
| |
| if (IsManagedUser()) { |
| policy::ProfilePolicyConnector* const connector = |
| profile()->GetProfilePolicyConnector(); |
| connector->OverrideIsManagedForTesting(true); |
| |
| profile()->GetTestingPrefService()->SetManagedPref( |
| prefs::kArcEnabled, std::make_unique<base::Value>(true)); |
| } |
| |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| if (IsArcPlayStoreEnabledForProfile(profile())) { |
| arc_session_manager()->RequestEnable(); |
| } |
| } |
| |
| void TearDown() override { |
| // Correctly stop service. |
| arc_session_manager()->Shutdown(); |
| |
| ArcSessionManager::SetArcTermsOfServiceOobeNegotiatorEnabledForTesting( |
| false); |
| TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr); |
| |
| ArcSessionManagerTest::TearDown(); |
| } |
| |
| protected: |
| bool IsManagedUser() { return GetParam(); } |
| |
| void EnableSessionManager() { |
| // To match ConsolidatedConsentScreen logic where Google Play Store |
| // enabled preference is set to true on showing UI, which eventually |
| // triggers a call to RequestEnable(). |
| arc_session_manager()->RequestEnable(); |
| } |
| |
| void ReportAccepted() { |
| login_display_host() |
| ->GetWizardController() |
| ->GetScreen<ash::ConsolidatedConsentScreen>() |
| ->NotifyConsolidatedConsentAcceptForTesting(); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| void ReportViewDestroyed() { |
| login_display_host() |
| ->GetWizardController() |
| ->screen_manager() |
| ->DeleteScreenForTesting(ash::ConsolidatedConsentScreenView::kScreenId); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| void CreateLoginDisplayHost() { |
| fake_login_display_host_ = std::make_unique<ash::FakeLoginDisplayHost>(); |
| } |
| |
| ash::FakeLoginDisplayHost* login_display_host() { |
| return fake_login_display_host_.get(); |
| } |
| |
| void CloseLoginDisplayHost() { fake_login_display_host_.reset(); } |
| |
| std::unique_ptr<ash::FakeLoginDisplayHost> fake_login_display_host_; |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P(All, |
| ArcSessionOobeOptInNegotiatorTest, |
| ::testing::Values(true, false)); |
| |
| TEST_P(ArcSessionOobeOptInNegotiatorTest, OobeTermsAccepted) { |
| EnableSessionManager(); |
| EXPECT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| ReportAccepted(); |
| EXPECT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| } |
| |
| TEST_P(ArcSessionOobeOptInNegotiatorTest, OobeTermsViewDestroyed) { |
| EnableSessionManager(); |
| EXPECT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| ReportViewDestroyed(); |
| CloseLoginDisplayHost(); |
| if (!IsManagedUser()) { |
| // ArcPlayStoreEnabledPreferenceHandler is not running, so the state should |
| // be kept as is. |
| EXPECT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| EXPECT_FALSE(IsArcPlayStoreEnabledForProfile(profile())); |
| } else { |
| // For managed case we handle closing outside of |
| // ArcPlayStoreEnabledPreferenceHandler. So it session turns to STOPPED. |
| EXPECT_EQ(ArcSessionManager::State::STOPPED, |
| arc_session_manager()->state()); |
| // Managed user's preference should not be overwritten. |
| EXPECT_TRUE(IsArcPlayStoreEnabledForProfile(profile())); |
| } |
| } |
| |
| struct ArcSessionRetryTestParam { |
| enum class Negotiation { |
| // Negotiation is required for provisioning. |
| REQUIRED, |
| // Negotiation is not required and not shown for provisioning. |
| SKIPPED, |
| }; |
| |
| Negotiation negotiation; |
| |
| // Whether ARC++ container is alive on error. |
| bool container_alive; |
| |
| // Whether data is removed on error. |
| bool data_removed; |
| |
| absl::variant<arc::mojom::GeneralSignInError, |
| arc::mojom::GMSSignInError, |
| arc::mojom::GMSCheckInError, |
| arc::mojom::CloudProvisionFlowError, |
| ArcStopReason, |
| ChromeProvisioningTimeout> |
| error; |
| }; |
| |
| ArcSessionRetryTestParam kRetryTestCases[] = { |
| {ArcSessionRetryTestParam::Negotiation::REQUIRED, true, true, |
| arc::mojom::GeneralSignInError::UNKNOWN_ERROR}, |
| {ArcSessionRetryTestParam::Negotiation::REQUIRED, true, false, |
| arc::mojom::GMSSignInError::GMS_SIGN_IN_NETWORK_ERROR}, |
| {ArcSessionRetryTestParam::Negotiation::REQUIRED, true, false, |
| arc::mojom::GMSSignInError::GMS_SIGN_IN_SERVICE_UNAVAILABLE}, |
| {ArcSessionRetryTestParam::Negotiation::REQUIRED, true, false, |
| arc::mojom::GMSSignInError::GMS_SIGN_IN_BAD_AUTHENTICATION}, |
| {ArcSessionRetryTestParam::Negotiation::REQUIRED, true, false, |
| arc::mojom::GMSCheckInError::GMS_CHECK_IN_FAILED}, |
| {ArcSessionRetryTestParam::Negotiation::SKIPPED, true, true, |
| arc::mojom::CloudProvisionFlowError::ERROR_OTHER}, |
| {ArcSessionRetryTestParam::Negotiation::REQUIRED, true, false, |
| arc::mojom::GeneralSignInError::MOJO_VERSION_MISMATCH}, |
| {ArcSessionRetryTestParam::Negotiation::REQUIRED, true, false, |
| arc::mojom::GeneralSignInError::GENERIC_PROVISIONING_TIMEOUT}, |
| {ArcSessionRetryTestParam::Negotiation::REQUIRED, true, false, |
| arc::mojom::GMSCheckInError::GMS_CHECK_IN_TIMEOUT}, |
| {ArcSessionRetryTestParam::Negotiation::REQUIRED, true, false, |
| arc::mojom::GMSCheckInError::GMS_CHECK_IN_INTERNAL_ERROR}, |
| {ArcSessionRetryTestParam::Negotiation::REQUIRED, true, false, |
| arc::mojom::GMSSignInError::GMS_SIGN_IN_FAILED}, |
| {ArcSessionRetryTestParam::Negotiation::REQUIRED, true, false, |
| arc::mojom::GMSSignInError::GMS_SIGN_IN_TIMEOUT}, |
| {ArcSessionRetryTestParam::Negotiation::REQUIRED, true, false, |
| arc::mojom::GMSSignInError::GMS_SIGN_IN_INTERNAL_ERROR}, |
| {ArcSessionRetryTestParam::Negotiation::SKIPPED, true, true, |
| arc::mojom::CloudProvisionFlowError::ERROR_TIMEOUT}, |
| {ArcSessionRetryTestParam::Negotiation::SKIPPED, true, true, |
| arc::mojom::CloudProvisionFlowError::ERROR_JSON}, |
| {ArcSessionRetryTestParam::Negotiation::REQUIRED, false, false, |
| ArcStopReason::CRASH}, |
| {ArcSessionRetryTestParam::Negotiation::REQUIRED, true, true, |
| ChromeProvisioningTimeout{}}, |
| {ArcSessionRetryTestParam::Negotiation::REQUIRED, true, false, |
| arc::mojom::GeneralSignInError::CHROME_SERVER_COMMUNICATION_ERROR}, |
| {ArcSessionRetryTestParam::Negotiation::REQUIRED, true, false, |
| arc::mojom::GeneralSignInError::NO_NETWORK_CONNECTION}, |
| }; |
| |
| class ArcSessionRetryTest |
| : public ArcSessionManagerTest, |
| public testing::WithParamInterface<ArcSessionRetryTestParam> { |
| public: |
| ArcSessionRetryTest() = default; |
| |
| ArcSessionRetryTest(const ArcSessionRetryTest&) = delete; |
| ArcSessionRetryTest& operator=(const ArcSessionRetryTest&) = delete; |
| |
| void SetUp() override { |
| ArcSessionManagerTest::SetUp(); |
| |
| GetFakeUserManager()->SetIsCurrentUserNew(true); |
| |
| // Make negotiation not needed by switching to managed flow with other |
| // preferences under the policy, similar to google.com provisioning case. |
| if (GetParam().negotiation == |
| ArcSessionRetryTestParam::Negotiation::SKIPPED) { |
| policy::ProfilePolicyConnector* const connector = |
| profile()->GetProfilePolicyConnector(); |
| connector->OverrideIsManagedForTesting(true); |
| |
| profile()->GetTestingPrefService()->SetManagedPref( |
| prefs::kArcEnabled, std::make_unique<base::Value>(true)); |
| // Set all prefs as managed to simulate google.com account provisioning. |
| profile()->GetTestingPrefService()->SetManagedPref( |
| prefs::kArcBackupRestoreEnabled, |
| std::make_unique<base::Value>(false)); |
| profile()->GetTestingPrefService()->SetManagedPref( |
| prefs::kArcLocationServiceEnabled, |
| std::make_unique<base::Value>(false)); |
| EXPECT_FALSE(arc::IsArcTermsOfServiceNegotiationNeeded(profile())); |
| } |
| } |
| |
| void TearDown() override { |
| // Correctly stop service. |
| arc_session_manager()->Shutdown(); |
| ArcSessionManagerTest::TearDown(); |
| } |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P(All, |
| ArcSessionRetryTest, |
| ::testing::ValuesIn(kRetryTestCases)); |
| |
| // Verifies that Android container behaves as expected.* This checks: |
| // * Whether ARC++ container alive or not on error. |
| // * Whether Android data is removed or not on error. |
| // * ARC++ Container is restarted on retry. |
| TEST_P(ArcSessionRetryTest, ContainerRestarted) { |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| |
| EXPECT_EQ(ArcSessionManager::State::CHECKING_REQUIREMENTS, |
| arc_session_manager()->state()); |
| arc_session_manager()->EmulateRequirementCheckCompletionForTesting(); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| ArcProvisioningResult result1 = CreateProvisioningResult(GetParam().error); |
| arc_session_manager()->OnProvisioningFinished(result1); |
| |
| // In case of permanent error data removal request is scheduled. |
| EXPECT_EQ(GetParam().data_removed, |
| profile()->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)); |
| |
| if (GetParam().container_alive) { |
| // We don't stop ARC due to let user submit user feedback with alive Android |
| // container. |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| } else { |
| // Container is stopped automatically on this error. |
| EXPECT_EQ(ArcSessionManager::State::STOPPED, |
| arc_session_manager()->state()); |
| } |
| |
| arc_session_manager()->OnRetryClicked(); |
| |
| if (GetParam().data_removed) { |
| // Check state goes from REMOVING_DATA_DIR to CHECKING_REQUIREMENTS. |
| EXPECT_TRUE( |
| WaitForDataRemoved(ArcSessionManager::State::CHECKING_REQUIREMENTS)); |
| } |
| |
| arc_session_manager()->StartArcForTesting(); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| // Successful retry keeps ARC++ container running. |
| arc::mojom::ArcSignInResultPtr result = |
| arc::mojom::ArcSignInResult::NewSuccess( |
| arc::mojom::ArcSignInSuccess::SUCCESS); |
| arc_session_manager()->OnProvisioningFinished( |
| ArcProvisioningResult(std::move(result))); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| arc_session_manager()->Shutdown(); |
| } |
| |
| // Test that when files have already been expanded, AddObserver() immediately |
| // calls OnPropertyFilesExpanded(). |
| TEST_F(ArcSessionManagerTest, FileExpansion_AlreadyDone) { |
| arc_session_manager()->reset_property_files_expansion_result(); |
| FileExpansionObserver observer; |
| arc_session_manager()->OnExpandPropertyFilesAndReadSaltForTesting(true); |
| arc_session_manager()->AddObserver(&observer); |
| ASSERT_TRUE(observer.property_files_expansion_result().has_value()); |
| EXPECT_TRUE(observer.property_files_expansion_result().value()); |
| } |
| |
| // Tests that OnPropertyFilesExpanded() is called with true when the files are |
| // expended. |
| TEST_F(ArcSessionManagerTest, FileExpansion) { |
| arc_session_manager()->reset_property_files_expansion_result(); |
| FileExpansionObserver observer; |
| arc_session_manager()->AddObserver(&observer); |
| EXPECT_FALSE(observer.property_files_expansion_result().has_value()); |
| arc_session_manager()->OnExpandPropertyFilesAndReadSaltForTesting(true); |
| ASSERT_TRUE(observer.property_files_expansion_result().has_value()); |
| EXPECT_TRUE(observer.property_files_expansion_result().value()); |
| } |
| |
| // Tests that OnPropertyFilesExpanded() is called with false when the expansion |
| // failed. |
| TEST_F(ArcSessionManagerTest, FileExpansion_Fail) { |
| arc_session_manager()->reset_property_files_expansion_result(); |
| FileExpansionObserver observer; |
| arc_session_manager()->AddObserver(&observer); |
| EXPECT_FALSE(observer.property_files_expansion_result().has_value()); |
| arc_session_manager()->OnExpandPropertyFilesAndReadSaltForTesting(false); |
| ASSERT_TRUE(observer.property_files_expansion_result().has_value()); |
| EXPECT_FALSE(observer.property_files_expansion_result().value()); |
| } |
| |
| // Tests that TrimVmMemory doesn't crash. |
| TEST_F(ArcSessionManagerTest, TrimVmMemory) { |
| bool callback_called = false; |
| arc_session_manager()->TrimVmMemory( |
| base::BindLambdaForTesting([&callback_called](bool, const std::string&) { |
| callback_called = true; |
| }), |
| 0); |
| base::RunLoop().RunUntilIdle(); |
| EXPECT_TRUE(callback_called); |
| } |
| |
| TEST_F(ArcSessionManagerTest, RequestArcEnableMemoryMargin) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures({ash::kCrOSMemoryPressureSignalStudyArc, |
| ash::kCrOSMemoryPressureSignalStudyNonArc}, |
| {}); |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| |
| arc_session_manager()->RequestEnable(); |
| |
| EXPECT_EQ(resourced_client_->get_critical_margin_bps(), 800u); |
| EXPECT_EQ(resourced_client_->get_moderate_margin_bps(), 4000u); |
| } |
| |
| TEST_F(ArcSessionManagerTest, RequestArcDisableMemoryMargin) { |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatures({ash::kCrOSMemoryPressureSignalStudyArc, |
| ash::kCrOSMemoryPressureSignalStudyNonArc}, |
| {}); |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->RequestEnable(); |
| |
| arc_session_manager()->RequestDisable(); |
| |
| EXPECT_EQ(resourced_client_->get_critical_margin_bps(), 1500u); |
| EXPECT_EQ(resourced_client_->get_moderate_margin_bps(), 4000u); |
| } |
| |
| class ArcTransitionToManagedTest |
| : public ArcSessionManagerTest, |
| public testing::WithParamInterface<std::tuple<bool, bool>> { |
| public: |
| ArcTransitionToManagedTest() = default; |
| ~ArcTransitionToManagedTest() override = default; |
| ArcTransitionToManagedTest(const ArcTransitionToManagedTest&) = delete; |
| ArcTransitionToManagedTest& operator=(const ArcTransitionToManagedTest&) = |
| delete; |
| |
| void SetUp() override { |
| ArcSessionManagerTest::SetUp(); |
| ArcSessionManager::SetUiEnabledForTesting(true); |
| |
| const std::string profile_name = profile()->GetProfileUserName(); |
| identity_test_environment_.MakeAccountAvailable(profile_name); |
| signin::IdentityManager* identity_manager = |
| identity_test_environment_.identity_manager(); |
| CoreAccountId account_id = identity_manager->PickAccountIdForAccount( |
| signin::GetTestGaiaIdForEmail(profile_name), profile_name); |
| |
| // Inject a fake AndroidManagementClient to return MANAGED as the result. |
| arc_session_manager()->SetAndroidManagementCheckerFactoryForTesting( |
| base::BindLambdaForTesting([=](Profile* profile, bool retry_on_error) { |
| auto fake_client = |
| std::make_unique<policy::FakeAndroidManagementClient>(); |
| fake_client->SetResult( |
| policy::AndroidManagementClient::Result::MANAGED); |
| |
| return std::make_unique<ArcAndroidManagementChecker>( |
| profile, identity_manager, account_id, retry_on_error, |
| std::move(fake_client)); |
| })); |
| } |
| |
| bool transition_feature_enabled() const { return std::get<0>(GetParam()); } |
| |
| bool user_become_managed() const { return std::get<1>(GetParam()); } |
| |
| bool ShouldArcTransitionToManaged() const { |
| return transition_feature_enabled() && user_become_managed(); |
| } |
| |
| protected: |
| signin::IdentityTestEnvironment identity_test_environment_; |
| }; |
| |
| TEST_P(ArcTransitionToManagedTest, TransitionFlow) { |
| // Initialize feature state. |
| base::test::ScopedFeatureList feature_list; |
| feature_list.InitWithFeatureState(kEnableUnmanagedToManagedTransitionFeature, |
| transition_feature_enabled()); |
| // Set up the situation that provisioning is successfully done in the |
| // previous session. |
| profile()->GetPrefs()->SetBoolean(prefs::kArcEnabled, true); |
| profile()->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, true); |
| profile()->GetPrefs()->SetBoolean(prefs::kArcSignedIn, true); |
| |
| // Initialize ARC. |
| arc_session_manager()->SetProfile(profile()); |
| arc_session_manager()->Initialize(); |
| arc_session_manager()->AllowActivation( |
| ArcSessionManager::AllowActivationReason::kImmediateActivation); |
| arc_session_manager()->RequestEnable(); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, arc_session_manager()->state()); |
| |
| // Emulate user management state change. |
| profile()->GetProfilePolicyConnector()->OverrideIsManagedForTesting( |
| user_become_managed()); |
| base::RunLoop().RunUntilIdle(); |
| |
| // Verify ARC state and ARC transition value. |
| EXPECT_EQ(profile()->GetPrefs()->GetBoolean(prefs::kArcEnabled), |
| ShouldArcTransitionToManaged()); |
| EXPECT_EQ(arc::GetManagementTransition(profile()), |
| ShouldArcTransitionToManaged() |
| ? arc::ArcManagementTransition::UNMANAGED_TO_MANAGED |
| : arc::ArcManagementTransition::NO_TRANSITION); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| ArcTransitionToManagedTest, |
| testing::Combine(testing::Bool() /* transition_feature_enabled */, |
| testing::Bool() /* user_become_managed */)); |
| |
| } // namespace |
| } // namespace arc |