Bug 1642744 [wpt PR 23920] - [ScrollTimeline] Update compositor timeline from blink...
[gecko.git] / ipc / glue / ProcessUtils_common.cpp
blobd07faba6f4374601251d4f369b52466ae571a98d
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/ipc/GeckoChildProcessHost.h"
11 #include "mozilla/UniquePtrExtensions.h"
13 namespace mozilla {
14 namespace ipc {
16 SharedPreferenceSerializer::SharedPreferenceSerializer() : mPrefMapSize(0) {
17 MOZ_COUNT_CTOR(SharedPreferenceSerializer);
20 SharedPreferenceSerializer::~SharedPreferenceSerializer() {
21 MOZ_COUNT_DTOR(SharedPreferenceSerializer);
24 SharedPreferenceSerializer::SharedPreferenceSerializer(
25 SharedPreferenceSerializer&& aOther)
26 : mPrefMapSize(aOther.mPrefMapSize),
27 mPrefsLength(aOther.mPrefsLength),
28 mPrefMapHandle(std::move(aOther.mPrefMapHandle)),
29 mPrefsHandle(std::move(aOther.mPrefsHandle)) {
30 MOZ_COUNT_CTOR(SharedPreferenceSerializer);
33 bool SharedPreferenceSerializer::SerializeToSharedMemory() {
34 mPrefMapHandle =
35 Preferences::EnsureSnapshot(&mPrefMapSize).TakePlatformHandle();
37 // Serialize the early prefs.
38 nsAutoCStringN<1024> prefs;
39 Preferences::SerializePreferences(prefs);
40 mPrefsLength = prefs.Length();
42 base::SharedMemory shm;
43 // Set up the shared memory.
44 if (!shm.Create(prefs.Length())) {
45 NS_ERROR("failed to create shared memory in the parent");
46 return false;
48 if (!shm.Map(prefs.Length())) {
49 NS_ERROR("failed to map shared memory in the parent");
50 return false;
53 // Copy the serialized prefs into the shared memory.
54 memcpy(static_cast<char*>(shm.memory()), prefs.get(), mPrefsLength);
56 mPrefsHandle = shm.TakeHandle();
57 return true;
60 void SharedPreferenceSerializer::AddSharedPrefCmdLineArgs(
61 mozilla::ipc::GeckoChildProcessHost& procHost,
62 std::vector<std::string>& aExtraOpts) const {
63 // Formats a pointer or pointer-sized-integer as a string suitable for passing
64 // in an arguments list.
65 auto formatPtrArg = [](auto arg) {
66 return nsPrintfCString("%zu", uintptr_t(arg));
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 aExtraOpts.push_back("-prefsHandle");
75 aExtraOpts.push_back(formatPtrArg(GetPrefsHandle().get()).get());
76 aExtraOpts.push_back("-prefMapHandle");
77 aExtraOpts.push_back(formatPtrArg(GetPrefMapHandle().get()).get());
78 #else
79 // In contrast, Unix fds are per-process. So remap the fd to a fixed one that
80 // will be used in the child.
81 // XXX: bug 1440207 is about improving how fixed fds are used.
83 // Note: on Android, AddFdToRemap() sets up the fd to be passed via a Parcel,
84 // and the fixed fd isn't used. However, we still need to mark it for
85 // remapping so it doesn't get closed in the child.
86 procHost.AddFdToRemap(GetPrefsHandle().get(), kPrefsFileDescriptor);
87 procHost.AddFdToRemap(GetPrefMapHandle().get(), kPrefMapFileDescriptor);
88 #endif
90 // Pass the lengths via command line flags.
91 aExtraOpts.push_back("-prefsLen");
92 aExtraOpts.push_back(formatPtrArg(GetPrefsLength()).get());
93 aExtraOpts.push_back("-prefMapSize");
94 aExtraOpts.push_back(formatPtrArg(GetPrefMapSize()).get());
97 #ifdef ANDROID
98 static int gPrefsFd = -1;
99 static int gPrefMapFd = -1;
101 void SetPrefsFd(int aFd) { gPrefsFd = aFd; }
103 void SetPrefMapFd(int aFd) { gPrefMapFd = aFd; }
104 #endif
106 SharedPreferenceDeserializer::SharedPreferenceDeserializer() {
107 MOZ_COUNT_CTOR(SharedPreferenceDeserializer);
110 SharedPreferenceDeserializer::~SharedPreferenceDeserializer() {
111 MOZ_COUNT_DTOR(SharedPreferenceDeserializer);
114 bool SharedPreferenceDeserializer::DeserializeFromSharedMemory(
115 char* aPrefsHandleStr, char* aPrefMapHandleStr, char* aPrefsLenStr,
116 char* aPrefMapSizeStr) {
117 #ifdef XP_WIN
118 MOZ_ASSERT(aPrefsHandleStr && aPrefMapHandleStr, "Can't be null");
119 #endif
120 MOZ_ASSERT(aPrefsLenStr && aPrefMapSizeStr, "Can't be null");
122 // Parses an arg containing a pointer-sized-integer.
123 auto parseUIntPtrArg = [](char*& aArg) {
124 // ContentParent uses %zu to print a word-sized unsigned integer. So
125 // even though strtoull() returns a long long int, it will fit in a
126 // uintptr_t.
127 return uintptr_t(strtoull(aArg, &aArg, 10));
130 #ifdef XP_WIN
131 auto parseHandleArg = [&](char*& aArg) {
132 return HANDLE(parseUIntPtrArg(aArg));
135 mPrefsHandle = Some(parseHandleArg(aPrefsHandleStr));
136 if (!aPrefsHandleStr || aPrefsHandleStr[0] != '\0') {
137 return false;
140 FileDescriptor::UniquePlatformHandle handle(
141 parseHandleArg(aPrefMapHandleStr));
142 if (!aPrefMapHandleStr || aPrefMapHandleStr[0] != '\0') {
143 return false;
146 mPrefMapHandle.emplace(std::move(handle));
147 #endif
149 mPrefsLen = Some(parseUIntPtrArg(aPrefsLenStr));
150 if (!aPrefsLenStr || aPrefsLenStr[0] != '\0') {
151 return false;
154 mPrefMapSize = Some(parseUIntPtrArg(aPrefMapSizeStr));
155 if (!aPrefMapSizeStr || aPrefMapSizeStr[0] != '\0') {
156 return false;
159 #ifdef ANDROID
160 // Android is different; get the FD via gPrefsFd instead of a fixed fd.
161 MOZ_RELEASE_ASSERT(gPrefsFd != -1);
162 mPrefsHandle = Some(base::FileDescriptor(gPrefsFd, /* auto_close */ true));
164 mPrefMapHandle.emplace(UniqueFileHandle(gPrefMapFd));
165 #elif XP_UNIX
166 mPrefsHandle = Some(base::FileDescriptor(kPrefsFileDescriptor,
167 /* auto_close */ true));
169 mPrefMapHandle.emplace(UniqueFileHandle(kPrefMapFileDescriptor));
170 #endif
172 if (mPrefsHandle.isNothing() || mPrefsLen.isNothing() ||
173 mPrefMapHandle.isNothing() || mPrefMapSize.isNothing()) {
174 return false;
177 // Init the shared-memory base preference mapping first, so that only changed
178 // preferences wind up in heap memory.
179 Preferences::InitSnapshot(mPrefMapHandle.ref(), *mPrefMapSize);
181 // Set up early prefs from the shared memory.
182 if (!mShmem.SetHandle(*mPrefsHandle, /* read_only */ true)) {
183 NS_ERROR("failed to open shared memory in the child");
184 return false;
186 if (!mShmem.Map(*mPrefsLen)) {
187 NS_ERROR("failed to map shared memory in the child");
188 return false;
190 Preferences::DeserializePreferences(static_cast<char*>(mShmem.memory()),
191 *mPrefsLen);
193 return true;
196 const base::SharedMemoryHandle& SharedPreferenceDeserializer::GetPrefsHandle()
197 const {
198 MOZ_ASSERT(mPrefsHandle.isSome());
200 return mPrefsHandle.ref();
203 const FileDescriptor& SharedPreferenceDeserializer::GetPrefMapHandle() const {
204 MOZ_ASSERT(mPrefMapHandle.isSome());
206 return mPrefMapHandle.ref();
209 } // namespace ipc
210 } // namespace mozilla