ChildProcessMac.mm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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. #import "config.h"
  26. #import "ChildProcess.h"
  27. #import "SandboxInitializationParameters.h"
  28. #import "WebKitSystemInterface.h"
  29. #import <WebCore/FileSystem.h>
  30. #import <WebCore/SystemVersionMac.h>
  31. #import <mach/task.h>
  32. #import <pwd.h>
  33. #import <stdlib.h>
  34. #import <sysexits.h>
  35. // We have to #undef __APPLE_API_PRIVATE to prevent sandbox.h from looking for a header file that does not exist (<rdar://problem/9679211>).
  36. #undef __APPLE_API_PRIVATE
  37. #import <sandbox.h>
  38. #define SANDBOX_NAMED_EXTERNAL 0x0003
  39. extern "C" int sandbox_init_with_parameters(const char *profile, uint64_t flags, const char *const parameters[], char **errorbuf);
  40. #ifdef __has_include
  41. #if __has_include(<HIServices/ProcessesPriv.h>)
  42. #include <HIServices/ProcessesPriv.h>
  43. #endif
  44. #endif
  45. #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
  46. typedef bool (^LSServerConnectionAllowedBlock) ( CFDictionaryRef optionsRef );
  47. extern "C" void _LSSetApplicationLaunchServicesServerConnectionStatus(uint64_t flags, LSServerConnectionAllowedBlock block);
  48. extern "C" CFDictionaryRef _LSApplicationCheckIn(int sessionID, CFDictionaryRef applicationInfo);
  49. #endif
  50. extern "C" OSStatus SetApplicationIsDaemon(Boolean isDaemon);
  51. using namespace WebCore;
  52. namespace WebKit {
  53. static const double kSuspensionHysteresisSeconds = 5.0;
  54. void ChildProcess::setProcessSuppressionEnabledInternal(bool processSuppressionEnabled)
  55. {
  56. #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
  57. if (this->processSuppressionEnabled() == processSuppressionEnabled)
  58. return;
  59. if (processSuppressionEnabled) {
  60. ASSERT(!m_activeTaskCount);
  61. [[NSProcessInfo processInfo] endActivity:m_processSuppressionAssertion.get()];
  62. m_processSuppressionAssertion.clear();
  63. } else {
  64. NSActivityOptions options = (NSActivityUserInitiatedAllowingIdleSystemSleep | NSActivityLatencyCritical) & ~(NSActivitySuddenTerminationDisabled | NSActivityAutomaticTerminationDisabled);
  65. m_processSuppressionAssertion = [[NSProcessInfo processInfo] beginActivityWithOptions:options reason:@"Process Suppression Disabled"];
  66. }
  67. #else
  68. UNUSED_PARAM(processSuppressionEnabled);
  69. #endif
  70. }
  71. void ChildProcess::setProcessSuppressionEnabled(bool processSuppressionEnabled)
  72. {
  73. if (this->processSuppressionEnabled() == processSuppressionEnabled)
  74. return;
  75. if (m_shouldSuspend == processSuppressionEnabled)
  76. return;
  77. m_shouldSuspend = processSuppressionEnabled;
  78. if (m_shouldSuspend) {
  79. if (!m_activeTaskCount)
  80. m_suspensionHysteresisTimer.startOneShot(kSuspensionHysteresisSeconds);
  81. return;
  82. }
  83. setProcessSuppressionEnabledInternal(false);
  84. }
  85. void ChildProcess::incrementActiveTaskCount()
  86. {
  87. m_activeTaskCount++;
  88. if (m_suspensionHysteresisTimer.isActive())
  89. m_suspensionHysteresisTimer.stop();
  90. if (m_activeTaskCount)
  91. setProcessSuppressionEnabledInternal(false);
  92. }
  93. void ChildProcess::decrementActiveTaskCount()
  94. {
  95. ASSERT(m_activeTaskCount);
  96. m_activeTaskCount--;
  97. if (m_activeTaskCount)
  98. return;
  99. if (m_shouldSuspend)
  100. m_suspensionHysteresisTimer.startOneShot(kSuspensionHysteresisSeconds);
  101. }
  102. void ChildProcess::suspensionHysteresisTimerFired()
  103. {
  104. ASSERT(!m_activeTaskCount);
  105. ASSERT(m_shouldSuspend);
  106. setProcessSuppressionEnabledInternal(true);
  107. }
  108. #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
  109. static void initializeTimerCoalescingPolicy()
  110. {
  111. // Set task_latency and task_throughput QOS tiers as appropriate for a visible application.
  112. struct task_qos_policy qosinfo = { LATENCY_QOS_TIER_0, THROUGHPUT_QOS_TIER_0 };
  113. kern_return_t kr = task_policy_set(mach_task_self(), TASK_BASE_QOS_POLICY, (task_policy_t)&qosinfo, TASK_QOS_POLICY_COUNT);
  114. ASSERT_UNUSED(kr, kr == KERN_SUCCESS);
  115. }
  116. #endif
  117. void ChildProcess::setApplicationIsDaemon()
  118. {
  119. OSStatus error = SetApplicationIsDaemon(true);
  120. ASSERT_UNUSED(error, error == noErr);
  121. #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
  122. _LSSetApplicationLaunchServicesServerConnectionStatus(0, 0);
  123. RetainPtr<CFDictionaryRef> unused = _LSApplicationCheckIn(-2, CFBundleGetInfoDictionary(CFBundleGetMainBundle()));
  124. #endif
  125. }
  126. void ChildProcess::platformInitialize()
  127. {
  128. #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
  129. initializeTimerCoalescingPolicy();
  130. #endif
  131. // Starting with process suppression disabled. The proxy for this process will
  132. // enable if appropriate from didFinishLaunching().
  133. // We use setProcessSuppressionEnabledInternal to avoid any short circuit logic
  134. // that would prevent us from taking the suppression assertion.
  135. setProcessSuppressionEnabledInternal(false);
  136. [[NSFileManager defaultManager] changeCurrentDirectoryPath:[[NSBundle mainBundle] bundlePath]];
  137. }
  138. void ChildProcess::initializeSandbox(const ChildProcessInitializationParameters& parameters, SandboxInitializationParameters& sandboxParameters)
  139. {
  140. NSBundle *webkit2Bundle = [NSBundle bundleForClass:NSClassFromString(@"WKView")];
  141. String defaultProfilePath = [webkit2Bundle pathForResource:[[NSBundle mainBundle] bundleIdentifier] ofType:@"sb"];
  142. if (sandboxParameters.systemDirectorySuffix().isNull()) {
  143. String defaultSystemDirectorySuffix = String([[NSBundle mainBundle] bundleIdentifier]) + "+" + parameters.clientIdentifier;
  144. sandboxParameters.setSystemDirectorySuffix(defaultSystemDirectorySuffix);
  145. }
  146. Vector<String> osVersionParts;
  147. String osSystemMarketingVersion = String(systemMarketingVersion());
  148. osSystemMarketingVersion.split('.', false, osVersionParts);
  149. if (osVersionParts.size() < 2) {
  150. WTFLogAlways("%s: Couldn't find OS Version\n", getprogname());
  151. exit(EX_NOPERM);
  152. }
  153. String osVersion = osVersionParts[0];
  154. osVersion.append('.');
  155. osVersion.append(osVersionParts[1]);
  156. sandboxParameters.addParameter("_OS_VERSION", osVersion.utf8().data());
  157. #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
  158. // Use private temporary and cache directories.
  159. setenv("DIRHELPER_USER_DIR_SUFFIX", fileSystemRepresentation(sandboxParameters.systemDirectorySuffix()).data(), 0);
  160. char temporaryDirectory[PATH_MAX];
  161. if (!confstr(_CS_DARWIN_USER_TEMP_DIR, temporaryDirectory, sizeof(temporaryDirectory))) {
  162. WTFLogAlways("%s: couldn't retrieve private temporary directory path: %d\n", getprogname(), errno);
  163. exit(EX_NOPERM);
  164. }
  165. setenv("TMPDIR", temporaryDirectory, 1);
  166. #endif
  167. sandboxParameters.addPathParameter("WEBKIT2_FRAMEWORK_DIR", [[webkit2Bundle bundlePath] stringByDeletingLastPathComponent]);
  168. sandboxParameters.addConfDirectoryParameter("DARWIN_USER_TEMP_DIR", _CS_DARWIN_USER_TEMP_DIR);
  169. sandboxParameters.addConfDirectoryParameter("DARWIN_USER_CACHE_DIR", _CS_DARWIN_USER_CACHE_DIR);
  170. char buffer[4096];
  171. int bufferSize = sizeof(buffer);
  172. struct passwd pwd;
  173. struct passwd* result = 0;
  174. if (getpwuid_r(getuid(), &pwd, buffer, bufferSize, &result) || !result) {
  175. WTFLogAlways("%s: Couldn't find home directory\n", getprogname());
  176. exit(EX_NOPERM);
  177. }
  178. sandboxParameters.addPathParameter("HOME_DIR", pwd.pw_dir);
  179. String path = String::fromUTF8(pwd.pw_dir);
  180. path.append("/Library");
  181. sandboxParameters.addPathParameter("HOME_LIBRARY_DIR", fileSystemRepresentation(path).data());
  182. path.append("/Preferences");
  183. sandboxParameters.addPathParameter("HOME_LIBRARY_PREFERENCES_DIR", fileSystemRepresentation(path).data());
  184. switch (sandboxParameters.mode()) {
  185. case SandboxInitializationParameters::UseDefaultSandboxProfilePath:
  186. case SandboxInitializationParameters::UseOverrideSandboxProfilePath: {
  187. String sandboxProfilePath = sandboxParameters.mode() == SandboxInitializationParameters::UseDefaultSandboxProfilePath ? defaultProfilePath : sandboxParameters.overrideSandboxProfilePath();
  188. if (!sandboxProfilePath.isEmpty()) {
  189. CString profilePath = fileSystemRepresentation(sandboxProfilePath);
  190. char* errorBuf;
  191. if (sandbox_init_with_parameters(profilePath.data(), SANDBOX_NAMED_EXTERNAL, sandboxParameters.namedParameterArray(), &errorBuf)) {
  192. WTFLogAlways("%s: Couldn't initialize sandbox profile [%s], error '%s'\n", getprogname(), profilePath.data(), errorBuf);
  193. for (size_t i = 0, count = sandboxParameters.count(); i != count; ++i)
  194. WTFLogAlways("%s=%s\n", sandboxParameters.name(i), sandboxParameters.value(i));
  195. exit(EX_NOPERM);
  196. }
  197. }
  198. break;
  199. }
  200. case SandboxInitializationParameters::UseSandboxProfile: {
  201. char* errorBuf;
  202. if (sandbox_init_with_parameters(sandboxParameters.sandboxProfile().utf8().data(), 0, sandboxParameters.namedParameterArray(), &errorBuf)) {
  203. WTFLogAlways("%s: Couldn't initialize sandbox profile, error '%s'\n", getprogname(), errorBuf);
  204. for (size_t i = 0, count = sandboxParameters.count(); i != count; ++i)
  205. WTFLogAlways("%s=%s\n", sandboxParameters.name(i), sandboxParameters.value(i));
  206. exit(EX_NOPERM);
  207. }
  208. break;
  209. }
  210. }
  211. // This will override LSFileQuarantineEnabled from Info.plist unless sandbox quarantine is globally disabled.
  212. OSStatus error = WKEnableSandboxStyleFileQuarantine();
  213. if (error) {
  214. WTFLogAlways("%s: Couldn't enable sandbox style file quarantine: %ld\n", getprogname(), (long)error);
  215. exit(EX_NOPERM);
  216. }
  217. }
  218. }