blob: 29aedabb3310cf8aa7d26fbb3e5147a41f475e0b [file] [log] [blame]
// Copyright 2012 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/profiles/profile_destroyer.h"
#include <array>
#include <vector>
#include "base/feature_list.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "build/build_config.h"
#include "build/buildflag.h"
#include "chrome/browser/browser_features.h"
#include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h"
#include "chrome/browser/profiles/keep_alive/scoped_profile_keep_alive.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/site_instance.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_renderer_host.h"
#include "testing/gtest/include/gtest/gtest.h"
class ProfileDestroyerTest : public testing::Test,
public testing::WithParamInterface<bool> {
public:
ProfileDestroyerTest() = default;
ProfileDestroyerTest(const ProfileDestroyerTest&) = delete;
ProfileDestroyerTest& operator=(const ProfileDestroyerTest&) = delete;
void SetUp() override { ASSERT_TRUE(profile_manager_.SetUp()); }
TestingProfile* original_profile() { return original_profile_; }
TestingProfile* OtrProfile(size_t i) {
return otr_profiles_.size() > i ? otr_profiles_[i] : nullptr;
}
void CreateOriginalProfile() {
original_profile_ = profile_manager_.CreateTestingProfile("foo");
original_profile_->SetProfileDestructionObserver(
base::BindOnce(&ProfileDestroyerTest::SetOriginalProfileDestroyed,
base::Unretained(this)));
original_profile_keep_alive_ = std::make_unique<ScopedProfileKeepAlive>(
original_profile_, ProfileKeepAliveOrigin::kBrowserWindow);
}
void CreateOTRProfile() {
Profile::OTRProfileID profile_id =
(is_primary_otr_ && otr_profiles_.size() == 0)
? Profile::OTRProfileID::PrimaryID()
: Profile::OTRProfileID::CreateUniqueForTesting();
TestingProfile::Builder builder;
builder.SetPath(original_profile_->GetPath());
TestingProfile* otr_profile =
builder.BuildOffTheRecord(original_profile_, profile_id);
otr_profile->SetProfileDestructionObserver(
base::BindOnce(&ProfileDestroyerTest::SetOTRProfileDestroyed,
base::Unretained(this), base::Unretained(otr_profile)));
otr_profiles_.push_back(otr_profile);
}
void SetOriginalProfileDestroyed() { original_profile_ = nullptr; }
void SetOTRProfileDestroyed(TestingProfile* destroyed_profile) {
for (auto& profile : otr_profiles_) {
if (profile == destroyed_profile) {
profile = nullptr;
}
}
}
// Creates a render process host based on a new site instance given the
// |profile| and mark it as used. Returns a reference to it.
content::RenderProcessHost* CreatedRendererProcessHost(Profile* profile) {
site_instances_.emplace_back(content::SiteInstance::Create(profile));
content::RenderProcessHost* rph =
site_instances_.back()->GetOrCreateProcessForTesting();
EXPECT_TRUE(rph);
rph->SetIsUsed();
return rph;
}
void StopKeepingAliveOriginalProfile() {
original_profile_keep_alive_.reset();
}
// Destroying profile is still not universally supported. We need to disable
// some tests, because it isn't possible to start destroying the profile.
bool IsScopedProfileKeepAliveSupported() {
#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
return false;
#else
return base::FeatureList::IsEnabled(
features::kDestroyProfileOnBrowserClose);
#endif
}
protected:
const bool is_primary_otr_ = GetParam();
raw_ptr<TestingProfile> original_profile_;
std::vector<raw_ptr<TestingProfile>> otr_profiles_;
content::BrowserTaskEnvironment task_environment_;
TestingProfileManager profile_manager_{TestingBrowserProcess::GetGlobal()};
content::RenderViewHostTestEnabler rvh_test_enabler_;
std::unique_ptr<ScopedProfileKeepAlive> original_profile_keep_alive_;
std::vector<scoped_refptr<content::SiteInstance>> site_instances_;
};
TEST_P(ProfileDestroyerTest, DestroyOriginalProfileImmediately) {
if (!IsScopedProfileKeepAliveSupported())
return;
CreateOriginalProfile();
CreateOTRProfile();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(original_profile());
EXPECT_TRUE(OtrProfile(0));
StopKeepingAliveOriginalProfile();
EXPECT_TRUE(original_profile());
EXPECT_TRUE(OtrProfile(0));
// This doesn't really match real-world scenarios, because TestingProfile is
// different from OffTheRecordProfileImpl. The real impl acquires a keepalive
// on the parent profile, whereas OTR TestingProfile doesn't do that.
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(original_profile());
EXPECT_FALSE(OtrProfile(0));
}
TEST_P(ProfileDestroyerTest, DestroyOriginalProfileDeferedByRenderProcessHost) {
if (!IsScopedProfileKeepAliveSupported())
return;
CreateOriginalProfile();
CreateOTRProfile();
content::RenderProcessHost* render_process_host =
CreatedRendererProcessHost(original_profile());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(original_profile());
EXPECT_TRUE(OtrProfile(0));
// The original profile is not destroyed, because of the RenderProcessHost.
StopKeepingAliveOriginalProfile();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(original_profile());
EXPECT_TRUE(OtrProfile(0));
// Releasing the RenderProcessHost triggers the deletion of the Profile. It
// happens in a posted task.
render_process_host->Cleanup();
EXPECT_TRUE(original_profile());
EXPECT_TRUE(OtrProfile(0));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(original_profile());
EXPECT_FALSE(OtrProfile(0));
}
TEST_P(ProfileDestroyerTest,
DestroyOriginalProfileDeferedByOffTheRecordRenderProcessHost) {
if (!IsScopedProfileKeepAliveSupported())
return;
CreateOriginalProfile();
CreateOTRProfile();
content::RenderProcessHost* render_process_host =
CreatedRendererProcessHost(OtrProfile(0));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(original_profile());
EXPECT_TRUE(OtrProfile(0));
// The original profile is not destroyed, because of the RenderProcessHost.
StopKeepingAliveOriginalProfile();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(original_profile());
EXPECT_TRUE(OtrProfile(0));
// Releasing the RenderProcessHost triggers the deletion of the Profile. It
// happens in a posted task.
render_process_host->Cleanup();
EXPECT_TRUE(original_profile());
EXPECT_TRUE(OtrProfile(0));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(original_profile());
EXPECT_FALSE(OtrProfile(0));
}
TEST_P(ProfileDestroyerTest,
DetroyBothProfileDeferedByMultipleRenderProcessHost) {
if (!IsScopedProfileKeepAliveSupported())
return;
CreateOriginalProfile();
CreateOTRProfile();
content::RenderProcessHost* rph_otr_profile =
CreatedRendererProcessHost(OtrProfile(0));
content::RenderProcessHost* rph_original_profile =
CreatedRendererProcessHost(original_profile());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(original_profile());
EXPECT_TRUE(OtrProfile(0));
// No profile are destroyed, because of the RenderProcessHosts.
StopKeepingAliveOriginalProfile();
ProfileDestroyer::DestroyOTRProfileWhenAppropriate(OtrProfile(0));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(original_profile());
EXPECT_TRUE(OtrProfile(0));
// Release the first process. It causes the associated profile to be released.
// This happens in a posted task.
rph_otr_profile->Cleanup();
EXPECT_TRUE(original_profile());
EXPECT_TRUE(OtrProfile(0));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(original_profile());
EXPECT_FALSE(OtrProfile(0));
// Release the second process. It causes the associated profile to be
// released. This happens in a posted task.
rph_original_profile->Cleanup();
EXPECT_TRUE(original_profile());
EXPECT_FALSE(OtrProfile(0));
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(original_profile());
EXPECT_FALSE(OtrProfile(0));
}
// Expect immediate OTR profile destruction when requested.
TEST_P(ProfileDestroyerTest, ImmediateOTRProfileDestructionNowWithNoHost) {
CreateOriginalProfile();
CreateOTRProfile();
EXPECT_TRUE(original_profile());
EXPECT_TRUE(OtrProfile(0));
// Ask for immediate destruction of OTR profile with no hosts and expect
// immediate destruction.
ProfileDestroyer::DestroyOTRProfileImmediately(OtrProfile(0));
EXPECT_FALSE(OtrProfile(0));
}
#if defined(GTEST_HAS_DEATH_TEST)
// Expect immediate OTR profile destruction when requested.
TEST_P(ProfileDestroyerTest, CrashOTRProfileDestructionNowWithHosts) {
CreateOriginalProfile();
CreateOTRProfile();
EXPECT_TRUE(original_profile());
EXPECT_TRUE(OtrProfile(0));
CreatedRendererProcessHost(OtrProfile(0));
// Immediate destruction of OTR profile with hosts will crash.
EXPECT_DEATH(ProfileDestroyer::DestroyOTRProfileImmediately(OtrProfile(0)),
"");
}
#endif // defined(GTEST_HAS_DEATH_TEST)
// Expect immediate OTR profile destruction when no pending renderer
// process host exists.
TEST_P(ProfileDestroyerTest, ImmediateOTRProfileDestructionWithNoHosts) {
CreateOriginalProfile();
CreateOTRProfile();
EXPECT_TRUE(original_profile());
EXPECT_TRUE(OtrProfile(0));
// Ask for destruction of OTR profile, and expect immediate destruction.
ProfileDestroyer::DestroyOTRProfileWhenAppropriate(OtrProfile(0));
EXPECT_FALSE(OtrProfile(0));
}
// Expect pending renderer process hosts delay OTR profile destruction.
TEST_P(ProfileDestroyerTest, DelayedOTRProfileDestruction) {
CreateOriginalProfile();
CreateOTRProfile();
// Create two render process hosts.
content::RenderProcessHost* render_process_host1 =
CreatedRendererProcessHost(OtrProfile(0));
content::RenderProcessHost* render_process_host2 =
CreatedRendererProcessHost(OtrProfile(0));
// Ask for destruction of OTR profile, but expect it to be delayed.
ProfileDestroyer::DestroyOTRProfileWhenAppropriate(OtrProfile(0));
EXPECT_TRUE(OtrProfile(0));
// Destroy the first pending render process host, and expect it not to destroy
// the OTR profile.
render_process_host1->Cleanup();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(OtrProfile(0));
// Destroy the other renderer process, and expect destruction of OTR
// profile.
render_process_host2->Cleanup();
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(OtrProfile(0));
}
TEST_P(ProfileDestroyerTest, RenderProcessAddedAfterDestroyRequested) {
if (!IsScopedProfileKeepAliveSupported())
return;
CreateOriginalProfile();
content::RenderProcessHost* render_process_host_1 =
CreatedRendererProcessHost(original_profile());
StopKeepingAliveOriginalProfile();
EXPECT_TRUE(original_profile());
content::RenderProcessHost* render_process_host_2 =
CreatedRendererProcessHost(original_profile());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(original_profile()); // Waiting for 2 processes to be released
render_process_host_1->Cleanup();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(original_profile()); // Waiting for 1 process to be released.
render_process_host_2->Cleanup();
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(original_profile()); // Destroyed.
}
// Regression test for:
// https://crbug.com/1337388#c11
TEST_P(ProfileDestroyerTest, DestructionRequestedTwiceWhileDelayedOTRProfile) {
CreateOriginalProfile();
CreateOTRProfile();
content::RenderProcessHost* render_process_host =
CreatedRendererProcessHost(OtrProfile(0));
ProfileDestroyer::DestroyOTRProfileWhenAppropriate(OtrProfile(0));
EXPECT_TRUE(OtrProfile(0));
ProfileDestroyer::DestroyOTRProfileWhenAppropriate(OtrProfile(0));
EXPECT_TRUE(OtrProfile(0));
render_process_host->Cleanup();
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(OtrProfile(0));
}
// Regression for: https://crbug.com/1357476
// When two OTR profile are associated with the same original profile,
// requesting the destruction of one, was incorrectly causing the
// ProfileDestroyer to wait for the destruction of the RenderProcessHost of the
// second OTR profile.
TEST_P(ProfileDestroyerTest, MultipleOTRPRofile) {
CreateOriginalProfile();
CreateOTRProfile();
CreateOTRProfile();
CreateOTRProfile();
// Create a renderer process associated with every OTR profiles.
std::array<content::RenderProcessHost*, 3> render_process_host = {
CreatedRendererProcessHost(OtrProfile(0)),
CreatedRendererProcessHost(OtrProfile(1)),
CreatedRendererProcessHost(OtrProfile(2)),
};
// Ask for the destruction of two of them. The destruction is delayed, because
// they are kept alive by two RenderProcessHost depending on them.
ProfileDestroyer::DestroyOTRProfileWhenAppropriate(OtrProfile(0));
ProfileDestroyer::DestroyOTRProfileWhenAppropriate(OtrProfile(1));
EXPECT_TRUE(original_profile());
EXPECT_TRUE(OtrProfile(0));
EXPECT_TRUE(OtrProfile(1));
EXPECT_TRUE(OtrProfile(2));
// Destroy the RenderProcessHost keeping alive the first OTR profile.
render_process_host[0]->Cleanup();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(original_profile());
EXPECT_FALSE(OtrProfile(0));
EXPECT_TRUE(OtrProfile(1));
EXPECT_TRUE(OtrProfile(2));
// Destroy the RenderProcessHost keeping alive the second OTR profile.
render_process_host[1]->Cleanup();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(original_profile());
EXPECT_FALSE(OtrProfile(0));
EXPECT_FALSE(OtrProfile(1));
EXPECT_TRUE(OtrProfile(2));
// Destroy the third RenderProcessHost.
render_process_host[2]->Cleanup();
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(original_profile());
EXPECT_FALSE(OtrProfile(0));
EXPECT_FALSE(OtrProfile(1));
EXPECT_TRUE(OtrProfile(2));
// Allow the deletion of the last OTR profile:
ProfileDestroyer::DestroyOTRProfileWhenAppropriate(OtrProfile(2));
EXPECT_TRUE(original_profile());
EXPECT_FALSE(OtrProfile(0));
EXPECT_FALSE(OtrProfile(1));
EXPECT_FALSE(OtrProfile(2));
}
#if defined(GTEST_HAS_DEATH_TEST)
// Crash if original profile has hosts at shutdown.
TEST_P(ProfileDestroyerTest, CrashShutdownAllPendingProfilesOriginalWithHosts) {
CreateOriginalProfile();
EXPECT_TRUE(original_profile());
CreatedRendererProcessHost(original_profile());
StopKeepingAliveOriginalProfile();
EXPECT_TRUE(original_profile());
EXPECT_DEATH(ProfileDestroyer::DestroyPendingProfilesForShutdown(), "");
}
// Crash if off-the-record profile has hosts at shutdown.
TEST_P(ProfileDestroyerTest, CrashShutdownAllPendingProfilesOTRWithHosts) {
CreateOriginalProfile();
CreateOTRProfile();
EXPECT_TRUE(original_profile());
EXPECT_TRUE(OtrProfile(0));
CreatedRendererProcessHost(OtrProfile(0));
StopKeepingAliveOriginalProfile();
EXPECT_TRUE(original_profile());
EXPECT_TRUE(OtrProfile(0));
// Ask for destruction of OTR profile with hosts and expect it will crash.
EXPECT_DEATH(ProfileDestroyer::DestroyPendingProfilesForShutdown(), "");
}
#endif // defined(GTEST_HAS_DEATH_TEST)
INSTANTIATE_TEST_SUITE_P(AllOTRProfileTypes,
ProfileDestroyerTest,
/*is_primary_otr=*/testing::Bool());