#include "extensions/test/extension_background_page_waiter.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "content/public/browser/browser_context.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_host.h"
#include "extensions/browser/extension_host_test_helper.h"
#include "extensions/browser/lazy_context_id.h"
#include "extensions/browser/lazy_context_task_queue.h"
#include "extensions/browser/process_manager.h"
#include "extensions/common/extension_features.h"
#include "extensions/common/manifest_handlers/background_info.h"
#include "extensions/common/manifest_handlers/incognito_info.h"
#include "extensions/common/mojom/view_type.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace extensions {
ExtensionBackgroundPageWaiter::ExtensionBackgroundPageWaiter(
content::BrowserContext* browser_context,
const Extension& extension)
: browser_context_(browser_context),
extension_(base::WrapRefCounted(&extension)) {
std::string reason;
if (!CanWaitFor(*extension_, reason))
ADD_FAILURE() << "Attempting to wait for an invalid extension: " << reason;
if (browser_context_->IsOffTheRecord() &&
!IncognitoInfo::IsSplitMode(extension_.get())) {
ADD_FAILURE() << "Trying to wait for an incognito background page from a "
<< "spanning mode extension. Use the on-the-record context.";
}
}
bool ExtensionBackgroundPageWaiter::CanWaitFor(const Extension& extension,
std::string& reason_out) {
if (extension.is_hosted_app()) {
reason_out = "ExtensionBackgroundPageWaiter does not support hosted apps.";
return false;
}
if (!BackgroundInfo::HasBackgroundPage(&extension) &&
!BackgroundInfo::IsServiceWorkerBased(&extension)) {
reason_out = "Extension has no background context.";
return false;
}
return true;
}
ExtensionBackgroundPageWaiter::~ExtensionBackgroundPageWaiter() = default;
void ExtensionBackgroundPageWaiter::WaitForBackgroundInitialized() {
if (BackgroundInfo::IsServiceWorkerBased(extension_.get())) {
WaitForBackgroundWorkerInitialized();
return;
}
DCHECK(BackgroundInfo::HasBackgroundPage(extension_.get()));
WaitForBackgroundPageInitialized();
}
void ExtensionBackgroundPageWaiter::WaitForBackgroundWorkerInitialized() {
const auto context_id =
LazyContextId::ForExtension(browser_context_, extension_.get());
LazyContextTaskQueue* task_queue = context_id.GetTaskQueue();
if (base::FeatureList::IsEnabled(
extensions_features::kOptimizeServiceWorkerStartRequests) &&
task_queue->IsReadyToRunTasks(browser_context_, extension_.get())) {
return;
}
base::RunLoop run_loop;
auto quit_loop_adapter =
[&run_loop](std::unique_ptr<LazyContextTaskQueue::ContextInfo>) {
run_loop.QuitWhenIdle();
};
task_queue->AddPendingTask(context_id,
base::BindLambdaForTesting(quit_loop_adapter));
run_loop.Run();
}
void ExtensionBackgroundPageWaiter::WaitForBackgroundPageInitialized() {
ProcessManager* process_manager = ProcessManager::Get(browser_context_);
ExtensionHost* extension_host =
process_manager->GetBackgroundHostForExtension(extension_->id());
if (extension_host) {
if (extension_host->has_loaded_once()) {
return;
}
ExtensionHostTestHelper host_helper(browser_context_, extension_->id());
host_helper.RestrictToHost(extension_host);
host_helper.WaitForHostCompletedFirstLoad();
return;
}
if (BackgroundInfo::HasLazyBackgroundPage(extension_.get()) &&
EventRouter::Get(browser_context_)
->HasRegisteredEvents(extension_->id())) {
return;
}
WaitForBackgroundOpen();
}
void ExtensionBackgroundPageWaiter::WaitForBackgroundOpen() {
ProcessManager* process_manager = ProcessManager::Get(browser_context_);
ExtensionHost* extension_host =
process_manager->GetBackgroundHostForExtension(extension_->id());
if (extension_host && !extension_host->has_loaded_once()) {
ExtensionHostTestHelper host_helper(browser_context_, extension_->id());
host_helper.RestrictToHost(extension_host);
host_helper.WaitForHostCompletedFirstLoad();
} else if (!extension_host) {
ExtensionHostTestHelper host_helper(browser_context_, extension_->id());
host_helper.RestrictToType(mojom::ViewType::kExtensionBackgroundPage);
extension_host = host_helper.WaitForHostCompletedFirstLoad();
}
if (extension_host) {
ASSERT_TRUE(extension_host->has_loaded_once());
ASSERT_EQ(extension_host,
process_manager->GetBackgroundHostForExtension(extension_->id()));
}
}
void ExtensionBackgroundPageWaiter::WaitForBackgroundClosed() {
ProcessManager* process_manager = ProcessManager::Get(browser_context_);
ExtensionHost* extension_host =
process_manager->GetBackgroundHostForExtension(extension_->id());
if (!extension_host)
return;
ExtensionHostTestHelper host_helper(browser_context_, extension_->id());
host_helper.RestrictToHost(extension_host);
host_helper.WaitForHostDestroyed();
ASSERT_FALSE(
process_manager->GetBackgroundHostForExtension(extension_->id()));
}
}