1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "FOGIPC.h"
7 
8 #include "mozilla/glean/fog_ffi_generated.h"
9 #include "mozilla/glean/GleanMetrics.h"
10 #include "mozilla/dom/ContentChild.h"
11 #include "mozilla/dom/ContentParent.h"
12 #include "mozilla/MozPromise.h"
13 #include "nsTArray.h"
14 #include "nsThreadUtils.h"
15 
16 using mozilla::dom::ContentParent;
17 using mozilla::ipc::ByteBuf;
18 using FlushFOGDataPromise = mozilla::dom::ContentParent::FlushFOGDataPromise;
19 
20 namespace mozilla {
21 namespace glean {
22 
23 /**
24  * The parent process is asking you to flush your data ASAP.
25  *
26  * @param aResolver - The function you need to call with the bincoded,
27  *                    serialized payload that the Rust impl hands you.
28  */
FlushFOGData(std::function<void (ipc::ByteBuf &&)> && aResolver)29 void FlushFOGData(std::function<void(ipc::ByteBuf&&)>&& aResolver) {
30 #ifndef MOZ_GLEAN_ANDROID
31   ByteBuf buf;
32   uint32_t ipcBufferSize = impl::fog_serialize_ipc_buf();
33   bool ok = buf.Allocate(ipcBufferSize);
34   if (!ok) {
35     return;
36   }
37   uint32_t writtenLen = impl::fog_give_ipc_buf(buf.mData, buf.mLen);
38   if (writtenLen != ipcBufferSize) {
39     return;
40   }
41   aResolver(std::move(buf));
42 #endif
43 }
44 
45 /**
46  * Called by FOG on the parent process when it wants to flush all its
47  * children's data.
48  * @param aResolver - The function that'll be called with the results.
49  */
FlushAllChildData(std::function<void (nsTArray<ipc::ByteBuf> &&)> && aResolver)50 void FlushAllChildData(
51     std::function<void(nsTArray<ipc::ByteBuf>&&)>&& aResolver) {
52 #ifndef MOZ_GLEAN_ANDROID
53   nsTArray<ContentParent*> parents;
54   ContentParent::GetAll(parents);
55   if (parents.Length() == 0) {
56     nsTArray<ipc::ByteBuf> results;
57     aResolver(std::move(results));
58     return;
59   }
60 
61   auto timerId = fog_ipc::flush_durations.Start();
62   nsTArray<RefPtr<FlushFOGDataPromise>> promises;
63   for (auto* parent : parents) {
64     promises.EmplaceBack(parent->SendFlushFOGData());
65   }
66   // TODO: Don't throw away resolved data if some of the promises reject.
67   // (not sure how, but it'll mean not using ::All... maybe a custom copy of
68   // AllPromiseHolder? Might be impossible outside MozPromise.h)
69   FlushFOGDataPromise::All(GetCurrentSerialEventTarget(), promises)
70       ->Then(GetCurrentSerialEventTarget(), __func__,
71              [aResolver = std::move(aResolver), timerId](
72                  FlushFOGDataPromise::AllPromiseType::ResolveOrRejectValue&&
73                      aValue) {
74                fog_ipc::flush_durations.StopAndAccumulate(std::move(timerId));
75                if (aValue.IsResolve()) {
76                  aResolver(std::move(aValue.ResolveValue()));
77                } else {
78                  nsTArray<ipc::ByteBuf> results;
79                  aResolver(std::move(results));
80                }
81              });
82 #endif
83 }
84 
85 /**
86  * A child process has sent you this buf as a treat.
87  * @param buf - a bincoded serialized payload that the Rust impl understands.
88  */
FOGData(ipc::ByteBuf && buf)89 void FOGData(ipc::ByteBuf&& buf) {
90 #ifndef MOZ_GLEAN_ANDROID
91   fog_ipc::buffer_sizes.Accumulate(buf.mLen);
92   impl::fog_use_ipc_buf(buf.mData, buf.mLen);
93 #endif
94 }
95 
96 /**
97  * Called by FOG on a child process when it wants to send a buf to the parent.
98  * @param buf - a bincoded serialized payload that the Rust impl understands.
99  */
SendFOGData(ipc::ByteBuf && buf)100 void SendFOGData(ipc::ByteBuf&& buf) {
101 #ifndef MOZ_GLEAN_ANDROID
102   switch (XRE_GetProcessType()) {
103     case GeckoProcessType_Content:
104       mozilla::dom::ContentChild::GetSingleton()->SendFOGData(std::move(buf));
105       break;
106     default:
107       MOZ_ASSERT_UNREACHABLE("Unsuppored process type");
108   }
109 #endif
110 }
111 
112 /**
113  * Called on the parent process to ask all child processes for data,
114  * sending it all down into Rust to be used.
115  */
FlushAndUseFOGData()116 RefPtr<GenericPromise> FlushAndUseFOGData() {
117   RefPtr<GenericPromise::Private> ret = new GenericPromise::Private(__func__);
118   std::function<void(nsTArray<ByteBuf> &&)> resolver =
119       [ret](nsTArray<ByteBuf>&& bufs) {
120         for (ByteBuf& buf : bufs) {
121           FOGData(std::move(buf));
122         }
123         ret->Resolve(true, __func__);
124       };
125   FlushAllChildData(std::move(resolver));
126   return ret;
127 }
128 
129 }  // namespace glean
130 }  // namespace mozilla
131