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/dom/RemoteType.h"
12 #include "mozilla/ipc/GeckoChildProcessHost.h"
13 #include "mozilla/UniquePtrExtensions.h"
14 #include "nsPrintfCString.h"
16 #include "XPCSelfHostedShmem.h"
21 SharedPreferenceSerializer::SharedPreferenceSerializer()
22 : mPrefMapSize(0), mPrefsLength(0) {
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 const GeckoProcessType aDestinationProcessType
,
41 const nsACString
& aDestinationRemoteType
) {
43 Preferences::EnsureSnapshot(&mPrefMapSize
).TakePlatformHandle();
45 bool destIsWebContent
=
46 aDestinationProcessType
== GeckoProcessType_Content
&&
47 (StringBeginsWith(aDestinationRemoteType
, WEB_REMOTE_TYPE
) ||
48 StringBeginsWith(aDestinationRemoteType
, PREALLOC_REMOTE_TYPE
));
50 // Serialize the early prefs.
51 nsAutoCStringN
<1024> prefs
;
52 Preferences::SerializePreferences(prefs
, destIsWebContent
);
53 mPrefsLength
= prefs
.Length();
55 base::SharedMemory shm
;
56 // Set up the shared memory.
57 if (!shm
.Create(prefs
.Length())) {
58 NS_ERROR("failed to create shared memory in the parent");
61 if (!shm
.Map(prefs
.Length())) {
62 NS_ERROR("failed to map shared memory in the parent");
66 // Copy the serialized prefs into the shared memory.
67 memcpy(static_cast<char*>(shm
.memory()), prefs
.get(), mPrefsLength
);
69 mPrefsHandle
= shm
.TakeHandle();
73 void SharedPreferenceSerializer::AddSharedPrefCmdLineArgs(
74 mozilla::ipc::GeckoChildProcessHost
& procHost
,
75 std::vector
<std::string
>& aExtraOpts
) const {
77 // Record the handle as to-be-shared, and pass it via a command flag. This
78 // works because Windows handles are system-wide.
79 procHost
.AddHandleToShare(GetPrefsHandle().get());
80 procHost
.AddHandleToShare(GetPrefMapHandle().get());
81 geckoargs::sPrefsHandle
.Put((uintptr_t)(GetPrefsHandle().get()), aExtraOpts
);
82 geckoargs::sPrefMapHandle
.Put((uintptr_t)(GetPrefMapHandle().get()),
85 // In contrast, Unix fds are per-process. So remap the fd to a fixed one that
86 // will be used in the child.
87 // XXX: bug 1440207 is about improving how fixed fds are used.
89 // Note: on Android, AddFdToRemap() sets up the fd to be passed via a Parcel,
90 // and the fixed fd isn't used. However, we still need to mark it for
91 // remapping so it doesn't get closed in the child.
92 procHost
.AddFdToRemap(GetPrefsHandle().get(), kPrefsFileDescriptor
);
93 procHost
.AddFdToRemap(GetPrefMapHandle().get(), kPrefMapFileDescriptor
);
96 // Pass the lengths via command line flags.
97 geckoargs::sPrefsLen
.Put((uintptr_t)(GetPrefsLength()), aExtraOpts
);
98 geckoargs::sPrefMapSize
.Put((uintptr_t)(GetPrefMapSize()), aExtraOpts
);
101 #if defined(ANDROID) || defined(XP_IOS)
102 static int gPrefsFd
= -1;
103 static int gPrefMapFd
= -1;
105 void SetPrefsFd(int aFd
) { gPrefsFd
= aFd
; }
107 void SetPrefMapFd(int aFd
) { gPrefMapFd
= aFd
; }
110 SharedPreferenceDeserializer::SharedPreferenceDeserializer() {
111 MOZ_COUNT_CTOR(SharedPreferenceDeserializer
);
114 SharedPreferenceDeserializer::~SharedPreferenceDeserializer() {
115 MOZ_COUNT_DTOR(SharedPreferenceDeserializer
);
118 bool SharedPreferenceDeserializer::DeserializeFromSharedMemory(
119 uint64_t aPrefsHandle
, uint64_t aPrefMapHandle
, uint64_t aPrefsLen
,
120 uint64_t aPrefMapSize
) {
121 Maybe
<base::SharedMemoryHandle
> prefsHandle
;
124 prefsHandle
= Some(UniqueFileHandle(HANDLE((uintptr_t)(aPrefsHandle
))));
129 FileDescriptor::UniquePlatformHandle
handle(
130 HANDLE((uintptr_t)(aPrefMapHandle
)));
131 if (!aPrefMapHandle
) {
135 mPrefMapHandle
.emplace(std::move(handle
));
138 mPrefsLen
= Some((uintptr_t)(aPrefsLen
));
143 mPrefMapSize
= Some((uintptr_t)(aPrefMapSize
));
148 #if defined(ANDROID) || defined(XP_IOS)
149 // Android/iOS is different; get the FD via gPrefsFd instead of a fixed fd.
150 MOZ_RELEASE_ASSERT(gPrefsFd
!= -1);
151 prefsHandle
= Some(UniqueFileHandle(gPrefsFd
));
153 mPrefMapHandle
.emplace(UniqueFileHandle(gPrefMapFd
));
155 prefsHandle
= Some(UniqueFileHandle(kPrefsFileDescriptor
));
157 mPrefMapHandle
.emplace(UniqueFileHandle(kPrefMapFileDescriptor
));
160 if (prefsHandle
.isNothing() || mPrefsLen
.isNothing() ||
161 mPrefMapHandle
.isNothing() || mPrefMapSize
.isNothing()) {
165 // Init the shared-memory base preference mapping first, so that only changed
166 // preferences wind up in heap memory.
167 Preferences::InitSnapshot(mPrefMapHandle
.ref(), *mPrefMapSize
);
169 // Set up early prefs from the shared memory.
170 if (!mShmem
.SetHandle(std::move(*prefsHandle
), /* read_only */ true)) {
171 NS_ERROR("failed to open shared memory in the child");
174 if (!mShmem
.Map(*mPrefsLen
)) {
175 NS_ERROR("failed to map shared memory in the child");
178 Preferences::DeserializePreferences(static_cast<char*>(mShmem
.memory()),
184 const FileDescriptor
& SharedPreferenceDeserializer::GetPrefMapHandle() const {
185 MOZ_ASSERT(mPrefMapHandle
.isSome());
187 return mPrefMapHandle
.ref();
191 // On Unix, file descriptors are per-process. This value is used when mapping
192 // a parent process handle to a content process handle.
193 static const int kJSInitFileDescriptor
= 11;
196 void ExportSharedJSInit(mozilla::ipc::GeckoChildProcessHost
& procHost
,
197 std::vector
<std::string
>& aExtraOpts
) {
198 #if defined(ANDROID) || defined(XP_IOS)
199 // The code to support Android/iOS is added in a follow-up patch.
202 auto& shmem
= xpc::SelfHostedShmem::GetSingleton();
203 const mozilla::UniqueFileHandle
& uniqHandle
= shmem
.Handle();
204 size_t len
= shmem
.Content().Length();
206 // If the file is not found or the content is empty, then we would start the
207 // content process without this optimization.
208 if (!uniqHandle
|| !len
) {
212 mozilla::detail::FileHandleType handle
= uniqHandle
.get();
213 // command line: [-jsInitHandle handle] -jsInitLen length
215 // Record the handle as to-be-shared, and pass it via a command flag.
216 procHost
.AddHandleToShare(HANDLE(handle
));
217 geckoargs::sJsInitHandle
.Put((uintptr_t)(HANDLE(handle
)), aExtraOpts
);
219 // In contrast, Unix fds are per-process. So remap the fd to a fixed one that
220 // will be used in the child.
221 // XXX: bug 1440207 is about improving how fixed fds are used.
223 // Note: on Android, AddFdToRemap() sets up the fd to be passed via a Parcel,
224 // and the fixed fd isn't used. However, we still need to mark it for
225 // remapping so it doesn't get closed in the child.
226 procHost
.AddFdToRemap(handle
, kJSInitFileDescriptor
);
229 // Pass the lengths via command line flags.
230 geckoargs::sJsInitLen
.Put((uintptr_t)(len
), aExtraOpts
);
234 bool ImportSharedJSInit(uint64_t aJsInitHandle
, uint64_t aJsInitLen
) {
235 // This is an optimization, and as such we can safely recover if the command
236 // line argument are not provided.
242 if (!aJsInitHandle
) {
248 base::SharedMemoryHandle
handle(HANDLE((uintptr_t)(aJsInitHandle
)));
249 if (!aJsInitHandle
) {
254 size_t len
= (uintptr_t)(aJsInitLen
);
260 auto handle
= UniqueFileHandle(kJSInitFileDescriptor
);
263 // Initialize the shared memory with the file handle and size of the content
264 // of the self-hosted Xdr.
265 auto& shmem
= xpc::SelfHostedShmem::GetSingleton();
266 if (!shmem
.InitFromChild(std::move(handle
), len
)) {
267 NS_ERROR("failed to open shared memory in the child");
275 } // namespace mozilla