[Android WebView] Fix webview perf bot switchover to use org.chromium.webview_shell...
[chromium-blink-merge.git] / content / child / notifications / notification_manager.cc
blobe39588e44abff3db1235b61266ddc6f946fb0a86
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/child/notifications/notification_manager.h"
7 #include <cmath>
9 #include "base/lazy_instance.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "base/threading/thread_local.h"
14 #include "content/child/notifications/notification_data_conversions.h"
15 #include "content/child/notifications/notification_dispatcher.h"
16 #include "content/child/service_worker/web_service_worker_registration_impl.h"
17 #include "content/child/thread_safe_sender.h"
18 #include "content/child/worker_task_runner.h"
19 #include "content/public/common/platform_notification_data.h"
20 #include "third_party/WebKit/public/platform/WebSerializedOrigin.h"
21 #include "third_party/WebKit/public/platform/modules/notifications/WebNotificationDelegate.h"
22 #include "third_party/skia/include/core/SkBitmap.h"
24 using blink::WebNotificationPermission;
26 namespace content {
27 namespace {
29 int CurrentWorkerId() {
30 return WorkerTaskRunner::Instance()->CurrentWorkerId();
33 } // namespace
35 static base::LazyInstance<base::ThreadLocalPointer<NotificationManager>>::Leaky
36 g_notification_manager_tls = LAZY_INSTANCE_INITIALIZER;
38 NotificationManager::NotificationManager(
39 ThreadSafeSender* thread_safe_sender,
40 base::SingleThreadTaskRunner* main_thread_task_runner,
41 NotificationDispatcher* notification_dispatcher)
42 : thread_safe_sender_(thread_safe_sender),
43 notification_dispatcher_(notification_dispatcher),
44 pending_notifications_(main_thread_task_runner) {
45 g_notification_manager_tls.Pointer()->Set(this);
48 NotificationManager::~NotificationManager() {
49 g_notification_manager_tls.Pointer()->Set(nullptr);
52 NotificationManager* NotificationManager::ThreadSpecificInstance(
53 ThreadSafeSender* thread_safe_sender,
54 base::SingleThreadTaskRunner* main_thread_task_runner,
55 NotificationDispatcher* notification_dispatcher) {
56 if (g_notification_manager_tls.Pointer()->Get())
57 return g_notification_manager_tls.Pointer()->Get();
59 NotificationManager* manager = new NotificationManager(
60 thread_safe_sender, main_thread_task_runner, notification_dispatcher);
61 if (CurrentWorkerId())
62 WorkerTaskRunner::Instance()->AddStopObserver(manager);
63 return manager;
66 void NotificationManager::OnWorkerRunLoopStopped() {
67 delete this;
70 void NotificationManager::show(
71 const blink::WebSerializedOrigin& origin,
72 const blink::WebNotificationData& notification_data,
73 blink::WebNotificationDelegate* delegate) {
74 if (notification_data.icon.isEmpty()) {
75 DisplayPageNotification(origin, notification_data, delegate, SkBitmap());
76 return;
79 pending_notifications_.FetchPageNotificationResources(
80 notification_data,
81 delegate,
82 base::Bind(&NotificationManager::DisplayPageNotification,
83 base::Unretained(this), // this owns |pending_notifications_|
84 origin,
85 notification_data,
86 delegate));
89 void NotificationManager::showPersistent(
90 const blink::WebSerializedOrigin& origin,
91 const blink::WebNotificationData& notification_data,
92 blink::WebServiceWorkerRegistration* service_worker_registration,
93 blink::WebNotificationShowCallbacks* callbacks) {
94 DCHECK(service_worker_registration);
95 int64_t service_worker_registration_id =
96 static_cast<WebServiceWorkerRegistrationImpl*>(
97 service_worker_registration)->registration_id();
99 scoped_ptr<blink::WebNotificationShowCallbacks> owned_callbacks(callbacks);
101 // Verify that the author-provided payload size does not exceed our limit.
102 // This is an implementation-defined limit to prevent abuse of notification
103 // data as a storage mechanism. A UMA histogram records the requested sizes,
104 // which enables us to track how much data authors are attempting to store.
106 // If the size exceeds this limit, reject the showNotification() promise. This
107 // is outside of the boundaries set by the specification, but it gives authors
108 // an indication that something has gone wrong.
109 size_t author_data_size = notification_data.data.size();
110 UMA_HISTOGRAM_MEMORY_KB("Notifications.AuthorDataSizeKB",
111 static_cast<int>(ceil(author_data_size / 1024.0)));
113 if (author_data_size > PlatformNotificationData::kMaximumDeveloperDataSize) {
114 owned_callbacks->onError();
115 return;
118 if (notification_data.icon.isEmpty()) {
119 DisplayPersistentNotification(origin,
120 notification_data,
121 service_worker_registration_id,
122 owned_callbacks.Pass(),
123 SkBitmap());
124 return;
127 pending_notifications_.FetchPersistentNotificationResources(
128 notification_data,
129 base::Bind(&NotificationManager::DisplayPersistentNotification,
130 base::Unretained(this), // this owns |pending_notifications_|
131 origin,
132 notification_data,
133 service_worker_registration_id,
134 base::Passed(&owned_callbacks)));
137 void NotificationManager::getNotifications(
138 const blink::WebString& filter_tag,
139 blink::WebServiceWorkerRegistration* service_worker_registration,
140 blink::WebNotificationGetCallbacks* callbacks) {
141 DCHECK(service_worker_registration);
142 DCHECK(callbacks);
144 WebServiceWorkerRegistrationImpl* service_worker_registration_impl =
145 static_cast<WebServiceWorkerRegistrationImpl*>(
146 service_worker_registration);
148 GURL origin = GURL(service_worker_registration_impl->scope()).GetOrigin();
149 int64_t service_worker_registration_id =
150 service_worker_registration_impl->registration_id();
152 // TODO(peter): GenerateNotificationId is more of a request id. Consider
153 // renaming the method in the NotificationDispatcher if this makes sense.
154 int request_id =
155 notification_dispatcher_->GenerateNotificationId(CurrentWorkerId());
157 pending_get_notification_requests_.AddWithID(callbacks, request_id);
159 thread_safe_sender_->Send(
160 new PlatformNotificationHostMsg_GetNotifications(
161 request_id,
162 service_worker_registration_id,
163 origin,
164 base::UTF16ToUTF8(filter_tag)));
167 void NotificationManager::close(blink::WebNotificationDelegate* delegate) {
168 if (pending_notifications_.CancelPageNotificationFetches(delegate))
169 return;
171 for (auto& iter : active_page_notifications_) {
172 if (iter.second != delegate)
173 continue;
175 thread_safe_sender_->Send(
176 new PlatformNotificationHostMsg_Close(iter.first));
177 active_page_notifications_.erase(iter.first);
178 return;
181 // It should not be possible for Blink to call close() on a Notification which
182 // does not exist in either the pending or active notification lists.
183 NOTREACHED();
186 void NotificationManager::closePersistent(
187 const blink::WebSerializedOrigin& origin,
188 int64_t persistent_notification_id) {
189 thread_safe_sender_->Send(new PlatformNotificationHostMsg_ClosePersistent(
190 GURL(origin.string()),
191 persistent_notification_id));
194 void NotificationManager::notifyDelegateDestroyed(
195 blink::WebNotificationDelegate* delegate) {
196 if (pending_notifications_.CancelPageNotificationFetches(delegate))
197 return;
199 for (auto& iter : active_page_notifications_) {
200 if (iter.second != delegate)
201 continue;
203 active_page_notifications_.erase(iter.first);
204 return;
208 WebNotificationPermission NotificationManager::checkPermission(
209 const blink::WebSerializedOrigin& origin) {
210 WebNotificationPermission permission =
211 blink::WebNotificationPermissionAllowed;
212 thread_safe_sender_->Send(new PlatformNotificationHostMsg_CheckPermission(
213 GURL(origin.string()), &permission));
215 return permission;
218 bool NotificationManager::OnMessageReceived(const IPC::Message& message) {
219 bool handled = true;
220 IPC_BEGIN_MESSAGE_MAP(NotificationManager, message)
221 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidShow, OnDidShow);
222 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidShowPersistent,
223 OnDidShowPersistent)
224 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidClose, OnDidClose);
225 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidClick, OnDidClick);
226 IPC_MESSAGE_HANDLER(PlatformNotificationMsg_DidGetNotifications,
227 OnDidGetNotifications)
228 IPC_MESSAGE_UNHANDLED(handled = false)
229 IPC_END_MESSAGE_MAP()
231 return handled;
234 void NotificationManager::OnDidShow(int notification_id) {
235 const auto& iter = active_page_notifications_.find(notification_id);
236 if (iter == active_page_notifications_.end())
237 return;
239 iter->second->dispatchShowEvent();
242 void NotificationManager::OnDidShowPersistent(int request_id, bool success) {
243 blink::WebNotificationShowCallbacks* callbacks =
244 pending_show_notification_requests_.Lookup(request_id);
245 DCHECK(callbacks);
247 if (!callbacks)
248 return;
250 if (success)
251 callbacks->onSuccess();
252 else
253 callbacks->onError();
255 pending_show_notification_requests_.Remove(request_id);
258 void NotificationManager::OnDidClose(int notification_id) {
259 const auto& iter = active_page_notifications_.find(notification_id);
260 if (iter == active_page_notifications_.end())
261 return;
263 iter->second->dispatchCloseEvent();
264 active_page_notifications_.erase(iter);
267 void NotificationManager::OnDidClick(int notification_id) {
268 const auto& iter = active_page_notifications_.find(notification_id);
269 if (iter == active_page_notifications_.end())
270 return;
272 iter->second->dispatchClickEvent();
275 void NotificationManager::OnDidGetNotifications(
276 int request_id,
277 const std::vector<PersistentNotificationInfo>& notification_infos) {
278 blink::WebNotificationGetCallbacks* callbacks =
279 pending_get_notification_requests_.Lookup(request_id);
280 DCHECK(callbacks);
281 if (!callbacks)
282 return;
284 scoped_ptr<blink::WebVector<blink::WebPersistentNotificationInfo>>
285 notifications(new blink::WebVector<blink::WebPersistentNotificationInfo>(
286 notification_infos.size()));
288 for (size_t i = 0; i < notification_infos.size(); ++i) {
289 blink::WebPersistentNotificationInfo web_notification_info;
290 web_notification_info.persistentId = notification_infos[i].first;
291 web_notification_info.data =
292 ToWebNotificationData(notification_infos[i].second);
294 (*notifications)[i] = web_notification_info;
297 callbacks->onSuccess(notifications.release());
299 pending_get_notification_requests_.Remove(request_id);
302 void NotificationManager::DisplayPageNotification(
303 const blink::WebSerializedOrigin& origin,
304 const blink::WebNotificationData& notification_data,
305 blink::WebNotificationDelegate* delegate,
306 const SkBitmap& icon) {
307 int notification_id =
308 notification_dispatcher_->GenerateNotificationId(CurrentWorkerId());
310 active_page_notifications_[notification_id] = delegate;
311 thread_safe_sender_->Send(
312 new PlatformNotificationHostMsg_Show(
313 notification_id,
314 GURL(origin.string()),
315 icon,
316 ToPlatformNotificationData(notification_data)));
319 void NotificationManager::DisplayPersistentNotification(
320 const blink::WebSerializedOrigin& origin,
321 const blink::WebNotificationData& notification_data,
322 int64_t service_worker_registration_id,
323 scoped_ptr<blink::WebNotificationShowCallbacks> callbacks,
324 const SkBitmap& icon) {
325 // TODO(peter): GenerateNotificationId is more of a request id. Consider
326 // renaming the method in the NotificationDispatcher if this makes sense.
327 int request_id =
328 notification_dispatcher_->GenerateNotificationId(CurrentWorkerId());
330 pending_show_notification_requests_.AddWithID(callbacks.release(),
331 request_id);
333 thread_safe_sender_->Send(
334 new PlatformNotificationHostMsg_ShowPersistent(
335 request_id,
336 service_worker_registration_id,
337 GURL(origin.string()),
338 icon,
339 ToPlatformNotificationData(notification_data)));
342 } // namespace content