diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:34:50 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-15 03:34:50 +0000 |
commit | def92d1b8e9d373e2f6f27c366d578d97d8960c6 (patch) | |
tree | 2ef34b9ad8bb9a9220e05d60352558b15f513894 /ipc/glue/GeckoChildProcessHost.cpp | |
parent | Adding debian version 125.0.3-1. (diff) | |
download | firefox-def92d1b8e9d373e2f6f27c366d578d97d8960c6.tar.xz firefox-def92d1b8e9d373e2f6f27c366d578d97d8960c6.zip |
Merging upstream version 126.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ipc/glue/GeckoChildProcessHost.cpp')
-rw-r--r-- | ipc/glue/GeckoChildProcessHost.cpp | 202 |
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) { |