Commit a51e3935 authored by kylechar's avatar kylechar Committed by Commit Bot

Fix two Ozone initialization races.

The first race is only for Ozone DRM. In DrmDisplayHostManager
|primary_drm_device_handle_| was being accessed from multiple threads.
The value was changed by the IO thread while the OzoneUI thread was
still using it.

Change calls to GpuThreadObserver OnGpuProcessLaunched() so it happens
on the OzoneUI thread. This delays the call slightly but it removes
the possibility for a race modifying |primary_drm_device_handle_|.

The second race was with OzonePlatform::RegisterStartupCallback(). This
is called from the IO thread and it checks if there is an OzonePlatform
instance and if Ozone UI initialization has happened. If both of those
things are true, then it runs a callback immediately, otherwise it runs
a callback after those things become true. The problem is that
|g_platform_initialized_ui| was set true on the UI thread before Ozone
UI initialization was fully finished. The callback accessed a null
OzonePlatform member variable and crashed.

Make sure that |g_platform_initialized_ui| is set after initialization
is finished and that variable change is protected by the same lock used
in RegisterStartupCallback(). The lock only protects changing
|g_platform_initialized_ui|, not all of initialization, so the IO thread
won't block for an extended period.

Bug: 824809, 828407
Change-Id: I73b9404c823c9eeaaeaba99feb1e113953a5bb1b
Reviewed-on: https://chromium-review.googlesource.com/980574Reviewed-by: default avatarRobert Kroeger <rjkroege@chromium.org>
Commit-Queue: kylechar <kylechar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#548481}
parent 6f6e2a84
...@@ -322,7 +322,7 @@ void DrmDisplayHostManager::OnGpuProcessLaunched() { ...@@ -322,7 +322,7 @@ void DrmDisplayHostManager::OnGpuProcessLaunched() {
MapDevPathToSysPath(primary_graphics_card_path_); MapDevPathToSysPath(primary_graphics_card_path_);
if (!handle) { if (!handle) {
handle.reset(new DrmDeviceHandle()); handle = std::make_unique<DrmDeviceHandle>();
if (!handle->Initialize(primary_graphics_card_path_, if (!handle->Initialize(primary_graphics_card_path_,
drm_devices_[primary_graphics_card_path_])) drm_devices_[primary_graphics_card_path_]))
LOG(FATAL) << "Failed to open primary graphics card"; LOG(FATAL) << "Failed to open primary graphics card";
...@@ -331,8 +331,10 @@ void DrmDisplayHostManager::OnGpuProcessLaunched() { ...@@ -331,8 +331,10 @@ void DrmDisplayHostManager::OnGpuProcessLaunched() {
// Send the primary device first since this is used to initialize graphics // Send the primary device first since this is used to initialize graphics
// state. // state.
proxy_->GpuAddGraphicsDevice(drm_devices_[primary_graphics_card_path_], if (!proxy_->GpuAddGraphicsDevice(drm_devices_[primary_graphics_card_path_],
handle->PassFD()); handle->PassFD())) {
LOG(ERROR) << "Failed to add primary graphics device.";
}
} }
void DrmDisplayHostManager::OnGpuThreadReady() { void DrmDisplayHostManager::OnGpuThreadReady() {
......
...@@ -115,7 +115,8 @@ void DrmGpuPlatformSupportHost::RemoveGpuThreadObserver( ...@@ -115,7 +115,8 @@ void DrmGpuPlatformSupportHost::RemoveGpuThreadObserver(
} }
bool DrmGpuPlatformSupportHost::IsConnected() { bool DrmGpuPlatformSupportHost::IsConnected() {
return host_id_ >= 0 && channel_established_; base::AutoLock auto_lock(host_id_lock_);
return host_id_ >= 0;
} }
void DrmGpuPlatformSupportHost::OnGpuServiceLaunched( void DrmGpuPlatformSupportHost::OnGpuServiceLaunched(
...@@ -139,27 +140,23 @@ void DrmGpuPlatformSupportHost::OnGpuProcessLaunched( ...@@ -139,27 +140,23 @@ void DrmGpuPlatformSupportHost::OnGpuProcessLaunched(
DCHECK(!ui_runner_->BelongsToCurrentThread()); DCHECK(!ui_runner_->BelongsToCurrentThread());
TRACE_EVENT1("drm", "DrmGpuPlatformSupportHost::OnGpuProcessLaunched", TRACE_EVENT1("drm", "DrmGpuPlatformSupportHost::OnGpuProcessLaunched",
"host_id", host_id); "host_id", host_id);
host_id_ = host_id;
send_runner_ = std::move(send_runner);
send_callback_ = send_callback;
for (GpuThreadObserver& observer : gpu_thread_observers_)
observer.OnGpuProcessLaunched();
ui_runner_->PostTask( ui_runner_->PostTask(
FROM_HERE, FROM_HERE,
base::BindOnce(&DrmGpuPlatformSupportHost::OnChannelEstablished, base::BindOnce(&DrmGpuPlatformSupportHost::OnChannelEstablished,
weak_ptr_)); weak_ptr_, host_id, std::move(send_runner),
std::move(send_callback)));
} }
void DrmGpuPlatformSupportHost::OnChannelDestroyed(int host_id) { void DrmGpuPlatformSupportHost::OnChannelDestroyed(int host_id) {
TRACE_EVENT1("drm", "DrmGpuPlatformSupportHost::OnChannelDestroyed", TRACE_EVENT1("drm", "DrmGpuPlatformSupportHost::OnChannelDestroyed",
"host_id", host_id); "host_id", host_id);
if (host_id_ == host_id) { if (host_id_ == host_id) {
{
base::AutoLock auto_lock(host_id_lock_);
host_id_ = -1;
}
cursor_->ResetDrmCursorProxy(); cursor_->ResetDrmCursorProxy();
host_id_ = -1;
channel_established_ = false;
send_runner_ = nullptr; send_runner_ = nullptr;
send_callback_.Reset(); send_callback_.Reset();
for (GpuThreadObserver& observer : gpu_thread_observers_) for (GpuThreadObserver& observer : gpu_thread_observers_)
...@@ -200,9 +197,22 @@ void DrmGpuPlatformSupportHost::UnRegisterHandlerForDrmDisplayHostManager() { ...@@ -200,9 +197,22 @@ void DrmGpuPlatformSupportHost::UnRegisterHandlerForDrmDisplayHostManager() {
display_manager_ = nullptr; display_manager_ = nullptr;
} }
void DrmGpuPlatformSupportHost::OnChannelEstablished() { void DrmGpuPlatformSupportHost::OnChannelEstablished(
int host_id,
scoped_refptr<base::SingleThreadTaskRunner> send_runner,
const base::Callback<void(IPC::Message*)>& send_callback) {
DCHECK(ui_runner_->BelongsToCurrentThread());
TRACE_EVENT0("drm", "DrmGpuPlatformSupportHost::OnChannelEstablished"); TRACE_EVENT0("drm", "DrmGpuPlatformSupportHost::OnChannelEstablished");
channel_established_ = true;
send_runner_ = std::move(send_runner);
send_callback_ = send_callback;
{
base::AutoLock auto_lock(host_id_lock_);
host_id_ = host_id;
}
for (GpuThreadObserver& observer : gpu_thread_observers_)
observer.OnGpuProcessLaunched();
for (GpuThreadObserver& observer : gpu_thread_observers_) for (GpuThreadObserver& observer : gpu_thread_observers_)
observer.OnGpuThreadReady(); observer.OnGpuThreadReady();
...@@ -278,22 +288,8 @@ bool DrmGpuPlatformSupportHost::GpuRelinquishDisplayControl() { ...@@ -278,22 +288,8 @@ bool DrmGpuPlatformSupportHost::GpuRelinquishDisplayControl() {
bool DrmGpuPlatformSupportHost::GpuAddGraphicsDevice(const base::FilePath& path, bool DrmGpuPlatformSupportHost::GpuAddGraphicsDevice(const base::FilePath& path,
base::ScopedFD fd) { base::ScopedFD fd) {
IPC::Message* message = new OzoneGpuMsg_AddGraphicsDevice( return Send(new OzoneGpuMsg_AddGraphicsDevice(
path, base::FileDescriptor(std::move(fd))); path, base::FileDescriptor(std::move(fd))));
// This function may be called from two places:
// - DrmDisplayHostManager::OnGpuProcessLaunched() invoked synchronously
// by GpuProcessHost::Init() on IO thread, which is the same thread as
// |send_runner_|. In this case we can synchronously send the IPC;
// - DrmDisplayHostManager::OnAddGraphicsDevice() on UI thread. In this
// case we need to post the send task to IO thread.
if (send_runner_ && send_runner_->BelongsToCurrentThread()) {
DCHECK(!send_callback_.is_null());
send_callback_.Run(message);
return true;
}
return Send(message);
} }
bool DrmGpuPlatformSupportHost::GpuRemoveGraphicsDevice( bool DrmGpuPlatformSupportHost::GpuRemoveGraphicsDevice(
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
#include "ui/display/types/display_constants.h" #include "ui/display/types/display_constants.h"
#include "ui/gfx/native_widget_types.h" #include "ui/gfx/native_widget_types.h"
#include "ui/ozone/common/gpu/ozone_gpu_message_params.h" #include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
...@@ -99,7 +100,10 @@ class DrmGpuPlatformSupportHost : public GpuPlatformSupportHost, ...@@ -99,7 +100,10 @@ class DrmGpuPlatformSupportHost : public GpuPlatformSupportHost,
const gfx::Rect& bounds) override; const gfx::Rect& bounds) override;
private: private:
void OnChannelEstablished(); void OnChannelEstablished(
int host_id,
scoped_refptr<base::SingleThreadTaskRunner> send_runner,
const base::Callback<void(IPC::Message*)>& send_callback);
bool OnMessageReceivedForDrmDisplayHostManager(const IPC::Message& message); bool OnMessageReceivedForDrmDisplayHostManager(const IPC::Message& message);
void OnUpdateNativeDisplays( void OnUpdateNativeDisplays(
const std::vector<DisplaySnapshot_Params>& displays); const std::vector<DisplaySnapshot_Params>& displays);
...@@ -117,7 +121,7 @@ class DrmGpuPlatformSupportHost : public GpuPlatformSupportHost, ...@@ -117,7 +121,7 @@ class DrmGpuPlatformSupportHost : public GpuPlatformSupportHost,
const std::vector<OverlayCheckReturn_Params>& returns); const std::vector<OverlayCheckReturn_Params>& returns);
int host_id_ = -1; int host_id_ = -1;
bool channel_established_ = false; base::Lock host_id_lock_;
scoped_refptr<base::SingleThreadTaskRunner> ui_runner_; scoped_refptr<base::SingleThreadTaskRunner> ui_runner_;
scoped_refptr<base::SingleThreadTaskRunner> send_runner_; scoped_refptr<base::SingleThreadTaskRunner> send_runner_;
......
...@@ -7,20 +7,19 @@ ...@@ -7,20 +7,19 @@
namespace ui { namespace ui {
// Observes the channel state. // Observes the channel state. All calls should happen on the same thread that
// OzonePlatform::InitializeForUI() is called on. This can be the browser UI
// thread or the WS thread for mus/mash.
class GpuThreadObserver { class GpuThreadObserver {
public: public:
virtual ~GpuThreadObserver() {} virtual ~GpuThreadObserver() {}
// Called when the GPU process is launched. // Called when the GPU process is launched.
// This is called from browser IO thread.
virtual void OnGpuProcessLaunched() = 0; virtual void OnGpuProcessLaunched() = 0;
// Called when a GPU thread implementation has become available. // Called when a GPU thread implementation has become available.
// This is called from browser UI thread.
virtual void OnGpuThreadReady() = 0; virtual void OnGpuThreadReady() = 0;
// Called when the GPU thread implementation has ceased to be // Called when the GPU thread implementation has ceased to be
// available. // available.
// This is called from browser UI thread.
virtual void OnGpuThreadRetired() = 0; virtual void OnGpuThreadRetired() = 0;
}; };
......
...@@ -42,8 +42,11 @@ void OzonePlatform::InitializeForUI(const InitParams& args) { ...@@ -42,8 +42,11 @@ void OzonePlatform::InitializeForUI(const InitParams& args) {
EnsureInstance(); EnsureInstance();
if (g_platform_initialized_ui) if (g_platform_initialized_ui)
return; return;
g_platform_initialized_ui = true;
instance_->InitializeUI(args); instance_->InitializeUI(args);
{
base::AutoLock lock(GetOzoneInstanceLock());
g_platform_initialized_ui = true;
}
// This is deliberately created after initializing so that the platform can // This is deliberately created after initializing so that the platform can
// create its own version of DDM. // create its own version of DDM.
DeviceDataManager::CreateInstance(); DeviceDataManager::CreateInstance();
...@@ -56,8 +59,11 @@ void OzonePlatform::InitializeForGPU(const InitParams& args) { ...@@ -56,8 +59,11 @@ void OzonePlatform::InitializeForGPU(const InitParams& args) {
EnsureInstance(); EnsureInstance();
if (g_platform_initialized_gpu) if (g_platform_initialized_gpu)
return; return;
g_platform_initialized_gpu = true;
instance_->InitializeGPU(args); instance_->InitializeGPU(args);
{
base::AutoLock lock(GetOzoneInstanceLock());
g_platform_initialized_gpu = true;
}
if (!args.single_process && !instance_callback.Get().is_null()) if (!args.single_process && !instance_callback.Get().is_null())
std::move(instance_callback.Get()).Run(instance_); std::move(instance_callback.Get()).Run(instance_);
} }
......
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