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 #include "mozilla/ipc/UtilityProcessParent.h"
7 #include "mozilla/ipc/UtilityProcessManager.h"
8 
9 #if defined(XP_WIN)
10 #  include <dwrite.h>
11 #  include <process.h>
12 #  include "mozilla/WinDllServices.h"
13 #endif
14 
15 #include "mozilla/ipc/ProcessChild.h"
16 #include "mozilla/FOGIPC.h"
17 
18 #include "nsHashPropertyBag.h"
19 #include "mozilla/Services.h"
20 #include "nsIObserverService.h"
21 
22 namespace mozilla::ipc {
23 
24 static std::atomic<UtilityProcessParent*> sUtilityProcessParent;
25 
UtilityProcessParent(UtilityProcessHost * aHost)26 UtilityProcessParent::UtilityProcessParent(UtilityProcessHost* aHost)
27     : mHost(aHost) {
28   MOZ_ASSERT(NS_IsMainThread());
29   MOZ_ASSERT(mHost);
30   sUtilityProcessParent = this;
31 }
32 
33 UtilityProcessParent::~UtilityProcessParent() = default;
34 
35 /* static */
GetSingleton()36 UtilityProcessParent* UtilityProcessParent::GetSingleton() {
37   MOZ_DIAGNOSTIC_ASSERT(sUtilityProcessParent);
38   return sUtilityProcessParent;
39 }
40 
SendRequestMemoryReport(const uint32_t & aGeneration,const bool & aAnonymize,const bool & aMinimizeMemoryUsage,const Maybe<FileDescriptor> & aDMDFile)41 bool UtilityProcessParent::SendRequestMemoryReport(
42     const uint32_t& aGeneration, const bool& aAnonymize,
43     const bool& aMinimizeMemoryUsage, const Maybe<FileDescriptor>& aDMDFile) {
44   mMemoryReportRequest = MakeUnique<MemoryReportRequestHost>(aGeneration);
45 
46   PUtilityProcessParent::SendRequestMemoryReport(
47       aGeneration, aAnonymize, aMinimizeMemoryUsage, aDMDFile,
48       [&](const uint32_t& aGeneration2) {
49         if (RefPtr<UtilityProcessManager> utilitypm =
50                 UtilityProcessManager::GetSingleton()) {
51           if (UtilityProcessParent* parent = utilitypm->GetProcessParent()) {
52             if (parent->mMemoryReportRequest) {
53               parent->mMemoryReportRequest->Finish(aGeneration2);
54               parent->mMemoryReportRequest = nullptr;
55             }
56           }
57         }
58       },
59       [&](mozilla::ipc::ResponseRejectReason) {
60         if (RefPtr<UtilityProcessManager> utilitypm =
61                 UtilityProcessManager::GetSingleton()) {
62           if (UtilityProcessParent* parent = utilitypm->GetProcessParent()) {
63             parent->mMemoryReportRequest = nullptr;
64           }
65         }
66       });
67 
68   return true;
69 }
70 
RecvAddMemoryReport(const MemoryReport & aReport)71 mozilla::ipc::IPCResult UtilityProcessParent::RecvAddMemoryReport(
72     const MemoryReport& aReport) {
73   if (mMemoryReportRequest) {
74     mMemoryReportRequest->RecvReport(aReport);
75   }
76   return IPC_OK();
77 }
78 
RecvFOGData(ByteBuf && aBuf)79 mozilla::ipc::IPCResult UtilityProcessParent::RecvFOGData(ByteBuf&& aBuf) {
80   glean::FOGData(std::move(aBuf));
81   return IPC_OK();
82 }
83 
RecvInitCompleted()84 mozilla::ipc::IPCResult UtilityProcessParent::RecvInitCompleted() {
85   MOZ_ASSERT(mHost);
86   mHost->ResolvePromise();
87   return IPC_OK();
88 }
89 
ActorDestroy(ActorDestroyReason aWhy)90 void UtilityProcessParent::ActorDestroy(ActorDestroyReason aWhy) {
91   RefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
92 
93   if (aWhy == AbnormalShutdown) {
94     nsAutoString dumpID;
95     GenerateCrashReport(OtherPid(), &dumpID);
96 
97     // It's okay for dumpID to be empty if there was no minidump generated
98     // tests like ipc/glue/test/browser/browser_utility_crashReporter.js are
99     // there to verify this
100     if (!dumpID.IsEmpty()) {
101       props->SetPropertyAsAString(u"dumpID"_ns, dumpID);
102     }
103   }
104 
105   nsAutoString pid;
106   pid.AppendInt(static_cast<uint64_t>(OtherPid()));
107 
108   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
109   if (obs) {
110     obs->NotifyObservers((nsIPropertyBag2*)props, "ipc:utility-shutdown",
111                          pid.get());
112   } else {
113     NS_WARNING("Could not get a nsIObserverService, ipc:utility-shutdown skip");
114   }
115 
116   mHost->OnChannelClosed();
117 }
118 
119 // To ensure that IPDL is finished before UtilityParent gets deleted.
120 class DeferredDeleteUtilityProcessParent : public Runnable {
121  public:
DeferredDeleteUtilityProcessParent(RefPtr<UtilityProcessParent> aParent)122   explicit DeferredDeleteUtilityProcessParent(
123       RefPtr<UtilityProcessParent> aParent)
124       : Runnable("ipc::glue::DeferredDeleteUtilityProcessParent"),
125         mParent(std::move(aParent)) {}
126 
Run()127   NS_IMETHODIMP Run() override { return NS_OK; }
128 
129  private:
130   RefPtr<UtilityProcessParent> mParent;
131 };
132 
133 /* static */
Destroy(RefPtr<UtilityProcessParent> aParent)134 void UtilityProcessParent::Destroy(RefPtr<UtilityProcessParent> aParent) {
135   NS_DispatchToMainThread(
136       new DeferredDeleteUtilityProcessParent(std::move(aParent)));
137 }
138 
139 }  // namespace mozilla::ipc
140