Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(300)

Side by Side Diff: chrome/browser/notifications/notification_platform_bridge_linux.cc

Issue 2849003002: Linux native notifications: Add initial unit test (Closed)
Patch Set: address thestig's comments Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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());
136 PostTaskToTaskRunnerThread( 138 }
137 base::BindOnce(&NotificationPlatformBridgeLinuxImpl::Init, this)); 139
140 // InitOnTaskRunner() cannot be posted from within the constructor
141 // because of a race condition. The reference count for |this|
142 // starts out as 0. Posting the Init task would increment the count
143 // to 1. If the task finishes before the constructor returns, the
144 // count will go to 0 and the object would be prematurely
145 // destructed.
146 void Init() {
147 PostTaskToTaskRunnerThread(base::BindOnce(
148 &NotificationPlatformBridgeLinuxImpl::InitOnTaskRunner, this));
138 } 149 }
139 150
140 void Display(NotificationCommon::Type notification_type, 151 void Display(NotificationCommon::Type notification_type,
141 const std::string& notification_id, 152 const std::string& notification_id,
142 const std::string& profile_id, 153 const std::string& profile_id,
143 bool is_incognito, 154 bool is_incognito,
144 const Notification& notification) override { 155 const Notification& notification) override {
145 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 156 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
146 // Notifications contain gfx::Image's which have reference counts 157 // Notifications contain gfx::Image's which have reference counts
147 // that are not thread safe. Because of this, we duplicate the 158 // that are not thread safe. Because of this, we duplicate the
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
181 192
182 void SetReadyCallback(NotificationBridgeReadyCallback callback) override { 193 void SetReadyCallback(NotificationBridgeReadyCallback callback) override {
183 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 194 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
184 if (connected_.has_value()) { 195 if (connected_.has_value()) {
185 std::move(callback).Run(connected_.value()); 196 std::move(callback).Run(connected_.value());
186 } else { 197 } else {
187 on_connected_callbacks_.push_back(std::move(callback)); 198 on_connected_callbacks_.push_back(std::move(callback));
188 } 199 }
189 } 200 }
190 201
202 void CleanUp() {
203 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
204 PostTaskToTaskRunnerThread(base::BindOnce(
205 &NotificationPlatformBridgeLinuxImpl::CleanUpOnTaskRunner, this));
206 }
207
191 private: 208 private:
192 friend class base::RefCountedThreadSafe<NotificationPlatformBridgeLinuxImpl>; 209 friend class base::RefCountedThreadSafe<NotificationPlatformBridgeLinuxImpl>;
193 210
194 struct ResourceFile { 211 struct ResourceFile {
195 explicit ResourceFile(const base::FilePath& file_path) 212 explicit ResourceFile(const base::FilePath& file_path)
196 : file_path(file_path) {} 213 : file_path(file_path) {}
197 ~ResourceFile() { base::DeleteFile(file_path, false); } 214 ~ResourceFile() { base::DeleteFile(file_path, false); }
198 const base::FilePath file_path; 215 const base::FilePath file_path;
199 }; 216 };
200 217
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
232 size_t action_end = 0; 249 size_t action_end = 0;
233 250
234 // Temporary resource files associated with the notification that 251 // Temporary resource files associated with the notification that
235 // should be cleaned up when the notification is closed or on 252 // should be cleaned up when the notification is closed or on
236 // shutdown. 253 // shutdown.
237 std::vector<std::unique_ptr<ResourceFile>> resource_files; 254 std::vector<std::unique_ptr<ResourceFile>> resource_files;
238 }; 255 };
239 256
240 ~NotificationPlatformBridgeLinuxImpl() override { 257 ~NotificationPlatformBridgeLinuxImpl() override {
241 DCHECK(!bus_); 258 DCHECK(!bus_);
259 DCHECK(!notification_proxy_);
242 DCHECK(notifications_.empty()); 260 DCHECK(notifications_.empty());
243 } 261 }
244 262
245 void Observe(int type, 263 void Observe(int type,
246 const content::NotificationSource& source, 264 const content::NotificationSource& source,
247 const content::NotificationDetails& details) override { 265 const content::NotificationDetails& details) override {
248 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 266 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
249 DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type); 267 DCHECK_EQ(chrome::NOTIFICATION_APP_TERMINATING, type);
250 // The browser process is about to exit. Post the CleanUp() task 268 // The browser process is about to exit. Post the CleanUp() task
251 // while we still can. 269 // while we still can.
252 CleanUp(); 270 CleanUp();
253 } 271 }
254 272
255 void PostTaskToUiThread(base::OnceClosure closure) const { 273 void PostTaskToUiThread(base::OnceClosure closure) const {
256 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 274 DCHECK(task_runner_->RunsTasksOnCurrentThread());
257 bool success = content::BrowserThread::PostTask( 275 bool success = content::BrowserThread::PostTask(
258 content::BrowserThread::UI, FROM_HERE, std::move(closure)); 276 content::BrowserThread::UI, FROM_HERE, std::move(closure));
259 DCHECK(success); 277 DCHECK(success);
260 } 278 }
261 279
262 void PostTaskToTaskRunnerThread(base::OnceClosure closure) const { 280 void PostTaskToTaskRunnerThread(base::OnceClosure closure) const {
263 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 281 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
264 DCHECK(task_runner_); 282 DCHECK(task_runner_);
265 bool success = task_runner_->PostTask(FROM_HERE, std::move(closure)); 283 bool success = task_runner_->PostTask(FROM_HERE, std::move(closure));
266 DCHECK(success); 284 DCHECK(success);
267 } 285 }
268 286
269 // Sets up the D-Bus connection. 287 // Sets up the D-Bus connection.
270 void Init() { 288 void InitOnTaskRunner() {
271 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 289 DCHECK(task_runner_->RunsTasksOnCurrentThread());
272 dbus::Bus::Options bus_options; 290 // |bus_| may be non-null in unit testing where a fake bus is used.
273 bus_options.bus_type = dbus::Bus::SESSION; 291 if (!bus_) {
274 bus_options.connection_type = dbus::Bus::PRIVATE; 292 dbus::Bus::Options bus_options;
275 bus_options.dbus_task_runner = task_runner_; 293 bus_options.bus_type = dbus::Bus::SESSION;
276 bus_ = make_scoped_refptr(new dbus::Bus(bus_options)); 294 bus_options.connection_type = dbus::Bus::PRIVATE;
295 bus_options.dbus_task_runner = task_runner_;
296 bus_ = make_scoped_refptr(new dbus::Bus(bus_options));
297 }
277 298
278 notification_proxy_ = 299 notification_proxy_ =
279 bus_->GetObjectProxy(kFreedesktopNotificationsName, 300 bus_->GetObjectProxy(kFreedesktopNotificationsName,
280 dbus::ObjectPath(kFreedesktopNotificationsPath)); 301 dbus::ObjectPath(kFreedesktopNotificationsPath));
281 if (!notification_proxy_) { 302 if (!notification_proxy_) {
282 OnConnectionInitializationFinishedOnTaskRunner(false); 303 OnConnectionInitializationFinishedOnTaskRunner(false);
283 return; 304 return;
284 } 305 }
285 306
286 connected_signals_barrier_ = base::BarrierClosure( 307 connected_signals_barrier_ = base::BarrierClosure(
287 2, base::Bind(&NotificationPlatformBridgeLinuxImpl:: 308 2, base::Bind(&NotificationPlatformBridgeLinuxImpl::
288 OnConnectionInitializationFinishedOnTaskRunner, 309 OnConnectionInitializationFinishedOnTaskRunner,
289 this, true)); 310 this, true));
290 notification_proxy_->ConnectToSignal( 311 notification_proxy_->ConnectToSignal(
291 kFreedesktopNotificationsName, "ActionInvoked", 312 kFreedesktopNotificationsName, "ActionInvoked",
292 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnActionInvoked, this), 313 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnActionInvoked, this),
293 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, 314 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected,
294 this)); 315 this));
295 notification_proxy_->ConnectToSignal( 316 notification_proxy_->ConnectToSignal(
296 kFreedesktopNotificationsName, "NotificationClosed", 317 kFreedesktopNotificationsName, "NotificationClosed",
297 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnNotificationClosed, 318 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnNotificationClosed,
298 this), 319 this),
299 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected, 320 base::Bind(&NotificationPlatformBridgeLinuxImpl::OnSignalConnected,
300 this)); 321 this));
301 } 322 }
302 323
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() { 324 void CleanUpOnTaskRunner() {
313 DCHECK(task_runner_->RunsTasksOnCurrentThread()); 325 DCHECK(task_runner_->RunsTasksOnCurrentThread());
314 bus_->ShutdownAndBlock(); 326 if (bus_)
327 bus_->ShutdownAndBlock();
315 bus_ = nullptr; 328 bus_ = nullptr;
316 notification_proxy_ = nullptr; 329 notification_proxy_ = nullptr;
317 notifications_.clear(); 330 notifications_.clear();
318 } 331 }
319 332
320 // Makes the "Notify" call to D-Bus. 333 // Makes the "Notify" call to D-Bus.
321 void DisplayOnTaskRunner(NotificationCommon::Type notification_type, 334 void DisplayOnTaskRunner(NotificationCommon::Type notification_type,
322 const std::string& notification_id, 335 const std::string& notification_id,
323 const std::string& profile_id, 336 const std::string& profile_id,
324 bool is_incognito, 337 bool is_incognito,
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after
579 592
580 scoped_refptr<base::SequencedTaskRunner> task_runner_; 593 scoped_refptr<base::SequencedTaskRunner> task_runner_;
581 594
582 content::NotificationRegistrar registrar_; 595 content::NotificationRegistrar registrar_;
583 596
584 // State necessary for OnConnectionInitializationFinished() and 597 // State necessary for OnConnectionInitializationFinished() and
585 // SetReadyCallback(). 598 // SetReadyCallback().
586 base::Optional<bool> connected_; 599 base::Optional<bool> connected_;
587 std::vector<NotificationBridgeReadyCallback> on_connected_callbacks_; 600 std::vector<NotificationBridgeReadyCallback> on_connected_callbacks_;
588 601
589 bool cleanup_posted_ = false;
590
591 ////////////////////////////////////////////////////////////////////////////// 602 //////////////////////////////////////////////////////////////////////////////
592 // Members used only on the task runner thread. 603 // Members used only on the task runner thread.
593 604
594 scoped_refptr<dbus::Bus> bus_; 605 scoped_refptr<dbus::Bus> bus_;
595 606
596 dbus::ObjectProxy* notification_proxy_ = nullptr; 607 dbus::ObjectProxy* notification_proxy_ = nullptr;
597 608
598 base::Closure connected_signals_barrier_; 609 base::Closure connected_signals_barrier_;
599 610
600 // A std::set<std::unique_ptr<T>> doesn't work well because 611 // 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> 612 // eg. std::set::erase(T) would require a std::unique_ptr<T>
602 // argument, so the data would get double-destructed. 613 // argument, so the data would get double-destructed.
603 template <typename T> 614 template <typename T>
604 using UnorderedUniqueSet = std::unordered_map<T*, std::unique_ptr<T>>; 615 using UnorderedUniqueSet = std::unordered_map<T*, std::unique_ptr<T>>;
605 616
606 UnorderedUniqueSet<NotificationData> notifications_; 617 UnorderedUniqueSet<NotificationData> notifications_;
607 618
608 DISALLOW_COPY_AND_ASSIGN(NotificationPlatformBridgeLinuxImpl); 619 DISALLOW_COPY_AND_ASSIGN(NotificationPlatformBridgeLinuxImpl);
609 }; 620 };
610 621
611 NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux() 622 NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux()
612 : impl_(new NotificationPlatformBridgeLinuxImpl()) {} 623 : NotificationPlatformBridgeLinux(nullptr) {}
624
625 NotificationPlatformBridgeLinux::NotificationPlatformBridgeLinux(
626 scoped_refptr<dbus::Bus> bus)
627 : impl_(new NotificationPlatformBridgeLinuxImpl(bus)) {
628 impl_->Init();
629 }
613 630
614 NotificationPlatformBridgeLinux::~NotificationPlatformBridgeLinux() = default; 631 NotificationPlatformBridgeLinux::~NotificationPlatformBridgeLinux() = default;
615 632
616 void NotificationPlatformBridgeLinux::Display( 633 void NotificationPlatformBridgeLinux::Display(
617 NotificationCommon::Type notification_type, 634 NotificationCommon::Type notification_type,
618 const std::string& notification_id, 635 const std::string& notification_id,
619 const std::string& profile_id, 636 const std::string& profile_id,
620 bool is_incognito, 637 bool is_incognito,
621 const Notification& notification) { 638 const Notification& notification) {
622 impl_->Display(notification_type, notification_id, profile_id, is_incognito, 639 impl_->Display(notification_type, notification_id, profile_id, is_incognito,
(...skipping 10 matching lines...) Expand all
633 const std::string& profile_id, 650 const std::string& profile_id,
634 bool incognito, 651 bool incognito,
635 const GetDisplayedNotificationsCallback& callback) const { 652 const GetDisplayedNotificationsCallback& callback) const {
636 impl_->GetDisplayed(profile_id, incognito, callback); 653 impl_->GetDisplayed(profile_id, incognito, callback);
637 } 654 }
638 655
639 void NotificationPlatformBridgeLinux::SetReadyCallback( 656 void NotificationPlatformBridgeLinux::SetReadyCallback(
640 NotificationBridgeReadyCallback callback) { 657 NotificationBridgeReadyCallback callback) {
641 impl_->SetReadyCallback(std::move(callback)); 658 impl_->SetReadyCallback(std::move(callback));
642 } 659 }
660
661 void NotificationPlatformBridgeLinux::CleanUp() {
662 impl_->CleanUp();
663 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698