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