Changeset 230640 in webkit


Ignore:
Timestamp:
Apr 13, 2018 11:04:22 AM (6 years ago)
Author:
beidson@apple.com
Message:

Introduce SuspendedPageProxy to keep old web processes around after their WebPageProxy has been swapped to a new one.
https://bugs.webkit.org/show_bug.cgi?id=184559

Reviewed by Alex Christensen.

Source/WebCore:

Covered by new API test.

WebCore changes rework the meaning of a "ForSuspension" policy to simply navigate the page to about:blank.

  • loader/DocumentLoader.cpp:

(WebCore::DocumentLoader::redirectReceived):
(WebCore::DocumentLoader::willSendRequest):
(WebCore::DocumentLoader::startLoadingMainResource):

  • loader/DocumentLoader.h:
  • loader/FrameLoader.cpp:

(WebCore::FrameLoader::init):
(WebCore::FrameLoader::continueLoadAfterNavigationPolicy):

Source/WebKit:

Before this patch, when a WebPageProxy navigates and is swapped to a new process, the old process almost always goes away.

This is not desirable for a few reasons:
1 - We can't keep the PageCache working for back/forward scenarios
2 - We throw away a "foo.com" web process, meaning the next time we need to host a "foo.com" web page we have to launch

and initialize a new web process.

This patch adds a SuspendedPageProxy object to keep around the old web process and to manage communication with it.

For now, a WebPageProxy keeps exactly one "suspended page" representing the most recently visited page and its process.
Additionally, that process is never reused.

So no benefit is achieved with this patch, but it enables future benefits.

  • Platform/Logging.h:
  • Shared/WebBackForwardListItem.cpp:

(WebKit::WebBackForwardListItem::setSuspendedPage):

  • Shared/WebBackForwardListItem.h:

New object to represent the state of a WebPageProxy in an old web process that is not currently hosting the view.

  • UIProcess/SuspendedPageProxy.cpp: Added.

(WebKit::SuspendedPageProxy::SuspendedPageProxy):
(WebKit::SuspendedPageProxy::~SuspendedPageProxy):
(WebKit::SuspendedPageProxy::webProcessDidClose):
(WebKit::SuspendedPageProxy::didFinishLoad):
(WebKit::SuspendedPageProxy::didReceiveMessage):
(WebKit::SuspendedPageProxy::loggingString const):

  • UIProcess/SuspendedPageProxy.h: Copied from Source/WebKit/Platform/Logging.h.

(WebKit::SuspendedPageProxy::create):
(WebKit::SuspendedPageProxy::page const):
(WebKit::SuspendedPageProxy::process const):
(WebKit::SuspendedPageProxy::item const):
(WebKit::SuspendedPageProxy::finishedSuspending const):

  • UIProcess/WebPageProxy.cpp:

(WebKit::WebPageProxy::reattachToWebProcess):
(WebKit::WebPageProxy::attachToProcessForNavigation):
(WebKit::WebPageProxy::maybeCreateSuspendedPage):
(WebKit::WebPageProxy::suspendedPageProcessClosed):
(WebKit::WebPageProxy::receivedPolicyDecision):
(WebKit::WebPageProxy::didFinishLoadForFrame):

  • UIProcess/WebPageProxy.h:
  • UIProcess/WebProcessProxy.cpp:

(WebKit::WebProcessProxy::suspendWebPageProxy):
(WebKit::WebProcessProxy::suspendedPageWasDestroyed):
(WebKit::WebProcessProxy::removeWebPage):
(WebKit::WebProcessProxy::didReceiveMessage): Optionally pass WebPageProxy messages along to SuspendedPageProxy objects.
(WebKit::WebProcessProxy::didClose):
(WebKit::WebProcessProxy::maybeShutDown):
(WebKit::WebProcessProxy::canTerminateChildProcess): Don't terminate child processes if they still have suspended pages.

  • UIProcess/WebProcessProxy.h:
  • WebKit.xcodeproj/project.pbxproj:
  • WebProcess/WebPage/WebPage.cpp:

(WebKit::WebPage::setIsSuspended):

  • WebProcess/WebPage/WebPage.h:

(WebKit::WebPage::isSuspended const): For now, used only by WebProcess::updateActivePages. Will have more uses soon.

  • WebProcess/WebPage/WebPage.messages.in:
  • WebProcess/WebProcess.messages.in:
  • WebProcess/cocoa/WebProcessCocoa.mm:

(WebKit::WebProcess::updateActivePages): Allow the UIProcess to request an update of the web processes user visible name.

Source/WTF:

  • wtf/DebugUtilities.h:

(WTF::debugString): Add a debug utility to easily construct a "const char*" that is released after a spin of the run loop.

This greatly eases uses our String classes and functions inside of "%s" style environments like printf and LOG.

Tools:

  • TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
Location:
trunk
Files:
1 added
22 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/Source/WTF/ChangeLog

    r230589 r230640  
     12018-04-13  Brady Eidson  <beidson@apple.com>
     2
     3        Introduce SuspendedPageProxy to keep old web processes around after their WebPageProxy has been swapped to a new one.
     4        https://bugs.webkit.org/show_bug.cgi?id=184559
     5
     6        Reviewed by Alex Christensen.
     7
     8        * wtf/DebugUtilities.h:
     9        (WTF::debugString): Add a debug utility to easily construct a "const char*" that is released after a spin of the run loop.
     10          This greatly eases uses our String classes and functions inside of "%s" style environments like printf and LOG.
     11
    1122018-04-12  Michael Catanzaro  <mcatanzaro@igalia.com>
    213
  • trunk/Source/WTF/wtf/DebugUtilities.h

    r229770 r230640  
    11/*
    2  * Copyright (C) 2017 Apple Inc. All rights reserved.
     2 * Copyright (C) 2017-2018 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2424 */
    2525
    26 #ifndef WTF_DebugUtilities_h
    27 #define WTF_DebugUtilities_h
     26#pragma once
    2827
    2928#include <wtf/Assertions.h>
    3029#include <wtf/ProcessID.h>
     30#include <wtf/text/StringConcatenate.h>
    3131
    3232#define SLEEP_THREAD_FOR_DEBUGGER() \
     
    4141} while (0)
    4242
    43 #endif /* WTF_DebugUtilities_h */
     43namespace WTF {
     44
     45template<typename... StringTypes>
     46const char* debugString(StringTypes... strings)
     47{
     48    String result = tryMakeString(strings...);
     49    if (!result)
     50        CRASH();
     51
     52    auto cString = result.utf8();
     53    const char* cStringData = cString.data();
     54
     55    callOnMainThread([cString = WTFMove(cString)] {
     56    });
     57
     58    return cStringData;
     59}
     60
     61} // namespace WTF
     62
     63using WTF::debugString;
  • trunk/Source/WebCore/ChangeLog

    r230639 r230640  
     12018-04-13  Brady Eidson  <beidson@apple.com>
     2
     3        Introduce SuspendedPageProxy to keep old web processes around after their WebPageProxy has been swapped to a new one.
     4        https://bugs.webkit.org/show_bug.cgi?id=184559
     5
     6        Reviewed by Alex Christensen.
     7
     8        Covered by new API test.
     9
     10        WebCore changes rework the meaning of a "ForSuspension" policy to simply navigate the page to about:blank.
     11
     12        * loader/DocumentLoader.cpp:
     13        (WebCore::DocumentLoader::redirectReceived):
     14        (WebCore::DocumentLoader::willSendRequest):
     15        (WebCore::DocumentLoader::startLoadingMainResource):
     16        * loader/DocumentLoader.h:
     17
     18        * loader/FrameLoader.cpp:
     19        (WebCore::FrameLoader::init):
     20        (WebCore::FrameLoader::continueLoadAfterNavigationPolicy):
     21
    1222018-04-13  Chris Dumez  <cdumez@apple.com>
    223
  • trunk/Source/WebCore/loader/DocumentLoader.cpp

    r230458 r230640  
    520520#if ENABLE(SERVICE_WORKER)
    521521    bool isRedirectionFromServiceWorker = redirectResponse.source() == ResourceResponse::Source::ServiceWorker;
    522     willSendRequest(WTFMove(request), redirectResponse, [isRedirectionFromServiceWorker, completionHandler = WTFMove(completionHandler), protectedThis = makeRef(*this), this] (auto&& request) mutable {
     522    willSendRequest(WTFMove(request), redirectResponse, ShouldContinue::Yes, [isRedirectionFromServiceWorker, completionHandler = WTFMove(completionHandler), protectedThis = makeRef(*this), this] (auto&& request) mutable {
    523523        ASSERT(!m_substituteData.isValid());
    524524        if (request.isNull() || !m_mainDocumentError.isNull() || !m_frame) {
     
    553553    });
    554554#else
    555     willSendRequest(WTFMove(request), redirectResponse, WTFMove(completionHandler));
    556 #endif
    557 }
    558 
    559 void DocumentLoader::willSendRequest(ResourceRequest&& newRequest, const ResourceResponse& redirectResponse, CompletionHandler<void(ResourceRequest&&)>&& completionHandler)
     555    willSendRequest(WTFMove(request), redirectResponse, ShouldContinue::Yes, WTFMove(completionHandler));
     556#endif
     557}
     558
     559void DocumentLoader::willSendRequest(ResourceRequest&& newRequest, const ResourceResponse& redirectResponse, ShouldContinue shouldContinue, CompletionHandler<void(ResourceRequest&&)>&& completionHandler)
    560560{
    561561    // Note that there are no asserts here as there are for the other callbacks. This is due to the
     
    564564    // callbacks is meant to prevent.
    565565    ASSERT(!newRequest.isNull());
     566
     567    ASSERT(shouldContinue != ShouldContinue::No);
    566568
    567569    bool didReceiveRedirectResponse = !redirectResponse.isNull();
     
    631633    setRequest(newRequest);
    632634
    633     // FIXME: Ideally we'd stop the I/O until we hear back from the navigation policy delegate
    634     // listener. But there's no way to do that in practice. So instead we cancel later if the
    635     // listener tells us to. In practice that means the navigation policy needs to be decided
    636     // synchronously for these redirect cases.
    637     if (!didReceiveRedirectResponse)
     635    if (!didReceiveRedirectResponse && shouldContinue != ShouldContinue::ForSuspension)
    638636        return completionHandler(WTFMove(newRequest));
    639637
    640     ASSERT(!m_waitingForNavigationPolicy);
    641     m_waitingForNavigationPolicy = true;
    642     frameLoader()->policyChecker().checkNavigationPolicy(ResourceRequest(newRequest), didReceiveRedirectResponse, [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)] (ResourceRequest&& request, FormState*, ShouldContinue shouldContinue) mutable {
     638    auto navigationPolicyCompletionHandler = [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)] (ResourceRequest&& request, FormState*, ShouldContinue shouldContinue) mutable {
    643639        m_waitingForNavigationPolicy = false;
    644640        switch (shouldContinue) {
    645641        case ShouldContinue::ForSuspension:
    646             FALLTHROUGH;
    647             // FIXME: Setup this page for suspension (e.g. Page Cache) here.
     642            // We handle suspension by navigating forward to about:blank, which leaves us setup to navigate back to resume.
     643            request = { blankURL() };
     644            break;
    648645        case ShouldContinue::No:
    649646            stopLoadingForPolicyChange();
     
    654651
    655652        completionHandler(WTFMove(request));
    656     });
     653    };
     654
     655    ASSERT(!m_waitingForNavigationPolicy);
     656    m_waitingForNavigationPolicy = true;
     657
     658    if (shouldContinue == ShouldContinue::ForSuspension) {
     659        navigationPolicyCompletionHandler(WTFMove(newRequest), nullptr, shouldContinue);
     660        return;
     661    }
     662
     663    frameLoader()->policyChecker().checkNavigationPolicy(ResourceRequest(newRequest), didReceiveRedirectResponse, WTFMove(navigationPolicyCompletionHandler));
    657664}
    658665
     
    16561663}
    16571664
    1658 void DocumentLoader::startLoadingMainResource()
    1659 {
     1665void DocumentLoader::startLoadingMainResource(ShouldContinue shouldContinue)
     1666{
     1667    ASSERT(shouldContinue != ShouldContinue::No);
     1668
    16601669    m_mainDocumentError = ResourceError();
    16611670    timing().markStartTimeAndFetchStart();
     
    16821691    ASSERT(timing().fetchStart());
    16831692
    1684     willSendRequest(ResourceRequest(m_request), ResourceResponse(), [this, protectedThis = makeRef(*this)] (ResourceRequest&& request) mutable {
     1693    willSendRequest(ResourceRequest(m_request), ResourceResponse(), shouldContinue, [this, protectedThis = makeRef(*this)] (ResourceRequest&& request) mutable {
    16851694        m_request = request;
    16861695
  • trunk/Source/WebCore/loader/DocumentLoader.h

    r229675 r230640  
    8585class SubstituteResource;
    8686
     87enum class ShouldContinue;
     88
    8789using ResourceLoaderMap = HashMap<unsigned long, RefPtr<ResourceLoader>>;
    8890
     
    238240    void setMainResourceDataBufferingPolicy(DataBufferingPolicy);
    239241
    240     void startLoadingMainResource();
     242    void startLoadingMainResource(ShouldContinue);
    241243    WEBCORE_EXPORT void cancelMainResourceLoad(const ResourceError&);
    242244    void willContinueMainResourceLoadAfterRedirect(const ResourceRequest&);
     
    352354#endif
    353355
    354     void willSendRequest(ResourceRequest&&, const ResourceResponse&, CompletionHandler<void(ResourceRequest&&)>&&);
     356    void willSendRequest(ResourceRequest&&, const ResourceResponse&, ShouldContinue, CompletionHandler<void(ResourceRequest&&)>&&);
    355357    void finishedLoading();
    356358    void mainReceivedError(const ResourceError&);
  • trunk/Source/WebCore/loader/FrameLoader.cpp

    r230458 r230640  
    307307    setPolicyDocumentLoader(m_client.createDocumentLoader(ResourceRequest(URL(ParsedURLString, emptyString())), SubstituteData()).ptr());
    308308    setProvisionalDocumentLoader(m_policyDocumentLoader.get());
    309     m_provisionalDocumentLoader->startLoadingMainResource();
     309    m_provisionalDocumentLoader->startLoadingMainResource(ShouldContinue::Yes);
    310310
    311311    Ref<Frame> protect(m_frame);
     
    32323232    }
    32333233
    3234     WTF::Function<void(void)> completionHandler = [this] {
     3234    CompletionHandler<void(void)> completionHandler = [this, shouldContinue] {
    32353235        if (!m_provisionalDocumentLoader)
    32363236            return;
     
    32523252       
    32533253        m_loadingFromCachedPage = false;
    3254         m_provisionalDocumentLoader->startLoadingMainResource();
     3254
     3255        // We handle suspension by navigating forward to about:blank, which leaves us setup to navigate back to resume.
     3256        if (shouldContinue == ShouldContinue::ForSuspension)
     3257            m_provisionalDocumentLoader->willContinueMainResourceLoadAfterRedirect({ blankURL() });
     3258
     3259        m_provisionalDocumentLoader->startLoadingMainResource(shouldContinue);
    32553260    };
    32563261   
  • trunk/Source/WebKit/ChangeLog

    r230636 r230640  
     12018-04-13  Brady Eidson  <beidson@apple.com>
     2
     3        Introduce SuspendedPageProxy to keep old web processes around after their WebPageProxy has been swapped to a new one.
     4        https://bugs.webkit.org/show_bug.cgi?id=184559
     5
     6        Reviewed by Alex Christensen.
     7
     8        Before this patch, when a WebPageProxy navigates and is swapped to a new process, the old process almost always goes away.
     9
     10        This is not desirable for a few reasons:
     11        1 - We can't keep the PageCache working for back/forward scenarios
     12        2 - We throw away a "foo.com" web process, meaning the next time we need to host a "foo.com" web page we have to launch
     13            and initialize a new web process.
     14
     15        This patch adds a SuspendedPageProxy object to keep around the old web process and to manage communication with it.
     16
     17        For now, a WebPageProxy keeps exactly one "suspended page" representing the most recently visited page and its process.
     18        Additionally, that process is never reused.
     19
     20        So no benefit is achieved with this patch, but it enables future benefits.
     21
     22        * Platform/Logging.h:
     23
     24        * Shared/WebBackForwardListItem.cpp:
     25        (WebKit::WebBackForwardListItem::setSuspendedPage):
     26        * Shared/WebBackForwardListItem.h:
     27
     28        New object to represent the state of a WebPageProxy in an old web process that is not currently hosting the view.
     29        * UIProcess/SuspendedPageProxy.cpp: Added.
     30        (WebKit::SuspendedPageProxy::SuspendedPageProxy):
     31        (WebKit::SuspendedPageProxy::~SuspendedPageProxy):
     32        (WebKit::SuspendedPageProxy::webProcessDidClose):
     33        (WebKit::SuspendedPageProxy::didFinishLoad):
     34        (WebKit::SuspendedPageProxy::didReceiveMessage):
     35        (WebKit::SuspendedPageProxy::loggingString const):
     36        * UIProcess/SuspendedPageProxy.h: Copied from Source/WebKit/Platform/Logging.h.
     37        (WebKit::SuspendedPageProxy::create):
     38        (WebKit::SuspendedPageProxy::page const):
     39        (WebKit::SuspendedPageProxy::process const):
     40        (WebKit::SuspendedPageProxy::item const):
     41        (WebKit::SuspendedPageProxy::finishedSuspending const):
     42
     43        * UIProcess/WebPageProxy.cpp:
     44        (WebKit::WebPageProxy::reattachToWebProcess):
     45        (WebKit::WebPageProxy::attachToProcessForNavigation):
     46        (WebKit::WebPageProxy::maybeCreateSuspendedPage):
     47        (WebKit::WebPageProxy::suspendedPageProcessClosed):
     48        (WebKit::WebPageProxy::receivedPolicyDecision):
     49        (WebKit::WebPageProxy::didFinishLoadForFrame):
     50        * UIProcess/WebPageProxy.h:
     51
     52        * UIProcess/WebProcessProxy.cpp:
     53        (WebKit::WebProcessProxy::suspendWebPageProxy):
     54        (WebKit::WebProcessProxy::suspendedPageWasDestroyed):
     55        (WebKit::WebProcessProxy::removeWebPage):
     56        (WebKit::WebProcessProxy::didReceiveMessage): Optionally pass WebPageProxy messages along to SuspendedPageProxy objects.
     57        (WebKit::WebProcessProxy::didClose):
     58        (WebKit::WebProcessProxy::maybeShutDown):
     59        (WebKit::WebProcessProxy::canTerminateChildProcess): Don't terminate child processes if they still have suspended pages.
     60        * UIProcess/WebProcessProxy.h:
     61
     62        * WebKit.xcodeproj/project.pbxproj:
     63
     64        * WebProcess/WebPage/WebPage.cpp:
     65        (WebKit::WebPage::setIsSuspended):
     66        * WebProcess/WebPage/WebPage.h:
     67        (WebKit::WebPage::isSuspended const): For now, used only by WebProcess::updateActivePages. Will have more uses soon.
     68        * WebProcess/WebPage/WebPage.messages.in:
     69
     70        * WebProcess/WebProcess.messages.in:
     71        * WebProcess/cocoa/WebProcessCocoa.mm:
     72        (WebKit::WebProcess::updateActivePages): Allow the UIProcess to request an update of the web processes user visible name.
     73
    1742018-04-13  Daniel Bates  <dabates@apple.com>
    275
  • trunk/Source/WebKit/Platform/Logging.h

    r230560 r230640  
    6363    M(Process) \
    6464    M(ProcessSuspension) \
     65    M(ProcessSwapping) \
    6566    M(RemoteLayerTree) \
    6667    M(Resize) \
  • trunk/Source/WebKit/Shared/WebBackForwardListItem.cpp

    r210042 r230640  
    104104}
    105105
     106void WebBackForwardListItem::setSuspendedPage(SuspendedPageProxy& page)
     107{
     108    m_suspendedPage = &page;
     109}
     110
    106111} // namespace WebKit
  • trunk/Source/WebKit/Shared/WebBackForwardListItem.h

    r222824 r230640  
    4242namespace WebKit {
    4343
     44class SuspendedPageProxy;
     45
    4446class WebBackForwardListItem : public API::ObjectImpl<API::Object::Type::BackForwardListItem> {
    4547public:
     
    6466    void setSnapshot(RefPtr<ViewSnapshot>&& snapshot) { m_itemState.snapshot = WTFMove(snapshot); }
    6567#endif
     68    void setSuspendedPage(SuspendedPageProxy&);
    6669
    6770    static uint64_t highestUsedItemID();
     
    7275    BackForwardListItemState m_itemState;
    7376    uint64_t m_pageID;
     77    SuspendedPageProxy* m_suspendedPage { nullptr };
    7478};
    7579
  • trunk/Source/WebKit/UIProcess/SuspendedPageProxy.h

    r230639 r230640  
    11/*
    2  * Copyright (C) 2010, 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2018 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2626#pragma once
    2727
    28 #include <pal/LogMacros.h>
    29 #include <wtf/Assertions.h>
    30 #include <wtf/text/WTFString.h>
     28#include "Connection.h"
     29#include "WebBackForwardListItem.h"
     30#include <wtf/RefCounted.h>
    3131
    32 #if !LOG_DISABLED || !RELEASE_LOG_DISABLED
     32namespace WebKit {
    3333
    34 #ifndef LOG_CHANNEL_PREFIX
    35 #define LOG_CHANNEL_PREFIX WebKit2Log
     34class WebPageProxy;
     35class WebProcessProxy;
     36
     37class SuspendedPageProxy : public RefCounted<SuspendedPageProxy> {
     38public:
     39    static Ref<SuspendedPageProxy> create(WebPageProxy& page, WebProcessProxy& process, WebBackForwardListItem& item)
     40    {
     41        return adoptRef(*new SuspendedPageProxy(page, process, item));
     42    }
     43
     44    virtual ~SuspendedPageProxy();
     45
     46    void didReceiveMessage(IPC::Connection&, IPC::Decoder&);
     47
     48    WebPageProxy& page() const { return m_page; }
     49    WebProcessProxy* process() const { return m_process; }
     50    WebBackForwardListItem& item() const { return m_backForwardListItem; }
     51
     52    bool finishedSuspending() const { return m_finishedSuspending; }
     53
     54    void webProcessDidClose(WebProcessProxy&);
     55
     56#if !LOG_DISABLED
     57    const char* loggingString() const;
    3658#endif
    3759
    38 #ifdef __cplusplus
    39 extern "C" {
    40 #endif
     60private:
     61    SuspendedPageProxy(WebPageProxy&, WebProcessProxy&, WebBackForwardListItem&);
    4162
    42 #define WEBKIT2_LOG_CHANNELS(M) \
    43     M(CacheStorage) \
    44     M(ContextMenu) \
    45     M(DragAndDrop) \
    46     M(Fullscreen) \
    47     M(Gamepad) \
    48     M(IconDatabase) \
    49     M(IndexedDB) \
    50     M(IPC) \
    51     M(KeyHandling) \
    52     M(Layers) \
    53     M(Loading) \
    54     M(Network) \
    55     M(NetworkCache) \
    56     M(NetworkCacheSpeculativePreloading) \
    57     M(NetworkCacheStorage) \
    58     M(NetworkScheduling) \
    59     M(NetworkSession) \
    60     M(PerformanceLogging) \
    61     M(Plugins) \
    62     M(Printing) \
    63     M(Process) \
    64     M(ProcessSuspension) \
    65     M(RemoteLayerTree) \
    66     M(Resize) \
    67     M(ResourceLoadStatistics) \
    68     M(ResourceLoadStatisticsDebug) \
    69     M(Selection) \
    70     M(ServiceWorker) \
    71     M(SessionState) \
    72     M(StorageAPI) \
    73     M(TextInput) \
    74     M(ViewGestures) \
    75     M(ViewState) \
    76     M(VirtualMemory) \
    77     M(VisibleRects) \
    78     M(WebRTC) \
    79     M(WiFiAssertions) \
     63    void didFinishLoad();
    8064
    81 WEBKIT2_LOG_CHANNELS(DECLARE_LOG_CHANNEL)
     65    WebPageProxy& m_page;
     66    WebProcessProxy* m_process;
     67    Ref<WebBackForwardListItem> m_backForwardListItem;
    8268
    83 #undef DECLARE_LOG_CHANNEL
     69    bool m_finishedSuspending { false };
     70};
    8471
    85 #ifdef __cplusplus
    86 }
    87 #endif
    88 
    89 #endif // !LOG_DISABLED || !RELEASE_LOG_DISABLED
    90 
     72} // namespace WebKit
  • trunk/Source/WebKit/UIProcess/WebPageProxy.cpp

    r230315 r230640  
    643643{
    644644    auto process = makeRef(m_process->processPool().createNewWebProcessRespectingProcessCountLimit(m_websiteDataStore.get()));
    645     reattachToWebProcess(WTFMove(process));
     645    reattachToWebProcess(WTFMove(process), false);
    646646}
    647647
     
    654654    // FIXME: this is to fix the ASSERT(isValid()) inside reattachToWebProcess, some other way to fix this is needed.
    655655    m_isValid = false;
    656     reattachToWebProcess(WTFMove(process));
    657 }
    658 
    659 void WebPageProxy::reattachToWebProcess(Ref<WebProcessProxy>&& process)
     656    reattachToWebProcess(WTFMove(process), true);
     657}
     658
     659SuspendedPageProxy* WebPageProxy::maybeCreateSuspendedPage(WebProcessProxy& process)
     660{
     661    ASSERT(!m_suspendedPage || m_suspendedPage->process() != &process);
     662
     663    auto* currentItem = m_backForwardList->currentItem();
     664    if (!currentItem) {
     665        LOG(ProcessSwapping, "WebPageProxy %" PRIu64 " unable to create suspended page for process pid %i - No current back/forward item", pageID(), process.processIdentifier());
     666        return nullptr;
     667    }
     668
     669    m_suspendedPage = SuspendedPageProxy::create(*this, process, *currentItem);
     670
     671    LOG(ProcessSwapping, "WebPageProxy %" PRIu64 " created suspended page %s for process pid %i, back/forward item %" PRIu64, pageID(), m_suspendedPage->loggingString(), process.processIdentifier(), currentItem->itemID());
     672
     673    return m_suspendedPage.get();
     674}
     675
     676void WebPageProxy::suspendedPageProcessClosed(SuspendedPageProxy& page)
     677{
     678    ASSERT_UNUSED(page, &page == m_suspendedPage.get());
     679    m_suspendedPage = nullptr;
     680}
     681
     682void WebPageProxy::reattachToWebProcess(Ref<WebProcessProxy>&& process, bool suspendInOldProcess)
    660683{
    661684    ASSERT(!m_isClosed);
     
    663686
    664687    m_isValid = true;
    665     m_process->removeWebPage(*this, m_pageID);
    666     m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID);
     688
     689    if (!suspendInOldProcess) {
     690        m_process->removeWebPage(*this, m_pageID);
     691        m_process->removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), m_pageID);
     692    } else
     693        m_process->suspendWebPageProxy(*this);
    667694
    668695    m_process = WTFMove(process);
     
    23552382
    23562383            if (proposedProcess.ptr() != &process()) {
    2357                 LOG(Loading, "Switching from process %i to new process for navigation %" PRIu64 " '%s'", processIdentifier(), navigation->navigationID(), navigation->loggingString().utf8().data());
     2384                LOG(ProcessSwapping, "Switching from process %i to new process for navigation %" PRIu64 " '%s'", processIdentifier(), navigation->navigationID(), navigation->loggingString().utf8().data());
    23582385
    23592386                RunLoop::main().dispatch([this, protectedThis = makeRef(*this), navigation = makeRef(*navigation), proposedProcess = WTFMove(proposedProcess)]() mutable {
     
    35723599void WebPageProxy::didFinishLoadForFrame(uint64_t frameID, uint64_t navigationID, const UserData& userData)
    35733600{
     3601    LOG(Loading, "WebPageProxy::didFinishLoadForFrame - WebPageProxy %p with navigationID %llu didFinishLoad", this, navigationID);
     3602
    35743603    PageClientProtector protector(m_pageClient);
    35753604
  • trunk/Source/WebKit/UIProcess/WebPageProxy.h

    r230591 r230640  
    4545#include "SandboxExtension.h"
    4646#include "ShareableBitmap.h"
     47#include "SuspendedPageProxy.h"
    4748#include "SystemPreviewController.h"
    4849#include "UserMediaPermissionRequestManagerProxy.h"
     
    12871288    WebPreferencesStore preferencesStore() const;
    12881289
     1290    SuspendedPageProxy* maybeCreateSuspendedPage(WebProcessProxy&);
     1291    void suspendedPageProcessClosed(SuspendedPageProxy&);
     1292
    12891293private:
    12901294    WebPageProxy(PageClient&, WebProcessProxy&, uint64_t pageID, Ref<API::PageConfiguration>&&);
     
    14371441    void reattachToWebProcess();
    14381442    void attachToProcessForNavigation(Ref<WebProcessProxy>&&);
    1439     void reattachToWebProcess(Ref<WebProcessProxy>&&);
     1443    void reattachToWebProcess(Ref<WebProcessProxy>&&, bool suspendInOldProcess);
    14401444
    14411445    RefPtr<API::Navigation> reattachToWebProcessForReload();
     
    21302134
    21312135    std::optional<MonotonicTime> m_pageLoadStart;
     2136
     2137    // FIXME: Support more than one suspended page per WebPageProxy,
     2138    // and have a global collection of them per process pool
     2139    // (e.g. for that process pool's page cache)
     2140    RefPtr<SuspendedPageProxy> m_suspendedPage;
    21322141};
    21332142
  • trunk/Source/WebKit/UIProcess/WebProcessProxy.cpp

    r230293 r230640  
    3535#include "PluginInfoStore.h"
    3636#include "PluginProcessManager.h"
     37#include "SuspendedPageProxy.h"
    3738#include "TextChecker.h"
    3839#include "TextCheckerState.h"
     
    396397}
    397398
     399void WebProcessProxy::suspendWebPageProxy(WebPageProxy& webPage)
     400{
     401    if (auto* suspendedPage = webPage.maybeCreateSuspendedPage(*this)) {
     402        LOG(ProcessSwapping, "WebProcessProxy pid %i added suspended page %s", processIdentifier(), suspendedPage->loggingString());
     403        m_suspendedPageMap.set(webPage.pageID(), suspendedPage);
     404    }
     405
     406    removeWebPage(webPage, webPage.pageID());
     407    removeMessageReceiver(Messages::WebPageProxy::messageReceiverName(), webPage.pageID());
     408}
     409
     410void WebProcessProxy::suspendedPageWasDestroyed(SuspendedPageProxy& suspendedPage)
     411{
     412    LOG(ProcessSwapping, "WebProcessProxy pid %i suspended page %s was destroyed", processIdentifier(), suspendedPage.loggingString());
     413
     414    ASSERT(m_suspendedPageMap.contains(suspendedPage.page().pageID()));
     415    m_suspendedPageMap.remove(suspendedPage.page().pageID());
     416
     417    maybeShutDown();
     418}
     419
    398420void WebProcessProxy::removeWebPage(WebPageProxy& webPage, uint64_t pageID)
    399421{
     
    415437        m_backForwardListItemMap.remove(itemID);
    416438
    417     // If this was the last WebPage open in that web process, and we have no other reason to keep it alive, let it go.
    418     // We only allow this when using a network process, as otherwise the WebProcess needs to preserve its session state.
    419     if (state() == State::Terminated || !canTerminateChildProcess())
    420         return;
    421 
    422     shutDown();
     439    maybeShutDown();
    423440}
    424441
     
    638655    }
    639656
     657    // WebPageProxy messages are normally handled by the normal "dispatchMessage" up above.
     658    // If they were not handled there, then they may potentially be handled by SuspendedPageProxy objects.
     659    if (decoder.messageReceiverName() == Messages::WebPageProxy::messageReceiverName()) {
     660        if (auto* suspendedPage = m_suspendedPageMap.get(decoder.destinationID())) {
     661            suspendedPage->didReceiveMessage(connection, decoder);
     662            return;
     663        }
     664    }
     665
    640666    // FIXME: Add unhandled message logging.
    641667}
     
    681707        page->processDidTerminate(ProcessTerminationReason::Crash);
    682708
     709    for (auto* suspendedPage : copyToVectorOf<SuspendedPageProxy*>(m_suspendedPageMap.values()))
     710        suspendedPage->webProcessDidClose(*this);
     711
     712    m_suspendedPageMap.clear();
    683713}
    684714
     
    828858}
    829859
     860void WebProcessProxy::maybeShutDown()
     861{
     862    if (state() == State::Terminated || !canTerminateChildProcess())
     863        return;
     864
     865    shutDown();
     866}
     867
    830868bool WebProcessProxy::canTerminateChildProcess()
    831869{
    832     if (!m_pageMap.isEmpty())
     870    if (!m_pageMap.isEmpty() || !m_suspendedPageMap.isEmpty())
    833871        return false;
    834872
  • trunk/Source/WebKit/UIProcess/WebProcessProxy.h

    r230293 r230640  
    6767class ObjCObjectGraph;
    6868class PageClient;
     69class SuspendedPageProxy;
    6970class UserMediaCaptureManagerProxy;
    7071class VisitedLinkStore;
     
    209210    bool hasCommittedAnyProvisionalLoads() const { return m_hasCommittedAnyProvisionalLoads; }
    210211
     212    void suspendWebPageProxy(WebPageProxy&);
     213    void suspendedPageWasDestroyed(SuspendedPageProxy&);
     214
    211215protected:
    212216    static uint64_t generatePageID();
     
    222226    // Will potentially cause the WebProcessProxy object to be freed.
    223227    void shutDown();
     228    void maybeShutDown();
    224229
    225230    // IPC message handlers.
     
    299304
    300305    WebPageProxyMap m_pageMap;
     306    HashMap<uint64_t, SuspendedPageProxy*> m_suspendedPageMap;
    301307    WebFrameProxyMap m_frameMap;
    302308    WebBackForwardListItemMap m_backForwardListItemMap;
  • trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj

    r230560 r230640  
    10711071                515BE1B51D5917FF00DD7C68 /* UIGamepad.h in Headers */ = {isa = PBXBuildFile; fileRef = 515BE1AD1D555C5100DD7C68 /* UIGamepad.h */; };
    10721072                515BE1B71D5A94FD00DD7C68 /* UIGamepadProviderMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 515BE1B61D5A94F900DD7C68 /* UIGamepadProviderMac.mm */; };
     1073                515C415C207D7CAE00726E02 /* SuspendedPageProxy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 515C415A207D74E000726E02 /* SuspendedPageProxy.cpp */; };
    10731074                515E7727183DD6F60007203F /* AsyncRequest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 515E7725183DD6F60007203F /* AsyncRequest.cpp */; };
    10741075                515E7728183DD6F60007203F /* AsyncRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 515E7726183DD6F60007203F /* AsyncRequest.h */; };
     
    34873488                515BE1B11D5902B600DD7C68 /* GamepadData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GamepadData.cpp; sourceTree = "<group>"; };
    34883489                515BE1B61D5A94F900DD7C68 /* UIGamepadProviderMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = UIGamepadProviderMac.mm; path = UIProcess/Gamepad/mac/UIGamepadProviderMac.mm; sourceTree = SOURCE_ROOT; };
     3490                515C415A207D74E000726E02 /* SuspendedPageProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SuspendedPageProxy.cpp; sourceTree = "<group>"; };
     3491                515C415B207D74E100726E02 /* SuspendedPageProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SuspendedPageProxy.h; sourceTree = "<group>"; };
    34893492                515E7725183DD6F60007203F /* AsyncRequest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AsyncRequest.cpp; sourceTree = "<group>"; };
    34903493                515E7726183DD6F60007203F /* AsyncRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AsyncRequest.h; sourceTree = "<group>"; };
     
    72707273                                51A4D5A816CAC4FF000E615E /* StatisticsRequest.cpp */,
    72717274                                514BDED216C98EDD00E4E25E /* StatisticsRequest.h */,
     7275                                515C415A207D74E000726E02 /* SuspendedPageProxy.cpp */,
     7276                                515C415B207D74E100726E02 /* SuspendedPageProxy.h */,
    72727277                                318A1F04204F4764003480BC /* SystemPreviewController.cpp */,
    72737278                                3157135D2040A9B20084F9CF /* SystemPreviewController.h */,
     
    1089410899                                1AE00D6B18327C1200087DD7 /* StringReference.cpp in Sources */,
    1089510900                                296BD85E15019BC30071F424 /* StringUtilities.mm in Sources */,
     10901                                515C415C207D7CAE00726E02 /* SuspendedPageProxy.cpp in Sources */,
    1089610902                                318A1F05204F4764003480BC /* SystemPreviewController.cpp in Sources */,
    1089710903                                3157135E2040A9B20084F9CF /* SystemPreviewControllerCocoa.mm in Sources */,
  • trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp

    r230506 r230640  
    58675867}
    58685868
     5869void WebPage::setIsSuspended(bool suspended)
     5870{
     5871    m_isSuspended = suspended;
     5872}
     5873
    58695874#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
    58705875static uint64_t nextRequestStorageAccessContextId()
  • trunk/Source/WebKit/WebProcess/WebPage/WebPage.h

    r230591 r230640  
    10731073    UserContentControllerIdentifier userContentControllerIdentifier() const { return m_userContentController->identifier(); }
    10741074
     1075    bool isSuspended() const { return m_isSuspended; }
     1076
    10751077private:
    10761078    WebPage(uint64_t pageID, WebPageCreationParameters&&);
     
    13891391    void urlSchemeTaskDidComplete(uint64_t handlerIdentifier, uint64_t taskIdentifier, const WebCore::ResourceError&);
    13901392
     1393    void setIsSuspended(bool);
     1394
    13911395    RefPtr<WebImage> snapshotAtSize(const WebCore::IntRect&, const WebCore::IntSize& bitmapSize, SnapshotOptions);
    13921396    RefPtr<WebImage> snapshotNode(WebCore::Node&, SnapshotOptions, unsigned maximumPixelCount = std::numeric_limits<unsigned>::max());
     
    17061710#endif
    17071711
     1712    bool m_isSuspended { false };
    17081713};
    17091714
  • trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in

    r230591 r230640  
    492492    URLSchemeTaskDidComplete(uint64_t handlerIdentifier, uint64_t taskIdentifier, WebCore::ResourceError error)
    493493
     494    SetIsSuspended(bool suspended)
     495
    494496#if HAVE(CFNETWORK_STORAGE_PARTITIONING)
    495497    StorageAccessResponse(bool wasGranted, uint64_t contextId)
  • trunk/Source/WebKit/WebProcess/WebProcess.messages.in

    r230454 r230640  
    129129    MessagesAvailableForPort(struct WebCore::MessagePortIdentifier port)
    130130
     131    UpdateActivePages()
     132
    131133#if PLATFORM(MAC)
    132134    SetScreenProperties(uint32_t primaryScreenID, HashMap<uint32_t, WebCore::ScreenProperties> screenProperties)
  • trunk/Source/WebKit/WebProcess/cocoa/WebProcessCocoa.mm

    r230225 r230640  
    388388
    389389    for (auto& page : m_pageMap.values()) {
    390         if (page->usesEphemeralSession())
     390        if (page->usesEphemeralSession() || page->isSuspended())
    391391            continue;
    392392
  • trunk/Tools/ChangeLog

    r230639 r230640  
     12018-04-13  Brady Eidson  <beidson@apple.com>
     2
     3        Introduce SuspendedPageProxy to keep old web processes around after their WebPageProxy has been swapped to a new one.
     4        https://bugs.webkit.org/show_bug.cgi?id=184559
     5
     6        Reviewed by Alex Christensen.
     7
     8        * TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm:
     9
    1102018-04-13  Chris Dumez  <cdumez@apple.com>
    211
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ProcessSwapOnNavigation.mm

    r230315 r230640  
    752752}
    753753
     754TEST(ProcessSwap, OnePreviousProcessRemains)
     755{
     756    auto processPoolConfiguration = adoptNS([[_WKProcessPoolConfiguration alloc] init]);
     757    [processPoolConfiguration setProcessSwapsOnNavigation:YES];
     758    auto processPool = adoptNS([[WKProcessPool alloc] _initWithConfiguration:processPoolConfiguration.get()]);
     759
     760    auto webViewConfiguration = adoptNS([[WKWebViewConfiguration alloc] init]);
     761    [webViewConfiguration setProcessPool:processPool.get()];
     762    auto handler = adoptNS([[PSONScheme alloc] init]);
     763    [webViewConfiguration setURLSchemeHandler:handler.get() forURLScheme:@"PSON"];
     764
     765    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:webViewConfiguration.get()]);
     766    auto delegate = adoptNS([[PSONNavigationDelegate alloc] init]);
     767    [webView setNavigationDelegate:delegate.get()];
     768
     769    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host1/main.html"]];
     770    [webView loadRequest:request];
     771
     772    TestWebKitAPI::Util::run(&done);
     773    done = false;
     774
     775    request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host2/main.html"]];
     776    [webView loadRequest:request];
     777
     778    TestWebKitAPI::Util::run(&done);
     779    done = false;
     780
     781    request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"pson://host3/main.html"]];
     782    [webView loadRequest:request];
     783
     784    TestWebKitAPI::Util::run(&done);
     785    done = false;
     786
     787    // Navigations to 3 different domains, we expect to have seen 3 different PIDs
     788    EXPECT_EQ(3u, seenPIDs.size());
     789
     790    // But only 2 of those processes should still be alive
     791    EXPECT_EQ(2u, [processPool _webProcessCount]);
     792}
     793
    754794#endif // WK_API_ENABLED
Note: See TracChangeset for help on using the changeset viewer.