Bug 1758813 [wpt PR 33142] - Implement RP sign out, a=testonly
[gecko.git] / ipc / glue / ProcessUtils_common.cpp
blob5dbe13cc7b2fd967d33369f9407ce81f2a692e3a
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ProcessUtils.h"
9 #include "mozilla/Preferences.h"
10 #include "mozilla/GeckoArgs.h"
11 #include "mozilla/ipc/GeckoChildProcessHost.h"
12 #include "mozilla/UniquePtrExtensions.h"
13 #include "nsPrintfCString.h"
15 #include "XPCSelfHostedShmem.h"
17 namespace mozilla {
18 namespace ipc {
20 SharedPreferenceSerializer::SharedPreferenceSerializer(
21 std::function<bool(const char*)>&& aShouldSerializeFn)
22 : mPrefMapSize(0), mPrefsLength(0), mShouldSerializeFn(aShouldSerializeFn) {
23 MOZ_COUNT_CTOR(SharedPreferenceSerializer);
26 SharedPreferenceSerializer::~SharedPreferenceSerializer() {
27 MOZ_COUNT_DTOR(SharedPreferenceSerializer);
30 SharedPreferenceSerializer::SharedPreferenceSerializer(
31 SharedPreferenceSerializer&& aOther)
32 : mPrefMapSize(aOther.mPrefMapSize),
33 mPrefsLength(aOther.mPrefsLength),
34 mPrefMapHandle(std::move(aOther.mPrefMapHandle)),
35 mPrefsHandle(std::move(aOther.mPrefsHandle)) {
36 MOZ_COUNT_CTOR(SharedPreferenceSerializer);
39 bool SharedPreferenceSerializer::SerializeToSharedMemory() {
40 mPrefMapHandle =
41 Preferences::EnsureSnapshot(&mPrefMapSize).TakePlatformHandle();
43 // Serialize the early prefs.
44 nsAutoCStringN<1024> prefs;
45 Preferences::SerializePreferences(prefs, mShouldSerializeFn);
46 mPrefsLength = prefs.Length();
48 base::SharedMemory shm;
49 // Set up the shared memory.
50 if (!shm.Create(prefs.Length())) {
51 NS_ERROR("failed to create shared memory in the parent");
52 return false;
54 if (!shm.Map(prefs.Length())) {
55 NS_ERROR("failed to map shared memory in the parent");
56 return false;
59 // Copy the serialized prefs into the shared memory.
60 memcpy(static_cast<char*>(shm.memory()), prefs.get(), mPrefsLength);
62 mPrefsHandle = shm.TakeHandle();
63 return true;
66 void SharedPreferenceSerializer::AddSharedPrefCmdLineArgs(
67 mozilla::ipc::GeckoChildProcessHost& procHost,
68 std::vector<std::string>& aExtraOpts) const {
69 #if defined(XP_WIN)
70 // Record the handle as to-be-shared, and pass it via a command flag. This
71 // works because Windows handles are system-wide.
72 procHost.AddHandleToShare(GetPrefsHandle().get());
73 procHost.AddHandleToShare(GetPrefMapHandle().get());
74 geckoargs::sPrefsHandle.Put((uintptr_t)(GetPrefsHandle().get()), aExtraOpts);
75 geckoargs::sPrefMapHandle.Put((uintptr_t)(GetPrefMapHandle().get()),
76 aExtraOpts);
77 #else
78 // In contrast, Unix fds are per-process. So remap the fd to a fixed one that
79 // will be used in the child.
80 // XXX: bug 1440207 is about improving how fixed fds are used.
82 // Note: on Android, AddFdToRemap() sets up the fd to be passed via a Parcel,
83 // and the fixed fd isn't used. However, we still need to mark it for
84 // remapping so it doesn't get closed in the child.
85 procHost.AddFdToRemap(GetPrefsHandle().get(), kPrefsFileDescriptor);
86 procHost.AddFdToRemap(GetPrefMapHandle().get(), kPrefMapFileDescriptor);
87 #endif
89 // Pass the lengths via command line flags.
90 geckoargs::sPrefsLen.Put((uintptr_t)(GetPrefsLength()), aExtraOpts);
91 geckoargs::sPrefMapSize.Put((uintptr_t)(GetPrefMapSize()), aExtraOpts);
94 #ifdef ANDROID
95 static int gPrefsFd = -1;
96 static int gPrefMapFd = -1;
98 void SetPrefsFd(int aFd) { gPrefsFd = aFd; }
100 void SetPrefMapFd(int aFd) { gPrefMapFd = aFd; }
101 #endif
103 SharedPreferenceDeserializer::SharedPreferenceDeserializer() {
104 MOZ_COUNT_CTOR(SharedPreferenceDeserializer);
107 SharedPreferenceDeserializer::~SharedPreferenceDeserializer() {
108 MOZ_COUNT_DTOR(SharedPreferenceDeserializer);
111 bool SharedPreferenceDeserializer::DeserializeFromSharedMemory(
112 uint64_t aPrefsHandle, uint64_t aPrefMapHandle, uint64_t aPrefsLen,
113 uint64_t aPrefMapSize) {
114 Maybe<base::SharedMemoryHandle> prefsHandle;
116 #ifdef XP_WIN
117 prefsHandle = Some(UniqueFileHandle(HANDLE((uintptr_t)(aPrefsHandle))));
118 if (!aPrefsHandle) {
119 return false;
122 FileDescriptor::UniquePlatformHandle handle(
123 HANDLE((uintptr_t)(aPrefMapHandle)));
124 if (!aPrefMapHandle) {
125 return false;
128 mPrefMapHandle.emplace(std::move(handle));
129 #endif
131 mPrefsLen = Some((uintptr_t)(aPrefsLen));
132 if (!aPrefsLen) {
133 return false;
136 mPrefMapSize = Some((uintptr_t)(aPrefMapSize));
137 if (!aPrefMapSize) {
138 return false;
141 #ifdef ANDROID
142 // Android is different; get the FD via gPrefsFd instead of a fixed fd.
143 MOZ_RELEASE_ASSERT(gPrefsFd != -1);
144 prefsHandle = Some(UniqueFileHandle(gPrefsFd));
146 mPrefMapHandle.emplace(UniqueFileHandle(gPrefMapFd));
147 #elif XP_UNIX
148 prefsHandle = Some(UniqueFileHandle(kPrefsFileDescriptor));
150 mPrefMapHandle.emplace(UniqueFileHandle(kPrefMapFileDescriptor));
151 #endif
153 if (prefsHandle.isNothing() || mPrefsLen.isNothing() ||
154 mPrefMapHandle.isNothing() || mPrefMapSize.isNothing()) {
155 return false;
158 // Init the shared-memory base preference mapping first, so that only changed
159 // preferences wind up in heap memory.
160 Preferences::InitSnapshot(mPrefMapHandle.ref(), *mPrefMapSize);
162 // Set up early prefs from the shared memory.
163 if (!mShmem.SetHandle(std::move(*prefsHandle), /* read_only */ true)) {
164 NS_ERROR("failed to open shared memory in the child");
165 return false;
167 if (!mShmem.Map(*mPrefsLen)) {
168 NS_ERROR("failed to map shared memory in the child");
169 return false;
171 Preferences::DeserializePreferences(static_cast<char*>(mShmem.memory()),
172 *mPrefsLen);
174 return true;
177 const FileDescriptor& SharedPreferenceDeserializer::GetPrefMapHandle() const {
178 MOZ_ASSERT(mPrefMapHandle.isSome());
180 return mPrefMapHandle.ref();
183 #ifdef XP_UNIX
184 // On Unix, file descriptors are per-process. This value is used when mapping
185 // a parent process handle to a content process handle.
186 static const int kJSInitFileDescriptor = 11;
187 #endif
189 void ExportSharedJSInit(mozilla::ipc::GeckoChildProcessHost& procHost,
190 std::vector<std::string>& aExtraOpts) {
191 #ifdef ANDROID
192 // The code to support Android is added in a follow-up patch.
193 return;
194 #else
195 auto& shmem = xpc::SelfHostedShmem::GetSingleton();
196 const mozilla::UniqueFileHandle& uniqHandle = shmem.Handle();
197 size_t len = shmem.Content().Length();
199 // If the file is not found or the content is empty, then we would start the
200 // content process without this optimization.
201 if (!uniqHandle || !len) {
202 return;
205 mozilla::detail::FileHandleType handle = uniqHandle.get();
206 // command line: [-jsInitHandle handle] -jsInitLen length
207 # if defined(XP_WIN)
208 // Record the handle as to-be-shared, and pass it via a command flag.
209 procHost.AddHandleToShare(HANDLE(handle));
210 geckoargs::sJsInitHandle.Put((uintptr_t)(HANDLE(handle)), aExtraOpts);
211 # else
212 // In contrast, Unix fds are per-process. So remap the fd to a fixed one that
213 // will be used in the child.
214 // XXX: bug 1440207 is about improving how fixed fds are used.
216 // Note: on Android, AddFdToRemap() sets up the fd to be passed via a Parcel,
217 // and the fixed fd isn't used. However, we still need to mark it for
218 // remapping so it doesn't get closed in the child.
219 procHost.AddFdToRemap(handle, kJSInitFileDescriptor);
220 # endif
222 // Pass the lengths via command line flags.
223 geckoargs::sJsInitLen.Put((uintptr_t)(len), aExtraOpts);
224 #endif
227 bool ImportSharedJSInit(uint64_t aJsInitHandle, uint64_t aJsInitLen) {
228 // This is an optimization, and as such we can safely recover if the command
229 // line argument are not provided.
230 if (!aJsInitLen) {
231 return true;
234 #ifdef XP_WIN
235 if (!aJsInitHandle) {
236 return true;
238 #endif
240 #ifdef XP_WIN
241 base::SharedMemoryHandle handle(HANDLE((uintptr_t)(aJsInitHandle)));
242 if (!aJsInitHandle) {
243 return false;
245 #endif
247 size_t len = (uintptr_t)(aJsInitLen);
248 if (!aJsInitLen) {
249 return false;
252 #ifdef XP_UNIX
253 auto handle = UniqueFileHandle(kJSInitFileDescriptor);
254 #endif
256 // Initialize the shared memory with the file handle and size of the content
257 // of the self-hosted Xdr.
258 auto& shmem = xpc::SelfHostedShmem::GetSingleton();
259 if (!shmem.InitFromChild(std::move(handle), len)) {
260 NS_ERROR("failed to open shared memory in the child");
261 return false;
264 return true;
267 } // namespace ipc
268 } // namespace mozilla