MessagePortService.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. /* -*- Mode: C++; tab-width: 8; 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. #include "MessagePortService.h"
  6. #include "MessagePortParent.h"
  7. #include "SharedMessagePortMessage.h"
  8. #include "mozilla/ipc/BackgroundParent.h"
  9. #include "mozilla/StaticPtr.h"
  10. #include "mozilla/Unused.h"
  11. #include "mozilla/WeakPtr.h"
  12. #include "nsTArray.h"
  13. using mozilla::ipc::AssertIsOnBackgroundThread;
  14. namespace mozilla {
  15. namespace dom {
  16. namespace {
  17. StaticRefPtr<MessagePortService> gInstance;
  18. void
  19. AssertIsInMainProcess()
  20. {
  21. MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
  22. }
  23. } // namespace
  24. class MessagePortService::MessagePortServiceData final
  25. {
  26. public:
  27. explicit MessagePortServiceData(const nsID& aDestinationUUID)
  28. : mDestinationUUID(aDestinationUUID)
  29. , mSequenceID(1)
  30. , mParent(nullptr)
  31. // By default we don't know the next parent.
  32. , mWaitingForNewParent(true)
  33. , mNextStepCloseAll(false)
  34. {
  35. MOZ_COUNT_CTOR(MessagePortServiceData);
  36. }
  37. MessagePortServiceData(const MessagePortServiceData& aOther) = delete;
  38. MessagePortServiceData& operator=(const MessagePortServiceData&) = delete;
  39. ~MessagePortServiceData()
  40. {
  41. MOZ_COUNT_DTOR(MessagePortServiceData);
  42. }
  43. nsID mDestinationUUID;
  44. uint32_t mSequenceID;
  45. MessagePortParent* mParent;
  46. struct NextParent
  47. {
  48. uint32_t mSequenceID;
  49. // MessagePortParent keeps the service alive, and we don't want a cycle.
  50. WeakPtr<MessagePortParent> mParent;
  51. };
  52. FallibleTArray<NextParent> mNextParents;
  53. FallibleTArray<RefPtr<SharedMessagePortMessage>> mMessages;
  54. bool mWaitingForNewParent;
  55. bool mNextStepCloseAll;
  56. };
  57. /* static */ MessagePortService*
  58. MessagePortService::Get()
  59. {
  60. AssertIsInMainProcess();
  61. AssertIsOnBackgroundThread();
  62. return gInstance;
  63. }
  64. /* static */ MessagePortService*
  65. MessagePortService::GetOrCreate()
  66. {
  67. AssertIsInMainProcess();
  68. AssertIsOnBackgroundThread();
  69. if (!gInstance) {
  70. gInstance = new MessagePortService();
  71. }
  72. return gInstance;
  73. }
  74. bool
  75. MessagePortService::RequestEntangling(MessagePortParent* aParent,
  76. const nsID& aDestinationUUID,
  77. const uint32_t& aSequenceID)
  78. {
  79. MOZ_ASSERT(aParent);
  80. MessagePortServiceData* data;
  81. // If we don't have a MessagePortServiceData, we must create 2 of them for
  82. // both ports.
  83. if (!mPorts.Get(aParent->ID(), &data)) {
  84. // Create the MessagePortServiceData for the destination.
  85. if (mPorts.Get(aDestinationUUID, nullptr)) {
  86. MOZ_ASSERT(false, "The creation of the 2 ports should be in sync.");
  87. return false;
  88. }
  89. data = new MessagePortServiceData(aParent->ID());
  90. mPorts.Put(aDestinationUUID, data);
  91. data = new MessagePortServiceData(aDestinationUUID);
  92. mPorts.Put(aParent->ID(), data);
  93. }
  94. // This is a security check.
  95. if (!data->mDestinationUUID.Equals(aDestinationUUID)) {
  96. MOZ_ASSERT(false, "DestinationUUIDs do not match!");
  97. CloseAll(aParent->ID());
  98. return false;
  99. }
  100. if (aSequenceID < data->mSequenceID) {
  101. MOZ_ASSERT(false, "Invalid sequence ID!");
  102. CloseAll(aParent->ID());
  103. return false;
  104. }
  105. if (aSequenceID == data->mSequenceID) {
  106. if (data->mParent) {
  107. MOZ_ASSERT(false, "Two ports cannot have the same sequenceID.");
  108. CloseAll(aParent->ID());
  109. return false;
  110. }
  111. // We activate this port, sending all the messages.
  112. data->mParent = aParent;
  113. data->mWaitingForNewParent = false;
  114. FallibleTArray<MessagePortMessage> array;
  115. if (!SharedMessagePortMessage::FromSharedToMessagesParent(aParent,
  116. data->mMessages,
  117. array)) {
  118. CloseAll(aParent->ID());
  119. return false;
  120. }
  121. data->mMessages.Clear();
  122. // We can entangle the port.
  123. if (!aParent->Entangled(array)) {
  124. CloseAll(aParent->ID());
  125. return false;
  126. }
  127. // If we were waiting for this parent in order to close this channel, this
  128. // is the time to do it.
  129. if (data->mNextStepCloseAll) {
  130. CloseAll(aParent->ID());
  131. }
  132. return true;
  133. }
  134. // This new parent will be the next one when a Disentangle request is
  135. // received from the current parent.
  136. MessagePortServiceData::NextParent* nextParent =
  137. data->mNextParents.AppendElement(mozilla::fallible);
  138. if (!nextParent) {
  139. CloseAll(aParent->ID());
  140. return false;
  141. }
  142. nextParent->mSequenceID = aSequenceID;
  143. nextParent->mParent = aParent;
  144. return true;
  145. }
  146. bool
  147. MessagePortService::DisentanglePort(
  148. MessagePortParent* aParent,
  149. FallibleTArray<RefPtr<SharedMessagePortMessage>>& aMessages)
  150. {
  151. MessagePortServiceData* data;
  152. if (!mPorts.Get(aParent->ID(), &data)) {
  153. MOZ_ASSERT(false, "Unknown MessagePortParent should not happen.");
  154. return false;
  155. }
  156. if (data->mParent != aParent) {
  157. MOZ_ASSERT(false, "DisentanglePort() should be called just from the correct parent.");
  158. return false;
  159. }
  160. // Let's put the messages in the correct order. |aMessages| contains the
  161. // unsent messages so they have to go first.
  162. if (!aMessages.AppendElements(data->mMessages, mozilla::fallible)) {
  163. return false;
  164. }
  165. data->mMessages.Clear();
  166. ++data->mSequenceID;
  167. // If we don't have a parent, we have to store the pending messages and wait.
  168. uint32_t index = 0;
  169. MessagePortParent* nextParent = nullptr;
  170. for (; index < data->mNextParents.Length(); ++index) {
  171. if (data->mNextParents[index].mSequenceID == data->mSequenceID) {
  172. nextParent = data->mNextParents[index].mParent;
  173. break;
  174. }
  175. }
  176. // We didn't find the parent.
  177. if (!nextParent) {
  178. data->mMessages.SwapElements(aMessages);
  179. data->mWaitingForNewParent = true;
  180. data->mParent = nullptr;
  181. return true;
  182. }
  183. data->mParent = nextParent;
  184. data->mNextParents.RemoveElementAt(index);
  185. FallibleTArray<MessagePortMessage> array;
  186. if (!SharedMessagePortMessage::FromSharedToMessagesParent(data->mParent,
  187. aMessages,
  188. array)) {
  189. return false;
  190. }
  191. Unused << data->mParent->Entangled(array);
  192. return true;
  193. }
  194. bool
  195. MessagePortService::ClosePort(MessagePortParent* aParent)
  196. {
  197. MessagePortServiceData* data;
  198. if (!mPorts.Get(aParent->ID(), &data)) {
  199. MOZ_ASSERT(false, "Unknown MessagePortParent should not happend.");
  200. return false;
  201. }
  202. if (data->mParent != aParent) {
  203. MOZ_ASSERT(false, "ClosePort() should be called just from the correct parent.");
  204. return false;
  205. }
  206. if (!data->mNextParents.IsEmpty()) {
  207. MOZ_ASSERT(false, "ClosePort() should be called when there are not next parents.");
  208. return false;
  209. }
  210. // We don't want to send a message to this parent.
  211. data->mParent = nullptr;
  212. CloseAll(aParent->ID());
  213. return true;
  214. }
  215. void
  216. MessagePortService::CloseAll(const nsID& aUUID, bool aForced)
  217. {
  218. MessagePortServiceData* data;
  219. if (!mPorts.Get(aUUID, &data)) {
  220. MaybeShutdown();
  221. return;
  222. }
  223. if (data->mParent) {
  224. data->mParent->Close();
  225. }
  226. for (const MessagePortServiceData::NextParent& nextParent : data->mNextParents) {
  227. MessagePortParent* const parent = nextParent.mParent;
  228. if (parent) {
  229. parent->CloseAndDelete();
  230. }
  231. }
  232. data->mNextParents.Clear();
  233. nsID destinationUUID = data->mDestinationUUID;
  234. // If we have informations about the other port and that port has some
  235. // pending messages to deliver but the parent has not processed them yet,
  236. // because its entangling request didn't arrive yet), we cannot close this
  237. // channel.
  238. MessagePortServiceData* destinationData;
  239. if (!aForced &&
  240. mPorts.Get(destinationUUID, &destinationData) &&
  241. !destinationData->mMessages.IsEmpty() &&
  242. destinationData->mWaitingForNewParent) {
  243. MOZ_ASSERT(!destinationData->mNextStepCloseAll);
  244. destinationData->mNextStepCloseAll = true;
  245. return;
  246. }
  247. mPorts.Remove(aUUID);
  248. CloseAll(destinationUUID, aForced);
  249. // CloseAll calls itself recursively and it can happen that it deletes
  250. // itself. Before continuing we must check if we are still alive.
  251. if (!gInstance) {
  252. return;
  253. }
  254. #ifdef DEBUG
  255. for (auto iter = mPorts.Iter(); !iter.Done(); iter.Next()) {
  256. MOZ_ASSERT(!aUUID.Equals(iter.Key()));
  257. }
  258. #endif
  259. MaybeShutdown();
  260. }
  261. // This service can be dismissed when there are not active ports.
  262. void
  263. MessagePortService::MaybeShutdown()
  264. {
  265. if (mPorts.Count() == 0) {
  266. gInstance = nullptr;
  267. }
  268. }
  269. bool
  270. MessagePortService::PostMessages(
  271. MessagePortParent* aParent,
  272. FallibleTArray<RefPtr<SharedMessagePortMessage>>& aMessages)
  273. {
  274. MessagePortServiceData* data;
  275. if (!mPorts.Get(aParent->ID(), &data)) {
  276. MOZ_ASSERT(false, "Unknown MessagePortParent should not happend.");
  277. return false;
  278. }
  279. if (data->mParent != aParent) {
  280. MOZ_ASSERT(false, "PostMessages() should be called just from the correct parent.");
  281. return false;
  282. }
  283. MOZ_ALWAYS_TRUE(mPorts.Get(data->mDestinationUUID, &data));
  284. if (!data->mMessages.AppendElements(aMessages, mozilla::fallible)) {
  285. return false;
  286. }
  287. // If the parent can send data to the child, let's proceed.
  288. if (data->mParent && data->mParent->CanSendData()) {
  289. FallibleTArray<MessagePortMessage> messages;
  290. if (!SharedMessagePortMessage::FromSharedToMessagesParent(data->mParent,
  291. data->mMessages,
  292. messages)) {
  293. return false;
  294. }
  295. data->mMessages.Clear();
  296. Unused << data->mParent->SendReceiveData(messages);
  297. }
  298. return true;
  299. }
  300. void
  301. MessagePortService::ParentDestroy(MessagePortParent* aParent)
  302. {
  303. // This port has already been destroyed.
  304. MessagePortServiceData* data;
  305. if (!mPorts.Get(aParent->ID(), &data)) {
  306. return;
  307. }
  308. if (data->mParent != aParent) {
  309. // We don't want to send a message to this parent.
  310. for (uint32_t i = 0; i < data->mNextParents.Length(); ++i) {
  311. if (aParent == data->mNextParents[i].mParent) {
  312. data->mNextParents.RemoveElementAt(i);
  313. break;
  314. }
  315. }
  316. }
  317. CloseAll(aParent->ID());
  318. }
  319. bool
  320. MessagePortService::ForceClose(const nsID& aUUID,
  321. const nsID& aDestinationUUID,
  322. const uint32_t& aSequenceID)
  323. {
  324. MessagePortServiceData* data;
  325. if (!mPorts.Get(aUUID, &data)) {
  326. NS_WARNING("Unknown MessagePort in ForceClose()");
  327. return true;
  328. }
  329. if (!data->mDestinationUUID.Equals(aDestinationUUID) ||
  330. data->mSequenceID != aSequenceID) {
  331. NS_WARNING("DestinationUUID and/or sequenceID do not match.");
  332. return false;
  333. }
  334. CloseAll(aUUID, true);
  335. return true;
  336. }
  337. } // namespace dom
  338. } // namespace mozilla