Changeset 238353 in webkit
- Timestamp:
- Nov 17, 2018 2:06:56 PM (5 years ago)
- Location:
- trunk/Source/WebKit
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebKit/ChangeLog
r238351 r238353 1 2018-11-17 Chris Dumez <cdumez@apple.com> 2 3 [PSON] ASSERTION FAILED: m_uncommittedState.state == State::Committed 4 https://bugs.webkit.org/show_bug.cgi?id=191781 5 6 Reviewed by Ryosuke Niwa. 7 8 The crash was happening when switching to a suspended page that is not yet done 9 suspending (e.g. in case of very fast back/forward navigation). The WebPageProxy 10 would reattach to the suspended process and get load notifications that it did 11 not expect since it did not schedule any load yet. Those notifications are for 12 the about:blank load we do for page suspension. 13 14 To address the issue, make swapToWebProcess() asynchronous and take a completion 15 handler. When we try to unsuspend a SuspendedPageProxy, we first make sure it 16 is actually done suspending. If it is not done suspending, we wait until it is 17 before telling in to unsuspend and proceeding with the new load. 18 19 * UIProcess/SuspendedPageProxy.cpp: 20 (WebKit::SuspendedPageProxy::unsuspend): 21 (WebKit::SuspendedPageProxy::didFinishLoad): 22 * UIProcess/SuspendedPageProxy.h: 23 * UIProcess/WebPageProxy.cpp: 24 (WebKit::WebPageProxy::swapToWebProcess): 25 (WebKit::WebPageProxy::continueNavigationInNewProcess): 26 * UIProcess/WebPageProxy.h: 27 1 28 2018-11-17 Chris Dumez <cdumez@apple.com> 2 29 -
trunk/Source/WebKit/UIProcess/SuspendedPageProxy.cpp
r238061 r238353 104 104 } 105 105 106 void SuspendedPageProxy::unsuspend( )106 void SuspendedPageProxy::unsuspend(CompletionHandler<void()>&& completionHandler) 107 107 { 108 108 ASSERT(m_isSuspended); 109 109 110 m_isSuspended = false; 111 m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_page.pageID()); 112 m_process->send(Messages::WebPage::SetIsSuspended(false), m_page.pageID()); 110 auto doUnsuspend = [this, completionHandler = WTFMove(completionHandler)]() mutable { 111 m_isSuspended = false; 112 m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_page.pageID()); 113 m_process->send(Messages::WebPage::SetIsSuspended(false), m_page.pageID()); 114 completionHandler(); 115 }; 116 117 if (!m_finishedSuspending) { 118 ASSERT(!m_finishedSuspendingHandler); 119 m_finishedSuspendingHandler = WTFMove(doUnsuspend); 120 } else 121 doUnsuspend(); 113 122 } 114 123 … … 117 126 LOG(ProcessSwapping, "SuspendedPageProxy %s from process %i finished transition to suspended", loggingString(), m_process->processIdentifier()); 118 127 119 #if !LOG_DISABLED120 128 m_finishedSuspending = true; 121 #endif122 129 123 130 m_process->send(Messages::WebProcess::UpdateActivePages(), 0); 131 132 if (auto finishedSuspendingHandler = WTFMove(m_finishedSuspendingHandler)) 133 finishedSuspendingHandler(); 124 134 } 125 135 -
trunk/Source/WebKit/UIProcess/SuspendedPageProxy.h
r237735 r238353 47 47 const String& registrableDomain() const { return m_registrableDomain; } 48 48 49 void unsuspend( );49 void unsuspend(CompletionHandler<void()>&&); 50 50 51 51 #if !LOG_DISABLED … … 67 67 bool m_isSuspended { true }; 68 68 69 #if !LOG_DISABLED70 69 bool m_finishedSuspending { false }; 71 #endif 70 CompletionHandler<void()> m_finishedSuspendingHandler; 72 71 }; 73 72 -
trunk/Source/WebKit/UIProcess/WebPageProxy.cpp
r238338 r238353 751 751 } 752 752 753 void WebPageProxy::swapToWebProcess(Ref<WebProcessProxy>&& process, API::Navigation& navigation, std::optional<uint64_t> mainFrameIDInPreviousProcess )753 void WebPageProxy::swapToWebProcess(Ref<WebProcessProxy>&& process, API::Navigation& navigation, std::optional<uint64_t> mainFrameIDInPreviousProcess, CompletionHandler<void()>&& completionHandler) 754 754 { 755 755 ASSERT(!m_isClosed); … … 761 761 destinationSuspendedPage = this->process().processPool().takeSuspendedPage(*backForwardListItem->suspendedPage()); 762 762 ASSERT(destinationSuspendedPage); 763 destinationSuspendedPage->unsuspend();764 763 } 765 764 } 766 765 767 m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID); 768 bool didSuspendPreviousPage = suspendCurrentPageIfPossible(navigation, mainFrameIDInPreviousProcess); 769 m_process->removeWebPage(*this, m_pageID); 770 771 m_process = WTFMove(process); 772 m_isValid = true; 773 774 // If we are reattaching to a SuspendedPage, then the WebProcess' WebPage already exists and 775 // WebPageProxy::didCreateMainFrame() will not be called to initialize m_mainFrame. In such 776 // case, we need to initialize m_mainFrame to reflect the fact the the WebProcess' WebPage 777 // already exists and already has a main frame. 778 if (destinationSuspendedPage) { 779 ASSERT(!m_mainFrame); 780 ASSERT(&destinationSuspendedPage->process() == m_process.ptr()); 781 m_mainFrame = WebFrameProxy::create(*this, destinationSuspendedPage->mainFrameID()); 782 m_process->frameCreated(destinationSuspendedPage->mainFrameID(), *m_mainFrame); 783 } 784 785 finishAttachingToWebProcess(didSuspendPreviousPage ? ShouldDelayAttachingDrawingArea::Yes : ShouldDelayAttachingDrawingArea::No); 766 auto* destinationSuspendedPagePtr = destinationSuspendedPage.get(); 767 auto doSwap = [this, protectedThis = makeRef(*this), navigation = makeRef(navigation), process = WTFMove(process), mainFrameIDInPreviousProcess, destinationSuspendedPage = WTFMove(destinationSuspendedPage), completionHandler = WTFMove(completionHandler)]() mutable { 768 processDidTerminate(ProcessTerminationReason::NavigationSwap); 769 770 m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID); 771 bool didSuspendPreviousPage = suspendCurrentPageIfPossible(navigation, mainFrameIDInPreviousProcess); 772 m_process->removeWebPage(*this, m_pageID); 773 774 m_process = WTFMove(process); 775 m_isValid = true; 776 777 // If we are reattaching to a SuspendedPage, then the WebProcess' WebPage already exists and 778 // WebPageProxy::didCreateMainFrame() will not be called to initialize m_mainFrame. In such 779 // case, we need to initialize m_mainFrame to reflect the fact the the WebProcess' WebPage 780 // already exists and already has a main frame. 781 if (destinationSuspendedPage) { 782 ASSERT(!m_mainFrame); 783 ASSERT(&destinationSuspendedPage->process() == m_process.ptr()); 784 m_mainFrame = WebFrameProxy::create(*this, destinationSuspendedPage->mainFrameID()); 785 m_process->frameCreated(destinationSuspendedPage->mainFrameID(), *m_mainFrame); 786 } 787 788 finishAttachingToWebProcess(didSuspendPreviousPage ? ShouldDelayAttachingDrawingArea::Yes : ShouldDelayAttachingDrawingArea::No); 789 completionHandler(); 790 }; 791 792 if (destinationSuspendedPagePtr) 793 destinationSuspendedPagePtr->unsuspend(WTFMove(doSwap)); 794 else 795 doSwap(); 786 796 } 787 797 … … 2649 2659 ASSERT(m_process.ptr() != process.ptr()); 2650 2660 2651 processDidTerminate(ProcessTerminationReason::NavigationSwap); 2652 2653 swapToWebProcess(WTFMove(process), navigation, mainFrameIDInPreviousProcess); 2654 2655 if (auto* item = navigation.targetItem()) { 2656 LOG(Loading, "WebPageProxy %p continueNavigationInNewProcess to back item URL %s", this, item->url().utf8().data()); 2657 2658 auto transaction = m_pageLoadState.transaction(); 2659 m_pageLoadState.setPendingAPIRequestURL(transaction, item->url()); 2660 2661 auto itemStates = m_backForwardList->filteredItemStates([this, targetItem = item](WebBackForwardListItem& item) { 2662 if (auto* page = item.suspendedPage()) { 2663 if (&page->process() == m_process.ptr()) 2664 return false; 2661 swapToWebProcess(WTFMove(process), navigation, mainFrameIDInPreviousProcess, [this, protectedThis = makeRef(*this), navigation = makeRef(navigation), previousProcess = WTFMove(previousProcess), mainFrameIDInPreviousProcess, mainFrameURL = WTFMove(mainFrameURL)]() mutable { 2662 if (auto* item = navigation->targetItem()) { 2663 LOG(Loading, "WebPageProxy %p continueNavigationInNewProcess to back item URL %s", this, item->url().utf8().data()); 2664 2665 auto transaction = m_pageLoadState.transaction(); 2666 m_pageLoadState.setPendingAPIRequestURL(transaction, item->url()); 2667 2668 auto itemStates = m_backForwardList->filteredItemStates([this, targetItem = item](WebBackForwardListItem& item) { 2669 if (auto* page = item.suspendedPage()) { 2670 if (&page->process() == m_process.ptr()) 2671 return false; 2672 } 2673 return &item != targetItem; 2674 }); 2675 m_process->send(Messages::WebPage::UpdateBackForwardListForReattach(WTFMove(itemStates)), m_pageID); 2676 m_process->send(Messages::WebPage::GoToBackForwardItem(navigation->navigationID(), item->itemID(), *navigation->backForwardFrameLoadType(), ShouldTreatAsContinuingLoad::Yes), m_pageID); 2677 m_process->responsivenessTimer().start(); 2678 2679 return; 2680 } 2681 2682 if (navigation->lockBackForwardList() == LockBackForwardList::Yes || navigation->lockHistory() == LockHistory::Yes) { 2683 // If WebCore is supposed to lock the history for this load, then the new process needs to know about the current history item so it can update 2684 // it instead of creating a new one. 2685 auto itemStates = m_backForwardList->filteredItemStates([currentItem = m_backForwardList->currentItem()](WebBackForwardListItem& item) { 2686 return &item == currentItem; 2687 }); 2688 RELEASE_ASSERT(itemStates.size() == 1); 2689 m_process->send(Messages::WebPage::SetCurrentHistoryItemForReattach(itemStates[0]), m_pageID); 2690 } 2691 2692 // FIXME: Work out timing of responding with the last policy delegate, etc 2693 ASSERT(!navigation->currentRequest().isEmpty()); 2694 if (auto& substituteData = navigation->substituteData()) 2695 loadDataWithNavigation(navigation, { substituteData->content.data(), substituteData->content.size() }, substituteData->MIMEType, substituteData->encoding, substituteData->baseURL, substituteData->userData.get()); 2696 else 2697 loadRequestWithNavigation(navigation, ResourceRequest { navigation->currentRequest() }, WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes, nullptr, ShouldTreatAsContinuingLoad::Yes); 2698 2699 ASSERT(!m_mainFrame); 2700 m_mainFrameCreationHandler = [this, protectedThis = makeRef(*this), navigation = navigation.copyRef(), request = navigation->currentRequest(), mainFrameURL, isServerRedirect = navigation->currentRequestIsRedirect()]() mutable { 2701 ASSERT(m_mainFrame); 2702 // Restore the main frame's committed URL as some clients may rely on it until the next load is committed. 2703 m_mainFrame->frameLoadState().setURL(mainFrameURL); 2704 2705 // Normally, notification of a server redirect comes from the WebContent process. 2706 // If we are process swapping in response to a server redirect then that notification will not come from the new WebContent process. 2707 // In this case we have the UIProcess synthesize the redirect notification at the appropriate time. 2708 if (isServerRedirect) { 2709 m_mainFrame->frameLoadState().didStartProvisionalLoad(request.url()); 2710 didReceiveServerRedirectForProvisionalLoadForFrame(m_mainFrame->frameID(), navigation->navigationID(), WTFMove(request), { }); 2665 2711 } 2666 return &item != targetItem; 2667 }); 2668 m_process->send(Messages::WebPage::UpdateBackForwardListForReattach(WTFMove(itemStates)), m_pageID); 2669 m_process->send(Messages::WebPage::GoToBackForwardItem(navigation.navigationID(), item->itemID(), *navigation.backForwardFrameLoadType(), ShouldTreatAsContinuingLoad::Yes), m_pageID); 2670 m_process->responsivenessTimer().start(); 2671 2672 return; 2673 } 2674 2675 if (navigation.lockBackForwardList() == LockBackForwardList::Yes || navigation.lockHistory() == LockHistory::Yes) { 2676 // If WebCore is supposed to lock the history for this load, then the new process needs to know about the current history item so it can update 2677 // it instead of creating a new one. 2678 auto itemStates = m_backForwardList->filteredItemStates([currentItem = m_backForwardList->currentItem()](WebBackForwardListItem& item) { 2679 return &item == currentItem; 2680 }); 2681 RELEASE_ASSERT(itemStates.size() == 1); 2682 m_process->send(Messages::WebPage::SetCurrentHistoryItemForReattach(itemStates[0]), m_pageID); 2683 } 2684 2685 // FIXME: Work out timing of responding with the last policy delegate, etc 2686 ASSERT(!navigation.currentRequest().isEmpty()); 2687 if (auto& substituteData = navigation.substituteData()) 2688 loadDataWithNavigation(navigation, { substituteData->content.data(), substituteData->content.size() }, substituteData->MIMEType, substituteData->encoding, substituteData->baseURL, substituteData->userData.get()); 2689 else 2690 loadRequestWithNavigation(navigation, ResourceRequest { navigation.currentRequest() }, WebCore::ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemes, nullptr, ShouldTreatAsContinuingLoad::Yes); 2691 2692 ASSERT(!m_mainFrame); 2693 m_mainFrameCreationHandler = [this, protectedThis = makeRef(*this), navigation = makeRef(navigation), request = navigation.currentRequest(), mainFrameURL, isServerRedirect = navigation.currentRequestIsRedirect()]() mutable { 2694 ASSERT(m_mainFrame); 2695 // Restore the main frame's committed URL as some clients may rely on it until the next load is committed. 2696 m_mainFrame->frameLoadState().setURL(mainFrameURL); 2697 2698 // Normally, notification of a server redirect comes from the WebContent process. 2699 // If we are process swapping in response to a server redirect then that notification will not come from the new WebContent process. 2700 // In this case we have the UIProcess synthesize the redirect notification at the appropriate time. 2701 if (isServerRedirect) { 2702 m_mainFrame->frameLoadState().didStartProvisionalLoad(request.url()); 2703 didReceiveServerRedirectForProvisionalLoadForFrame(m_mainFrame->frameID(), navigation->navigationID(), WTFMove(request), { }); 2704 } 2705 }; 2706 2707 bool isInitialNavigationInNewWindow = openedByDOM() && !hasCommittedAnyProvisionalLoads(); 2708 if (!isInitialNavigationInNewWindow || !mainFrameIDInPreviousProcess) 2709 return; 2710 2711 m_mainFrameWindowCreationHandler = [this, previousProcess = WTFMove(previousProcess), mainFrameIDInPreviousProcess = *mainFrameIDInPreviousProcess](const GlobalWindowIdentifier& windowIdentifier) { 2712 ASSERT(m_mainFrame); 2713 GlobalFrameIdentifier navigatedFrameIdentifierInNewProcess { pageID(), m_mainFrame->frameID() }; 2714 previousProcess->send(Messages::WebPage::FrameBecameRemote(mainFrameIDInPreviousProcess, navigatedFrameIdentifierInNewProcess, windowIdentifier), pageID()); 2715 }; 2712 }; 2713 2714 bool isInitialNavigationInNewWindow = openedByDOM() && !hasCommittedAnyProvisionalLoads(); 2715 if (!isInitialNavigationInNewWindow || !mainFrameIDInPreviousProcess) 2716 return; 2717 2718 m_mainFrameWindowCreationHandler = [this, previousProcess = WTFMove(previousProcess), mainFrameIDInPreviousProcess = *mainFrameIDInPreviousProcess](const GlobalWindowIdentifier& windowIdentifier) { 2719 ASSERT(m_mainFrame); 2720 GlobalFrameIdentifier navigatedFrameIdentifierInNewProcess { pageID(), m_mainFrame->frameID() }; 2721 previousProcess->send(Messages::WebPage::FrameBecameRemote(mainFrameIDInPreviousProcess, navigatedFrameIdentifierInNewProcess, windowIdentifier), pageID()); 2722 }; 2723 }); 2716 2724 } 2717 2725 -
trunk/Source/WebKit/UIProcess/WebPageProxy.h
r238330 r238353 1544 1544 1545 1545 void reattachToWebProcess(); 1546 void swapToWebProcess(Ref<WebProcessProxy>&&, API::Navigation&, std::optional<uint64_t> mainFrameIDInPreviousProcess );1546 void swapToWebProcess(Ref<WebProcessProxy>&&, API::Navigation&, std::optional<uint64_t> mainFrameIDInPreviousProcess, CompletionHandler<void()>&&); 1547 1547 1548 1548 void finishAttachingToWebProcess(ShouldDelayAttachingDrawingArea = ShouldDelayAttachingDrawingArea::No);
Note: See TracChangeset
for help on using the changeset viewer.