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..bd4c1764014d64fb7b4b4423adbe149acfa40e28 100644 |
--- a/chrome/browser/notifications/notification_platform_bridge_linux.cc |
+++ b/chrome/browser/notifications/notification_platform_bridge_linux.cc |
@@ -88,7 +88,6 @@ void ForwardNotificationOperationOnUiThread( |
int action_index, |
const std::string& profile_id, |
bool is_incognito) { |
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
ProfileManager* profile_manager = g_browser_process->profile_manager(); |
profile_manager->LoadProfile( |
@@ -127,12 +126,29 @@ class NotificationPlatformBridgeLinuxImpl |
public content::NotificationObserver, |
public base::RefCountedThreadSafe<NotificationPlatformBridgeLinuxImpl> { |
public: |
- NotificationPlatformBridgeLinuxImpl() |
- : task_runner_(base::CreateSingleThreadTaskRunnerWithTraits( |
- base::TaskTraits().MayBlock().WithPriority( |
- base::TaskPriority::USER_BLOCKING))) { |
+ NotificationPlatformBridgeLinuxImpl( |
+ scoped_refptr<base::SequencedTaskRunner> notification_task_runner, |
+ scoped_refptr<base::SequencedTaskRunner> ui_task_runner, |
+ scoped_refptr<dbus::Bus> bus) |
+ : notification_task_runner_(notification_task_runner), |
+ ui_task_runner_(ui_task_runner), |
+ bus_(bus) { |
+ if (!notification_task_runner_) { |
+ notification_task_runner_ = base::CreateSingleThreadTaskRunnerWithTraits( |
+ base::TaskTraits().MayBlock().WithPriority( |
+ base::TaskPriority::USER_BLOCKING)); |
+ } |
+ DCHECK(ui_task_runner_); |
registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING, |
content::NotificationService::AllSources()); |
+ } |
+ |
+ // Init() cannot be called 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 InitAfterConstructor() { |
PostTaskToTaskRunnerThread( |
base::BindOnce(&NotificationPlatformBridgeLinuxImpl::Init, this)); |
} |
@@ -142,7 +158,7 @@ class NotificationPlatformBridgeLinuxImpl |
const std::string& profile_id, |
bool is_incognito, |
const Notification& notification) override { |
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
// Notifications contain gfx::Image's which have reference counts |
// that are not thread safe. Because of this, we duplicate the |
// notification and its images. Wrap the notification in a |
@@ -163,7 +179,7 @@ class NotificationPlatformBridgeLinuxImpl |
void Close(const std::string& profile_id, |
const std::string& notification_id) override { |
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
PostTaskToTaskRunnerThread( |
base::BindOnce(&NotificationPlatformBridgeLinuxImpl::CloseOnTaskRunner, |
this, profile_id, notification_id)); |
@@ -173,14 +189,14 @@ class NotificationPlatformBridgeLinuxImpl |
const std::string& profile_id, |
bool incognito, |
const GetDisplayedNotificationsCallback& callback) const override { |
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
PostTaskToTaskRunnerThread(base::BindOnce( |
&NotificationPlatformBridgeLinuxImpl::GetDisplayedOnTaskRunner, this, |
profile_id, incognito, callback)); |
} |
void SetReadyCallback(NotificationBridgeReadyCallback callback) override { |
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
if (connected_.has_value()) { |
std::move(callback).Run(connected_.value()); |
} else { |
@@ -188,6 +204,15 @@ class NotificationPlatformBridgeLinuxImpl |
} |
} |
+ void CleanUp() { |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
+ if (cleanup_posted_) |
+ return; |
+ PostTaskToTaskRunnerThread(base::BindOnce( |
+ &NotificationPlatformBridgeLinuxImpl::CleanUpOnTaskRunner, this)); |
+ cleanup_posted_ = true; |
+ } |
+ |
private: |
friend class base::RefCountedThreadSafe<NotificationPlatformBridgeLinuxImpl>; |
@@ -238,14 +263,16 @@ class NotificationPlatformBridgeLinuxImpl |
}; |
~NotificationPlatformBridgeLinuxImpl() override { |
+ DCHECK(cleanup_posted_); |
DCHECK(!bus_); |
+ DCHECK(!notification_proxy_); |
DCHECK(notifications_.empty()); |
} |
void Observe(int type, |
const content::NotificationSource& source, |
const content::NotificationDetails& details) override { |
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type); |
// The browser process is about to exit. Post the CleanUp() task |
// while we still can. |
@@ -253,27 +280,30 @@ class NotificationPlatformBridgeLinuxImpl |
} |
void PostTaskToUiThread(base::OnceClosure closure) const { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
- bool success = content::BrowserThread::PostTask( |
- content::BrowserThread::UI, FROM_HERE, std::move(closure)); |
+ DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
+ DCHECK(ui_task_runner_); |
+ bool success = ui_task_runner_->PostTask(FROM_HERE, std::move(closure)); |
DCHECK(success); |
} |
void PostTaskToTaskRunnerThread(base::OnceClosure closure) const { |
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
- DCHECK(task_runner_); |
- bool success = task_runner_->PostTask(FROM_HERE, std::move(closure)); |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
+ DCHECK(notification_task_runner_); |
+ bool success = |
+ notification_task_runner_->PostTask(FROM_HERE, std::move(closure)); |
DCHECK(success); |
} |
// Sets up the D-Bus connection. |
void Init() { |
- 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)); |
+ DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
+ 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 = notification_task_runner_; |
+ bus_ = make_scoped_refptr(new dbus::Bus(bus_options)); |
+ } |
notification_proxy_ = |
bus_->GetObjectProxy(kFreedesktopNotificationsName, |
@@ -300,17 +330,8 @@ 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()); |
+ DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
bus_->ShutdownAndBlock(); |
bus_ = nullptr; |
notification_proxy_ = nullptr; |
@@ -323,7 +344,7 @@ class NotificationPlatformBridgeLinuxImpl |
const std::string& profile_id, |
bool is_incognito, |
std::unique_ptr<Notification> notification) { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
+ DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
NotificationData* data = |
FindNotificationData(notification_id, profile_id, is_incognito); |
if (data) { |
@@ -431,7 +452,7 @@ class NotificationPlatformBridgeLinuxImpl |
// Makes the "CloseNotification" call to D-Bus. |
void CloseOnTaskRunner(const std::string& profile_id, |
const std::string& notification_id) { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
+ DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
std::vector<NotificationData*> to_erase; |
for (const auto& pair : notifications_) { |
NotificationData* data = pair.first; |
@@ -453,7 +474,7 @@ class NotificationPlatformBridgeLinuxImpl |
const std::string& profile_id, |
bool incognito, |
const GetDisplayedNotificationsCallback& callback) const { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
+ DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
// TODO(thomasanderson): Implement. |
PostTaskToUiThread(base::BindOnce( |
callback, base::Passed(base::MakeUnique<std::set<std::string>>()), |
@@ -463,7 +484,7 @@ class NotificationPlatformBridgeLinuxImpl |
NotificationData* FindNotificationData(const std::string& notification_id, |
const std::string& profile_id, |
bool is_incognito) { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
+ DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
for (const auto& pair : notifications_) { |
NotificationData* data = pair.first; |
if (data->notification_id == notification_id && |
@@ -477,7 +498,7 @@ class NotificationPlatformBridgeLinuxImpl |
} |
NotificationData* FindNotificationData(uint32_t dbus_id) { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
+ DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
for (const auto& pair : notifications_) { |
NotificationData* data = pair.first; |
if (data->dbus_id == dbus_id) |
@@ -490,7 +511,7 @@ class NotificationPlatformBridgeLinuxImpl |
void ForwardNotificationOperation(NotificationData* data, |
NotificationCommon::Operation operation, |
int action_index) { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
+ DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
PostTaskToUiThread(base::BindOnce( |
ForwardNotificationOperationOnUiThread, operation, |
data->notification_type, data->origin_url.spec(), data->notification_id, |
@@ -498,7 +519,7 @@ class NotificationPlatformBridgeLinuxImpl |
} |
void OnActionInvoked(dbus::Signal* signal) { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
+ DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
dbus::MessageReader reader(signal); |
uint32_t dbus_id; |
if (!reader.PopUint32(&dbus_id)) |
@@ -529,7 +550,7 @@ class NotificationPlatformBridgeLinuxImpl |
} |
void OnNotificationClosed(dbus::Signal* signal) { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
+ DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
dbus::MessageReader reader(signal); |
uint32_t dbus_id; |
if (!reader.PopUint32(&dbus_id)) |
@@ -546,7 +567,7 @@ class NotificationPlatformBridgeLinuxImpl |
// Called once the connection has been set up (or not). |success| |
// indicates the connection is ready to use. |
void OnConnectionInitializationFinishedOnUiThread(bool success) { |
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+ DCHECK(ui_task_runner_->RunsTasksOnCurrentThread()); |
connected_ = success; |
for (auto& callback : on_connected_callbacks_) |
std::move(callback).Run(success); |
@@ -556,7 +577,7 @@ class NotificationPlatformBridgeLinuxImpl |
} |
void OnConnectionInitializationFinishedOnTaskRunner(bool success) { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
+ DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
PostTaskToUiThread( |
base::BindOnce(&NotificationPlatformBridgeLinuxImpl:: |
OnConnectionInitializationFinishedOnUiThread, |
@@ -566,7 +587,7 @@ class NotificationPlatformBridgeLinuxImpl |
void OnSignalConnected(const std::string& interface_name, |
const std::string& signal_name, |
bool success) { |
- DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
+ DCHECK(notification_task_runner_->RunsTasksOnCurrentThread()); |
if (!success) { |
OnConnectionInitializationFinishedOnTaskRunner(false); |
return; |
@@ -577,7 +598,7 @@ class NotificationPlatformBridgeLinuxImpl |
////////////////////////////////////////////////////////////////////////////// |
// Members used only on the UI thread. |
- scoped_refptr<base::SequencedTaskRunner> task_runner_; |
+ scoped_refptr<base::SequencedTaskRunner> notification_task_runner_; |
content::NotificationRegistrar registrar_; |
@@ -591,6 +612,8 @@ class NotificationPlatformBridgeLinuxImpl |
////////////////////////////////////////////////////////////////////////////// |
// Members used only on the task runner thread. |
+ scoped_refptr<base::SequencedTaskRunner> ui_task_runner_; |
+ |
scoped_refptr<dbus::Bus> bus_; |
dbus::ObjectProxy* notification_proxy_ = nullptr; |
@@ -609,7 +632,23 @@ class NotificationPlatformBridgeLinuxImpl |
}; |
NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux() |
- : impl_(new NotificationPlatformBridgeLinuxImpl()) {} |
+ : NotificationPlatformBridgeLinux( |
+ nullptr, |
+ content::BrowserThread::GetTaskRunnerForThread( |
+ content::BrowserThread::UI), |
+ nullptr) { |
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
+} |
+ |
+NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux( |
+ scoped_refptr<base::SequencedTaskRunner> notification_task_runner, |
+ scoped_refptr<base::SequencedTaskRunner> ui_task_runner, |
+ scoped_refptr<dbus::Bus> bus) |
+ : impl_(new NotificationPlatformBridgeLinuxImpl(notification_task_runner, |
+ ui_task_runner, |
+ bus)) { |
+ impl_->InitAfterConstructor(); |
+} |
NotificationPlatformBridgeLinux::~NotificationPlatformBridgeLinux() = default; |
@@ -640,3 +679,7 @@ void NotificationPlatformBridgeLinux::SetReadyCallback( |
NotificationBridgeReadyCallback callback) { |
impl_->SetReadyCallback(std::move(callback)); |
} |
+ |
+void NotificationPlatformBridgeLinux::CleanUp() { |
+ impl_->CleanUp(); |
+} |