| // 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 <string> |
| |
| #include "ash/wm/window_pin_util.h" |
| #include "base/auto_reset.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/scoped_refptr.h" |
| #include "base/run_loop.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/time/time.h" |
| #include "chrome/browser/ash/arc/arc_util.h" |
| #include "chrome/browser/ash/arc/session/arc_service_launcher.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/certificate_provider/certificate_provider_service.h" |
| #include "chrome/browser/ash/certificate_provider/certificate_provider_service_factory.h" |
| #include "chrome/browser/ash/policy/test_support/embedded_policy_test_server_mixin.h" |
| #include "chrome/browser/ash/test/regular_logged_in_browser_test_mixin.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/policy/profile_policy_connector.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_window.h" |
| #include "chrome/test/base/in_process_browser_test.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "chromeos/ash/components/browser_context_helper/browser_context_types.h" |
| #include "chromeos/ash/components/dbus/cicerone/cicerone_client.h" |
| #include "chromeos/ash/components/dbus/concierge/fake_concierge_client.h" |
| #include "chromeos/ash/components/dbus/vm_concierge/concierge_service.pb.h" |
| #include "chromeos/ash/experiences/arc/arc_prefs.h" |
| #include "chromeos/ash/experiences/arc/session/arc_service_manager.h" |
| #include "chromeos/ash/experiences/arc/session/arc_session_runner.h" |
| #include "chromeos/ash/experiences/arc/test/arc_util_test_support.h" |
| #include "chromeos/ash/experiences/arc/test/fake_arc_session.h" |
| #include "components/account_id/account_id.h" |
| #include "components/policy/core/common/cloud/device_management_service.h" |
| #include "components/policy/core/common/cloud/mock_cloud_policy_client.h" |
| #include "components/policy/core/common/cloud/user_cloud_policy_manager.h" |
| #include "components/policy/core/common/policy_switches.h" |
| #include "components/policy/test_support/request_handler_for_check_android_management.h" |
| #include "components/prefs/pref_member.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/signin/public/base/consent_level.h" |
| #include "components/signin/public/identity_manager/identity_test_environment.h" |
| #include "components/user_manager/user_manager.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/test_utils.h" |
| #include "google_apis/gaia/gaia_id.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/gurl.h" |
| |
| namespace { |
| |
| constexpr char kWellKnownConsumerName[] = "test@gmail.com"; |
| constexpr char kFakeUserName[] = "test@example.com"; |
| constexpr char kMuteAudioWithSuccessHistogram[] = "Arc.MuteAudioSuccess"; |
| constexpr char kUnmuteAudioWithSuccessHistogram[] = "Arc.UnmuteAudioSuccess"; |
| constexpr GaiaId::Literal kFakeGaiaId("1234567890"); |
| |
| std::unique_ptr<KeyedService> CreateCertificateProviderService( |
| content::BrowserContext* context) { |
| return std::make_unique<chromeos::CertificateProviderService>(); |
| } |
| |
| } // namespace |
| |
| namespace arc { |
| |
| // Waits for the "arc.enabled" preference value from true to false. |
| class ArcPlayStoreDisabledWaiter : public ArcSessionManagerObserver { |
| public: |
| ArcPlayStoreDisabledWaiter() { ArcSessionManager::Get()->AddObserver(this); } |
| |
| ArcPlayStoreDisabledWaiter(const ArcPlayStoreDisabledWaiter&) = delete; |
| ArcPlayStoreDisabledWaiter& operator=(const ArcPlayStoreDisabledWaiter&) = |
| delete; |
| |
| ~ArcPlayStoreDisabledWaiter() override { |
| ArcSessionManager::Get()->RemoveObserver(this); |
| } |
| |
| void Wait() { |
| base::RunLoop run_loop; |
| base::AutoReset<raw_ptr<base::RunLoop>> reset(&run_loop_, &run_loop); |
| run_loop.Run(); |
| } |
| |
| private: |
| // ArcSessionManagerObserver override: |
| void OnArcPlayStoreEnabledChanged(bool enabled) override { |
| if (!enabled) { |
| DCHECK(run_loop_); |
| run_loop_->Quit(); |
| } |
| } |
| |
| raw_ptr<base::RunLoop> run_loop_ = nullptr; |
| }; |
| |
| class ArcSessionManagerTest : public MixinBasedInProcessBrowserTest { |
| protected: |
| explicit ArcSessionManagerTest(std::string_view user_email = kFakeUserName) |
| : account_id_(AccountId::FromUserEmailGaiaId(user_email, kFakeGaiaId)) {} |
| |
| ArcSessionManagerTest(const ArcSessionManagerTest&) = delete; |
| ArcSessionManagerTest& operator=(const ArcSessionManagerTest&) = delete; |
| |
| ~ArcSessionManagerTest() override = default; |
| |
| // MixinBasedInProcessBrowserTest: |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| MixinBasedInProcessBrowserTest::SetUpCommandLine(command_line); |
| arc::SetArcAvailableCommandLineForTesting(command_line); |
| } |
| |
| void SetUpInProcessBrowserTestFixture() override { |
| MixinBasedInProcessBrowserTest::SetUpInProcessBrowserTestFixture(); |
| |
| // Init ArcSessionManager for testing. |
| ArcSessionManager::SetUiEnabledForTesting(false); |
| ArcSessionManager::EnableCheckAndroidManagementForTesting(true); |
| ArcServiceLauncher::SetArcSessionRunnerForTesting( |
| std::make_unique<ArcSessionRunner>( |
| base::BindRepeating(FakeArcSession::Create))); |
| } |
| |
| void SetUpBrowserContextKeyedServices( |
| content::BrowserContext* context) override { |
| MixinBasedInProcessBrowserTest::SetUpBrowserContextKeyedServices(context); |
| |
| // Inject only for a user Profile. |
| if (ash::IsSigninBrowserContext(context)) { |
| return; |
| } |
| IdentityTestEnvironmentProfileAdaptor:: |
| SetIdentityTestEnvironmentFactoriesOnBrowserContext(context); |
| chromeos::CertificateProviderServiceFactory::GetInstance() |
| ->SetTestingFactory( |
| context, base::BindRepeating(&CreateCertificateProviderService)); |
| } |
| |
| void SetUpOnMainThread() override { |
| MixinBasedInProcessBrowserTest::SetUpOnMainThread(); |
| |
| identity_test_environment_adaptor_ = |
| std::make_unique<IdentityTestEnvironmentProfileAdaptor>(profile()); |
| // Seed account info properly. |
| identity_test_env()->MakePrimaryAccountAvailable( |
| account_id_.GetUserEmail(), signin::ConsentLevel::kSignin); |
| |
| profile()->GetPrefs()->SetBoolean(prefs::kArcSignedIn, true); |
| profile()->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, true); |
| } |
| |
| void TearDownOnMainThread() override { |
| identity_test_environment_adaptor_.reset(); |
| MixinBasedInProcessBrowserTest::TearDownOnMainThread(); |
| } |
| |
| void EnableArc() { |
| PrefService* const prefs = profile()->GetPrefs(); |
| prefs->SetBoolean(prefs::kArcEnabled, true); |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| Profile* profile() { return browser()->profile(); } |
| |
| signin::IdentityTestEnvironment* identity_test_env() { |
| return identity_test_environment_adaptor_->identity_test_env(); |
| } |
| |
| signin::IdentityManager* identity_manager() { |
| return identity_test_env()->identity_manager(); |
| } |
| |
| private: |
| const AccountId account_id_; |
| ash::RegularLoggedInBrowserTestMixin logged_in_mixin_{&mixin_host_, |
| account_id_}; |
| ash::EmbeddedPolicyTestServerMixin policy_test_server_mixin_{&mixin_host_}; |
| std::unique_ptr<IdentityTestEnvironmentProfileAdaptor> |
| identity_test_environment_adaptor_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(ArcSessionManagerTest, ConsumerAccount) { |
| EnableArc(); |
| identity_test_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( |
| identity_manager()->GetPrimaryAccountId(signin::ConsentLevel::kSignin), |
| policy::kUnmanagedAuthToken, base::Time::Max()); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, |
| ArcSessionManager::Get()->state()); |
| } |
| |
| class ArcSessionManagerWellKnownConsumerNameTest |
| : public ArcSessionManagerTest { |
| public: |
| ArcSessionManagerWellKnownConsumerNameTest() |
| : ArcSessionManagerTest(kWellKnownConsumerName) {} |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(ArcSessionManagerWellKnownConsumerNameTest, |
| WellKnownConsumerAccount) { |
| EnableArc(); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, |
| ArcSessionManager::Get()->state()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ArcSessionManagerTest, ManagedChromeAccount) { |
| policy::ProfilePolicyConnector* const connector = |
| profile()->GetProfilePolicyConnector(); |
| connector->OverrideIsManagedForTesting(true); |
| |
| EnableArc(); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, |
| ArcSessionManager::Get()->state()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ArcSessionManagerTest, ManagedAndroidAccount) { |
| EnableArc(); |
| identity_test_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken( |
| identity_manager()->GetPrimaryAccountId(signin::ConsentLevel::kSignin), |
| policy::kManagedAuthToken, base::Time::Max()); |
| ArcPlayStoreDisabledWaiter().Wait(); |
| EXPECT_FALSE(IsArcPlayStoreEnabledForProfile(profile())); |
| } |
| |
| // TODO - crbug.com/401589420: Move audio tests to the |
| // //c/b/ash/arc/locked_fullscreen folder. |
| class ArcSessionManagerLockedFullscreenWithMuteAudioTest |
| : public ArcSessionManagerTest, |
| public ::testing::WithParamInterface<bool> { |
| protected: |
| bool IsMuteArcVMAudioSuccess() { return GetParam(); } |
| }; |
| |
| IN_PROC_BROWSER_TEST_P(ArcSessionManagerLockedFullscreenWithMuteAudioTest, |
| AttemptArcVMMuteAudioInLockedFullscreen) { |
| base::HistogramTester histogram_tester; |
| EnableArc(); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, |
| ArcSessionManager::Get()->state()); |
| |
| ash::FakeConciergeClient* const concierge_client = |
| ash::FakeConciergeClient::Get(); |
| vm_tools::concierge::SuccessFailureResponse mute_vm_audio_response; |
| mute_vm_audio_response.set_success(IsMuteArcVMAudioSuccess()); |
| concierge_client->set_mute_vm_audio_response(mute_vm_audio_response); |
| |
| // ARC should remain enabled when entering fullscreen mode. This is because |
| // we attempt to mute ARC VM audio instead. |
| ash::PinWindow(browser()->window()->GetNativeWindow(), /*trusted=*/true); |
| content::RunAllTasksUntilIdle(); |
| ASSERT_EQ(ArcSessionManager::State::ACTIVE, |
| ArcSessionManager::Get()->state()); |
| EXPECT_EQ(concierge_client->mute_vm_audio_call_count(), 1); |
| histogram_tester.ExpectUniqueSample(kMuteAudioWithSuccessHistogram, |
| IsMuteArcVMAudioSuccess(), 1); |
| |
| // ARC should remain enabled once we exit locked fullscreen mode. |
| ash::UnpinWindow(browser()->window()->GetNativeWindow()); |
| content::RunAllTasksUntilIdle(); |
| EXPECT_EQ(ArcSessionManager::State::ACTIVE, |
| ArcSessionManager::Get()->state()); |
| EXPECT_EQ(concierge_client->mute_vm_audio_call_count(), 2); |
| histogram_tester.ExpectUniqueSample(kUnmuteAudioWithSuccessHistogram, |
| IsMuteArcVMAudioSuccess(), 1); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(ArcSessionManagerLockedFullscreenWithMuteAudioTests, |
| ArcSessionManagerLockedFullscreenWithMuteAudioTest, |
| ::testing::Bool()); |
| |
| } // namespace arc |