Changeset 209212 in webkit


Ignore:
Timestamp:
Dec 1, 2016 2:31:01 PM (7 years ago)
Author:
timothy_horton@apple.com
Message:

Every WKWebView initialization spends a few milliseconds hitting the disk
https://bugs.webkit.org/show_bug.cgi?id=165268
<rdar://problem/29010113>

Reviewed by Brady Eidson.

Every WKWebView init currently involves doing directory creation and
symlink resolution for a number of paths (to create sandbox extensions
for all of our storage directories), which means touching the disk a
lot during init. All of these paths are immutable per-WebProcessPool,
so, instead, cache them on WebProcessPool and create sandbox extensions
from the already-resolved paths. This is a sizable (~4x) speedup when
initializing subsequent web views.

  • Shared/SandboxExtension.h:

(WebKit::SandboxExtension::createHandleWithoutResolvingPath):
Add createHandleWithoutResolvingPath, which makes a sandbox extension
handle without doing symlink resolution.

(WebKit::resolvePathForSandboxExtension):
(WebKit::resolveAndCreateReadWriteDirectoryForSandboxExtension):
Add two functions that do the same resolution that SandboxExtension::createHandle
and ::createHandleForReadWriteDirectory do, but just return the paths,
for later use with createHandleWithoutResolvingPath.

  • Shared/mac/SandboxExtensionMac.mm:

(WebKit::resolveAndCreateReadWriteDirectoryForSandboxExtension):
(WebKit::resolvePathForSandboxExtension):
(WebKit::SandboxExtension::createHandleWithoutResolvingPath):
(WebKit::SandboxExtension::createHandle):
(WebKit::SandboxExtension::createHandleForReadWriteDirectory):
Implement the aforementioned functions, and reimplement the existing
createHandle{ForReadWriteDirectory} functions in terms of them.

  • UIProcess/Cocoa/WebProcessPoolCocoa.mm:

(WebKit::WebProcessPool::platformDefaultIconDatabasePath):
Stop wasting time generating and resolving a platform default icon
database path, since we don't actually use it for anything anymore except
to determine whether the icon database is enabled, and we only want to
enable it if the client has provided a path.

(WebKit::WebProcessPool::platformResolvePathsForSandboxExtensions):
(WebKit::WebProcessPool::platformInitializeWebProcess):

  • UIProcess/WebProcessPool.cpp:

(WebKit::m_hiddenPageThrottlingTimer):
(WebKit::WebProcessPool::resolvePathsForSandboxExtensions):
(WebKit::WebProcessPool::createNewWebProcess):

  • UIProcess/WebProcessPool.h:

Resolve paths in resolvePathsForSandboxExtensions, and use the resolved
paths along with createHandleWithoutResolvingPath in order to effectively
cache the resolution operation.

Location:
trunk/Source/WebKit2
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit2/ChangeLog

    r209189 r209212  
     12016-12-01  Tim Horton  <timothy_horton@apple.com>
     2
     3        Every WKWebView initialization spends a few milliseconds hitting the disk
     4        https://bugs.webkit.org/show_bug.cgi?id=165268
     5        <rdar://problem/29010113>
     6
     7        Reviewed by Brady Eidson.
     8
     9        Every WKWebView init currently involves doing directory creation and
     10        symlink resolution for a number of paths (to create sandbox extensions
     11        for all of our storage directories), which means touching the disk a
     12        lot during init. All of these paths are immutable per-WebProcessPool,
     13        so, instead, cache them on WebProcessPool and create sandbox extensions
     14        from the already-resolved paths. This is a sizable (~4x) speedup when
     15        initializing subsequent web views.
     16
     17        * Shared/SandboxExtension.h:
     18        (WebKit::SandboxExtension::createHandleWithoutResolvingPath):
     19        Add createHandleWithoutResolvingPath, which makes a sandbox extension
     20        handle without doing symlink resolution.
     21
     22        (WebKit::resolvePathForSandboxExtension):
     23        (WebKit::resolveAndCreateReadWriteDirectoryForSandboxExtension):
     24        Add two functions that do the same resolution that SandboxExtension::createHandle
     25        and ::createHandleForReadWriteDirectory do, but just return the paths,
     26        for later use with createHandleWithoutResolvingPath.
     27
     28        * Shared/mac/SandboxExtensionMac.mm:
     29        (WebKit::resolveAndCreateReadWriteDirectoryForSandboxExtension):
     30        (WebKit::resolvePathForSandboxExtension):
     31        (WebKit::SandboxExtension::createHandleWithoutResolvingPath):
     32        (WebKit::SandboxExtension::createHandle):
     33        (WebKit::SandboxExtension::createHandleForReadWriteDirectory):
     34        Implement the aforementioned functions, and reimplement the existing
     35        createHandle{ForReadWriteDirectory} functions in terms of them.
     36
     37        * UIProcess/Cocoa/WebProcessPoolCocoa.mm:
     38        (WebKit::WebProcessPool::platformDefaultIconDatabasePath):
     39        Stop wasting time generating and resolving a platform default icon
     40        database path, since we don't actually use it for anything anymore except
     41        to determine whether the icon database is enabled, and we only want to
     42        enable it if the client has provided a path.
     43
     44        (WebKit::WebProcessPool::platformResolvePathsForSandboxExtensions):
     45        (WebKit::WebProcessPool::platformInitializeWebProcess):
     46        * UIProcess/WebProcessPool.cpp:
     47        (WebKit::m_hiddenPageThrottlingTimer):
     48        (WebKit::WebProcessPool::resolvePathsForSandboxExtensions):
     49        (WebKit::WebProcessPool::createNewWebProcess):
     50        * UIProcess/WebProcessPool.h:
     51        Resolve paths in resolvePathsForSandboxExtensions, and use the resolved
     52        paths along with createHandleWithoutResolvingPath in order to effectively
     53        cache the resolution operation.
     54
    1552016-12-01  Antti Koivisto  <antti@apple.com>
    256
  • trunk/Source/WebKit2/Shared/SandboxExtension.h

    r207704 r209212  
    9292   
    9393    static RefPtr<SandboxExtension> create(const Handle&);
    94     static bool createHandle(const String& path, Type type, Handle&);
     94    static bool createHandle(const String& path, Type, Handle&);
     95    static bool createHandleWithoutResolvingPath(const String& path, Type, Handle&);
    9596    static bool createHandleForReadWriteDirectory(const String& path, Handle&); // Will attempt to create the directory.
    96     static String createHandleForTemporaryFile(const String& prefix, Type type, Handle&);
     97    static String createHandleForTemporaryFile(const String& prefix, Type, Handle&);
    9798    static bool createHandleForGenericExtension(const String& extensionClass, Handle&);
    9899    ~SandboxExtension();
     
    128129inline RefPtr<SandboxExtension> SandboxExtension::create(const Handle&) { return nullptr; }
    129130inline bool SandboxExtension::createHandle(const String&, Type, Handle&) { return true; }
     131inline bool SandboxExtension::createHandleWithoutResolvingPath(const String&, Type, Handle&) { return true; }
    130132inline bool SandboxExtension::createHandleForReadWriteDirectory(const String&, Handle&) { return true; }
    131133inline String SandboxExtension::createHandleForTemporaryFile(const String& /*prefix*/, Type, Handle&) {return String();}
     
    137139inline bool SandboxExtension::consumePermanently(const Handle&) { return true; }
    138140inline String stringByResolvingSymlinksInPath(const String& path) { return path; }
     141inline String resolvePathForSandboxExtension(const String& path) { return path; }
     142inline String resolveAndCreateReadWriteDirectoryForSandboxExtension(const String& path) { return path; }
    139143#else
    140144String stringByResolvingSymlinksInPath(const String& path);
     145String resolvePathForSandboxExtension(const String& path);
     146String resolveAndCreateReadWriteDirectoryForSandboxExtension(const String& path);
    141147#endif
    142148
  • trunk/Source/WebKit2/Shared/mac/SandboxExtensionMac.mm

    r207704 r209212  
    216216}
    217217
    218 bool SandboxExtension::createHandle(const String& path, Type type, Handle& handle)
    219 {
    220     ASSERT(!handle.m_sandboxExtension);
    221 
     218String resolveAndCreateReadWriteDirectoryForSandboxExtension(const String& path)
     219{
     220    NSError *error = nil;
     221    NSString *nsPath = path;
     222
     223    if (![[NSFileManager defaultManager] createDirectoryAtPath:nsPath withIntermediateDirectories:YES attributes:nil error:&error]) {
     224        NSLog(@"could not create \"%@\", error %@", nsPath, error);
     225        return { };
     226    }
     227
     228    return resolvePathForSandboxExtension(path);
     229}
     230
     231String resolvePathForSandboxExtension(const String& path)
     232{
    222233    // FIXME: Do we need both resolveSymlinksInPath() and -stringByStandardizingPath?
    223234    CString fileSystemPath = fileSystemRepresentation([(NSString *)path stringByStandardizingPath]);
    224235    if (fileSystemPath.isNull()) {
    225236        LOG_ERROR("Could not create a valid file system representation for the string '%s' of length %lu", fileSystemPath.data(), fileSystemPath.length());
    226         return false;
     237        return { };
    227238    }
    228239
    229240    CString standardizedPath = resolveSymlinksInPath(fileSystemPath);
    230     handle.m_sandboxExtension = WKSandboxExtensionCreate(standardizedPath.data(), wkSandboxExtensionType(type));
     241    return String::fromUTF8(standardizedPath);
     242}
     243
     244bool SandboxExtension::createHandleWithoutResolvingPath(const String& path, Type type, Handle& handle)
     245{
     246    ASSERT(!handle.m_sandboxExtension);
     247
     248    handle.m_sandboxExtension = WKSandboxExtensionCreate(path.utf8().data(), wkSandboxExtensionType(type));
    231249    if (!handle.m_sandboxExtension) {
    232250        LOG_ERROR("Could not create a sandbox extension for '%s'", path.utf8().data());
     
    236254}
    237255
     256bool SandboxExtension::createHandle(const String& path, Type type, Handle& handle)
     257{
     258    ASSERT(!handle.m_sandboxExtension);
     259
     260    return createHandleWithoutResolvingPath(resolvePathForSandboxExtension(path), type, handle);
     261}
     262
    238263bool SandboxExtension::createHandleForReadWriteDirectory(const String& path, SandboxExtension::Handle& handle)
    239264{
    240     NSError *error = nil;
    241     NSString *nsPath = path;
    242 
    243     if (![[NSFileManager defaultManager] createDirectoryAtPath:nsPath withIntermediateDirectories:YES attributes:nil error:&error]) {
    244         NSLog(@"could not create \"%@\", error %@", nsPath, error);
    245         return false;
    246     }
    247 
    248     return SandboxExtension::createHandle(path, SandboxExtension::ReadWrite, handle);
     265    String resolvedPath = resolveAndCreateReadWriteDirectoryForSandboxExtension(path);
     266    if (resolvedPath.isNull())
     267        return false;
     268
     269    return SandboxExtension::createHandleWithoutResolvingPath(resolvedPath, SandboxExtension::ReadWrite, handle);
    249270}
    250271
  • trunk/Source/WebKit2/UIProcess/Cocoa/WebProcessPoolCocoa.mm

    r207812 r209212  
    160160#endif
    161161
     162void WebProcessPool::platformResolvePathsForSandboxExtensions()
     163{
     164    m_resolvedPaths.uiProcessBundleResourcePath = resolvePathForSandboxExtension([[NSBundle mainBundle] resourcePath]);
     165
     166#if PLATFORM(IOS)
     167    m_resolvedPaths.cookieStorageDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(cookieStorageDirectory());
     168    m_resolvedPaths.containerCachesDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(webContentCachesDirectory());
     169    m_resolvedPaths.containerTemporaryDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(containerTemporaryDirectory());
     170#endif
     171}
     172
    162173void WebProcessPool::platformInitializeWebProcess(WebProcessCreationParameters& parameters)
    163174{
     
    187198
    188199    // FIXME: This should really be configurable; we shouldn't just blindly allow read access to the UI process bundle.
    189     parameters.uiProcessBundleResourcePath = [[NSBundle mainBundle] resourcePath];
    190     SandboxExtension::createHandle(parameters.uiProcessBundleResourcePath, SandboxExtension::ReadOnly, parameters.uiProcessBundleResourcePathExtensionHandle);
     200    parameters.uiProcessBundleResourcePath = m_resolvedPaths.uiProcessBundleResourcePath;
     201    SandboxExtension::createHandleWithoutResolvingPath(parameters.uiProcessBundleResourcePath, SandboxExtension::ReadOnly, parameters.uiProcessBundleResourcePathExtensionHandle);
    191202
    192203    parameters.uiProcessBundleIdentifier = String([[NSBundle mainBundle] bundleIdentifier]);
     204
     205#if PLATFORM(IOS)
     206    if (!m_resolvedPaths.cookieStorageDirectory.isEmpty())
     207        SandboxExtension::createHandleWithoutResolvingPath(m_resolvedPaths.cookieStorageDirectory, SandboxExtension::ReadWrite, parameters.cookieStorageDirectoryExtensionHandle);
     208
     209    if (!m_resolvedPaths.containerCachesDirectory.isEmpty())
     210        SandboxExtension::createHandleWithoutResolvingPath(m_resolvedPaths.containerCachesDirectory, SandboxExtension::ReadWrite, parameters.containerCachesDirectoryExtensionHandle);
     211
     212    if (!m_resolvedPaths.containerTemporaryDirectory.isEmpty())
     213        SandboxExtension::createHandleWithoutResolvingPath(m_resolvedPaths.containerTemporaryDirectory, SandboxExtension::ReadWrite, parameters.containerTemporaryDirectoryExtensionHandle);
     214#endif
    193215
    194216    parameters.fontWhitelist = m_fontWhitelist;
     
    438460String WebProcessPool::platformDefaultIconDatabasePath() const
    439461{
    440     // FIXME: <rdar://problem/9138817> - After this "backwards compatibility" radar is removed, this code should be removed to only return an empty String.
    441     NSString *databasesDirectory = [[NSUserDefaults standardUserDefaults] objectForKey:WebIconDatabaseDirectoryDefaultsKey];
    442     if (!databasesDirectory || ![databasesDirectory isKindOfClass:[NSString class]])
    443         databasesDirectory = @"~/Library/Icons/WebpageIcons.db";
    444     return stringByResolvingSymlinksInPath([databasesDirectory stringByStandardizingPath]);
     462    return "";
    445463}
    446464
  • trunk/Source/WebKit2/UIProcess/WebProcessPool.cpp

    r208959 r209212  
    203203    addLanguageChangeObserver(this, languageChanged);
    204204
     205    resolvePathsForSandboxExtensions();
     206
    205207#if !LOG_DISABLED || !RELEASE_LOG_DISABLED
    206208    WebCore::initializeLogChannelsIfNecessary();
     
    528530}
    529531
     532void WebProcessPool::resolvePathsForSandboxExtensions()
     533{
     534    m_resolvedPaths.injectedBundlePath = resolvePathForSandboxExtension(injectedBundlePath());
     535    m_resolvedPaths.applicationCacheDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->applicationCacheDirectory());
     536    m_resolvedPaths.webSQLDatabaseDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->webSQLDatabaseDirectory());
     537    m_resolvedPaths.mediaCacheDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->mediaCacheDirectory());
     538    m_resolvedPaths.mediaKeyStorageDirectory = resolveAndCreateReadWriteDirectoryForSandboxExtension(m_configuration->mediaKeysStorageDirectory());
     539
     540    platformResolvePathsForSandboxExtensions();
     541}
     542
    530543WebProcessProxy& WebProcessPool::createNewWebProcess()
    531544{
     
    538551    parameters.urlParserEnabled = URLParser::enabled();
    539552   
    540     parameters.injectedBundlePath = injectedBundlePath();
     553    parameters.injectedBundlePath = m_resolvedPaths.injectedBundlePath;
    541554    if (!parameters.injectedBundlePath.isEmpty())
    542         SandboxExtension::createHandle(parameters.injectedBundlePath, SandboxExtension::ReadOnly, parameters.injectedBundlePathExtensionHandle);
    543 
    544     parameters.applicationCacheDirectory = m_configuration->applicationCacheDirectory();
     555        SandboxExtension::createHandleWithoutResolvingPath(parameters.injectedBundlePath, SandboxExtension::ReadOnly, parameters.injectedBundlePathExtensionHandle);
     556
     557    parameters.applicationCacheDirectory = m_resolvedPaths.applicationCacheDirectory;
     558    if (!parameters.applicationCacheDirectory.isEmpty())
     559        SandboxExtension::createHandleWithoutResolvingPath(parameters.applicationCacheDirectory, SandboxExtension::ReadWrite, parameters.applicationCacheDirectoryExtensionHandle);
     560
    545561    parameters.applicationCacheFlatFileSubdirectoryName = m_configuration->applicationCacheFlatFileSubdirectoryName();
    546562
    547     if (!parameters.applicationCacheDirectory.isEmpty())
    548         SandboxExtension::createHandleForReadWriteDirectory(parameters.applicationCacheDirectory, parameters.applicationCacheDirectoryExtensionHandle);
    549 
    550     parameters.webSQLDatabaseDirectory = m_configuration->webSQLDatabaseDirectory();
     563    parameters.webSQLDatabaseDirectory = m_resolvedPaths.webSQLDatabaseDirectory;
    551564    if (!parameters.webSQLDatabaseDirectory.isEmpty())
    552         SandboxExtension::createHandleForReadWriteDirectory(parameters.webSQLDatabaseDirectory, parameters.webSQLDatabaseDirectoryExtensionHandle);
    553 
    554     parameters.mediaCacheDirectory = m_configuration->mediaCacheDirectory();
     565        SandboxExtension::createHandleWithoutResolvingPath(parameters.webSQLDatabaseDirectory, SandboxExtension::ReadWrite, parameters.webSQLDatabaseDirectoryExtensionHandle);
     566
     567    parameters.mediaCacheDirectory = m_resolvedPaths.mediaCacheDirectory;
    555568    if (!parameters.mediaCacheDirectory.isEmpty())
    556         SandboxExtension::createHandleForReadWriteDirectory(parameters.mediaCacheDirectory, parameters.mediaCacheDirectoryExtensionHandle);
    557 
    558 #if PLATFORM(IOS)
    559     String cookieStorageDirectory = this->cookieStorageDirectory();
    560     if (!cookieStorageDirectory.isEmpty())
    561         SandboxExtension::createHandleForReadWriteDirectory(cookieStorageDirectory, parameters.cookieStorageDirectoryExtensionHandle);
    562 
    563     String containerCachesDirectory = this->webContentCachesDirectory();
    564     if (!containerCachesDirectory.isEmpty())
    565         SandboxExtension::createHandleForReadWriteDirectory(containerCachesDirectory, parameters.containerCachesDirectoryExtensionHandle);
    566 
    567     String containerTemporaryDirectory = this->containerTemporaryDirectory();
    568     if (!containerTemporaryDirectory.isEmpty())
    569         SandboxExtension::createHandleForReadWriteDirectory(containerTemporaryDirectory, parameters.containerTemporaryDirectoryExtensionHandle);
    570 #endif
    571 
    572     parameters.mediaKeyStorageDirectory = m_configuration->mediaKeysStorageDirectory();
     569        SandboxExtension::createHandleWithoutResolvingPath(parameters.mediaCacheDirectory, SandboxExtension::ReadWrite, parameters.mediaCacheDirectoryExtensionHandle);
     570
     571    parameters.mediaKeyStorageDirectory = m_resolvedPaths.mediaKeyStorageDirectory;
    573572    if (!parameters.mediaKeyStorageDirectory.isEmpty())
    574         SandboxExtension::createHandleForReadWriteDirectory(parameters.mediaKeyStorageDirectory, parameters.mediaKeyStorageDirectoryExtensionHandle);
     573        SandboxExtension::createHandleWithoutResolvingPath(parameters.mediaKeyStorageDirectory, SandboxExtension::ReadWrite, parameters.mediaKeyStorageDirectoryExtensionHandle);
    575574
    576575    parameters.shouldUseTestingNetworkSession = m_shouldUseTestingNetworkSession;
     
    595594    parameters.shouldUseFontSmoothing = m_shouldUseFontSmoothing;
    596595
    597     // FIXME: This leaves UI process and WebProcess disagreeing about the state if the client hasn't set the path.
    598     // iconDatabasePath is non-empty by default, but m_iconDatabase isn't enabled in UI process unless setDatabasePath is called explicitly.
    599596    parameters.iconDatabaseEnabled = !iconDatabasePath().isEmpty();
    600597
  • trunk/Source/WebKit2/UIProcess/WebProcessPool.h

    r208959 r209212  
    445445    void setAnyPageGroupMightHavePrivateBrowsingEnabled(bool);
    446446
     447    void resolvePathsForSandboxExtensions();
     448    void platformResolvePathsForSandboxExtensions();
     449
    447450    Ref<API::ProcessPoolConfiguration> m_configuration;
    448451
     
    575578    bool m_cookieStoragePartitioningEnabled { false };
    576579#endif
     580
     581    struct Paths {
     582        String injectedBundlePath;
     583        String applicationCacheDirectory;
     584        String webSQLDatabaseDirectory;
     585        String mediaCacheDirectory;
     586        String mediaKeyStorageDirectory;
     587        String uiProcessBundleResourcePath;
     588
     589#if PLATFORM(IOS)
     590        String cookieStorageDirectory;
     591        String containerCachesDirectory;
     592        String containerTemporaryDirectory;
     593#endif
     594    };
     595    Paths m_resolvedPaths;
    577596};
    578597
Note: See TracChangeset for help on using the changeset viewer.