Index: chrome/browser/notifications/notification_platform_bridge_linux.cc |
diff --git a/chrome/browser/notifications/notification_platform_bridge_linux.cc b/chrome/browser/notifications/notification_platform_bridge_linux.cc |
index cf71db8869d0a8a1c7c5f89085a7fd8338243d6c..3f00eb82d46e4b0e26e3b5016d241cedfca2efb5 100644 |
--- a/chrome/browser/notifications/notification_platform_bridge_linux.cc |
+++ b/chrome/browser/notifications/notification_platform_bridge_linux.cc |
@@ -127,14 +127,25 @@ class NotificationPlatformBridgeLinuxImpl |
public content::NotificationObserver, |
public base::RefCountedThreadSafe<NotificationPlatformBridgeLinuxImpl> { |
public: |
- NotificationPlatformBridgeLinuxImpl() |
- : task_runner_(base::CreateSingleThreadTaskRunnerWithTraits( |
- base::TaskTraits().MayBlock().WithPriority( |
- base::TaskPriority::USER_BLOCKING))) { |
+ explicit NotificationPlatformBridgeLinuxImpl(scoped_refptr<dbus::Bus> bus) |
+ : bus_(bus) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ task_runner_ = base::CreateSingleThreadTaskRunnerWithTraits( |
+ base::TaskTraits().MayBlock().WithPriority( |
+ base::TaskPriority::USER_BLOCKING)); |
registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING, |
content::NotificationService::AllSources()); |
- PostTaskToTaskRunnerThread( |
- base::BindOnce(&NotificationPlatformBridgeLinuxImpl::Init, this)); |
+ } |
+ |
+ // InitOnTaskRunner() cannot be posted from within the constructor |
+ // because of a race condition. The reference count for |this| |
+ // starts out as 0. Posting the Init task would increment the count |
+ // to 1. If the task finishes before the constructor returns, the |
+ // count will go to 0 and the object would be prematurely |
+ // destructed. |
+ void Init() { |
+ PostTaskToTaskRunnerThread(base::BindOnce( |
+ &NotificationPlatformBridgeLinuxImpl::InitOnTaskRunner, this)); |
} |
void Display(NotificationCommon::Type notification_type, |
@@ -188,6 +199,12 @@ class NotificationPlatformBridgeLinuxImpl |
} |
} |
+ void CleanUp() { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ PostTaskToTaskRunnerThread(base::BindOnce( |
+ &NotificationPlatformBridgeLinuxImpl::CleanUpOnTaskRunner, this)); |
+ } |
+ |
private: |
friend class base::RefCountedThreadSafe<NotificationPlatformBridgeLinuxImpl>; |
@@ -239,6 +256,7 @@ class NotificationPlatformBridgeLinuxImpl |
~NotificationPlatformBridgeLinuxImpl() override { |
DCHECK(!bus_); |
+ DCHECK(!notification_proxy_); |
DCHECK(notifications_.empty()); |
} |
@@ -267,13 +285,16 @@ class NotificationPlatformBridgeLinuxImpl |
} |
// Sets up the D-Bus connection. |
- void Init() { |
+ void InitOnTaskRunner() { |
DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
- dbus::Bus::Options bus_options; |
- bus_options.bus_type = dbus::Bus::SESSION; |
- bus_options.connection_type = dbus::Bus::PRIVATE; |
- bus_options.dbus_task_runner = task_runner_; |
- bus_ = make_scoped_refptr(new dbus::Bus(bus_options)); |
+ // |bus_| may be non-null in unit testing where a fake bus is used. |
+ if (!bus_) { |
+ dbus::Bus::Options bus_options; |
+ bus_options.bus_type = dbus::Bus::SESSION; |
+ bus_options.connection_type = dbus::Bus::PRIVATE; |
+ bus_options.dbus_task_runner = task_runner_; |
+ bus_ = make_scoped_refptr(new dbus::Bus(bus_options)); |
+ } |
notification_proxy_ = |
bus_->GetObjectProxy(kFreedesktopNotificationsName, |
@@ -300,18 +321,10 @@ class NotificationPlatformBridgeLinuxImpl |
this)); |
} |
- void CleanUp() { |
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
- if (cleanup_posted_) |
- return; |
- PostTaskToTaskRunnerThread(base::BindOnce( |
- &NotificationPlatformBridgeLinuxImpl::CleanUpOnTaskRunner, this)); |
- cleanup_posted_ = true; |
- } |
- |
void CleanUpOnTaskRunner() { |
DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
- bus_->ShutdownAndBlock(); |
+ if (bus_) |
+ bus_->ShutdownAndBlock(); |
bus_ = nullptr; |
notification_proxy_ = nullptr; |
notifications_.clear(); |
@@ -586,8 +599,6 @@ class NotificationPlatformBridgeLinuxImpl |
base::Optional<bool> connected_; |
std::vector<NotificationBridgeReadyCallback> on_connected_callbacks_; |
- bool cleanup_posted_ = false; |
- |
////////////////////////////////////////////////////////////////////////////// |
// Members used only on the task runner thread. |
@@ -609,7 +620,13 @@ class NotificationPlatformBridgeLinuxImpl |
}; |
NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux() |
- : impl_(new NotificationPlatformBridgeLinuxImpl()) {} |
+ : NotificationPlatformBridgeLinux(nullptr) {} |
+ |
+NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux( |
+ scoped_refptr<dbus::Bus> bus) |
+ : impl_(new NotificationPlatformBridgeLinuxImpl(bus)) { |
+ impl_->Init(); |
+} |
NotificationPlatformBridgeLinux::~NotificationPlatformBridgeLinux() = default; |
@@ -640,3 +657,7 @@ void NotificationPlatformBridgeLinux::SetReadyCallback( |
NotificationBridgeReadyCallback callback) { |
impl_->SetReadyCallback(std::move(callback)); |
} |
+ |
+void NotificationPlatformBridgeLinux::CleanUp() { |
+ impl_->CleanUp(); |
+} |