Commit 95570f3a authored by Bo Liu's avatar Bo Liu Committed by Commit Bot

Allow shutdown GPU when not in use

There are roughly two changes in this CL.

First is in CompositorImpl and BrowserGpuChannelHostFactory to drop the
gpu channel from the browser process when all CompositorImpls are
destroyed. BGCHF will check if it has the only reference to the
GpuChannelHost, and if so, destroy it. The check is performed in
CompositorImpl destructor to minimize impact to chrome; it is possible
to consider checking when CompositorImpl becomes invisible in the
future.

Second piece is GpuChannelManager in the GPU process will send a message
when all GpuChannels are destroyed. This message is passed to
GpuHostImpl, which will has a timeout of 10s. If there are no pending
or new establish channel requests in this time, then it will tell
GpuProcessHost. GpuProcessHost will give the content embedder a chance
to decide whether to kill the GPU process, and if yes, shutdown
the GPU process.

There are different GPU shutdown paths. This implementation just
deletes GpuProcessHost. The benefit over paths that tell the GPU process
to quit its main loop is deleting GpuProcessHost can guarantee no
trasient failures. All establish channel request are routed through the
browser IO thread. GpuHostImpl makes sure to only shutdown when there
are no requests and the GpuProcessHost is deleted synchrnously on the IO
thread. So subsequent requests will start by creating a new
GpuProcessHost and launching a new GPU process.

On Android, deleting GpuProcessHost will remove all bindings to the GPU
process, at which point Android OS will kill the GPU process; most
desktop platforms will send sigterm, then after a timeout, sigkill to
the GPU process. This does not involve cleanly exiting the GPU main
loop, which in the past has caused crashes.

Enable this behavior in weblayer, which does not use any other
gpu-hosted services.

Bug: 1058509
Change-Id: I81055a118d0e9b3f7e8ed8203780ad1b124e3f6c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2102592
Commit-Queue: Bo <boliu@chromium.org>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarkylechar <kylechar@chromium.org>
Reviewed-by: default avatarKhushal <khushalsagar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#750780}
parent 18d5be86
...@@ -206,6 +206,8 @@ void GpuHostImpl::EstablishGpuChannel(int client_id, ...@@ -206,6 +206,8 @@ void GpuHostImpl::EstablishGpuChannel(int client_id,
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
TRACE_EVENT0("gpu", "GpuHostImpl::EstablishGpuChannel"); TRACE_EVENT0("gpu", "GpuHostImpl::EstablishGpuChannel");
shutdown_timeout_.Stop();
// If GPU features are already blacklisted, no need to establish the channel. // If GPU features are already blacklisted, no need to establish the channel.
if (!delegate_->GpuAccessAllowed()) { if (!delegate_->GpuAccessAllowed()) {
DVLOG(1) << "GPU blacklisted, refusing to open a GPU channel."; DVLOG(1) << "GPU blacklisted, refusing to open a GPU channel.";
...@@ -456,6 +458,22 @@ void GpuHostImpl::DidDestroyChannel(int32_t client_id) { ...@@ -456,6 +458,22 @@ void GpuHostImpl::DidDestroyChannel(int32_t client_id) {
client_id_to_shader_cache_.erase(client_id); client_id_to_shader_cache_.erase(client_id);
} }
void GpuHostImpl::DidDestroyAllChannels() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!channel_requests_.empty())
return;
constexpr base::TimeDelta kShutDownTimeout = base::TimeDelta::FromSeconds(10);
shutdown_timeout_.Start(FROM_HERE, kShutDownTimeout,
base::BindOnce(&GpuHostImpl::MaybeShutdownGpuProcess,
base::Unretained(this)));
}
void GpuHostImpl::MaybeShutdownGpuProcess() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(channel_requests_.empty());
delegate_->MaybeShutdownGpuProcess();
}
void GpuHostImpl::DidLoseContext(bool offscreen, void GpuHostImpl::DidLoseContext(bool offscreen,
gpu::error::ContextLostReason reason, gpu::error::ContextLostReason reason,
const GURL& active_url) { const GURL& active_url) {
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "base/optional.h" #include "base/optional.h"
#include "base/process/process_handle.h" #include "base/process/process_handle.h"
#include "base/sequence_checker.h" #include "base/sequence_checker.h"
#include "base/timer/timer.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "components/discardable_memory/public/mojom/discardable_shared_memory_manager.mojom.h" #include "components/discardable_memory/public/mojom/discardable_shared_memory_manager.mojom.h"
#include "components/ui_devtools/buildflags.h" #include "components/ui_devtools/buildflags.h"
...@@ -65,6 +66,7 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost { ...@@ -65,6 +66,7 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost {
const gpu::GpuExtraInfo& gpu_extra_info) = 0; const gpu::GpuExtraInfo& gpu_extra_info) = 0;
virtual void DidFailInitialize() = 0; virtual void DidFailInitialize() = 0;
virtual void DidCreateContextSuccessfully() = 0; virtual void DidCreateContextSuccessfully() = 0;
virtual void MaybeShutdownGpuProcess() = 0;
#if defined(OS_WIN) #if defined(OS_WIN)
virtual void DidUpdateOverlayInfo(const gpu::OverlayInfo& overlay_info) = 0; virtual void DidUpdateOverlayInfo(const gpu::OverlayInfo& overlay_info) = 0;
#endif #endif
...@@ -200,6 +202,7 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost { ...@@ -200,6 +202,7 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost {
void OnChannelEstablished(int client_id, void OnChannelEstablished(int client_id,
mojo::ScopedMessagePipeHandle channel_handle); mojo::ScopedMessagePipeHandle channel_handle);
void MaybeShutdownGpuProcess();
// mojom::GpuHost: // mojom::GpuHost:
void DidInitialize( void DidInitialize(
...@@ -214,6 +217,7 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost { ...@@ -214,6 +217,7 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost {
void DidCreateOffscreenContext(const GURL& url) override; void DidCreateOffscreenContext(const GURL& url) override;
void DidDestroyOffscreenContext(const GURL& url) override; void DidDestroyOffscreenContext(const GURL& url) override;
void DidDestroyChannel(int32_t client_id) override; void DidDestroyChannel(int32_t client_id) override;
void DidDestroyAllChannels() override;
void DidLoseContext(bool offscreen, void DidLoseContext(bool offscreen,
gpu::error::ContextLostReason reason, gpu::error::ContextLostReason reason,
const GURL& active_url) override; const GURL& active_url) override;
...@@ -266,6 +270,8 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost { ...@@ -266,6 +270,8 @@ class VIZ_HOST_EXPORT GpuHostImpl : public mojom::GpuHost {
// service, but haven't heard back about yet. // service, but haven't heard back about yet.
base::queue<EstablishChannelCallback> channel_requests_; base::queue<EstablishChannelCallback> channel_requests_;
base::OneShotTimer shutdown_timeout_;
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<GpuHostImpl> weak_ptr_factory_{this}; base::WeakPtrFactory<GpuHostImpl> weak_ptr_factory_{this};
......
...@@ -730,6 +730,11 @@ void GpuServiceImpl::DidDestroyChannel(int client_id) { ...@@ -730,6 +730,11 @@ void GpuServiceImpl::DidDestroyChannel(int client_id) {
gpu_host_->DidDestroyChannel(client_id); gpu_host_->DidDestroyChannel(client_id);
} }
void GpuServiceImpl::DidDestroyAllChannels() {
DCHECK(main_runner_->BelongsToCurrentThread());
gpu_host_->DidDestroyAllChannels();
}
void GpuServiceImpl::DidDestroyOffscreenContext(const GURL& active_url) { void GpuServiceImpl::DidDestroyOffscreenContext(const GURL& active_url) {
DCHECK(main_runner_->BelongsToCurrentThread()); DCHECK(main_runner_->BelongsToCurrentThread());
gpu_host_->DidDestroyOffscreenContext(active_url); gpu_host_->DidDestroyOffscreenContext(active_url);
......
...@@ -197,6 +197,7 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate, ...@@ -197,6 +197,7 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
void DidCreateContextSuccessfully() override; void DidCreateContextSuccessfully() override;
void DidCreateOffscreenContext(const GURL& active_url) override; void DidCreateOffscreenContext(const GURL& active_url) override;
void DidDestroyChannel(int client_id) override; void DidDestroyChannel(int client_id) override;
void DidDestroyAllChannels() override;
void DidDestroyOffscreenContext(const GURL& active_url) override; void DidDestroyOffscreenContext(const GURL& active_url) override;
void DidLoseContext(bool offscreen, void DidLoseContext(bool offscreen,
gpu::error::ContextLostReason reason, gpu::error::ContextLostReason reason,
......
...@@ -261,6 +261,15 @@ void BrowserGpuChannelHostFactory::Terminate() { ...@@ -261,6 +261,15 @@ void BrowserGpuChannelHostFactory::Terminate() {
instance_ = nullptr; instance_ = nullptr;
} }
void BrowserGpuChannelHostFactory::MaybeCloseChannel() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!gpu_channel_ || !gpu_channel_->HasOneRef())
return;
gpu_channel_->DestroyChannel();
gpu_channel_ = nullptr;
}
void BrowserGpuChannelHostFactory::CloseChannel() { void BrowserGpuChannelHostFactory::CloseChannel() {
if (gpu_channel_) { if (gpu_channel_) {
gpu_channel_->DestroyChannel(); gpu_channel_->DestroyChannel();
......
...@@ -38,6 +38,11 @@ class CONTENT_EXPORT BrowserGpuChannelHostFactory ...@@ -38,6 +38,11 @@ class CONTENT_EXPORT BrowserGpuChannelHostFactory
gpu::GpuChannelHost* GetGpuChannel(); gpu::GpuChannelHost* GetGpuChannel();
int GetGpuChannelId() { return gpu_client_id_; } int GetGpuChannelId() { return gpu_client_id_; }
// Close the channel if there is no usage other usage of the channel.
// Note this is different from |CloseChannel| as this can be called at
// any point. The next EstablishGpuChannel will simply return a new channel.
void MaybeCloseChannel();
// Closes the channel to the GPU process. This should be called before the IO // Closes the channel to the GPU process. This should be called before the IO
// thread stops. // thread stops.
void CloseChannel(); void CloseChannel();
......
...@@ -1014,6 +1014,13 @@ void GpuProcessHost::DidCreateContextSuccessfully() { ...@@ -1014,6 +1014,13 @@ void GpuProcessHost::DidCreateContextSuccessfully() {
#endif #endif
} }
void GpuProcessHost::MaybeShutdownGpuProcess() {
if (!in_process_ &&
GetContentClient()->browser()->CanShutdownGpuProcessNowOnIOThread()) {
delete this;
}
}
#if defined(OS_WIN) #if defined(OS_WIN)
void GpuProcessHost::DidUpdateOverlayInfo( void GpuProcessHost::DidUpdateOverlayInfo(
const gpu::OverlayInfo& overlay_info) { const gpu::OverlayInfo& overlay_info) {
......
...@@ -149,6 +149,7 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate, ...@@ -149,6 +149,7 @@ class GpuProcessHost : public BrowserChildProcessHostDelegate,
const gpu::GpuExtraInfo& gpu_extra_info) override; const gpu::GpuExtraInfo& gpu_extra_info) override;
void DidFailInitialize() override; void DidFailInitialize() override;
void DidCreateContextSuccessfully() override; void DidCreateContextSuccessfully() override;
void MaybeShutdownGpuProcess() override;
#if defined(OS_WIN) #if defined(OS_WIN)
void DidUpdateOverlayInfo(const gpu::OverlayInfo& overlay_info) override; void DidUpdateOverlayInfo(const gpu::OverlayInfo& overlay_info) override;
#endif #endif
......
...@@ -44,8 +44,8 @@ ...@@ -44,8 +44,8 @@
#include "components/viz/common/surfaces/local_surface_id_allocation.h" #include "components/viz/common/surfaces/local_surface_id_allocation.h"
#include "components/viz/common/viz_utils.h" #include "components/viz/common/viz_utils.h"
#include "components/viz/host/host_display_client.h" #include "components/viz/host/host_display_client.h"
#include "content/browser/browser_main_loop.h"
#include "content/browser/compositor/surface_utils.h" #include "content/browser/compositor/surface_utils.h"
#include "content/browser/gpu/browser_gpu_channel_host_factory.h"
#include "content/browser/gpu/compositor_util.h" #include "content/browser/gpu/compositor_util.h"
#include "content/browser/gpu/gpu_process_host.h" #include "content/browser/gpu/gpu_process_host.h"
#include "content/browser/renderer_host/compositor_dependencies_android.h" #include "content/browser/renderer_host/compositor_dependencies_android.h"
...@@ -161,7 +161,7 @@ void CreateContextProviderAfterGpuChannelEstablished( ...@@ -161,7 +161,7 @@ void CreateContextProviderAfterGpuChannelEstablished(
} }
gpu::GpuChannelEstablishFactory* factory = gpu::GpuChannelEstablishFactory* factory =
BrowserMainLoop::GetInstance()->gpu_channel_establish_factory(); BrowserGpuChannelHostFactory::instance();
int32_t stream_id = kGpuStreamIdDefault; int32_t stream_id = kGpuStreamIdDefault;
gpu::SchedulingPriority stream_priority = kGpuStreamPriorityUI; gpu::SchedulingPriority stream_priority = kGpuStreamPriorityUI;
...@@ -241,11 +241,9 @@ void Compositor::CreateContextProvider( ...@@ -241,11 +241,9 @@ void Compositor::CreateContextProvider(
gpu::SharedMemoryLimits shared_memory_limits, gpu::SharedMemoryLimits shared_memory_limits,
ContextProviderCallback callback) { ContextProviderCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserMainLoop::GetInstance() BrowserGpuChannelHostFactory::instance()->EstablishGpuChannel(
->gpu_channel_establish_factory() base::BindOnce(&CreateContextProviderAfterGpuChannelEstablished, handle,
->EstablishGpuChannel(base::BindOnce( attributes, shared_memory_limits, std::move(callback)));
&CreateContextProviderAfterGpuChannelEstablished, handle, attributes,
shared_memory_limits, std::move(callback)));
} }
// static // static
...@@ -277,6 +275,8 @@ CompositorImpl::~CompositorImpl() { ...@@ -277,6 +275,8 @@ CompositorImpl::~CompositorImpl() {
DetachRootWindow(); DetachRootWindow();
// Clean-up any surface references. // Clean-up any surface references.
SetSurface(nullptr, false); SetSurface(nullptr, false);
BrowserGpuChannelHostFactory::instance()->MaybeCloseChannel();
} }
void CompositorImpl::DetachRootWindow() { void CompositorImpl::DetachRootWindow() {
...@@ -561,11 +561,8 @@ void CompositorImpl::HandlePendingLayerTreeFrameSinkRequest() { ...@@ -561,11 +561,8 @@ void CompositorImpl::HandlePendingLayerTreeFrameSinkRequest() {
return; return;
DCHECK(surface_handle_ != gpu::kNullSurfaceHandle); DCHECK(surface_handle_ != gpu::kNullSurfaceHandle);
BrowserMainLoop::GetInstance() BrowserGpuChannelHostFactory::instance()->EstablishGpuChannel(base::BindOnce(
->gpu_channel_establish_factory() &CompositorImpl::OnGpuChannelEstablished, weak_factory_.GetWeakPtr()));
->EstablishGpuChannel(
base::BindOnce(&CompositorImpl::OnGpuChannelEstablished,
weak_factory_.GetWeakPtr()));
} }
void CompositorImpl::OnGpuChannelEstablished( void CompositorImpl::OnGpuChannelEstablished(
...@@ -594,7 +591,7 @@ void CompositorImpl::OnGpuChannelEstablished( ...@@ -594,7 +591,7 @@ void CompositorImpl::OnGpuChannelEstablished(
DCHECK_NE(surface_handle_, gpu::kNullSurfaceHandle); DCHECK_NE(surface_handle_, gpu::kNullSurfaceHandle);
gpu::GpuChannelEstablishFactory* factory = gpu::GpuChannelEstablishFactory* factory =
BrowserMainLoop::GetInstance()->gpu_channel_establish_factory(); BrowserGpuChannelHostFactory::instance();
int32_t stream_id = kGpuStreamIdDefault; int32_t stream_id = kGpuStreamIdDefault;
gpu::SchedulingPriority stream_priority = kGpuStreamPriorityUI; gpu::SchedulingPriority stream_priority = kGpuStreamPriorityUI;
...@@ -828,9 +825,8 @@ void CompositorImpl::InitializeVizLayerTreeFrameSink( ...@@ -828,9 +825,8 @@ void CompositorImpl::InitializeVizLayerTreeFrameSink(
// Create LayerTreeFrameSink with the browser end of CompositorFrameSink. // Create LayerTreeFrameSink with the browser end of CompositorFrameSink.
cc::mojo_embedder::AsyncLayerTreeFrameSink::InitParams params; cc::mojo_embedder::AsyncLayerTreeFrameSink::InitParams params;
params.compositor_task_runner = task_runner; params.compositor_task_runner = task_runner;
params.gpu_memory_buffer_manager = BrowserMainLoop::GetInstance() params.gpu_memory_buffer_manager =
->gpu_channel_establish_factory() BrowserGpuChannelHostFactory::instance()->GetGpuMemoryBufferManager();
->GetGpuMemoryBufferManager();
params.pipes.compositor_frame_sink_associated_remote = std::move(sink_remote); params.pipes.compositor_frame_sink_associated_remote = std::move(sink_remote);
params.pipes.client_receiver = std::move(client_receiver); params.pipes.client_receiver = std::move(client_receiver);
params.client_name = kBrowser; params.client_name = kBrowser;
......
...@@ -89,6 +89,10 @@ bool ContentBrowserClient::AllowGpuLaunchRetryOnIOThread() { ...@@ -89,6 +89,10 @@ bool ContentBrowserClient::AllowGpuLaunchRetryOnIOThread() {
return true; return true;
} }
bool ContentBrowserClient::CanShutdownGpuProcessNowOnIOThread() {
return false;
}
GURL ContentBrowserClient::GetEffectiveURL(BrowserContext* browser_context, GURL ContentBrowserClient::GetEffectiveURL(BrowserContext* browser_context,
const GURL& url) { const GURL& url) {
DCHECK(browser_context); DCHECK(browser_context);
......
...@@ -274,6 +274,15 @@ class CONTENT_EXPORT ContentBrowserClient { ...@@ -274,6 +274,15 @@ class CONTENT_EXPORT ContentBrowserClient {
// Allow embedder control GPU process launch retry on failure behavior. // Allow embedder control GPU process launch retry on failure behavior.
virtual bool AllowGpuLaunchRetryOnIOThread(); virtual bool AllowGpuLaunchRetryOnIOThread();
// Called when GPU process is not used for compositing. Allow embedder to
// control whether to shut down the GPU process to save memory, at the cost
// of slower start up the next time GPU process is needed.
// Note this only ensures the GPU process is not used for compositing. It is
// the embedder's responsibility to ensure there are no other services hosted
// by the GPU process being used; examples include accelerated media decoders
// and encoders.
virtual bool CanShutdownGpuProcessNowOnIOThread();
// Notifies that a render process will be created. This is called before // Notifies that a render process will be created. This is called before
// the content layer adds its own BrowserMessageFilters, so that the // the content layer adds its own BrowserMessageFilters, so that the
// embedder's IPC filters have priority. // embedder's IPC filters have priority.
......
...@@ -317,6 +317,9 @@ void GpuChannelManager::RemoveChannel(int client_id) { ...@@ -317,6 +317,9 @@ void GpuChannelManager::RemoveChannel(int client_id) {
delegate_->DidDestroyChannel(client_id); delegate_->DidDestroyChannel(client_id);
gpu_channels_.erase(client_id); gpu_channels_.erase(client_id);
if (gpu_channels_.empty()) {
delegate_->DidDestroyAllChannels();
}
} }
GpuChannel* GpuChannelManager::LookupChannel(int32_t client_id) const { GpuChannel* GpuChannelManager::LookupChannel(int32_t client_id) const {
......
...@@ -37,6 +37,11 @@ class GpuChannelManagerDelegate { ...@@ -37,6 +37,11 @@ class GpuChannelManagerDelegate {
// Notification from GPU that the channel is destroyed. // Notification from GPU that the channel is destroyed.
virtual void DidDestroyChannel(int client_id) = 0; virtual void DidDestroyChannel(int client_id) = 0;
// Notification that all GPU channels are shutdown properly.
// Note this is NOT called in error conditions such as losing channel due to
// context loss, or from debug messages.
virtual void DidDestroyAllChannels() = 0;
// Tells the delegate that an offscreen context was destroyed for the provided // Tells the delegate that an offscreen context was destroyed for the provided
// |active_url|. // |active_url|.
virtual void DidDestroyOffscreenContext(const GURL& active_url) = 0; virtual void DidDestroyOffscreenContext(const GURL& active_url) = 0;
......
...@@ -34,6 +34,7 @@ class TestGpuChannelManagerDelegate : public GpuChannelManagerDelegate { ...@@ -34,6 +34,7 @@ class TestGpuChannelManagerDelegate : public GpuChannelManagerDelegate {
void DidCreateContextSuccessfully() override {} void DidCreateContextSuccessfully() override {}
void DidCreateOffscreenContext(const GURL& active_url) override {} void DidCreateOffscreenContext(const GURL& active_url) override {}
void DidDestroyChannel(int client_id) override {} void DidDestroyChannel(int client_id) override {}
void DidDestroyAllChannels() override {}
void DidDestroyOffscreenContext(const GURL& active_url) override {} void DidDestroyOffscreenContext(const GURL& active_url) override {}
void DidLoseContext(bool offscreen, void DidLoseContext(bool offscreen,
error::ContextLostReason reason, error::ContextLostReason reason,
......
...@@ -29,6 +29,9 @@ interface GpuHost { ...@@ -29,6 +29,9 @@ interface GpuHost {
DidDestroyOffscreenContext(url.mojom.Url url); DidDestroyOffscreenContext(url.mojom.Url url);
DidDestroyChannel(int32 client_id); DidDestroyChannel(int32 client_id);
// Called when all channels are destroyed by client. Not called for tearing
// down all channels due to lost context.
DidDestroyAllChannels();
DidLoseContext(bool offscreen, DidLoseContext(bool offscreen,
ContextLostReason reason, ContextLostReason reason,
url.mojom.Url active_url); url.mojom.Url active_url);
......
...@@ -236,6 +236,10 @@ ContentBrowserClientImpl::GetWebContentsViewDelegate( ...@@ -236,6 +236,10 @@ ContentBrowserClientImpl::GetWebContentsViewDelegate(
return new WebContentsViewDelegateImpl(web_contents); return new WebContentsViewDelegateImpl(web_contents);
} }
bool ContentBrowserClientImpl::CanShutdownGpuProcessNowOnIOThread() {
return true;
}
content::DevToolsManagerDelegate* content::DevToolsManagerDelegate*
ContentBrowserClientImpl::GetDevToolsManagerDelegate() { ContentBrowserClientImpl::GetDevToolsManagerDelegate() {
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
......
...@@ -35,6 +35,7 @@ class ContentBrowserClientImpl : public content::ContentBrowserClient { ...@@ -35,6 +35,7 @@ class ContentBrowserClientImpl : public content::ContentBrowserClient {
std::string GetAcceptLangs(content::BrowserContext* context) override; std::string GetAcceptLangs(content::BrowserContext* context) override;
content::WebContentsViewDelegate* GetWebContentsViewDelegate( content::WebContentsViewDelegate* GetWebContentsViewDelegate(
content::WebContents* web_contents) override; content::WebContents* web_contents) override;
bool CanShutdownGpuProcessNowOnIOThread() override;
content::DevToolsManagerDelegate* GetDevToolsManagerDelegate() override; content::DevToolsManagerDelegate* GetDevToolsManagerDelegate() override;
base::Optional<service_manager::Manifest> GetServiceManifestOverlay( base::Optional<service_manager::Manifest> GetServiceManifestOverlay(
base::StringPiece name) override; base::StringPiece name) override;
......
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