Changeset 268097 in webkit
- Timestamp:
- Oct 6, 2020 5:21:02 PM (4 years ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebKit/ChangeLog
r268095 r268097 1 2020-10-06 Chris Dumez <cdumez@apple.com> 2 3 Reloading a view in its processTerminationHandler does not work reliably when using related views 4 https://bugs.webkit.org/show_bug.cgi?id=217407 5 6 Reviewed by Geoff Garen. 7 8 Related web views share the same WebContent process. When this process crashes, we iterate over 9 the list of WebPageProxy objects sharing this process and let them know that their process has 10 crashed. This causes the WebPageProxy to reset its state (so that it is aware it no longer has 11 a running process) and to notify the client application. Because we were notifying the client 12 application synchronously, the client could trigger a load in the view synchronously while we 13 are still iterating over the WebPageProxy objects. When triggering a load in a web view that 14 has no running process, we normally relaunch one. However, in the case of related web views, 15 the view uses its related webview's process, relaunching it if necessary. The 'relaunching 16 if necessary' part was not reliably happening here because the related web view may not have 17 been notified yet that its WebProcess has crashed (since we are still iterating over the 18 pages to notify them). 19 20 To address the issue, we now notify the client asynchronously of the process termination. 21 22 * UIProcess/WebPageProxy.cpp: 23 (WebKit::WebPageProxy::dispatchProcessDidTerminate): 24 1 25 2020-10-06 Peng Liu <peng.liu6@apple.com> 2 26 -
trunk/Source/WebKit/UIProcess/WebPageProxy.cpp
r268074 r268097 7465 7465 RELEASE_LOG_ERROR_IF_ALLOWED(Loading, "dispatchProcessDidTerminate: reason = %d", reason); 7466 7466 7467 bool handledByClient = false; 7468 if (m_loaderClient) 7469 handledByClient = reason != ProcessTerminationReason::RequestedByClient && m_loaderClient->processDidCrash(*this); 7470 else 7471 handledByClient = m_navigationClient->processDidTerminate(*this, reason); 7472 7473 if (!handledByClient && shouldReloadAfterProcessTermination(reason)) 7474 tryReloadAfterProcessTermination(); 7467 // We notify the client asynchronously because several pages may share the same process 7468 // and we want to make sure all pages are aware their process has crashed before the 7469 // the client reacts to the process termination. 7470 RunLoop::main().dispatch([this, weakThis = makeWeakPtr(*this), reason] { 7471 if (!weakThis) 7472 return; 7473 7474 bool handledByClient = false; 7475 if (m_loaderClient) 7476 handledByClient = reason != ProcessTerminationReason::RequestedByClient && m_loaderClient->processDidCrash(*this); 7477 else 7478 handledByClient = m_navigationClient->processDidTerminate(*this, reason); 7479 7480 if (!handledByClient && shouldReloadAfterProcessTermination(reason)) 7481 tryReloadAfterProcessTermination(); 7482 }); 7475 7483 } 7476 7484 -
trunk/Tools/ChangeLog
r268086 r268097 1 2020-10-06 Chris Dumez <cdumez@apple.com> 2 3 Reloading a view in its processTerminationHandler does not work reliably when using related views 4 https://bugs.webkit.org/show_bug.cgi?id=217407 5 6 Reviewed by Geoff Garen. 7 8 Add API test coverage. 9 10 * TestWebKitAPI/Tests/WebKitCocoa/WebContentProcessDidTerminate.mm: 11 (-[NavigationDelegateWithCrashHandlerThatLoadsAgain _webView:webContentProcessDidTerminateWithReason:]): 12 (-[NavigationDelegateWithCrashHandlerThatLoadsAgain webView:didFinishNavigation:]): 13 (TEST): 14 1 15 2020-10-06 Devin Rousso <drousso@apple.com> 2 16 -
trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/WebContentProcessDidTerminate.mm
r260366 r268097 32 32 #import <WebKit/WKProcessPoolPrivate.h> 33 33 #import <WebKit/WKWebView.h> 34 #import <WebKit/WKWebViewConfigurationPrivate.h> 34 35 #import <WebKit/WKWebViewPrivate.h> 35 36 #import <wtf/RetainPtr.h> 37 #import <wtf/Vector.h> 36 38 37 39 static bool didCrash; … … 43 45 static bool calledAllCallbacks; 44 46 static unsigned callbackCount; 47 static unsigned crashHandlerCount; 48 static unsigned loadCount; 49 static unsigned expectedLoadCount; 45 50 46 51 static NSString *testHTML = @"<script>window.webkit.messageHandlers.testHandler.postMessage('LOADED');</script>"; … … 278 283 EXPECT_EQ(6U, callbackCount); 279 284 } 285 286 @interface NavigationDelegateWithCrashHandlerThatLoadsAgain : NSObject <WKNavigationDelegate> 287 @end 288 289 @implementation NavigationDelegateWithCrashHandlerThatLoadsAgain 290 291 - (void)_webView:(WKWebView *)webView webContentProcessDidTerminateWithReason:(_WKProcessTerminationReason)reason 292 { 293 ++crashHandlerCount; 294 295 // Attempt the load again synchronously. 296 [webView loadHTMLString:@"foo" baseURL:nil]; 297 } 298 299 - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation 300 { 301 if (++loadCount == expectedLoadCount) 302 finishedLoad = true; 303 } 304 305 @end 306 307 TEST(WKNavigation, ReloadRelatedViewsInProcessDidTerminate) 308 { 309 const unsigned numberOfViews = 20; 310 auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]); 311 auto webView1 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) configuration:configuration.get()]); 312 313 Vector<RetainPtr<WKWebView>> webViews; 314 webViews.append(webView1); 315 316 configuration.get()._relatedWebView = webView1.get(); 317 for (unsigned i = 0; i < numberOfViews - 1; ++i) { 318 auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 100, 100) configuration:configuration.get()]); 319 webViews.append(webView); 320 } 321 auto delegate = adoptNS([[NavigationDelegateWithCrashHandlerThatLoadsAgain alloc] init]); 322 for (auto& webView : webViews) 323 [webView setNavigationDelegate:delegate.get()]; 324 325 crashHandlerCount = 0; 326 loadCount = 0; 327 expectedLoadCount = numberOfViews; 328 finishedLoad = false; 329 330 for (auto& webView : webViews) 331 [webView loadHTMLString:@"foo" baseURL:nil]; 332 333 TestWebKitAPI::Util::run(&finishedLoad); 334 EXPECT_EQ(0U, crashHandlerCount); 335 336 auto pidBefore = [webView1 _webProcessIdentifier]; 337 EXPECT_TRUE(!!pidBefore); 338 for (auto& webView : webViews) 339 EXPECT_EQ(pidBefore, [webView _webProcessIdentifier]); 340 341 loadCount = 0; 342 finishedLoad = false; 343 344 // Kill the WebContent process. The crash handler should reload all views. 345 kill(pidBefore, 9); 346 347 TestWebKitAPI::Util::run(&finishedLoad); 348 EXPECT_EQ(numberOfViews, crashHandlerCount); 349 350 auto pidAfter = [webView1 _webProcessIdentifier]; 351 EXPECT_TRUE(!!pidAfter); 352 for (auto& webView : webViews) 353 EXPECT_EQ(pidAfter, [webView _webProcessIdentifier]); 354 }
Note: See TracChangeset
for help on using the changeset viewer.