Add an UMA stat to be able to see if the User pods are show on start screen,
[chromium-blink-merge.git] / content / child / permissions / permission_dispatcher.cc
blob2b0278fb954e5e37ad72b308f696da7b1f313c68
1 // Copyright 2015 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/permissions/permission_dispatcher.h"
7 #include "base/callback.h"
8 #include "content/child/worker_task_runner.h"
9 #include "content/public/common/service_registry.h"
10 #include "third_party/WebKit/public/platform/WebURL.h"
11 #include "third_party/WebKit/public/platform/modules/permissions/WebPermissionObserver.h"
13 using blink::WebPermissionObserver;
15 namespace content {
17 namespace {
19 PermissionName GetPermissionName(blink::WebPermissionType type) {
20 switch (type) {
21 case blink::WebPermissionTypeGeolocation:
22 return PERMISSION_NAME_GEOLOCATION;
23 case blink::WebPermissionTypeNotifications:
24 return PERMISSION_NAME_NOTIFICATIONS;
25 case blink::WebPermissionTypePushNotifications:
26 return PERMISSION_NAME_PUSH_NOTIFICATIONS;
27 case blink::WebPermissionTypeMidiSysEx:
28 return PERMISSION_NAME_MIDI_SYSEX;
29 default:
30 // The default statement is only there to prevent compilation failures if
31 // WebPermissionType enum gets extended.
32 NOTREACHED();
33 return PERMISSION_NAME_GEOLOCATION;
37 PermissionStatus GetPermissionStatus(blink::WebPermissionStatus status) {
38 switch (status) {
39 case blink::WebPermissionStatusGranted:
40 return PERMISSION_STATUS_GRANTED;
41 case blink::WebPermissionStatusDenied:
42 return PERMISSION_STATUS_DENIED;
43 case blink::WebPermissionStatusPrompt:
44 return PERMISSION_STATUS_ASK;
47 NOTREACHED();
48 return PERMISSION_STATUS_DENIED;
51 blink::WebPermissionStatus GetWebPermissionStatus(PermissionStatus status) {
52 switch (status) {
53 case PERMISSION_STATUS_GRANTED:
54 return blink::WebPermissionStatusGranted;
55 case PERMISSION_STATUS_DENIED:
56 return blink::WebPermissionStatusDenied;
57 case PERMISSION_STATUS_ASK:
58 return blink::WebPermissionStatusPrompt;
61 NOTREACHED();
62 return blink::WebPermissionStatusDenied;
65 const int kNoWorkerThread = 0;
67 } // anonymous namespace
69 // static
70 bool PermissionDispatcher::IsObservable(blink::WebPermissionType type) {
71 return type == blink::WebPermissionTypeGeolocation ||
72 type == blink::WebPermissionTypeNotifications ||
73 type == blink::WebPermissionTypePushNotifications ||
74 type == blink::WebPermissionTypeMidiSysEx;
77 PermissionDispatcher::CallbackInformation::CallbackInformation(
78 blink::WebPermissionQueryCallback* callback,
79 int worker_thread_id)
80 : callback_(callback),
81 worker_thread_id_(worker_thread_id) {
84 blink::WebPermissionQueryCallback*
85 PermissionDispatcher::CallbackInformation::callback() const {
86 return callback_.get();
89 int PermissionDispatcher::CallbackInformation::worker_thread_id() const {
90 return worker_thread_id_;
93 blink::WebPermissionQueryCallback*
94 PermissionDispatcher::CallbackInformation::ReleaseCallback() {
95 return callback_.release();
98 PermissionDispatcher::CallbackInformation::~CallbackInformation() {
101 PermissionDispatcher::PermissionDispatcher(ServiceRegistry* service_registry)
102 : service_registry_(service_registry) {
105 PermissionDispatcher::~PermissionDispatcher() {
108 void PermissionDispatcher::queryPermission(
109 blink::WebPermissionType type,
110 const blink::WebURL& origin,
111 blink::WebPermissionQueryCallback* callback) {
112 QueryPermissionInternal(
113 type, origin.string().utf8(), callback, kNoWorkerThread);
116 void PermissionDispatcher::startListening(
117 blink::WebPermissionType type,
118 const blink::WebURL& origin,
119 WebPermissionObserver* observer) {
120 if (!IsObservable(type))
121 return;
123 RegisterObserver(observer);
125 GetNextPermissionChange(type,
126 origin.string().utf8(),
127 observer,
128 // We initialize with an arbitrary value because the
129 // mojo service wants a value. Worst case, the
130 // observer will get notified about a non-change which
131 // should be a no-op. After the first notification,
132 // GetNextPermissionChange will be called with the
133 // latest known value.
134 PERMISSION_STATUS_ASK);
137 void PermissionDispatcher::stopListening(WebPermissionObserver* observer) {
138 UnregisterObserver(observer);
141 void PermissionDispatcher::QueryPermissionForWorker(
142 blink::WebPermissionType type,
143 const std::string& origin,
144 blink::WebPermissionQueryCallback* callback,
145 int worker_thread_id) {
146 QueryPermissionInternal(type, origin, callback, worker_thread_id);
149 void PermissionDispatcher::StartListeningForWorker(
150 blink::WebPermissionType type,
151 const std::string& origin,
152 int worker_thread_id,
153 const base::Callback<void(blink::WebPermissionStatus)>& callback) {
154 GetPermissionServicePtr()->GetNextPermissionChange(
155 GetPermissionName(type),
156 origin,
157 // We initialize with an arbitrary value because the mojo service wants a
158 // value. Worst case, the observer will get notified about a non-change
159 // which should be a no-op. After the first notification,
160 // GetNextPermissionChange will be called with the latest known value.
161 PERMISSION_STATUS_ASK,
162 base::Bind(&PermissionDispatcher::OnPermissionChangedForWorker,
163 base::Unretained(this),
164 worker_thread_id,
165 callback));
168 void PermissionDispatcher::GetNextPermissionChangeForWorker(
169 blink::WebPermissionType type,
170 const std::string& origin,
171 blink::WebPermissionStatus status,
172 int worker_thread_id,
173 const base::Callback<void(blink::WebPermissionStatus)>& callback) {
174 GetPermissionServicePtr()->GetNextPermissionChange(
175 GetPermissionName(type),
176 origin,
177 GetPermissionStatus(status),
178 base::Bind(&PermissionDispatcher::OnPermissionChangedForWorker,
179 base::Unretained(this),
180 worker_thread_id,
181 callback));
184 // static
185 void PermissionDispatcher::RunCallbackOnWorkerThread(
186 blink::WebPermissionQueryCallback* callback,
187 scoped_ptr<blink::WebPermissionStatus> status) {
188 callback->onSuccess(status.release());
189 delete callback;
192 PermissionServicePtr& PermissionDispatcher::GetPermissionServicePtr() {
193 if (!permission_service_.get())
194 service_registry_->ConnectToRemoteService(&permission_service_);
195 return permission_service_;
198 void PermissionDispatcher::QueryPermissionInternal(
199 blink::WebPermissionType type,
200 const std::string& origin,
201 blink::WebPermissionQueryCallback* callback,
202 int worker_thread_id) {
203 // We need to save the |callback| in an IDMap so if |this| gets deleted, the
204 // callback will not leak. In the case of |this| gets deleted, the
205 // |permission_service_| pipe will be destroyed too so OnQueryPermission will
206 // not be called.
207 int request_id = pending_callbacks_.Add(
208 new CallbackInformation(callback, worker_thread_id));
209 GetPermissionServicePtr()->HasPermission(
210 GetPermissionName(type),
211 origin,
212 base::Bind(&PermissionDispatcher::OnQueryPermission,
213 base::Unretained(this),
214 request_id));
217 void PermissionDispatcher::OnQueryPermission(int request_id,
218 PermissionStatus result) {
219 CallbackInformation* callback_information =
220 pending_callbacks_.Lookup(request_id);
221 DCHECK(callback_information && callback_information->callback());
222 scoped_ptr<blink::WebPermissionStatus> status(
223 new blink::WebPermissionStatus(GetWebPermissionStatus(result)));
225 if (callback_information->worker_thread_id() != kNoWorkerThread) {
226 blink::WebPermissionQueryCallback* callback =
227 callback_information->ReleaseCallback();
228 int worker_thread_id = callback_information->worker_thread_id();
229 pending_callbacks_.Remove(request_id);
231 // If the worker is no longer running, ::PostTask() will return false and
232 // gracefully fail, destroying the callback too.
233 WorkerTaskRunner::Instance()->PostTask(
234 worker_thread_id,
235 base::Bind(&PermissionDispatcher::RunCallbackOnWorkerThread,
236 base::Unretained(callback),
237 base::Passed(&status)));
238 return;
241 callback_information->callback()->onSuccess(status.release());
242 pending_callbacks_.Remove(request_id);
245 void PermissionDispatcher::OnPermissionChanged(
246 blink::WebPermissionType type,
247 const std::string& origin,
248 WebPermissionObserver* observer,
249 PermissionStatus status) {
250 if (!IsObserverRegistered(observer))
251 return;
253 observer->permissionChanged(type, GetWebPermissionStatus(status));
255 GetNextPermissionChange(type, origin, observer, status);
258 void PermissionDispatcher::OnPermissionChangedForWorker(
259 int worker_thread_id,
260 const base::Callback<void(blink::WebPermissionStatus)>& callback,
261 PermissionStatus status) {
262 DCHECK(worker_thread_id != kNoWorkerThread);
264 WorkerTaskRunner::Instance()->PostTask(
265 worker_thread_id, base::Bind(callback, GetWebPermissionStatus(status)));
268 void PermissionDispatcher::GetNextPermissionChange(
269 blink::WebPermissionType type,
270 const std::string& origin,
271 WebPermissionObserver* observer,
272 PermissionStatus current_status) {
273 GetPermissionServicePtr()->GetNextPermissionChange(
274 GetPermissionName(type),
275 origin,
276 current_status,
277 base::Bind(&PermissionDispatcher::OnPermissionChanged,
278 base::Unretained(this),
279 type,
280 origin,
281 base::Unretained(observer)));
284 } // namespace content