Changeset 246093 in webkit
- Timestamp:
- Jun 4, 2019, 6:03:04 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 8 edited
-
Source/WebKit/ChangeLog (modified) (1 diff)
-
Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp (modified) (8 diffs)
-
Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.h (modified) (5 diffs)
-
Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.cpp (modified) (4 diffs)
-
Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.h (modified) (1 diff)
-
Tools/ChangeLog (modified) (1 diff)
-
Tools/TestWebKitAPI/Tests/WebKit/GetUserMediaReprompt.mm (modified) (3 diffs)
-
Tools/TestWebKitAPI/Tests/WebKit/getUserMedia.html (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebKit/ChangeLog
r246090 r246093 1 2019-06-04 Youenn Fablet <youenn@apple.com> 2 3 getUserMedia requests should be processed sequentially in UIProcess 4 https://bugs.webkit.org/show_bug.cgi?id=198430 5 <rdar://problem/51311420> 6 7 Reviewed by Eric Carlson. 8 9 Before the patch, we process all incoming gum/gdm requests in parallel. 10 We now queueu them and process them one at a time. 11 This allows to take into consideration state changes triggered by one request for the next one. 12 In particular, if a user grants a request, this might grant the next one as well. 13 14 To implement that, we keep a reference of the current request to process. 15 We queue other requests happening whenever another request comes. 16 When the request is processed, we look at the next one in the queue. 17 To ensure we do not stop processing the queue for no good reason, some refactoring is done: 18 - queue processing happens when sending back IPC response to WebProcess. 19 - denyRequest/grantRequest are consistently called in the manager proxy. 20 21 * UIProcess/UserMediaPermissionRequestManagerProxy.cpp: 22 (WebKit::UserMediaPermissionRequestManagerProxy::invalidatePendingRequests): 23 Invalidate pregranted requests as well. 24 (WebKit::UserMediaPermissionRequestManagerProxy::denyRequest): 25 Renamed from userMediaAccessWasDenied to denyRequest. 26 This method is now consistently used whenever the manager proxy wants to deny the request. 27 It does the IPC to the WebProcess and triggers processing of the next request. 28 (WebKit::UserMediaPermissionRequestManagerProxy::grantRequest): 29 Renamed from userMediaAccessWasGranted to grantRequest. 30 (WebKit::UserMediaPermissionRequestManagerProxy::finishGrantingRequest): 31 This method is now consistently used whenever the manager proxy wants to deny the request. 32 It does the IPC to the WebProcess and triggers processing of the next request. 33 (WebKit::UserMediaPermissionRequestManagerProxy::rejectionTimerFired): 34 We now keep a queue of request instead of request IDs to make the deny code path more consistent. 35 (WebKit::UserMediaPermissionRequestManagerProxy::requestUserMediaPermissionForFrame): 36 (WebKit::UserMediaPermissionRequestManagerProxy::processNextUserMediaRequestIfNeeded): 37 (WebKit::UserMediaPermissionRequestManagerProxy::startProcessingUserMediaPermissionRequest): 38 (WebKit::UserMediaPermissionRequestManagerProxy::processUserMediaPermissionRequest): 39 To make sure we do not process a different request, we keep a pointer to the request and compare it with the current media request. 40 (WebKit::UserMediaPermissionRequestManagerProxy::processUserMediaPermissionInvalidRequest): 41 (WebKit::UserMediaPermissionRequestManagerProxy::processUserMediaPermissionValidRequest): 42 (WebKit::UserMediaPermissionRequestManagerProxy::viewIsBecomingVisible): 43 * UIProcess/UserMediaPermissionRequestManagerProxy.h: 44 (WebKit::UserMediaPermissionRequestManagerProxy::denyRequest): 45 * UIProcess/UserMediaPermissionRequestProxy.cpp: 46 (WebKit::setDeviceAsFirst): 47 (WebKit::UserMediaPermissionRequestProxy::allow): 48 (WebKit::UserMediaPermissionRequestProxy::deny): 49 * UIProcess/UserMediaPermissionRequestProxy.h: 50 1 51 2019-06-04 Commit Queue <commit-queue@webkit.org> 2 52 -
trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.cpp
r245335 r246093 92 92 void UserMediaPermissionRequestManagerProxy::invalidatePendingRequests() 93 93 { 94 for (auto& request : m_pendingUserMediaRequests.values()) 94 if (m_currentUserMediaRequest) { 95 m_currentUserMediaRequest->invalidate(); 96 m_currentUserMediaRequest = nullptr; 97 } 98 99 auto pendingUserMediaRequests = WTFMove(m_pendingUserMediaRequests); 100 for (auto& request : pendingUserMediaRequests) 95 101 request->invalidate(); 96 m_pendingUserMediaRequests.clear(); 102 103 auto pregrantedRequests = WTFMove(m_pregrantedRequests); 104 for (auto& request : pregrantedRequests) 105 request->invalidate(); 97 106 98 107 m_pendingDeviceRequests.clear(); … … 159 168 #endif 160 169 161 void UserMediaPermissionRequestManagerProxy:: userMediaAccessWasDenied(uint64_t userMediaID, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason reason)170 void UserMediaPermissionRequestManagerProxy::denyRequest(UserMediaPermissionRequestProxy& request, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason reason, const String& invalidConstraint) 162 171 { 163 172 if (!m_page.hasRunningProcess()) 164 173 return; 165 174 166 ALWAYS_LOG(LOGIDENTIFIER, userMediaID, ", reason: ", reason); 167 168 auto request = m_pendingUserMediaRequests.take(userMediaID); 169 if (!request) 170 return; 175 ALWAYS_LOG(LOGIDENTIFIER, request.userMediaID(), ", reason: ", reason); 171 176 172 177 if (reason == UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied) 173 m_deniedRequests.append(DeniedRequest { request->mainFrameID(), request->userMediaDocumentSecurityOrigin(), request->topLevelDocumentSecurityOrigin(), request->requiresAudioCapture(), request->requiresVideoCapture(), request->requiresDisplayCapture() }); 174 175 denyRequest(userMediaID, reason, emptyString()); 176 } 177 178 void UserMediaPermissionRequestManagerProxy::denyRequest(uint64_t userMediaID, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason reason, const String& invalidConstraint) 179 { 180 ASSERT(m_page.hasRunningProcess()); 181 182 ALWAYS_LOG(LOGIDENTIFIER, userMediaID, ", reason: ", reason); 183 184 #if ENABLE(MEDIA_STREAM) 185 m_page.process().send(Messages::WebPage::UserMediaAccessWasDenied(userMediaID, toWebCore(reason), invalidConstraint), m_page.pageID()); 178 m_deniedRequests.append(DeniedRequest { request.mainFrameID(), request.userMediaDocumentSecurityOrigin(), request.topLevelDocumentSecurityOrigin(), request.requiresAudioCapture(), request.requiresVideoCapture(), request.requiresDisplayCapture() }); 179 180 #if ENABLE(MEDIA_STREAM) 181 m_page.process().send(Messages::WebPage::UserMediaAccessWasDenied(request.userMediaID(), toWebCore(reason), invalidConstraint), m_page.pageID()); 186 182 #else 187 183 UNUSED_PARAM(reason); 188 184 UNUSED_PARAM(invalidConstraint); 189 185 #endif 190 } 191 192 void UserMediaPermissionRequestManagerProxy::userMediaAccessWasGranted(uint64_t userMediaID, CaptureDevice&& audioDevice, CaptureDevice&& videoDevice) 193 { 194 ASSERT(audioDevice || videoDevice); 195 186 187 processNextUserMediaRequestIfNeeded(); 188 } 189 190 void UserMediaPermissionRequestManagerProxy::grantRequest(UserMediaPermissionRequestProxy& request) 191 { 196 192 if (!m_page.hasRunningProcess()) 197 193 return; 198 194 199 195 #if ENABLE(MEDIA_STREAM) 200 auto logSiteIdentifier = LOGIDENTIFIER; 201 ALWAYS_LOG(logSiteIdentifier, userMediaID, ", video: ", videoDevice ? videoDevice.label() : "", ", audio: ", audioDevice ? audioDevice.label() : " "); 202 203 auto request = m_pendingUserMediaRequests.take(userMediaID); 204 if (!request) 205 return; 206 207 auto& userMediaDocumentSecurityOrigin = request->userMediaDocumentSecurityOrigin(); 208 auto& topLevelDocumentSecurityOrigin = request->topLevelDocumentSecurityOrigin(); 209 m_page.websiteDataStore().deviceIdHashSaltStorage().deviceIdHashSaltForOrigin(userMediaDocumentSecurityOrigin, topLevelDocumentSecurityOrigin, [this, weakThis = makeWeakPtr(*this), request = request.releaseNonNull(), logSiteIdentifier] (String&& deviceIDHashSalt) mutable { 196 ALWAYS_LOG(LOGIDENTIFIER, request.userMediaID(), ", video: ", request.videoDevice().label(), ", audio: ", request.audioDevice().label()); 197 198 auto& userMediaDocumentSecurityOrigin = request.userMediaDocumentSecurityOrigin(); 199 auto& topLevelDocumentSecurityOrigin = request.topLevelDocumentSecurityOrigin(); 200 m_page.websiteDataStore().deviceIdHashSaltStorage().deviceIdHashSaltForOrigin(userMediaDocumentSecurityOrigin, topLevelDocumentSecurityOrigin, [this, weakThis = makeWeakPtr(*this), request = makeRef(request)](String&&) mutable { 210 201 if (!weakThis) 211 202 return; 212 if (!grantAccess(request)) 213 return; 214 215 ALWAYS_LOG(logSiteIdentifier, deviceIDHashSalt); 216 m_grantedRequests.append(WTFMove(request)); 217 if (m_hasFilteredDeviceList) 218 captureDevicesChanged(); 219 m_hasFilteredDeviceList = false; 203 finishGrantingRequest(request); 220 204 }); 221 205 #else 222 UNUSED_PARAM(userMediaID); 223 UNUSED_PARAM(audioDevice); 224 UNUSED_PARAM(videoDevice); 225 #endif 226 } 227 228 #if ENABLE(MEDIA_STREAM) 206 UNUSED_PARAM(request); 207 #endif 208 } 209 210 #if ENABLE(MEDIA_STREAM) 211 void UserMediaPermissionRequestManagerProxy::finishGrantingRequest(UserMediaPermissionRequestProxy& request) 212 { 213 ALWAYS_LOG(LOGIDENTIFIER, request.userMediaID()); 214 if (!UserMediaProcessManager::singleton().willCreateMediaStream(*this, request.hasAudioDevice(), request.hasVideoDevice())) { 215 denyRequest(request, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::OtherFailure, "Unable to extend sandbox."); 216 return; 217 } 218 219 if (request.requestType() == MediaStreamRequest::Type::UserMedia) 220 m_grantedRequests.append(makeRef(request)); 221 222 if (m_hasFilteredDeviceList) 223 captureDevicesChanged(); 224 m_hasFilteredDeviceList = false; 225 226 ++m_hasPendingCapture; 227 m_page.process().connection()->sendWithAsyncReply(Messages::WebPage::UserMediaAccessWasGranted { request.userMediaID(), request.audioDevice(), request.videoDevice(), request.deviceIdentifierHashSalt() }, [this, weakThis = makeWeakPtr(this)] { 228 if (!weakThis) 229 return; 230 --m_hasPendingCapture; 231 }, m_page.pageID()); 232 233 processNextUserMediaRequestIfNeeded(); 234 } 235 229 236 void UserMediaPermissionRequestManagerProxy::resetAccess(uint64_t frameID) 230 237 { … … 288 295 } 289 296 290 bool UserMediaPermissionRequestManagerProxy::grantAccess(const UserMediaPermissionRequestProxy& request)291 {292 ALWAYS_LOG(LOGIDENTIFIER, request.userMediaID());293 if (!UserMediaProcessManager::singleton().willCreateMediaStream(*this, request.hasAudioDevice(), request.hasVideoDevice())) {294 denyRequest(request.userMediaID(), UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::OtherFailure, "Unable to extend sandbox.");295 return false;296 }297 298 ++m_hasPendingCapture;299 m_page.process().connection()->sendWithAsyncReply(Messages::WebPage::UserMediaAccessWasGranted { request.userMediaID(), request.audioDevice(), request.videoDevice(), request.deviceIdentifierHashSalt() }, [this, weakThis = makeWeakPtr(this)] {300 if (!weakThis)301 return;302 --m_hasPendingCapture;303 }, m_page.pageID());304 return true;305 }306 297 #endif 307 298 308 299 void UserMediaPermissionRequestManagerProxy::rejectionTimerFired() 309 300 { 310 uint64_t userMediaID = m_pendingRejections[0]; 311 m_pendingRejections.remove(0); 312 313 denyRequest(userMediaID, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied, emptyString()); 301 denyRequest(m_pendingRejections.takeFirst(), UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied, emptyString()); 314 302 if (!m_pendingRejections.isEmpty()) 315 303 scheduleNextRejection(); … … 348 336 auto logSiteIdentifier = LOGIDENTIFIER; 349 337 338 if (!m_page.hasRunningProcess()) 339 return; 340 341 ALWAYS_LOG(logSiteIdentifier, userMediaID); 342 343 auto request = UserMediaPermissionRequestProxy::create(*this, userMediaID, m_page.mainFrame()->frameID(), frameID, WTFMove(userMediaDocumentOrigin), WTFMove(topLevelDocumentOrigin), { }, { }, WTFMove(userRequest)); 344 if (m_currentUserMediaRequest) { 345 m_pendingUserMediaRequests.append(WTFMove(request)); 346 return; 347 } 348 350 349 if (!UserMediaProcessManager::singleton().captureEnabled()) { 351 350 ALWAYS_LOG(logSiteIdentifier, "capture disabled"); 352 m_pendingRejections.append( userMediaID);351 m_pendingRejections.append(WTFMove(request)); 353 352 scheduleNextRejection(); 354 353 return; 355 354 } 356 355 357 if (!m_page.hasRunningProcess()) 358 return; 359 360 ALWAYS_LOG(logSiteIdentifier, userMediaID); 361 362 auto request = m_pendingUserMediaRequests.add(userMediaID, UserMediaPermissionRequestProxy::create(*this, userMediaID, m_page.mainFrame()->frameID(), frameID, WTFMove(userMediaDocumentOrigin), WTFMove(topLevelDocumentOrigin), { }, { }, WTFMove(userRequest))).iterator->value.copyRef(); 363 364 auto& userMediaOrigin = request->userMediaDocumentSecurityOrigin(); 365 auto& topLevelOrigin = request->topLevelDocumentSecurityOrigin(); 366 getUserMediaPermissionInfo(frameID, userMediaOrigin, topLevelOrigin, [this, request = request.releaseNonNull(), logSiteIdentifier](Optional<bool> hasPersistentAccess) mutable { 367 if (!request->isPending()) 368 return; 369 370 if (!hasPersistentAccess) { 371 request->deny(UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::OtherFailure); 372 return; 373 } 374 375 ALWAYS_LOG(logSiteIdentifier, request->userMediaID(), ", persistent access: ", *hasPersistentAccess); 376 processUserMediaPermissionRequest(WTFMove(request), *hasPersistentAccess); 377 }); 378 } 379 380 void UserMediaPermissionRequestManagerProxy::processUserMediaPermissionRequest(Ref<UserMediaPermissionRequestProxy>&& request, bool hasPersistentAccess) 381 { 382 ALWAYS_LOG(LOGIDENTIFIER, request->userMediaID()); 383 384 if (hasPersistentAccess) 385 request->setHasPersistentAccess(); 386 387 auto& userMediaDocumentSecurityOrigin = request->userMediaDocumentSecurityOrigin(); 388 auto& topLevelDocumentSecurityOrigin = request->topLevelDocumentSecurityOrigin(); 389 m_page.websiteDataStore().deviceIdHashSaltStorage().deviceIdHashSaltForOrigin(userMediaDocumentSecurityOrigin, topLevelDocumentSecurityOrigin, [this, request = WTFMove(request)] (String&& deviceIDHashSalt) mutable { 390 if (!request->isPending()) 391 return; 392 393 RealtimeMediaSourceCenter::InvalidConstraintsHandler invalidHandler = [this, request = request.copyRef()](const String& invalidConstraint) { 394 if (!request->isPending()) 395 return; 396 397 if (!m_page.hasRunningProcess()) 398 return; 399 400 processUserMediaPermissionInvalidRequest(request.get(), invalidConstraint); 401 }; 402 403 auto validHandler = [this, request = request.copyRef()](Vector<CaptureDevice>&& audioDevices, Vector<CaptureDevice>&& videoDevices, String&& deviceIdentifierHashSalt) mutable { 404 if (!request->isPending()) 405 return; 406 407 if (!m_page.hasRunningProcess() || !m_page.mainFrame()) 408 return; 409 410 processUserMediaPermissionValidRequest(WTFMove(request), WTFMove(audioDevices), WTFMove(videoDevices), WTFMove(deviceIdentifierHashSalt)); 411 }; 412 413 syncWithWebCorePrefs(); 414 415 RealtimeMediaSourceCenter::singleton().validateRequestConstraints(WTFMove(validHandler), WTFMove(invalidHandler), request->userRequest(), WTFMove(deviceIDHashSalt)); 416 }); 356 startProcessingUserMediaPermissionRequest(WTFMove(request)); 417 357 #else 418 358 UNUSED_PARAM(userMediaID); … … 424 364 } 425 365 426 #if ENABLE(MEDIA_STREAM) 427 void UserMediaPermissionRequestManagerProxy::processUserMediaPermissionInvalidRequest(const UserMediaPermissionRequestProxy& request, const String& invalidConstraint) 428 { 429 ALWAYS_LOG(LOGIDENTIFIER, request.userMediaID()); 430 bool filterConstraint = !request.hasPersistentAccess() && !wasGrantedVideoOrAudioAccess(request.frameID(), request.userMediaDocumentSecurityOrigin(), request.topLevelDocumentSecurityOrigin()); 431 432 denyRequest(request.userMediaID(), UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::InvalidConstraint, filterConstraint ? String { } : invalidConstraint); 433 } 434 435 void UserMediaPermissionRequestManagerProxy::processUserMediaPermissionValidRequest(Ref<UserMediaPermissionRequestProxy>&& request, Vector<CaptureDevice>&& audioDevices, Vector<CaptureDevice>&& videoDevices, String&& deviceIdentifierHashSalt) 436 { 437 ALWAYS_LOG(LOGIDENTIFIER, request->userMediaID(), ", video: ", videoDevices.size(), " audio: ", audioDevices.size()); 366 void UserMediaPermissionRequestManagerProxy::processNextUserMediaRequestIfNeeded() 367 { 368 #if ENABLE(MEDIA_STREAM) 369 if (m_pendingUserMediaRequests.isEmpty()) { 370 m_currentUserMediaRequest = nullptr; 371 return; 372 } 373 startProcessingUserMediaPermissionRequest(m_pendingUserMediaRequests.takeFirst()); 374 #endif 375 } 376 377 #if ENABLE(MEDIA_STREAM) 378 void UserMediaPermissionRequestManagerProxy::startProcessingUserMediaPermissionRequest(Ref<UserMediaPermissionRequestProxy>&& request) 379 { 380 m_currentUserMediaRequest = WTFMove(request); 381 382 auto& userMediaDocumentSecurityOrigin = m_currentUserMediaRequest->userMediaDocumentSecurityOrigin(); 383 auto& topLevelDocumentSecurityOrigin = m_currentUserMediaRequest->topLevelDocumentSecurityOrigin(); 384 getUserMediaPermissionInfo(m_currentUserMediaRequest->frameID(), userMediaDocumentSecurityOrigin, topLevelDocumentSecurityOrigin, [this, request = m_currentUserMediaRequest](Optional<bool> hasPersistentAccess) mutable { 385 if (!request->isPending()) 386 return; 387 388 if (!hasPersistentAccess) { 389 denyRequest(*m_currentUserMediaRequest, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::OtherFailure); 390 return; 391 } 392 393 ALWAYS_LOG(LOGIDENTIFIER, m_currentUserMediaRequest->userMediaID(), ", persistent access: ", *hasPersistentAccess); 394 processUserMediaPermissionRequest(*hasPersistentAccess); 395 }); 396 } 397 398 void UserMediaPermissionRequestManagerProxy::processUserMediaPermissionRequest(bool hasPersistentAccess) 399 { 400 ALWAYS_LOG(LOGIDENTIFIER, m_currentUserMediaRequest->userMediaID()); 401 402 if (hasPersistentAccess) 403 m_currentUserMediaRequest->setHasPersistentAccess(); 404 405 auto& userMediaDocumentSecurityOrigin = m_currentUserMediaRequest->userMediaDocumentSecurityOrigin(); 406 auto& topLevelDocumentSecurityOrigin = m_currentUserMediaRequest->topLevelDocumentSecurityOrigin(); 407 m_page.websiteDataStore().deviceIdHashSaltStorage().deviceIdHashSaltForOrigin(userMediaDocumentSecurityOrigin, topLevelDocumentSecurityOrigin, [this, request = m_currentUserMediaRequest] (String&& deviceIDHashSalt) mutable { 408 if (!request->isPending()) 409 return; 410 411 RealtimeMediaSourceCenter::InvalidConstraintsHandler invalidHandler = [this, request](const String& invalidConstraint) { 412 if (!request->isPending()) 413 return; 414 415 if (!m_page.hasRunningProcess()) 416 return; 417 418 processUserMediaPermissionInvalidRequest(invalidConstraint); 419 }; 420 421 auto validHandler = [this, request](Vector<CaptureDevice>&& audioDevices, Vector<CaptureDevice>&& videoDevices, String&& deviceIdentifierHashSalt) mutable { 422 if (!request->isPending()) 423 return; 424 425 if (!m_page.hasRunningProcess() || !m_page.mainFrame()) 426 return; 427 428 processUserMediaPermissionValidRequest(WTFMove(audioDevices), WTFMove(videoDevices), WTFMove(deviceIdentifierHashSalt)); 429 }; 430 431 syncWithWebCorePrefs(); 432 433 RealtimeMediaSourceCenter::singleton().validateRequestConstraints(WTFMove(validHandler), WTFMove(invalidHandler), m_currentUserMediaRequest->userRequest(), WTFMove(deviceIDHashSalt)); 434 }); 435 } 436 #endif 437 438 #if ENABLE(MEDIA_STREAM) 439 void UserMediaPermissionRequestManagerProxy::processUserMediaPermissionInvalidRequest(const String& invalidConstraint) 440 { 441 ALWAYS_LOG(LOGIDENTIFIER, m_currentUserMediaRequest->userMediaID()); 442 bool filterConstraint = !m_currentUserMediaRequest->hasPersistentAccess() && !wasGrantedVideoOrAudioAccess(m_currentUserMediaRequest->frameID(), m_currentUserMediaRequest->userMediaDocumentSecurityOrigin(), m_currentUserMediaRequest->topLevelDocumentSecurityOrigin()); 443 444 denyRequest(*m_currentUserMediaRequest, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::InvalidConstraint, filterConstraint ? String { } : invalidConstraint); 445 } 446 447 void UserMediaPermissionRequestManagerProxy::processUserMediaPermissionValidRequest(Vector<CaptureDevice>&& audioDevices, Vector<CaptureDevice>&& videoDevices, String&& deviceIdentifierHashSalt) 448 { 449 ALWAYS_LOG(LOGIDENTIFIER, m_currentUserMediaRequest->userMediaID(), ", video: ", videoDevices.size(), " audio: ", audioDevices.size()); 438 450 if (videoDevices.isEmpty() && audioDevices.isEmpty()) { 439 denyRequest( request->userMediaID(), UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::NoConstraints, emptyString());440 return; 441 } 442 443 request->setDeviceIdentifierHashSalt(WTFMove(deviceIdentifierHashSalt));444 request->setEligibleVideoDeviceUIDs(WTFMove(videoDevices));445 request->setEligibleAudioDeviceUIDs(WTFMove(audioDevices));446 447 auto action = getRequestAction( request);448 ALWAYS_LOG(LOGIDENTIFIER, request->userMediaID(), ", action: ", action);451 denyRequest(*m_currentUserMediaRequest, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::NoConstraints, emptyString()); 452 return; 453 } 454 455 m_currentUserMediaRequest->setDeviceIdentifierHashSalt(WTFMove(deviceIdentifierHashSalt)); 456 m_currentUserMediaRequest->setEligibleVideoDeviceUIDs(WTFMove(videoDevices)); 457 m_currentUserMediaRequest->setEligibleAudioDeviceUIDs(WTFMove(audioDevices)); 458 459 auto action = getRequestAction(*m_currentUserMediaRequest); 460 ALWAYS_LOG(LOGIDENTIFIER, m_currentUserMediaRequest->userMediaID(), ", action: ", action); 449 461 450 462 if (action == RequestAction::Deny) { 451 denyRequest( request->userMediaID(), UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied, emptyString());463 denyRequest(*m_currentUserMediaRequest, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied, emptyString()); 452 464 return; 453 465 } 454 466 455 467 if (action == RequestAction::Grant) { 456 ASSERT( request->requestType() != MediaStreamRequest::Type::DisplayMedia);468 ASSERT(m_currentUserMediaRequest->requestType() != MediaStreamRequest::Type::DisplayMedia); 457 469 458 470 if (m_page.isViewVisible()) 459 grant Access(request);471 grantRequest(*m_currentUserMediaRequest); 460 472 else 461 m_pregrantedRequests.append( WTFMove(request));473 m_pregrantedRequests.append(m_currentUserMediaRequest.releaseNonNull()); 462 474 463 475 return; … … 466 478 if (m_page.isControlledByAutomation()) { 467 479 if (WebAutomationSession* automationSession = m_page.process().processPool().automationSession()) { 468 ALWAYS_LOG(LOGIDENTIFIER, request->userMediaID(), ", page controlled by automation");480 ALWAYS_LOG(LOGIDENTIFIER, m_currentUserMediaRequest->userMediaID(), ", page controlled by automation"); 469 481 if (automationSession->shouldAllowGetUserMediaForPage(m_page)) 470 request->allow();482 grantRequest(*m_currentUserMediaRequest); 471 483 else 472 userMediaAccessWasDenied(request->userMediaID(), UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied); 473 484 denyRequest(*m_currentUserMediaRequest, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::PermissionDenied); 474 485 return; 475 486 } … … 477 488 478 489 if (m_page.preferences().mockCaptureDevicesEnabled() && !m_page.preferences().mockCaptureDevicesPromptEnabled()) { 479 ALWAYS_LOG(LOGIDENTIFIER, request->userMediaID(), ", mock devices don't require prompt");480 request->allow();490 ALWAYS_LOG(LOGIDENTIFIER, m_currentUserMediaRequest->userMediaID(), ", mock devices don't require prompt"); 491 grantRequest(*m_currentUserMediaRequest); 481 492 return; 482 493 } 483 494 484 495 // If page navigated, there is no need to call the page client for authorization. 485 auto* webFrame = m_page.process().webFrame( request->frameID());486 487 if (!webFrame || !SecurityOrigin::createFromString(m_page.pageLoadState().activeURL())->isSameSchemeHostPort( request->topLevelDocumentSecurityOrigin())) {488 denyRequest( request->userMediaID(), UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::NoConstraints, emptyString());496 auto* webFrame = m_page.process().webFrame(m_currentUserMediaRequest->frameID()); 497 498 if (!webFrame || !SecurityOrigin::createFromString(m_page.pageLoadState().activeURL())->isSameSchemeHostPort(m_currentUserMediaRequest->topLevelDocumentSecurityOrigin())) { 499 denyRequest(*m_currentUserMediaRequest, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason::NoConstraints, emptyString()); 489 500 return; 490 501 } 491 502 492 503 // FIXME: Remove webFrame, userMediaOrigin and topLevelOrigin from this uiClient API call. 493 auto userMediaOrigin = API::SecurityOrigin::create( request->userMediaDocumentSecurityOrigin());494 auto topLevelOrigin = API::SecurityOrigin::create( request->topLevelDocumentSecurityOrigin());495 m_page.uiClient().decidePolicyForUserMediaPermissionRequest(m_page, *webFrame, WTFMove(userMediaOrigin), WTFMove(topLevelOrigin), request);504 auto userMediaOrigin = API::SecurityOrigin::create(m_currentUserMediaRequest->userMediaDocumentSecurityOrigin()); 505 auto topLevelOrigin = API::SecurityOrigin::create(m_currentUserMediaRequest->topLevelDocumentSecurityOrigin()); 506 m_page.uiClient().decidePolicyForUserMediaPermissionRequest(m_page, *webFrame, WTFMove(userMediaOrigin), WTFMove(topLevelOrigin), *m_currentUserMediaRequest); 496 507 } 497 508 … … 664 675 void UserMediaPermissionRequestManagerProxy::viewIsBecomingVisible() 665 676 { 666 for (auto& request : m_pregrantedRequests)667 request->allow();668 m_pregrantedRequests.clear();677 auto pregrantedRequests = WTFMove(m_pregrantedRequests); 678 for (auto& request : pregrantedRequests) 679 grantRequest(request); 669 680 } 670 681 -
trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestManagerProxy.h
r245335 r246093 25 25 #include <WebCore/SecurityOrigin.h> 26 26 #include <wtf/CompletionHandler.h> 27 #include <wtf/Deque.h> 27 28 #include <wtf/HashMap.h> 28 29 #include <wtf/LoggerHelper.h> … … 65 66 void viewIsBecomingVisible(); 66 67 67 void userMediaAccessWasGranted(uint64_t, WebCore::CaptureDevice&& audioDevice, WebCore::CaptureDevice&& videoDevice);68 void userMediaAccessWasDenied(uint64_t, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason);68 void grantRequest(UserMediaPermissionRequestProxy&); 69 void denyRequest(UserMediaPermissionRequestProxy&, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason, const String& invalidConstraint = { }); 69 70 70 71 void enumerateMediaDevicesForFrame(uint64_t userMediaID, uint64_t frameID, Ref<WebCore::SecurityOrigin>&& userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin); … … 94 95 95 96 Ref<UserMediaPermissionRequestProxy> createPermissionRequest(uint64_t userMediaID, uint64_t mainFrameID, uint64_t frameID, Ref<WebCore::SecurityOrigin>&& userMediaDocumentOrigin, Ref<WebCore::SecurityOrigin>&& topLevelDocumentOrigin, Vector<WebCore::CaptureDevice>&& audioDevices, Vector<WebCore::CaptureDevice>&& videoDevices, WebCore::MediaStreamRequest&&); 96 void denyRequest(uint64_t userMediaID, UserMediaPermissionRequestProxy::UserMediaAccessDenialReason, const String& invalidConstraint);97 97 #if ENABLE(MEDIA_STREAM) 98 bool grantAccess(constUserMediaPermissionRequestProxy&);98 void finishGrantingRequest(UserMediaPermissionRequestProxy&); 99 99 100 100 const UserMediaPermissionRequestProxy* searchForGrantedRequest(uint64_t frameID, const WebCore::SecurityOrigin& userMediaDocumentOrigin, const WebCore::SecurityOrigin& topLevelDocumentOrigin, bool needsAudio, bool needsVideo) const; … … 109 109 Vector<WebCore::CaptureDevice> computeFilteredDeviceList(bool revealIdsAndLabels, const String& deviceIDHashSalt); 110 110 111 void processUserMediaPermissionRequest(Ref<UserMediaPermissionRequestProxy>&&, bool hasPersistentAccess); 112 void processUserMediaPermissionInvalidRequest(const UserMediaPermissionRequestProxy&, const String& invalidConstraint); 113 void processUserMediaPermissionValidRequest(Ref<UserMediaPermissionRequestProxy>&&, Vector<WebCore::CaptureDevice>&& audioDevices, Vector<WebCore::CaptureDevice>&& videoDevices, String&& deviceIdentifierHashSalt); 111 void processUserMediaPermissionRequest(bool hasPersistentAccess); 112 void processUserMediaPermissionInvalidRequest(const String& invalidConstraint); 113 void processUserMediaPermissionValidRequest(Vector<WebCore::CaptureDevice>&& audioDevices, Vector<WebCore::CaptureDevice>&& videoDevices, String&& deviceIdentifierHashSalt); 114 void startProcessingUserMediaPermissionRequest(Ref<UserMediaPermissionRequestProxy>&&); 114 115 #endif 115 116 116 117 void watchdogTimerFired(); 117 118 118 HashMap<uint64_t, RefPtr<UserMediaPermissionRequestProxy>> m_pendingUserMediaRequests; 119 void processNextUserMediaRequestIfNeeded(); 120 121 RefPtr<UserMediaPermissionRequestProxy> m_currentUserMediaRequest; 122 Deque<Ref<UserMediaPermissionRequestProxy>> m_pendingUserMediaRequests; 119 123 HashSet<uint64_t> m_pendingDeviceRequests; 120 124 … … 122 126 123 127 RunLoop::Timer<UserMediaPermissionRequestManagerProxy> m_rejectionTimer; 124 Vector<uint64_t> m_pendingRejections;128 Deque<Ref<UserMediaPermissionRequestProxy>> m_pendingRejections; 125 129 126 130 Vector<Ref<UserMediaPermissionRequestProxy>> m_pregrantedRequests; -
trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.cpp
r243328 r246093 44 44 } 45 45 46 #if ENABLE(MEDIA_STREAM) 47 static inline void setDeviceAsFirst(Vector<CaptureDevice>& devices, const String& deviceID) 48 { 49 size_t index = devices.findMatching([&deviceID](const auto& device) { 50 return device.persistentId() == deviceID; 51 }); 52 ASSERT(index != notFound); 53 54 if (index) { 55 auto device = devices[index]; 56 ASSERT(device.enabled()); 57 58 devices.remove(index); 59 devices.insert(0, WTFMove(device)); 60 } 61 } 62 #endif 63 46 64 void UserMediaPermissionRequestProxy::allow(const String& audioDeviceUID, const String& videoDeviceUID) 47 65 { 48 ASSERT(m_manager);49 if (!m_manager)50 return;51 52 66 #if ENABLE(MEDIA_STREAM) 53 CaptureDevice audioDevice; 54 if (!audioDeviceUID.isEmpty()) { 55 size_t index = m_eligibleAudioDevices.findMatching([&](const auto& device) { 56 return device.persistentId() == audioDeviceUID; 57 }); 58 ASSERT(index != notFound); 59 60 if (index != notFound) 61 audioDevice = m_eligibleAudioDevices[index]; 62 63 ASSERT(audioDevice.enabled()); 64 } 65 66 CaptureDevice videoDevice; 67 if (!videoDeviceUID.isEmpty()) { 68 size_t index = m_eligibleVideoDevices.findMatching([&](const auto& device) { 69 return device.persistentId() == videoDeviceUID; 70 }); 71 ASSERT(index != notFound); 72 73 if (index != notFound) 74 videoDevice = m_eligibleVideoDevices[index]; 75 76 ASSERT(videoDevice.enabled()); 77 } 78 79 m_manager->userMediaAccessWasGranted(m_userMediaID, WTFMove(audioDevice), WTFMove(videoDevice)); 67 if (!audioDeviceUID.isEmpty()) 68 setDeviceAsFirst(m_eligibleAudioDevices, audioDeviceUID); 69 if (!videoDeviceUID.isEmpty()) 70 setDeviceAsFirst(m_eligibleVideoDevices, videoDeviceUID); 80 71 #else 81 72 UNUSED_PARAM(audioDeviceUID); … … 83 74 #endif 84 75 85 invalidate(); 86 } 87 88 void UserMediaPermissionRequestProxy::allow(WebCore::CaptureDevice&& audioDevice, WebCore::CaptureDevice&& videoDevice) 89 { 90 ASSERT(m_manager); 91 if (!m_manager) 92 return; 93 94 m_manager->userMediaAccessWasGranted(m_userMediaID, WTFMove(audioDevice), WTFMove(videoDevice)); 95 invalidate(); 76 allow(); 96 77 } 97 78 … … 102 83 return; 103 84 104 auto audioDevice = !m_eligibleAudioDevices.isEmpty() ? m_eligibleAudioDevices[0] : CaptureDevice(); 105 auto videoDevice = !m_eligibleVideoDevices.isEmpty() ? m_eligibleVideoDevices[0] : CaptureDevice(); 106 107 m_manager->userMediaAccessWasGranted(m_userMediaID, WTFMove(audioDevice), WTFMove(videoDevice)); 85 m_manager->grantRequest(*this); 108 86 invalidate(); 109 87 } … … 114 92 return; 115 93 116 m_manager-> userMediaAccessWasDenied(m_userMediaID, reason);94 m_manager->denyRequest(*this, reason); 117 95 invalidate(); 118 96 } -
trunk/Source/WebKit/UIProcess/UserMediaPermissionRequestProxy.h
r243328 r246093 42 42 43 43 void allow(const String& audioDeviceUID, const String& videoDeviceUID); 44 void allow(WebCore::CaptureDevice&& audioDevice, WebCore::CaptureDevice&& videoDevice);45 44 void allow(); 46 45 -
trunk/Tools/ChangeLog
r246085 r246093 1 2019-06-04 Youenn Fablet <youenn@apple.com> 2 3 getUserMedia requests should be processed sequentially in UIProcess 4 https://bugs.webkit.org/show_bug.cgi?id=198430 5 <rdar://problem/51311420> 6 7 Reviewed by Eric Carlson. 8 9 * TestWebKitAPI/Tests/WebKit/GetUserMediaReprompt.mm: 10 (-[GetUserMediaRepromptUIDelegate _webView:requestMediaCaptureAuthorization:decisionHandler:]): 11 (TestWebKitAPI::TEST): 12 * TestWebKitAPI/Tests/WebKit/getUserMedia.html: 13 1 14 2019-06-04 David Kilzer <ddkilzer@apple.com> 2 15 -
trunk/Tools/TestWebKitAPI/Tests/WebKit/GetUserMediaReprompt.mm
r242339 r246093 38 38 39 39 static bool wasPrompted = false; 40 static int numberOfPrompts = 0; 40 41 41 42 @interface GetUserMediaRepromptUIDelegate : NSObject<WKUIDelegate> … … 47 48 - (void)_webView:(WKWebView *)webView requestMediaCaptureAuthorization: (_WKCaptureDevices)devices decisionHandler:(void (^)(BOOL))decisionHandler 48 49 { 50 numberOfPrompts++; 49 51 wasPrompted = true; 50 52 decisionHandler(YES); … … 118 120 } 119 121 122 TEST(WebKit2, MultipleGetUserMediaSynchronously) 123 { 124 auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); 125 auto processPoolConfig = adoptNS([[_WKProcessPoolConfiguration alloc] init]); 126 auto preferences = [configuration preferences]; 127 preferences._mediaCaptureRequiresSecureConnection = NO; 128 preferences._mediaDevicesEnabled = YES; 129 preferences._mockCaptureDevicesEnabled = YES; 130 auto webView = [[GetUserMediaRepromptTestView alloc] initWithFrame:CGRectMake(0, 0, 320, 500) configuration:configuration.get() processPoolConfiguration:processPoolConfig.get()]; 131 auto delegate = adoptNS([[GetUserMediaRepromptUIDelegate alloc] init]); 132 webView.UIDelegate = delegate.get(); 133 134 wasPrompted = false; 135 numberOfPrompts = 0; 136 [webView loadTestPageNamed:@"getUserMedia"]; 137 TestWebKitAPI::Util::run(&wasPrompted); 138 EXPECT_EQ(numberOfPrompts, 1); 139 140 wasPrompted = false; 141 numberOfPrompts = 0; 142 [webView stringByEvaluatingJavaScript:@"doMultipleGetUserMediaSynchronously()"]; 143 TestWebKitAPI::Util::run(&wasPrompted); 144 EXPECT_EQ(numberOfPrompts, 1); 145 } 146 120 147 } // namespace TestWebKitAPI 121 148 -
trunk/Tools/TestWebKitAPI/Tests/WebKit/getUserMedia.html
r240856 r246093 37 37 return stream !== null; 38 38 } 39 40 function doMultipleGetUserMediaSynchronously() 41 { 42 navigator.mediaDevices.getUserMedia({video: true}); 43 navigator.mediaDevices.getUserMedia({video: true}); 44 navigator.mediaDevices.getUserMedia({video: true}); 45 46 // This one should prompt. 47 navigator.mediaDevices.getUserMedia({audio: true}); 48 49 navigator.mediaDevices.getUserMedia({audio: true}); 50 navigator.mediaDevices.getUserMedia({audio: true}); 51 navigator.mediaDevices.getUserMedia({audio: true, video: true}); 52 } 39 53 </script> 40 54 <head>
Note:
See TracChangeset
for help on using the changeset viewer.