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

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

Issue 2849003002: Linux native notifications: Add initial unit test (Closed)
Patch Set: peter'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());
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698