summaryrefslogtreecommitdiffstats
path: root/ipc/glue/GeckoChildProcessHost.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/glue/GeckoChildProcessHost.cpp')
-rw-r--r--ipc/glue/GeckoChildProcessHost.cpp202
1 files changed, 180 insertions, 22 deletions
diff --git a/ipc/glue/GeckoChildProcessHost.cpp b/ipc/glue/GeckoChildProcessHost.cpp
index 3e444060bc..cb038911d4 100644
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -13,15 +13,16 @@
#include "base/task.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/process_watcher.h"
-#include "mozilla/ProcessType.h"
-#ifdef MOZ_WIDGET_COCOA
-# include <bsm/libbsm.h>
+#ifdef XP_DARWIN
# include <mach/mach_traps.h>
-# include <servers/bootstrap.h>
# include "SharedMemoryBasic.h"
# include "base/rand_util.h"
# include "chrome/common/mach_ipc_mac.h"
# include "mozilla/StaticPrefs_media.h"
+#endif
+#ifdef MOZ_WIDGET_COCOA
+# include <bsm/libbsm.h>
+# include <servers/bootstrap.h>
# include "nsILocalFileMac.h"
#endif
@@ -128,9 +129,14 @@ namespace ipc {
struct LaunchResults {
base::ProcessHandle mHandle = 0;
-#ifdef XP_MACOSX
+#ifdef XP_DARWIN
task_t mChildTask = MACH_PORT_NULL;
#endif
+#ifdef XP_IOS
+ Maybe<ExtensionKitProcess> mExtensionKitProcess;
+ DarwinObjectPtr<xpc_connection_t> mXPCConnection;
+ UniqueBEProcessCapabilityGrant mForegroundCapabilityGrant;
+#endif
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
RefPtr<AbstractSandboxBroker> mSandboxBroker;
#endif
@@ -354,9 +360,9 @@ class IosProcessLauncher : public PosixProcessLauncher {
: PosixProcessLauncher(aHost, std::move(aExtraOpts)) {}
protected:
- virtual RefPtr<ProcessHandlePromise> DoLaunch() override {
- MOZ_CRASH("IosProcessLauncher::DoLaunch not implemented");
- }
+ virtual RefPtr<ProcessHandlePromise> DoLaunch() override;
+
+ DarwinObjectPtr<xpc_object_t> mBootstrapMessage;
};
typedef IosProcessLauncher ProcessLauncher;
# else
@@ -390,7 +396,7 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
#endif
mHandleLock("mozilla.ipc.GeckoChildProcessHost.mHandleLock"),
mChildProcessHandle(0),
-#if defined(MOZ_WIDGET_COCOA)
+#if defined(XP_DARWIN)
mChildTask(MACH_PORT_NULL),
#endif
#if defined(MOZ_SANDBOX) && defined(XP_MACOSX)
@@ -443,11 +449,22 @@ GeckoChildProcessHost::~GeckoChildProcessHost()
{
mozilla::AutoWriteLock hLock(mHandleLock);
-#if defined(MOZ_WIDGET_COCOA)
+#if defined(XP_DARWIN)
if (mChildTask != MACH_PORT_NULL) {
mach_port_deallocate(mach_task_self(), mChildTask);
}
#endif
+#if defined(XP_IOS)
+ if (mForegroundCapabilityGrant) {
+ mForegroundCapabilityGrant.reset();
+ }
+ if (mExtensionKitProcess) {
+ mExtensionKitProcess->Invalidate();
+ }
+ if (mXPCConnection) {
+ xpc_connection_cancel(mXPCConnection.get());
+ }
+#endif
if (mChildProcessHandle != 0) {
ProcessWatcher::EnsureProcessTerminated(
@@ -483,7 +500,7 @@ base::ProcessId GeckoChildProcessHost::GetChildProcessId() {
return base::GetProcId(mChildProcessHandle);
}
-#ifdef XP_MACOSX
+#ifdef XP_DARWIN
task_t GeckoChildProcessHost::GetChildTask() {
mozilla::AutoReadLock handleLock(mHandleLock);
return mChildTask;
@@ -765,14 +782,20 @@ bool GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts) {
// "safe" invalid value to use in places like this.
aResults.mHandle = 0;
-#ifdef XP_MACOSX
+#ifdef XP_DARWIN
this->mChildTask = aResults.mChildTask;
#endif
+#ifdef XP_IOS
+ this->mExtensionKitProcess = aResults.mExtensionKitProcess;
+ this->mXPCConnection = aResults.mXPCConnection;
+ this->mForegroundCapabilityGrant =
+ std::move(aResults.mForegroundCapabilityGrant);
+#endif
if (mNodeChannel) {
mNodeChannel->SetOtherPid(
base::GetProcId(this->mChildProcessHandle));
-#ifdef XP_MACOSX
+#ifdef XP_DARWIN
mNodeChannel->SetMachTaskPort(this->mChildTask);
#endif
}
@@ -798,7 +821,8 @@ bool GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts) {
CHROMIUM_LOG(ERROR)
<< "Failed to launch "
<< XRE_GeckoProcessTypeToString(mProcessType)
- << " subprocess";
+ << " subprocess @" << aError.FunctionName()
+ << " (Error:" << aError.ErrorCode() << ")";
Telemetry::Accumulate(
Telemetry::SUBPROCESS_LAUNCH_FAILURE,
nsDependentCString(
@@ -1243,16 +1267,13 @@ Result<Ok, LaunchError> PosixProcessLauncher::DoSetup() {
// STDOUT_FILENO, for example
// The fork server doesn't use IPC::Channel, so can skip this step.
if (mProcessType != GeckoProcessType_ForkServer) {
-# ifdef MOZ_WIDGET_ANDROID
- // On Android mChannelDstFd is uninitialised and the launching code uses
- // only the first of each pair.
- mLaunchOptions->fds_to_remap.push_back(
- std::pair<int, int>(mClientChannelHandle.get(), -1));
-# else
+# if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_UIKIT)
+ // On Android/iOS, mChannelDstFd is initialised to -1 and the launching
+ // code uses only the first of each pair.
MOZ_ASSERT(mChannelDstFd >= 0);
+# endif
mLaunchOptions->fds_to_remap.push_back(
std::pair<int, int>(mClientChannelHandle.get(), mChannelDstFd));
-# endif
}
// no need for kProcessChannelID, the child process inherits the
@@ -1356,6 +1377,143 @@ RefPtr<ProcessHandlePromise> PosixProcessLauncher::DoLaunch() {
}
#endif // XP_UNIX
+#ifdef XP_IOS
+RefPtr<ProcessHandlePromise> IosProcessLauncher::DoLaunch() {
+ MOZ_RELEASE_ASSERT(mLaunchOptions->fds_to_remap.size() == 3,
+ "Unexpected fds_to_remap on iOS");
+
+ ExtensionKitProcess::Kind kind = ExtensionKitProcess::Kind::WebContent;
+ if (mProcessType == GeckoProcessType_GPU) {
+ kind = ExtensionKitProcess::Kind::Rendering;
+ } else if (mProcessType == GeckoProcessType_Socket) {
+ kind = ExtensionKitProcess::Kind::Networking;
+ }
+
+ DarwinObjectPtr<xpc_object_t> bootstrapMessage =
+ AdoptDarwinObject(xpc_dictionary_create_empty());
+ xpc_dictionary_set_string(bootstrapMessage.get(), "message-name",
+ "bootstrap");
+
+ DarwinObjectPtr<xpc_object_t> environDict =
+ AdoptDarwinObject(xpc_dictionary_create_empty());
+ for (auto& [envKey, envValue] : mLaunchOptions->env_map) {
+ xpc_dictionary_set_string(environDict.get(), envKey.c_str(),
+ envValue.c_str());
+ }
+ xpc_dictionary_set_value(bootstrapMessage.get(), "environ",
+ environDict.get());
+
+ // XXX: this processing depends entirely on the internals of
+ // ContentParent::LaunchSubprocess()
+ // GeckoChildProcessHost::PerformAsyncLaunch(), and the order in
+ // which they append to fds_to_remap. There must be a better way to do it.
+ // See bug 1440207.
+ int prefsFd = mLaunchOptions->fds_to_remap[0].first;
+ int prefMapFd = mLaunchOptions->fds_to_remap[1].first;
+ int ipcFd = mLaunchOptions->fds_to_remap[2].first;
+ xpc_dictionary_set_fd(bootstrapMessage.get(), "prefs", prefsFd);
+ xpc_dictionary_set_fd(bootstrapMessage.get(), "prefmap", prefMapFd);
+ xpc_dictionary_set_fd(bootstrapMessage.get(), "channel", ipcFd);
+
+ // Setup stdout and stderr to inherit.
+ xpc_dictionary_set_fd(bootstrapMessage.get(), "stdout", STDOUT_FILENO);
+ xpc_dictionary_set_fd(bootstrapMessage.get(), "stderr", STDERR_FILENO);
+
+ DarwinObjectPtr<xpc_object_t> argsArray =
+ AdoptDarwinObject(xpc_array_create_empty());
+ for (auto& argv : mChildArgv) {
+ xpc_array_set_string(argsArray.get(), XPC_ARRAY_APPEND, argv.c_str());
+ }
+ MOZ_ASSERT(xpc_array_get_count(argsArray.get()) == mChildArgv.size());
+ xpc_dictionary_set_value(bootstrapMessage.get(), "argv", argsArray.get());
+
+ auto promise = MakeRefPtr<ProcessHandlePromise::Private>(__func__);
+ ExtensionKitProcess::StartProcess(kind, [self = RefPtr{this}, promise,
+ bootstrapMessage =
+ std::move(bootstrapMessage)](
+ Result<ExtensionKitProcess,
+ LaunchError>&& result) {
+ if (result.isErr()) {
+ CHROMIUM_LOG(ERROR) << "ExtensionKitProcess::StartProcess failed";
+ promise->Reject(result.unwrapErr(), __func__);
+ return;
+ }
+
+ auto process = result.unwrap();
+ self->mResults.mForegroundCapabilityGrant =
+ process.GrantForegroundCapability();
+ self->mResults.mXPCConnection = process.MakeLibXPCConnection();
+ self->mResults.mExtensionKitProcess = Some(std::move(process));
+
+ // We don't actually use the event handler for anything other than
+ // watching for errors. Once the promise is resolved, this becomes a
+ // no-op.
+ xpc_connection_set_event_handler(self->mResults.mXPCConnection.get(), ^(
+ xpc_object_t event) {
+ if (!event || xpc_get_type(event) == XPC_TYPE_ERROR) {
+ CHROMIUM_LOG(WARNING) << "XPC connection received encountered an error";
+ promise->Reject(LaunchError("xpc_connection_event_handler"), __func__);
+ }
+ });
+ xpc_connection_resume(self->mResults.mXPCConnection.get());
+
+ // Send our bootstrap message to the content and wait for it to reply with
+ // the task port before resolving.
+ // FIXME: Should we have a time-out for if the child process doesn't respond
+ // in time? The main thread may be blocked while we're starting this
+ // process.
+ xpc_connection_send_message_with_reply(
+ self->mResults.mXPCConnection.get(), bootstrapMessage.get(), nullptr,
+ ^(xpc_object_t reply) {
+ if (xpc_get_type(reply) == XPC_TYPE_ERROR) {
+ CHROMIUM_LOG(ERROR)
+ << "Got error sending XPC bootstrap message to child";
+ promise->Reject(
+ LaunchError("xpc_connection_send_message_with_reply error"),
+ __func__);
+ return;
+ }
+
+ if (xpc_get_type(reply) != XPC_TYPE_DICTIONARY) {
+ CHROMIUM_LOG(ERROR)
+ << "Unexpected reply type for bootstrap message from child";
+ promise->Reject(
+ LaunchError(
+ "xpc_connection_send_message_with_reply non-dictionary"),
+ __func__);
+ return;
+ }
+
+ // FIXME: We have to trust the child to tell us its pid & mach task.
+ // WebKit uses `xpc_connection_get_pid` to get the pid, however this
+ // is marked as unavailable on iOS.
+ //
+ // Given how the process is started, however, validating this
+ // information it sends us this early during startup may be
+ // unnecessary.
+ self->mResults.mChildTask =
+ xpc_dictionary_copy_mach_send(reply, "task");
+ pid_t pid =
+ static_cast<pid_t>(xpc_dictionary_get_int64(reply, "pid"));
+ CHROMIUM_LOG(INFO) << "ExtensionKit process started, task: "
+ << self->mResults.mChildTask << ", pid: " << pid;
+
+ pid_t taskPid;
+ kern_return_t kr = pid_for_task(self->mResults.mChildTask, &taskPid);
+ if (kr != KERN_SUCCESS || pid != taskPid) {
+ CHROMIUM_LOG(ERROR) << "Could not validate child task matches pid";
+ promise->Reject(LaunchError("pid_for_task mismatch"), __func__);
+ return;
+ }
+
+ promise->Resolve(pid, __func__);
+ });
+ });
+
+ return promise;
+}
+#endif
+
#ifdef XP_MACOSX
Result<Ok, LaunchError> MacProcessLauncher::DoFinishLaunch() {
Result<Ok, LaunchError> aError = PosixProcessLauncher::DoFinishLaunch();
@@ -1647,7 +1805,7 @@ RefPtr<ProcessLaunchPromise> BaseProcessLauncher::FinishLaunch() {
Telemetry::AccumulateTimeDelta(Telemetry::CHILD_PROCESS_LAUNCH_MS,
mStartTimeStamp);
- return ProcessLaunchPromise::CreateAndResolve(mResults, __func__);
+ return ProcessLaunchPromise::CreateAndResolve(std::move(mResults), __func__);
}
bool GeckoChildProcessHost::OpenPrivilegedHandle(base::ProcessId aPid) {