Ensure ITP state is relayed to Network Process on restart
authorbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 17 Jun 2019 17:41:39 +0000 (17:41 +0000)
committerbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 17 Jun 2019 17:41:39 +0000 (17:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=198797
<rdar://problem/51646944>

Reviewed by Youenn Fablet.

Source/WebKit:

Now that the ITP state is maintained in the Network Process, we have to make sure that we update
that process with current ITP state if the Network Process crashes and is relaunched. This wasn't a
problem in earlier releases because we tracked all ITP state in the UIProcess.

This patch does the following:
1. Add a new method to WKWebsiteDataStore to allow us to trigger statistics processing, which has the
   side effect of syncing ITP state persistently so that it will be available after bouncing the process.
2. Adds a new test that sets a tracking domain, bounces the process, and confirms the state is still
   consistent.

Tested by TestWebKitAPI.

* NetworkProcess/Classifier/ResourceLoadStatisticsStore.cpp:
(WebKit::ResourceLoadStatisticsStore::processStatisticsAndDataRecords):
* UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
(-[WKWebsiteDataStore _clearPrevalentDomain:completionHandler:]):
(-[WKWebsiteDataStore _processStatisticsAndDataRecords:]):
* UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h:
* UIProcess/WebProcessPool.cpp:
(WebKit::WebProcessPool::ensureNetworkProcess):
(WebKit::WebProcessPool::setResourceLoadStatisticsEnabled):
* UIProcess/WebProcessPool.h:
* UIProcess/WebsiteData/WebsiteDataStore.cpp:
(WebKit::WebsiteDataStore::setResourceLoadStatisticsEnabled):

Tools:

* TestWebKitAPI/Tests/WebKitCocoa/ResourceLoadStatistics.mm:
(cleanupITPDatabase): Added.
(TEST:EnableDisableITP): Update to use cleanup method.
(TEST:NetworkProcessRestart): Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@246500 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit/ChangeLog
Source/WebKit/NetworkProcess/Classifier/ResourceLoadStatisticsStore.cpp
Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStore.mm
Source/WebKit/UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h
Source/WebKit/UIProcess/WebProcessPool.cpp
Source/WebKit/UIProcess/WebProcessPool.h
Source/WebKit/UIProcess/WebsiteData/WebsiteDataStore.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/Tests/WebKitCocoa/ResourceLoadStatistics.mm

index 6e8c6a0..5295e9b 100644 (file)
@@ -1,3 +1,36 @@
+2019-06-17  Brent Fulgham  <bfulgham@apple.com>
+
+        Ensure ITP state is relayed to Network Process on restart
+        https://bugs.webkit.org/show_bug.cgi?id=198797
+        <rdar://problem/51646944>
+
+        Reviewed by Youenn Fablet.
+
+        Now that the ITP state is maintained in the Network Process, we have to make sure that we update
+        that process with current ITP state if the Network Process crashes and is relaunched. This wasn't a
+        problem in earlier releases because we tracked all ITP state in the UIProcess.
+
+        This patch does the following:
+        1. Add a new method to WKWebsiteDataStore to allow us to trigger statistics processing, which has the
+           side effect of syncing ITP state persistently so that it will be available after bouncing the process.
+        2. Adds a new test that sets a tracking domain, bounces the process, and confirms the state is still
+           consistent.
+
+        Tested by TestWebKitAPI.
+
+        * NetworkProcess/Classifier/ResourceLoadStatisticsStore.cpp:
+        (WebKit::ResourceLoadStatisticsStore::processStatisticsAndDataRecords):
+        * UIProcess/API/Cocoa/WKWebsiteDataStore.mm:
+        (-[WKWebsiteDataStore _clearPrevalentDomain:completionHandler:]):
+        (-[WKWebsiteDataStore _processStatisticsAndDataRecords:]):
+        * UIProcess/API/Cocoa/WKWebsiteDataStorePrivate.h:
+        * UIProcess/WebProcessPool.cpp:
+        (WebKit::WebProcessPool::ensureNetworkProcess):
+        (WebKit::WebProcessPool::setResourceLoadStatisticsEnabled):
+        * UIProcess/WebProcessPool.h:
+        * UIProcess/WebsiteData/WebsiteDataStore.cpp:
+        (WebKit::WebsiteDataStore::setResourceLoadStatisticsEnabled):
+
 2019-06-17  Ludovico de Nittis  <ludovico.denittis@collabora.com>
 
         [GTK] Stop accessing GdkEvent fields when possible
index b7d25de..f8078b3 100644 (file)
@@ -246,6 +246,8 @@ void ResourceLoadStatisticsStore::processStatisticsAndDataRecords()
         pruneStatisticsIfNeeded();
         syncStorageIfNeeded();
 
+        logTestingEvent("Storage Synced"_s);
+
         if (!m_parameters.shouldNotifyPagesWhenDataRecordsWereScanned)
             return;
 
index af4218d..e178dcd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -513,6 +513,28 @@ static Vector<WebKit::WebsiteDataRecord> toWebsiteDataRecords(NSArray *dataRecor
 #endif
 }
 
+- (void)_clearPrevalentDomain:(NSURL *)domain completionHandler:(void (^)(void))completionHandler
+{
+#if ENABLE(RESOURCE_LOAD_STATISTICS)
+    _websiteDataStore->websiteDataStore().clearPrevalentResource(URL(domain), [completionHandler = makeBlockPtr(completionHandler)]() {
+        completionHandler();
+    });
+#else
+    completionHandler();
+#endif
+}
+
+- (void)_processStatisticsAndDataRecords:(void (^)(void))completionHandler
+{
+#if ENABLE(RESOURCE_LOAD_STATISTICS)
+    _websiteDataStore->websiteDataStore().scheduleStatisticsAndDataRecordsProcessing([completionHandler = makeBlockPtr(completionHandler)]() {
+        completionHandler();
+    });
+#else
+    completionHandler();
+#endif
+}
+
 - (bool)_hasRegisteredServiceWorker
 {
     return WebKit::ServiceWorkerProcessProxy::hasRegisteredServiceWorkers(_websiteDataStore->websiteDataStore().serviceWorkerRegistrationDirectory());
index e52d93f..7ff5c8b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ * Copyright (C) 2016-2019 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -70,6 +70,8 @@ typedef NS_OPTIONS(NSUInteger, _WKWebsiteDataStoreFetchOptions) {
 - (void)_scheduleCookieBlockingUpdate:(void (^)(void))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (void)_setPrevalentDomain:(NSURL *)domain completionHandler:(void (^)(void))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 - (void)_getIsPrevalentDomain:(NSURL *)domain completionHandler:(void (^)(BOOL))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
+- (void)_clearPrevalentDomain:(NSURL *)domain completionHandler:(void (^)(void))completionHandler;
+- (void)_processStatisticsAndDataRecords:(void (^)(void))completionHandler WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 
 @property (nullable, nonatomic, weak) id <_WKWebsiteDataStoreDelegate> _delegate WK_API_AVAILABLE(macos(WK_MAC_TBA), ios(WK_IOS_TBA));
 
index 837caf7..7864a18 100644 (file)
@@ -582,7 +582,7 @@ NetworkProcessProxy& WebProcessPool::ensureNetworkProcess(WebsiteDataStore* with
 
     SandboxExtension::createHandleForReadWriteDirectory(parameters.defaultDataStoreParameters.networkSessionParameters.resourceLoadStatisticsDirectory, parameters.defaultDataStoreParameters.networkSessionParameters.resourceLoadStatisticsDirectoryExtensionHandle);
 
-    bool enableResourceLoadStatistics = false;
+    bool enableResourceLoadStatistics = m_shouldEnableITPForDefaultSessions;
     bool shouldIncludeLocalhost = true;
     bool enableResourceLoadStatisticsDebugMode = false;
     WebCore::RegistrableDomain manualPrevalentResource { };
@@ -1487,6 +1487,7 @@ void WebProcessPool::setShouldUseFontSmoothing(bool useFontSmoothing)
 
 void WebProcessPool::setResourceLoadStatisticsEnabled(bool enabled)
 {
+    m_shouldEnableITPForDefaultSessions = enabled;
     sendToAllProcesses(Messages::WebProcess::SetResourceLoadStatisticsEnabled(enabled));
 #if ENABLE(RESOURCE_LOAD_STATISTICS)
     sendToNetworkingProcess(Messages::NetworkProcess::SetResourceLoadStatisticsEnabled(enabled));
index 1d29825..71f2051 100644 (file)
@@ -727,6 +727,7 @@ private:
     bool m_shouldTakeUIBackgroundAssertion;
     bool m_shouldMakeNextWebProcessLaunchFailForTesting { false };
     bool m_shouldMakeNextNetworkProcessLaunchFailForTesting { false };
+    bool m_shouldEnableITPForDefaultSessions { false };
 
     UserObservablePageCounter m_userObservablePageCounter;
     ProcessSuppressionDisabledCounter m_processSuppressionDisabledForPageCounter;
index c28a640..83e3a1f 100644 (file)
@@ -1875,6 +1875,8 @@ void WebsiteDataStore::setResourceLoadStatisticsEnabled(bool enabled)
         processPool->setResourceLoadStatisticsEnabled(false);
         processPool->sendToNetworkingProcess(Messages::NetworkProcess::SetResourceLoadStatisticsEnabled(false));
     }
+
+    m_resourceLoadStatisticsEnabled = false;
 #else
     UNUSED_PARAM(enabled);
 #endif
index 3863b74..c13be67 100644 (file)
@@ -1,3 +1,16 @@
+2019-06-17  Brent Fulgham  <bfulgham@apple.com>
+
+        Ensure ITP state is relayed to Network Process on restart
+        https://bugs.webkit.org/show_bug.cgi?id=198797
+        <rdar://problem/51646944>
+
+        Reviewed by Youenn Fablet.
+
+        * TestWebKitAPI/Tests/WebKitCocoa/ResourceLoadStatistics.mm:
+        (cleanupITPDatabase): Added.
+        (TEST:EnableDisableITP): Update to use cleanup method.
+        (TEST:NetworkProcessRestart): Added.
+
 2019-06-17  Aakash Jain  <aakash_jain@apple.com>
 
         New EWS can't process patches larger than 640kb
index d2b79c3..6ae399c 100644 (file)
@@ -208,10 +208,43 @@ TEST(ResourceLoadStatistics, IPCAfterStoreDestruction)
     TestWebKitAPI::Util::run(&finishedNavigation);
 }
 
+static void cleanupITPDatabase(WKWebsiteDataStore *dataStore)
+{
+    [dataStore _setResourceLoadStatisticsEnabled:YES];
+
+    // Make sure 'evil.com' is not in our data set.
+    static bool doneFlag;
+    [dataStore _clearPrevalentDomain:[NSURL URLWithString:@"http://evil.com"] completionHandler: ^(void) {
+        doneFlag = true;
+    }];
+    
+    static bool dataSyncCompleted;
+    [dataStore _setResourceLoadStatisticsTestingCallback:^(WKWebsiteDataStore *, NSString *message) {
+        if (![message isEqualToString:@"Storage Synced"])
+            return;
+
+        dataSyncCompleted = true;
+    }];
+
+    TestWebKitAPI::Util::run(&doneFlag);
+
+    // Trigger ITP to process its data to force a sync to persistent storage.
+    [dataStore _processStatisticsAndDataRecords: ^(void) {
+        doneFlag = true;
+    }];
+    
+    TestWebKitAPI::Util::run(&doneFlag);
+    TestWebKitAPI::Util::run(&dataSyncCompleted);
+    
+    TestWebKitAPI::Util::spinRunLoop(1);
+
+    [dataStore _setResourceLoadStatisticsEnabled:NO];
+}
+
 TEST(ResourceLoadStatistics, EnableDisableITP)
 {
     // Ensure the shared process pool exists so the data store operations we're about to do work with it.
-    WKProcessPool *sharedProcessPool = [WKProcessPool _sharedProcessPool];
+    auto *sharedProcessPool = [WKProcessPool _sharedProcessPool];
     auto *dataStore = [WKWebsiteDataStore defaultDataStore];
 
     auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -223,6 +256,8 @@ TEST(ResourceLoadStatistics, EnableDisableITP)
     [webView loadHTMLString:@"WebKit Test" baseURL:[NSURL URLWithString:@"http://webkit.org"]];
     [webView _test_waitForDidFinishNavigation];
 
+    cleanupITPDatabase(dataStore);
+
     // ITP should be off, no URLs are prevalent.
     static bool doneFlag;
     [dataStore _getIsPrevalentDomain:[NSURL URLWithString:@"http://evil.com"] completionHandler: ^(BOOL prevalent) {
@@ -317,3 +352,124 @@ TEST(ResourceLoadStatistics, RemoveSessionID)
     [webView2 loadHTMLString:@"WebKit Test" baseURL:[NSURL URLWithString:@"http://webkit.org"]];
     [webView2 _test_waitForDidFinishNavigation];
 }
+
+TEST(ResourceLoadStatistics, NetworkProcessRestart)
+{
+    // Ensure the shared process pool exists so the data store operations we're about to do work with it.
+    auto *sharedProcessPool = [WKProcessPool _sharedProcessPool];
+    auto *dataStore = [WKWebsiteDataStore defaultDataStore];
+
+    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+    [configuration setProcessPool: sharedProcessPool];
+    configuration.get().websiteDataStore = dataStore;
+
+    auto webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+
+    [webView loadHTMLString:@"WebKit Test" baseURL:[NSURL URLWithString:@"http://webkit.org"]];
+    [webView _test_waitForDidFinishNavigation];
+
+    cleanupITPDatabase(dataStore);
+
+    // Turn it on
+    [dataStore _setResourceLoadStatisticsEnabled:YES];
+
+    [webView loadHTMLString:@"WebKit Test" baseURL:[NSURL URLWithString:@"http://webkit.org"]];
+    [webView _test_waitForDidFinishNavigation];
+
+    // ITP should be on, but nothing was registered as prevalent yet.
+    static bool doneFlag;
+    [dataStore _getIsPrevalentDomain:[NSURL URLWithString:@"http://evil.com"] completionHandler: ^(BOOL prevalent) {
+        EXPECT_FALSE(prevalent);
+        doneFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&doneFlag);
+
+    // Teach ITP about a bad origin:
+    doneFlag = false;
+    [dataStore _setPrevalentDomain:[NSURL URLWithString:@"http://evil.com"] completionHandler: ^(void) {
+        doneFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&doneFlag);
+
+    [webView loadHTMLString:@"WebKit Test" baseURL:[NSURL URLWithString:@"http://webkit.org"]];
+    [webView _test_waitForDidFinishNavigation];
+
+    // ITP should be on, and know about 'evil.com'
+    doneFlag = false;
+    [dataStore _getIsPrevalentDomain:[NSURL URLWithString:@"http://evil.com"] completionHandler: ^(BOOL prevalent) {
+        EXPECT_TRUE(prevalent);
+        doneFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&doneFlag);
+
+    static bool dataSyncCompleted;
+    [dataStore _setResourceLoadStatisticsTestingCallback:^(WKWebsiteDataStore *, NSString *message) {
+        if (![message isEqualToString:@"Storage Synced"])
+            return;
+        dataSyncCompleted = true;
+    }];
+
+    // Tell ITP to process data so it will sync the new 'bad guy' to persistent storage:
+    [dataStore _processStatisticsAndDataRecords: ^(void) {
+        doneFlag = true;
+     }];
+
+    TestWebKitAPI::Util::run(&doneFlag);
+    TestWebKitAPI::Util::run(&dataSyncCompleted);
+
+    TestWebKitAPI::Util::spinRunLoop(1);
+
+    [configuration.get().processPool _terminateNetworkProcess];
+
+    auto webView2 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+
+    [webView2 loadHTMLString:@"WebKit Test 2" baseURL:[NSURL URLWithString:@"http://webkit.org"]];
+    [webView2 _test_waitForDidFinishNavigation];
+
+    // ITP should be on, and know about 'evil.com'
+    doneFlag = false;
+    [dataStore _getIsPrevalentDomain:[NSURL URLWithString:@"http://evil.com"] completionHandler: ^(BOOL prevalent) {
+        EXPECT_TRUE(prevalent);
+        doneFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&doneFlag);
+
+    // Turn it off
+    [dataStore _setResourceLoadStatisticsEnabled:NO];
+
+    [webView loadHTMLString:@"WebKit Test" baseURL:[NSURL URLWithString:@"http://webkit.org"]];
+    [webView _test_waitForDidFinishNavigation];
+
+    // ITP should be off, no URLs are prevalent.
+    doneFlag = false;
+    [dataStore _getIsPrevalentDomain:[NSURL URLWithString:@"http://evil.com"] completionHandler: ^(BOOL prevalent) {
+        EXPECT_FALSE(prevalent);
+        doneFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&doneFlag);
+
+    TestWebKitAPI::Util::spinRunLoop(1);
+
+    [configuration.get().processPool _terminateNetworkProcess];
+
+    auto webView3 = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+
+    [webView3 loadHTMLString:@"WebKit Test 3" baseURL:[NSURL URLWithString:@"http://webkit.org"]];
+    [webView3 _test_waitForDidFinishNavigation];
+
+    TestWebKitAPI::Util::run(&doneFlag);
+
+    // ITP should still be off, and should not know about 'evil.com'
+    doneFlag = false;
+    [dataStore _getIsPrevalentDomain:[NSURL URLWithString:@"http://evil.com"] completionHandler: ^(BOOL prevalent) {
+        EXPECT_FALSE(prevalent);
+        doneFlag = true;
+    }];
+
+    TestWebKitAPI::Util::run(&doneFlag);
+}