OLD | NEW |
---|---|
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/notifications/notification_platform_bridge_linux.h" | 5 #include "chrome/browser/notifications/notification_platform_bridge_linux.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/barrier_closure.h" | 9 #include "base/barrier_closure.h" |
10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
120 // static | 120 // static |
121 NotificationPlatformBridge* NotificationPlatformBridge::Create() { | 121 NotificationPlatformBridge* NotificationPlatformBridge::Create() { |
122 return new NotificationPlatformBridgeLinux(); | 122 return new NotificationPlatformBridgeLinux(); |
123 } | 123 } |
124 | 124 |
125 class NotificationPlatformBridgeLinuxImpl | 125 class NotificationPlatformBridgeLinuxImpl |
126 : public NotificationPlatformBridge, | 126 : public NotificationPlatformBridge, |
127 public content::NotificationObserver, | 127 public content::NotificationObserver, |
128 public base::RefCountedThreadSafe<NotificationPlatformBridgeLinuxImpl> { | 128 public base::RefCountedThreadSafe<NotificationPlatformBridgeLinuxImpl> { |
129 public: | 129 public: |
130 NotificationPlatformBridgeLinuxImpl() | 130 explicit NotificationPlatformBridgeLinuxImpl(scoped_refptr<dbus::Bus> bus) |
131 : task_runner_(base::CreateSingleThreadTaskRunnerWithTraits( | 131 : bus_(bus) { |
132 base::TaskTraits().MayBlock().WithPriority( | 132 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
133 base::TaskPriority::USER_BLOCKING))) { | 133 task_runner_ = base::CreateSingleThreadTaskRunnerWithTraits( |
134 base::TaskTraits().MayBlock().WithPriority( | |
135 base::TaskPriority::USER_BLOCKING)); | |
134 registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING, | 136 registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING, |
135 content::NotificationService::AllSources()); | 137 content::NotificationService::AllSources()); |
138 } | |
139 | |
140 // Init() cannot be called from within the constructor because of a | |
141 // race condition. The reference count for |this| starts out as 0. | |
142 // Posting the Init task would increment the count to 1. If the | |
143 // task finishes before the constructor returns, the count will go | |
144 // to 0 and the object would be prematurely destructed. | |
Peter Beverloo
2017/05/03 00:31:26
Thank you for the detailed comment!
| |
145 void InitAfterConstructor() { | |
Lei Zhang
2017/05/03 01:10:45
This can be Init(), and Init() can be InitOnTaskRu
Tom (Use chromium acct)
2017/05/03 01:22:17
Done.
| |
136 PostTaskToTaskRunnerThread( | 146 PostTaskToTaskRunnerThread( |
137 base::BindOnce(&NotificationPlatformBridgeLinuxImpl::Init, this)); | 147 base::BindOnce(&NotificationPlatformBridgeLinuxImpl::Init, this)); |
138 } | 148 } |
139 | 149 |
140 void Display(NotificationCommon::Type notification_type, | 150 void Display(NotificationCommon::Type notification_type, |
141 const std::string& notification_id, | 151 const std::string& notification_id, |
142 const std::string& profile_id, | 152 const std::string& profile_id, |
143 bool is_incognito, | 153 bool is_incognito, |
144 const Notification& notification) override { | 154 const Notification& notification) override { |
145 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 155 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
181 | 191 |
182 void SetReadyCallback(NotificationBridgeReadyCallback callback) override { | 192 void SetReadyCallback(NotificationBridgeReadyCallback callback) override { |
183 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 193 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
184 if (connected_.has_value()) { | 194 if (connected_.has_value()) { |
185 std::move(callback).Run(connected_.value()); | 195 std::move(callback).Run(connected_.value()); |
186 } else { | 196 } else { |
187 on_connected_callbacks_.push_back(std::move(callback)); | 197 on_connected_callbacks_.push_back(std::move(callback)); |
188 } | 198 } |
189 } | 199 } |
190 | 200 |
201 void CleanUp() { | |
202 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
203 PostTaskToTaskRunnerThread(base::BindOnce( | |
204 &NotificationPlatformBridgeLinuxImpl::CleanUpOnTaskRunner, this)); | |
205 } | |
206 | |
191 private: | 207 private: |
192 friend class base::RefCountedThreadSafe<NotificationPlatformBridgeLinuxImpl>; | 208 friend class base::RefCountedThreadSafe<NotificationPlatformBridgeLinuxImpl>; |
193 | 209 |
194 struct ResourceFile { | 210 struct ResourceFile { |
195 explicit ResourceFile(const base::FilePath& file_path) | 211 explicit ResourceFile(const base::FilePath& file_path) |
196 : file_path(file_path) {} | 212 : file_path(file_path) {} |
197 ~ResourceFile() { base::DeleteFile(file_path, false); } | 213 ~ResourceFile() { base::DeleteFile(file_path, false); } |
198 const base::FilePath file_path; | 214 const base::FilePath file_path; |
199 }; | 215 }; |
200 | 216 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
232 size_t action_end = 0; | 248 size_t action_end = 0; |
233 | 249 |
234 // Temporary resource files associated with the notification that | 250 // Temporary resource files associated with the notification that |
235 // should be cleaned up when the notification is closed or on | 251 // should be cleaned up when the notification is closed or on |
236 // shutdown. | 252 // shutdown. |
237 std::vector<std::unique_ptr<ResourceFile>> resource_files; | 253 std::vector<std::unique_ptr<ResourceFile>> resource_files; |
238 }; | 254 }; |
239 | 255 |
240 ~NotificationPlatformBridgeLinuxImpl() override { | 256 ~NotificationPlatformBridgeLinuxImpl() override { |
241 DCHECK(!bus_); | 257 DCHECK(!bus_); |
258 DCHECK(!notification_proxy_); | |
242 DCHECK(notifications_.empty()); | 259 DCHECK(notifications_.empty()); |
243 } | 260 } |
244 | 261 |
245 void Observe(int type, | 262 void Observe(int type, |
246 const content::NotificationSource& source, | 263 const content::NotificationSource& source, |
247 const content::NotificationDetails& details) override { | 264 const content::NotificationDetails& details) override { |
248 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 265 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
249 DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type); | 266 DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type); |
250 // The browser process is about to exit. Post the CleanUp() task | 267 // The browser process is about to exit. Post the CleanUp() task |
251 // while we still can. | 268 // while we still can. |
(...skipping 10 matching lines...) Expand all Loading... | |
262 void PostTaskToTaskRunnerThread(base::OnceClosure closure) const { | 279 void PostTaskToTaskRunnerThread(base::OnceClosure closure) const { |
263 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 280 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
264 DCHECK(task_runner_); | 281 DCHECK(task_runner_); |
265 bool success = task_runner_->PostTask(FROM_HERE, std::move(closure)); | 282 bool success = task_runner_->PostTask(FROM_HERE, std::move(closure)); |
266 DCHECK(success); | 283 DCHECK(success); |
267 } | 284 } |
268 | 285 |
269 // Sets up the D-Bus connection. | 286 // Sets up the D-Bus connection. |
270 void Init() { | 287 void Init() { |
271 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 288 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
272 dbus::Bus::Options bus_options; | 289 if (!bus_) { |
Lei Zhang
2017/05/03 01:10:46
May be good to mention this happens under normal c
Tom (Use chromium acct)
2017/05/03 01:22:17
Done.
| |
273 bus_options.bus_type = dbus::Bus::SESSION; | 290 dbus::Bus::Options bus_options; |
274 bus_options.connection_type = dbus::Bus::PRIVATE; | 291 bus_options.bus_type = dbus::Bus::SESSION; |
275 bus_options.dbus_task_runner = task_runner_; | 292 bus_options.connection_type = dbus::Bus::PRIVATE; |
276 bus_ = make_scoped_refptr(new dbus::Bus(bus_options)); | 293 bus_options.dbus_task_runner = task_runner_; |
294 bus_ = make_scoped_refptr(new dbus::Bus(bus_options)); | |
295 } | |
277 | 296 |
278 notification_proxy_ = | 297 notification_proxy_ = |
279 bus_->GetObjectProxy(kFreedesktopNotificationsName, | 298 bus_->GetObjectProxy(kFreedesktopNotificationsName, |
280 dbus::ObjectPath(kFreedesktopNotificationsPath)); | 299 dbus::ObjectPath(kFreedesktopNotificationsPath)); |
281 if (!notification_proxy_) { | 300 if (!notification_proxy_) { |
282 OnConnectionInitializationFinishedOnTaskRunner(false); | 301 OnConnectionInitializationFinishedOnTaskRunner(false); |
283 return; | 302 return; |
284 } | 303 } |
285 | 304 |
286 connected_signals_barrier_ = base::BarrierClosure( | 305 connected_signals_barrier_ = base::BarrierClosure( |
287 2, base::Bind(&NotificationPlatformBridgeLinuxImpl:: | 306 2, base::Bind(&NotificationPlatformBridgeLinuxImpl:: |
288 OnConnectionInitializationFinishedOnTaskRunner, | 307 OnConnectionInitializationFinishedOnTaskRunner, |
289 this, true)); | 308 this, true)); |
290 notification_proxy_->ConnectToSignal( | 309 notification_proxy_->ConnectToSignal( |
291 kFreedesktopNotificationsName, "ActionInvoked", | 310 kFreedesktopNotificationsName, "ActionInvoked", |
292 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnActionInvoked, this), | 311 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnActionInvoked, this), |
293 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, | 312 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, |
294 this)); | 313 this)); |
295 notification_proxy_->ConnectToSignal( | 314 notification_proxy_->ConnectToSignal( |
296 kFreedesktopNotificationsName, "NotificationClosed", | 315 kFreedesktopNotificationsName, "NotificationClosed", |
297 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnNotificationClosed, | 316 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnNotificationClosed, |
298 this), | 317 this), |
299 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, | 318 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, |
300 this)); | 319 this)); |
301 } | 320 } |
302 | 321 |
303 void CleanUp() { | |
304 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
305 if (cleanup_posted_) | |
306 return; | |
307 PostTaskToTaskRunnerThread(base::BindOnce( | |
308 &NotificationPlatformBridgeLinuxImpl::CleanUpOnTaskRunner, this)); | |
309 cleanup_posted_ = true; | |
310 } | |
311 | |
312 void CleanUpOnTaskRunner() { | 322 void CleanUpOnTaskRunner() { |
313 DCHECK(task_runner_->RunsTasksOnCurrentThread()); | 323 DCHECK(task_runner_->RunsTasksOnCurrentThread()); |
314 bus_->ShutdownAndBlock(); | 324 if (bus_) |
325 bus_->ShutdownAndBlock(); | |
315 bus_ = nullptr; | 326 bus_ = nullptr; |
316 notification_proxy_ = nullptr; | 327 notification_proxy_ = nullptr; |
317 notifications_.clear(); | 328 notifications_.clear(); |
318 } | 329 } |
319 | 330 |
320 // Makes the "Notify" call to D-Bus. | 331 // Makes the "Notify" call to D-Bus. |
321 void DisplayOnTaskRunner(NotificationCommon::Type notification_type, | 332 void DisplayOnTaskRunner(NotificationCommon::Type notification_type, |
322 const std::string& notification_id, | 333 const std::string& notification_id, |
323 const std::string& profile_id, | 334 const std::string& profile_id, |
324 bool is_incognito, | 335 bool is_incognito, |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
579 | 590 |
580 scoped_refptr<base::SequencedTaskRunner> task_runner_; | 591 scoped_refptr<base::SequencedTaskRunner> task_runner_; |
581 | 592 |
582 content::NotificationRegistrar registrar_; | 593 content::NotificationRegistrar registrar_; |
583 | 594 |
584 // State necessary for OnConnectionInitializationFinished() and | 595 // State necessary for OnConnectionInitializationFinished() and |
585 // SetReadyCallback(). | 596 // SetReadyCallback(). |
586 base::Optional<bool> connected_; | 597 base::Optional<bool> connected_; |
587 std::vector<NotificationBridgeReadyCallback> on_connected_callbacks_; | 598 std::vector<NotificationBridgeReadyCallback> on_connected_callbacks_; |
588 | 599 |
589 bool cleanup_posted_ = false; | |
590 | |
591 ////////////////////////////////////////////////////////////////////////////// | 600 ////////////////////////////////////////////////////////////////////////////// |
592 // Members used only on the task runner thread. | 601 // Members used only on the task runner thread. |
593 | 602 |
594 scoped_refptr<dbus::Bus> bus_; | 603 scoped_refptr<dbus::Bus> bus_; |
595 | 604 |
596 dbus::ObjectProxy* notification_proxy_ = nullptr; | 605 dbus::ObjectProxy* notification_proxy_ = nullptr; |
597 | 606 |
598 base::Closure connected_signals_barrier_; | 607 base::Closure connected_signals_barrier_; |
599 | 608 |
600 // A std::set<std::unique_ptr<T>> doesn't work well because | 609 // A std::set<std::unique_ptr<T>> doesn't work well because |
601 // eg. std::set::erase(T) would require a std::unique_ptr<T> | 610 // eg. std::set::erase(T) would require a std::unique_ptr<T> |
602 // argument, so the data would get double-destructed. | 611 // argument, so the data would get double-destructed. |
603 template <typename T> | 612 template <typename T> |
604 using UnorderedUniqueSet = std::unordered_map<T*, std::unique_ptr<T>>; | 613 using UnorderedUniqueSet = std::unordered_map<T*, std::unique_ptr<T>>; |
605 | 614 |
606 UnorderedUniqueSet<NotificationData> notifications_; | 615 UnorderedUniqueSet<NotificationData> notifications_; |
607 | 616 |
608 DISALLOW_COPY_AND_ASSIGN(NotificationPlatformBridgeLinuxImpl); | 617 DISALLOW_COPY_AND_ASSIGN(NotificationPlatformBridgeLinuxImpl); |
609 }; | 618 }; |
610 | 619 |
611 NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux() | 620 NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux() |
612 : impl_(new NotificationPlatformBridgeLinuxImpl()) {} | 621 : NotificationPlatformBridgeLinux(nullptr) {} |
622 | |
623 NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux( | |
624 scoped_refptr<dbus::Bus> bus) | |
625 : impl_(new NotificationPlatformBridgeLinuxImpl(bus)) { | |
626 impl_->InitAfterConstructor(); | |
627 } | |
613 | 628 |
614 NotificationPlatformBridgeLinux::~NotificationPlatformBridgeLinux() = default; | 629 NotificationPlatformBridgeLinux::~NotificationPlatformBridgeLinux() = default; |
615 | 630 |
616 void NotificationPlatformBridgeLinux::Display( | 631 void NotificationPlatformBridgeLinux::Display( |
617 NotificationCommon::Type notification_type, | 632 NotificationCommon::Type notification_type, |
618 const std::string& notification_id, | 633 const std::string& notification_id, |
619 const std::string& profile_id, | 634 const std::string& profile_id, |
620 bool is_incognito, | 635 bool is_incognito, |
621 const Notification& notification) { | 636 const Notification& notification) { |
622 impl_->Display(notification_type, notification_id, profile_id, is_incognito, | 637 impl_->Display(notification_type, notification_id, profile_id, is_incognito, |
(...skipping 10 matching lines...) Expand all Loading... | |
633 const std::string& profile_id, | 648 const std::string& profile_id, |
634 bool incognito, | 649 bool incognito, |
635 const GetDisplayedNotificationsCallback& callback) const { | 650 const GetDisplayedNotificationsCallback& callback) const { |
636 impl_->GetDisplayed(profile_id, incognito, callback); | 651 impl_->GetDisplayed(profile_id, incognito, callback); |
637 } | 652 } |
638 | 653 |
639 void NotificationPlatformBridgeLinux::SetReadyCallback( | 654 void NotificationPlatformBridgeLinux::SetReadyCallback( |
640 NotificationBridgeReadyCallback callback) { | 655 NotificationBridgeReadyCallback callback) { |
641 impl_->SetReadyCallback(std::move(callback)); | 656 impl_->SetReadyCallback(std::move(callback)); |
642 } | 657 } |
658 | |
659 void NotificationPlatformBridgeLinux::CleanUp() { | |
660 impl_->CleanUp(); | |
661 } | |
OLD | NEW |