blob: a3415c75d7014dda8977f6c8765bbc0aec1d42b7 [file] [log] [blame]
/*
* Copyright (C) 2017-2020 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "config.h"
#import "AuxiliaryProcess.h"
#import "OSStateSPI.h"
#import "WKCrashReporter.h"
#import "XPCServiceEntryPoint.h"
#import <WebCore/FloatingPointEnvironment.h>
#import <WebCore/RuntimeApplicationChecks.h>
#import <mach/task.h>
#import <wtf/cocoa/Entitlements.h>
#import <wtf/cocoa/RuntimeApplicationChecksCocoa.h>
#import <wtf/cocoa/SoftLinking.h>
#if ENABLE(CFPREFS_DIRECT_MODE)
#import "AccessibilitySupportSPI.h"
#import <pal/spi/cocoa/AccessibilitySupportSPI.h>
#endif
#if HAVE(UPDATE_WEB_ACCESSIBILITY_SETTINGS) && ENABLE(CFPREFS_DIRECT_MODE)
SOFT_LINK_LIBRARY(libAccessibility)
SOFT_LINK_OPTIONAL(libAccessibility, _AXSUpdateWebAccessibilitySettings, void, (), ());
#endif
namespace WebKit {
#if PLATFORM(MAC) || PLATFORM(MACCATALYST)
static void initializeTimerCoalescingPolicy()
{
// Set task_latency and task_throughput QOS tiers as appropriate for a visible application.
struct task_qos_policy qosinfo = { LATENCY_QOS_TIER_0, THROUGHPUT_QOS_TIER_0 };
kern_return_t kr = task_policy_set(mach_task_self(), TASK_BASE_QOS_POLICY, (task_policy_t)&qosinfo, TASK_QOS_POLICY_COUNT);
ASSERT_UNUSED(kr, kr == KERN_SUCCESS);
}
#endif
void AuxiliaryProcess::platformInitialize(const AuxiliaryProcessInitializationParameters& parameters)
{
#if PLATFORM(MAC) || PLATFORM(MACCATALYST)
initializeTimerCoalescingPolicy();
#endif
FloatingPointEnvironment& floatingPointEnvironment = FloatingPointEnvironment::singleton();
#if PLATFORM(IOS_FAMILY) && !PLATFORM(MACCATALYST)
floatingPointEnvironment.enableDenormalSupport();
#endif
floatingPointEnvironment.saveMainThreadEnvironment();
[[NSFileManager defaultManager] changeCurrentDirectoryPath:[[NSBundle mainBundle] bundlePath]];
WebCore::setApplicationBundleIdentifier(parameters.clientBundleIdentifier);
setApplicationSDKVersion(parameters.clientSDKVersion);
}
void AuxiliaryProcess::didReceiveInvalidMessage(IPC::Connection&, IPC::MessageName messageName)
{
auto errorMessage = makeString("Received invalid message: '", description(messageName), "' (", messageName, ')');
logAndSetCrashLogMessage(errorMessage.utf8().data());
CRASH_WITH_INFO(WTF::enumToUnderlyingType(messageName));
}
bool AuxiliaryProcess::parentProcessHasEntitlement(const char* entitlement)
{
return WTF::hasEntitlement(m_connection->xpcConnection(), entitlement);
}
void AuxiliaryProcess::platformStopRunLoop()
{
XPCServiceExit(WTFMove(m_priorityBoostMessage));
}
#if USE(OS_STATE)
void AuxiliaryProcess::registerWithStateDumper(ASCIILiteral title)
{
os_state_add_handler(dispatch_get_main_queue(), [this, title] (os_state_hints_t hints) {
@autoreleasepool {
os_state_data_t os_state = nullptr;
// Only gather state on faults and sysdiagnose. It's overkill for
// general error messages.
if (hints->osh_api == OS_STATE_API_ERROR)
return os_state;
auto stateDictionary = additionalStateForDiagnosticReport();
// Submitting an empty process state object may provide an
// indication of the existance of private sessions, which we'd like
// to hide, so don't return empty dictionaries.
if (![stateDictionary count])
return os_state;
// Serialize the accumulated process state so that we can put the
// result in an os_state_data_t structure.
NSError *error = nil;
auto data = [NSPropertyListSerialization dataWithPropertyList:stateDictionary.get() format:NSPropertyListBinaryFormat_v1_0 options:0 error:&error];
if (!data) {
ASSERT(data);
return os_state;
}
auto neededSize = OS_STATE_DATA_SIZE_NEEDED(data.length);
os_state = (os_state_data_t)malloc(neededSize);
if (os_state) {
memset(os_state, 0, neededSize);
os_state->osd_type = OS_STATE_DATA_SERIALIZED_NSCF_OBJECT;
os_state->osd_data_size = data.length;
strlcpy(os_state->osd_title, title.characters(), sizeof(os_state->osd_title));
memcpy(os_state->osd_data, data.bytes, data.length);
}
return os_state;
}
});
}
#endif // USE(OS_STATE)
#if ENABLE(CFPREFS_DIRECT_MODE)
id AuxiliaryProcess::decodePreferenceValue(const std::optional<String>& encodedValue)
{
if (!encodedValue)
return nil;
auto encodedData = adoptNS([[NSData alloc] initWithBase64EncodedString:*encodedValue options:0]);
if (!encodedData)
return nil;
NSError *err = nil;
auto classes = [NSSet setWithArray:@[[NSString class], [NSNumber class], [NSDate class], [NSDictionary class], [NSArray class], [NSData class]]];
id value = [NSKeyedUnarchiver unarchivedObjectOfClasses:classes fromData:encodedData.get() error:&err];
ASSERT(!err);
if (err)
return nil;
return value;
}
void AuxiliaryProcess::setPreferenceValue(const String& domain, const String& key, id value)
{
if (domain.isEmpty()) {
CFPreferencesSetValue(key.createCFString().get(), (__bridge CFPropertyListRef)value, kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
#if ASSERT_ENABLED
id valueAfterSetting = [[NSUserDefaults standardUserDefaults] objectForKey:key];
ASSERT(valueAfterSetting == value || [valueAfterSetting isEqual:value] || key == "AppleLanguages");
#endif
} else
CFPreferencesSetValue(key.createCFString().get(), (__bridge CFPropertyListRef)value, domain.createCFString().get(), kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
}
void AuxiliaryProcess::preferenceDidUpdate(const String& domain, const String& key, const std::optional<String>& encodedValue)
{
id value = nil;
if (encodedValue) {
value = decodePreferenceValue(encodedValue);
if (!value)
return;
}
setPreferenceValue(domain, key, value);
handlePreferenceChange(domain, key, value);
}
#if !HAVE(UPDATE_WEB_ACCESSIBILITY_SETTINGS) && PLATFORM(IOS_FAMILY)
static const WTF::String& increaseContrastPreferenceKey()
{
static NeverDestroyed<WTF::String> key(MAKE_STATIC_STRING_IMPL("DarkenSystemColors"));
return key;
}
#endif
void AuxiliaryProcess::handlePreferenceChange(const String& domain, const String& key, id value)
{
if (domain == String(kAXSAccessibilityPreferenceDomain)) {
#if HAVE(UPDATE_WEB_ACCESSIBILITY_SETTINGS)
if (_AXSUpdateWebAccessibilitySettingsPtr())
_AXSUpdateWebAccessibilitySettingsPtr()();
#elif PLATFORM(IOS_FAMILY)
// If the update method is not available, to update the cache inside AccessibilitySupport,
// these methods need to be called directly.
if (CFEqual(key.createCFString().get(), kAXSReduceMotionPreference) && [value isKindOfClass:[NSNumber class]])
_AXSSetReduceMotionEnabled([(NSNumber *)value boolValue]);
else if (CFEqual(key.createCFString().get(), increaseContrastPreferenceKey()) && [value isKindOfClass:[NSNumber class]])
_AXSSetDarkenSystemColors([(NSNumber *)value boolValue]);
#endif
}
dispatchSimulatedNotificationsForPreferenceChange(key);
}
#endif // ENABLE(CFPREFS_DIRECT_MODE)
} // namespace WebKit