Implement DownloadMonitor to prevent long-running slow downloads from background...
[WebKit-https.git] / Source / WebKit / UIProcess / Downloads / DownloadProxyMap.cpp
1 /*
2  * Copyright (C) 2012 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "DownloadProxyMap.h"
28
29 #include "AuxiliaryProcessProxy.h"
30 #include "DownloadProxy.h"
31 #include "DownloadProxyMessages.h"
32 #include "MessageReceiverMap.h"
33 #include "ProcessAssertion.h"
34 #include <wtf/StdLibExtras.h>
35
36 #if PLATFORM(COCOA)
37 #include <wtf/cocoa/Entitlements.h>
38 #endif
39
40 namespace WebKit {
41
42 DownloadProxyMap::DownloadProxyMap(NetworkProcessProxy& process)
43     : m_process(makeWeakPtr(process))
44 #if PLATFORM(COCOA)
45     , m_shouldTakeAssertion(WTF::processHasEntitlement("com.apple.multitasking.systemappassertions"))
46 #endif
47 {
48     platformCreate();
49 }
50
51 DownloadProxyMap::~DownloadProxyMap()
52 {
53     ASSERT(m_downloads.isEmpty());
54     platformDestroy();
55 }
56
57 #if !PLATFORM(COCOA)
58 void DownloadProxyMap::platformCreate()
59 {
60 }
61
62 void DownloadProxyMap::platformDestroy()
63 {
64 }
65 #endif
66
67 void DownloadProxyMap::applicationDidEnterBackground()
68 {
69     if (m_process)
70         m_process->send(Messages::NetworkProcess::ApplicationDidEnterBackground(), 0);
71 }
72
73 void DownloadProxyMap::applicationWillEnterForeground()
74 {
75     if (m_process)
76         m_process->send(Messages::NetworkProcess::ApplicationWillEnterForeground(), 0);
77 }
78
79 DownloadProxy& DownloadProxyMap::createDownloadProxy(WebProcessPool& processPool, const WebCore::ResourceRequest& resourceRequest)
80 {
81     auto downloadProxy = DownloadProxy::create(*this, processPool, resourceRequest);
82     m_downloads.set(downloadProxy->downloadID(), downloadProxy.copyRef());
83
84     if (m_downloads.size() == 1 && m_shouldTakeAssertion) {
85         ASSERT(!m_downloadAssertion);
86         m_downloadAssertion = std::make_unique<ProcessAssertion>(getCurrentProcessID(), "WebKit downloads"_s, AssertionState::UnboundedNetworking);
87     }
88
89     m_process->addMessageReceiver(Messages::DownloadProxy::messageReceiverName(), downloadProxy->downloadID().downloadID(), downloadProxy.get());
90
91     return downloadProxy;
92 }
93
94 void DownloadProxyMap::downloadFinished(DownloadProxy& downloadProxy)
95 {
96     auto downloadID = downloadProxy.downloadID();
97
98     // The DownloadProxy may be holding the last reference to the process pool.
99     auto protectedProcessPool = makeRefPtr(m_process->processPool());
100
101     ASSERT(m_downloads.contains(downloadID));
102
103     m_process->removeMessageReceiver(Messages::DownloadProxy::messageReceiverName(), downloadID.downloadID());
104     downloadProxy.invalidate();
105     m_downloads.remove(downloadID);
106
107     if (m_downloads.isEmpty() && m_shouldTakeAssertion) {
108         ASSERT(m_downloadAssertion);
109         m_downloadAssertion = nullptr;
110     }
111 }
112
113 void DownloadProxyMap::processDidClose()
114 {
115     // Invalidate all outstanding downloads.
116     for (const auto& download : m_downloads.values()) {
117         download->processDidClose();
118         download->invalidate();
119         m_process->removeMessageReceiver(Messages::DownloadProxy::messageReceiverName(), download->downloadID().downloadID());
120     }
121
122     m_downloads.clear();
123     m_downloadAssertion = nullptr;
124     m_process = nullptr;
125 }
126
127 } // namespace WebKit