Commit 7806af1c authored by Andrey Lushnikov's avatar Andrey Lushnikov Committed by Commit Bot

DevTools: untie browser context lifetime from protocol session

Currently, browser contexts created with `Target.createBrowserContext()`
method will die once the protocol session is closed. This is inconvenient
and inconsistent with headless behavior.

This patch introduces a new DevToolsBrowserContextManager class to take
care of browser context management. The instance of this class is shared
between all protocol sessions.

R=dgozman
BUG=836272

Change-Id: If8b4b542d1a861298ef417a40b44c218d04d2f22
Reviewed-on: https://chromium-review.googlesource.com/1049110
Commit-Queue: Andrey Lushnikov <lushnikov@chromium.org>
Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#556923}
parent b9ee1080
...@@ -11,8 +11,119 @@ ...@@ -11,8 +11,119 @@
#include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_navigator.h"
#include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/devtools_agent_host.h"
TargetHandler::TargetHandler(protocol::UberDispatcher* dispatcher) namespace {
: weak_factory_(this) {
class DevToolsBrowserContextManager : public BrowserListObserver {
public:
DevToolsBrowserContextManager();
protocol::Response CreateBrowserContext(std::string* out_context_id);
Profile* GetBrowserContext(const std::string& context_id);
void DisposeBrowserContext(
const std::string& context_id,
std::unique_ptr<TargetHandler::DisposeBrowserContextCallback> callback);
private:
void OnOriginalProfileDestroyed(Profile* profile);
void OnBrowserRemoved(Browser* browser) override;
base::flat_map<
std::string,
std::unique_ptr<IndependentOTRProfileManager::OTRProfileRegistration>>
registrations_;
base::flat_map<std::string,
std::unique_ptr<TargetHandler::DisposeBrowserContextCallback>>
pending_context_disposals_;
base::WeakPtrFactory<DevToolsBrowserContextManager> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(DevToolsBrowserContextManager);
};
DevToolsBrowserContextManager::DevToolsBrowserContextManager()
: weak_factory_(this) {}
Profile* DevToolsBrowserContextManager::GetBrowserContext(
const std::string& context_id) {
auto it = registrations_.find(context_id);
return it == registrations_.end() ? nullptr : it->second->profile();
}
protocol::Response DevToolsBrowserContextManager::CreateBrowserContext(
std::string* out_context_id) {
Profile* original_profile =
ProfileManager::GetActiveUserProfile()->GetOriginalProfile();
auto registration =
IndependentOTRProfileManager::GetInstance()->CreateFromOriginalProfile(
original_profile,
base::BindOnce(
&DevToolsBrowserContextManager::OnOriginalProfileDestroyed,
weak_factory_.GetWeakPtr()));
*out_context_id = registration->profile()->UniqueId();
registrations_[*out_context_id] = std::move(registration);
return protocol::Response::OK();
}
void DevToolsBrowserContextManager::DisposeBrowserContext(
const std::string& context_id,
std::unique_ptr<TargetHandler::DisposeBrowserContextCallback> callback) {
if (pending_context_disposals_.find(context_id) !=
pending_context_disposals_.end()) {
callback->sendFailure(protocol::Response::Error(
"Disposal of browser context " + context_id + " is already pending"));
return;
}
auto it = registrations_.find(context_id);
if (it == registrations_.end()) {
callback->sendFailure(protocol::Response::InvalidParams(
"Failed to find browser context with id " + context_id));
return;
}
if (pending_context_disposals_.empty())
BrowserList::AddObserver(this);
pending_context_disposals_[context_id] = std::move(callback);
Profile* profile = it->second->profile();
BrowserList::CloseAllBrowsersWithIncognitoProfile(
profile, base::DoNothing(), base::DoNothing(),
true /* skip_beforeunload */);
}
void DevToolsBrowserContextManager::OnOriginalProfileDestroyed(
Profile* profile) {
base::EraseIf(registrations_, [&profile](const auto& it) {
return it.second->profile()->GetOriginalProfile() == profile;
});
}
void DevToolsBrowserContextManager::OnBrowserRemoved(Browser* browser) {
std::string context_id = browser->profile()->UniqueId();
auto pending_disposal = pending_context_disposals_.find(context_id);
if (pending_disposal == pending_context_disposals_.end())
return;
for (auto* opened_browser : *BrowserList::GetInstance()) {
if (opened_browser->profile() == browser->profile())
return;
}
auto it = registrations_.find(context_id);
// We cannot delete immediately here: the profile might still be referenced
// during the browser tier-down process.
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE,
it->second.release());
registrations_.erase(it);
pending_disposal->second->sendSuccess();
pending_context_disposals_.erase(pending_disposal);
if (pending_context_disposals_.empty())
BrowserList::RemoveObserver(this);
}
base::LazyInstance<DevToolsBrowserContextManager>::Leaky
g_devtools_browser_context_manager;
} // namespace
TargetHandler::TargetHandler(protocol::UberDispatcher* dispatcher) {
protocol::Target::Dispatcher::wire(dispatcher, this); protocol::Target::Dispatcher::wire(dispatcher, this);
} }
...@@ -21,8 +132,6 @@ TargetHandler::~TargetHandler() { ...@@ -21,8 +132,6 @@ TargetHandler::~TargetHandler() {
ChromeDevToolsManagerDelegate::GetInstance(); ChromeDevToolsManagerDelegate::GetInstance();
if (delegate) if (delegate)
delegate->UpdateDeviceDiscovery(); delegate->UpdateDeviceDiscovery();
registrations_.clear();
BrowserList::RemoveObserver(this);
} }
protocol::Response TargetHandler::SetRemoteLocations( protocol::Response TargetHandler::SetRemoteLocations(
...@@ -55,12 +164,12 @@ protocol::Response TargetHandler::CreateTarget( ...@@ -55,12 +164,12 @@ protocol::Response TargetHandler::CreateTarget(
Profile* profile = ProfileManager::GetActiveUserProfile(); Profile* profile = ProfileManager::GetActiveUserProfile();
if (browser_context_id.isJust()) { if (browser_context_id.isJust()) {
std::string profile_id = browser_context_id.fromJust(); std::string profile_id = browser_context_id.fromJust();
auto it = registrations_.find(profile_id); profile =
if (it == registrations_.end()) { g_devtools_browser_context_manager.Get().GetBrowserContext(profile_id);
if (!profile) {
return protocol::Response::Error( return protocol::Response::Error(
"Failed to find browser context with id " + profile_id); "Failed to find browser context with id " + profile_id);
} }
profile = it->second->profile();
} }
NavigateParams params(profile, GURL(url), ui::PAGE_TRANSITION_AUTO_TOPLEVEL); NavigateParams params(profile, GURL(url), ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
...@@ -93,68 +202,14 @@ protocol::Response TargetHandler::CreateTarget( ...@@ -93,68 +202,14 @@ protocol::Response TargetHandler::CreateTarget(
protocol::Response TargetHandler::CreateBrowserContext( protocol::Response TargetHandler::CreateBrowserContext(
std::string* out_context_id) { std::string* out_context_id) {
Profile* original_profile = return g_devtools_browser_context_manager.Get().CreateBrowserContext(
ProfileManager::GetActiveUserProfile()->GetOriginalProfile(); out_context_id);
auto registration =
IndependentOTRProfileManager::GetInstance()->CreateFromOriginalProfile(
original_profile,
base::BindOnce(&TargetHandler::OnOriginalProfileDestroyed,
weak_factory_.GetWeakPtr()));
*out_context_id = registration->profile()->UniqueId();
registrations_[*out_context_id] = std::move(registration);
return protocol::Response::OK();
}
void TargetHandler::OnOriginalProfileDestroyed(Profile* profile) {
base::EraseIf(registrations_, [&profile](const auto& it) {
return it.second->profile()->GetOriginalProfile() == profile;
});
} }
void TargetHandler::DisposeBrowserContext( void TargetHandler::DisposeBrowserContext(
const std::string& context_id, const std::string& context_id,
std::unique_ptr<DisposeBrowserContextCallback> callback) { std::unique_ptr<DisposeBrowserContextCallback> callback) {
if (pending_context_disposals_.find(context_id) != g_devtools_browser_context_manager.Get().DisposeBrowserContext(
pending_context_disposals_.end()) { context_id, std::move(callback));
callback->sendFailure(protocol::Response::Error(
"Disposal of browser context " + context_id + " is already pending"));
return;
}
auto it = registrations_.find(context_id);
if (it == registrations_.end()) {
callback->sendFailure(protocol::Response::Error(
"Failed to find browser context with id " + context_id));
return;
}
if (pending_context_disposals_.empty())
BrowserList::AddObserver(this);
pending_context_disposals_[context_id] = std::move(callback);
Profile* profile = it->second->profile();
BrowserList::CloseAllBrowsersWithIncognitoProfile(
profile, base::DoNothing(), base::DoNothing(),
true /* skip_beforeunload */);
} }
void TargetHandler::OnBrowserRemoved(Browser* browser) {
std::string context_id = browser->profile()->UniqueId();
auto pending_disposal = pending_context_disposals_.find(context_id);
if (pending_disposal == pending_context_disposals_.end())
return;
for (auto* opened_browser : *BrowserList::GetInstance()) {
if (opened_browser->profile() == browser->profile())
return;
}
auto it = registrations_.find(context_id);
// We cannot delete immediately here: the profile might still be referenced
// during the browser tier-down process.
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE,
it->second.release());
registrations_.erase(it);
pending_disposal->second->sendSuccess();
pending_context_disposals_.erase(pending_disposal);
if (pending_context_disposals_.empty())
BrowserList::RemoveObserver(this);
}
...@@ -17,8 +17,7 @@ ...@@ -17,8 +17,7 @@
using RemoteLocations = std::set<net::HostPortPair>; using RemoteLocations = std::set<net::HostPortPair>;
class TargetHandler : public protocol::Target::Backend, class TargetHandler : public protocol::Target::Backend {
public BrowserListObserver {
public: public:
explicit TargetHandler(protocol::UberDispatcher* dispatcher); explicit TargetHandler(protocol::UberDispatcher* dispatcher);
~TargetHandler() override; ~TargetHandler() override;
...@@ -42,21 +41,8 @@ class TargetHandler : public protocol::Target::Backend, ...@@ -42,21 +41,8 @@ class TargetHandler : public protocol::Target::Backend,
std::unique_ptr<DisposeBrowserContextCallback> callback) override; std::unique_ptr<DisposeBrowserContextCallback> callback) override;
private: private:
void OnOriginalProfileDestroyed(Profile* profile);
void OnBrowserRemoved(Browser* browser) override;
base::flat_map<
std::string,
std::unique_ptr<IndependentOTRProfileManager::OTRProfileRegistration>>
registrations_;
base::flat_map<std::string, std::unique_ptr<DisposeBrowserContextCallback>>
pending_context_disposals_;
RemoteLocations remote_locations_; RemoteLocations remote_locations_;
base::WeakPtrFactory<TargetHandler> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(TargetHandler); DISALLOW_COPY_AND_ASSIGN(TargetHandler);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment