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/. */
6
7 #include "XPCSelfHostedShmem.h"
8
9 // static
10 mozilla::StaticRefPtr<xpc::SelfHostedShmem>
11 xpc::SelfHostedShmem::sSelfHostedXdr;
12
NS_IMPL_ISUPPORTS(xpc::SelfHostedShmem,nsIMemoryReporter)13 NS_IMPL_ISUPPORTS(xpc::SelfHostedShmem, nsIMemoryReporter)
14
15 // static
16 xpc::SelfHostedShmem& xpc::SelfHostedShmem::GetSingleton() {
17 MOZ_ASSERT_IF(!sSelfHostedXdr, NS_IsMainThread());
18
19 if (!sSelfHostedXdr) {
20 sSelfHostedXdr = new SelfHostedShmem;
21 }
22
23 return *sSelfHostedXdr;
24 }
25
InitMemoryReporter()26 void xpc::SelfHostedShmem::InitMemoryReporter() {
27 mozilla::RegisterWeakMemoryReporter(this);
28 }
29
30 // static
Shutdown()31 void xpc::SelfHostedShmem::Shutdown() {
32 MOZ_ASSERT(NS_IsMainThread());
33 // NOTE: We cannot call UnregisterWeakMemoryReporter(sSelfHostedXdr) as the
34 // service is shutdown at the time this call is made. In any cases, this would
35 // already be done when the memory reporter got destroyed.
36 sSelfHostedXdr = nullptr;
37 }
38
InitFromParent(ContentType aXdr)39 void xpc::SelfHostedShmem::InitFromParent(ContentType aXdr) {
40 MOZ_ASSERT(XRE_IsParentProcess());
41 MOZ_ASSERT(NS_IsMainThread());
42 MOZ_ASSERT(!mLen, "Shouldn't call this more than once");
43
44 size_t len = aXdr.Length();
45 auto shm = mozilla::MakeUnique<base::SharedMemory>();
46 if (NS_WARN_IF(!shm->CreateFreezeable(len))) {
47 return;
48 }
49
50 if (NS_WARN_IF(!shm->Map(len))) {
51 return;
52 }
53
54 void* address = shm->memory();
55 memcpy(address, aXdr.Elements(), aXdr.LengthBytes());
56
57 base::SharedMemory roCopy;
58 if (NS_WARN_IF(!shm->ReadOnlyCopy(&roCopy))) {
59 return;
60 }
61
62 mMem = std::move(shm);
63 mHandle = roCopy.TakeHandle();
64 mLen = len;
65 }
66
InitFromChild(::base::SharedMemoryHandle aHandle,size_t aLen)67 bool xpc::SelfHostedShmem::InitFromChild(::base::SharedMemoryHandle aHandle,
68 size_t aLen) {
69 MOZ_ASSERT(!XRE_IsParentProcess());
70 MOZ_ASSERT(NS_IsMainThread());
71 MOZ_ASSERT(!mLen, "Shouldn't call this more than once");
72
73 auto shm = mozilla::MakeUnique<base::SharedMemory>();
74 if (NS_WARN_IF(!shm->SetHandle(std::move(aHandle), /* read_only */ true))) {
75 return false;
76 }
77
78 if (NS_WARN_IF(!shm->Map(aLen))) {
79 return false;
80 }
81
82 // Note: mHandle remains empty, as content processes are not spawning more
83 // content processes.
84 mMem = std::move(shm);
85 mLen = aLen;
86 return true;
87 }
88
Content() const89 xpc::SelfHostedShmem::ContentType xpc::SelfHostedShmem::Content() const {
90 if (!mMem) {
91 MOZ_ASSERT(mLen == 0);
92 return ContentType();
93 }
94 return ContentType(reinterpret_cast<uint8_t*>(mMem->memory()), mLen);
95 }
96
Handle() const97 const mozilla::UniqueFileHandle& xpc::SelfHostedShmem::Handle() const {
98 return mHandle;
99 }
100
101 NS_IMETHODIMP
CollectReports(nsIHandleReportCallback * aHandleReport,nsISupports * aData,bool aAnonymize)102 xpc::SelfHostedShmem::CollectReports(nsIHandleReportCallback* aHandleReport,
103 nsISupports* aData, bool aAnonymize) {
104 // If this is the parent process, then we have a handle and this instance owns
105 // the data and shares it with other processes, otherwise this is shared data.
106 if (XRE_IsParentProcess()) {
107 // This does not exactly report the amount of data mapped by the system,
108 // but the space requested when creating the handle.
109 MOZ_COLLECT_REPORT("explicit/js-non-window/shared-memory/self-hosted-xdr",
110 KIND_NONHEAP, UNITS_BYTES, mLen,
111 "Memory used to initialize the JS engine with the "
112 "self-hosted code encoded by the parent process.");
113 }
114 return NS_OK;
115 }
116