MsaaIdGenerator.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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. #include "MsaaIdGenerator.h"
  6. #include "mozilla/a11y/AccessibleWrap.h"
  7. #include "mozilla/ClearOnShutdown.h"
  8. #include "mozilla/dom/ContentChild.h"
  9. #include "mozilla/StaticPtr.h"
  10. #include "mozilla/Unused.h"
  11. #include "nsDataHashtable.h"
  12. #include "nsIXULRuntime.h"
  13. // These constants may be adjusted to modify the proportion of the Child ID
  14. // allocated to the content ID vs proportion allocated to the unique ID. They
  15. // must always sum to 31, ie. the width of a 32-bit integer less the sign bit.
  16. // NB: kNumContentProcessIDBits must be large enough to successfully hold the
  17. // maximum permitted number of e10s content processes. If the e10s maximum
  18. // number of content processes changes, then kNumContentProcessIDBits must also
  19. // be updated if necessary to accommodate that new value!
  20. static const uint32_t kNumContentProcessIDBits = 7UL;
  21. static const uint32_t kNumUniqueIDBits = (31UL - kNumContentProcessIDBits);
  22. static_assert(kNumContentProcessIDBits + kNumUniqueIDBits == 31,
  23. "Allocation of Content ID bits and Unique ID bits must sum to 31");
  24. namespace mozilla {
  25. namespace a11y {
  26. namespace detail {
  27. typedef nsDataHashtable<nsUint64HashKey, uint32_t> ContentParentIdMap;
  28. #pragma pack(push, 1)
  29. union MsaaID
  30. {
  31. int32_t mInt32;
  32. uint32_t mUInt32;
  33. struct
  34. {
  35. uint32_t mUniqueID:kNumUniqueIDBits;
  36. uint32_t mContentProcessID:kNumContentProcessIDBits;
  37. uint32_t mSignBit:1;
  38. }
  39. mCracked;
  40. };
  41. #pragma pack(pop)
  42. static uint32_t
  43. BuildMsaaID(const uint32_t aID, const uint32_t aContentProcessID)
  44. {
  45. MsaaID id;
  46. id.mCracked.mSignBit = 0;
  47. id.mCracked.mUniqueID = aID;
  48. id.mCracked.mContentProcessID = aContentProcessID;
  49. return ~id.mUInt32;
  50. }
  51. class MsaaIDCracker
  52. {
  53. public:
  54. explicit MsaaIDCracker(const uint32_t aMsaaID)
  55. {
  56. mID.mUInt32 = ~aMsaaID;
  57. }
  58. uint32_t GetContentProcessId()
  59. {
  60. return mID.mCracked.mContentProcessID;
  61. }
  62. uint32_t GetUniqueId()
  63. {
  64. return mID.mCracked.mUniqueID;
  65. }
  66. private:
  67. MsaaID mID;
  68. };
  69. } // namespace detail
  70. MsaaIdGenerator::MsaaIdGenerator()
  71. : mIDSet(kNumUniqueIDBits)
  72. {}
  73. uint32_t
  74. MsaaIdGenerator::GetID()
  75. {
  76. uint32_t id = mIDSet.GetID();
  77. MOZ_ASSERT(id <= ((1UL << kNumUniqueIDBits) - 1UL));
  78. return detail::BuildMsaaID(id, ResolveContentProcessID());
  79. }
  80. void
  81. MsaaIdGenerator::ReleaseID(AccessibleWrap* aAccWrap)
  82. {
  83. MOZ_ASSERT(aAccWrap);
  84. uint32_t id = aAccWrap->GetExistingID();
  85. MOZ_ASSERT(id != AccessibleWrap::kNoID);
  86. detail::MsaaIDCracker cracked(id);
  87. if (cracked.GetContentProcessId() != ResolveContentProcessID()) {
  88. // This may happen if chrome holds a proxy whose ID was originally generated
  89. // by a content process. Since ReleaseID only has meaning in the process
  90. // that originally generated that ID, we ignore ReleaseID calls for any ID
  91. // that did not come from the current process.
  92. MOZ_ASSERT(aAccWrap->IsProxy());
  93. return;
  94. }
  95. mIDSet.ReleaseID(cracked.GetUniqueId());
  96. }
  97. bool
  98. MsaaIdGenerator::IsChromeID(uint32_t aID)
  99. {
  100. detail::MsaaIDCracker cracked(aID);
  101. return cracked.GetContentProcessId() == 0;
  102. }
  103. bool
  104. MsaaIdGenerator::IsIDForThisContentProcess(uint32_t aID)
  105. {
  106. MOZ_ASSERT(XRE_IsContentProcess());
  107. detail::MsaaIDCracker cracked(aID);
  108. return cracked.GetContentProcessId() == ResolveContentProcessID();
  109. }
  110. bool
  111. MsaaIdGenerator::IsIDForContentProcess(uint32_t aID,
  112. dom::ContentParentId aIPCContentProcessId)
  113. {
  114. MOZ_ASSERT(XRE_IsParentProcess());
  115. detail::MsaaIDCracker cracked(aID);
  116. return cracked.GetContentProcessId() ==
  117. GetContentProcessIDFor(aIPCContentProcessId);
  118. }
  119. bool
  120. MsaaIdGenerator::IsSameContentProcessFor(uint32_t aFirstID, uint32_t aSecondID)
  121. {
  122. detail::MsaaIDCracker firstCracked(aFirstID);
  123. detail::MsaaIDCracker secondCracked(aSecondID);
  124. return firstCracked.GetContentProcessId() ==
  125. secondCracked.GetContentProcessId();
  126. }
  127. uint32_t
  128. MsaaIdGenerator::ResolveContentProcessID()
  129. {
  130. if (XRE_IsParentProcess()) {
  131. return 0;
  132. }
  133. dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
  134. uint32_t result = contentChild->GetMsaaID();
  135. MOZ_ASSERT(result);
  136. return result;
  137. }
  138. /**
  139. * Each dom::ContentParent has a 64-bit ID. This ID is monotonically increasing
  140. * with each new content process, so those IDs are effectively single-use. OTOH,
  141. * MSAA requires 32-bit IDs. Since we only allocate kNumContentProcessIDBits for
  142. * the content process ID component, the MSAA content process ID value must be
  143. * reusable. sContentParentIdMap holds the current associations between
  144. * dom::ContentParent IDs and the MSAA content parent IDs that have been
  145. * allocated to them.
  146. */
  147. static StaticAutoPtr<detail::ContentParentIdMap> sContentParentIdMap;
  148. static const uint32_t kBitsPerByte = 8UL;
  149. // Set sContentProcessIdBitmap[0] to 1 to reserve the Chrome process's id
  150. static uint64_t sContentProcessIdBitmap[(1UL << kNumContentProcessIDBits) /
  151. (sizeof(uint64_t) * kBitsPerByte)] = {1ULL};
  152. static const uint32_t kBitsPerElement = sizeof(sContentProcessIdBitmap[0]) *
  153. kBitsPerByte;
  154. uint32_t
  155. MsaaIdGenerator::GetContentProcessIDFor(dom::ContentParentId aIPCContentProcessID)
  156. {
  157. MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread());
  158. if (!sContentParentIdMap) {
  159. sContentParentIdMap = new detail::ContentParentIdMap();
  160. ClearOnShutdown(&sContentParentIdMap);
  161. }
  162. uint32_t value = 0;
  163. if (sContentParentIdMap->Get(aIPCContentProcessID, &value)) {
  164. return value;
  165. }
  166. uint32_t index = 0;
  167. for (; index < ArrayLength(sContentProcessIdBitmap); ++index) {
  168. if (sContentProcessIdBitmap[index] == UINT64_MAX) {
  169. continue;
  170. }
  171. uint32_t bitIndex = CountTrailingZeroes64(~sContentProcessIdBitmap[index]);
  172. MOZ_ASSERT(!(sContentProcessIdBitmap[index] & (1ULL << bitIndex)));
  173. MOZ_ASSERT(bitIndex != 0 || index != 0);
  174. sContentProcessIdBitmap[index] |= (1ULL << bitIndex);
  175. value = index * kBitsPerElement + bitIndex;
  176. break;
  177. }
  178. // If we run out of content process IDs, we're in trouble
  179. MOZ_RELEASE_ASSERT(index < ArrayLength(sContentProcessIdBitmap));
  180. sContentParentIdMap->Put(aIPCContentProcessID, value);
  181. return value;
  182. }
  183. void
  184. MsaaIdGenerator::ReleaseContentProcessIDFor(dom::ContentParentId aIPCContentProcessID)
  185. {
  186. MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread());
  187. if (!sContentParentIdMap) {
  188. // Since Content IDs are generated lazily, ContentParent might attempt
  189. // to release an ID that was never allocated to begin with.
  190. return;
  191. }
  192. Maybe<uint32_t> mapping = sContentParentIdMap->GetAndRemove(aIPCContentProcessID);
  193. if (!mapping) {
  194. // Since Content IDs are generated lazily, ContentParent might attempt
  195. // to release an ID that was never allocated to begin with.
  196. return;
  197. }
  198. uint32_t index = mapping.ref() / kBitsPerElement;
  199. MOZ_ASSERT(index < ArrayLength(sContentProcessIdBitmap));
  200. uint64_t mask = 1ULL << (mapping.ref() % kBitsPerElement);
  201. MOZ_ASSERT(sContentProcessIdBitmap[index] & mask);
  202. sContentProcessIdBitmap[index] &= ~mask;
  203. }
  204. } // namespace a11y
  205. } // namespace mozilla