123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "MsaaIdGenerator.h"
- #include "mozilla/a11y/AccessibleWrap.h"
- #include "mozilla/ClearOnShutdown.h"
- #include "mozilla/dom/ContentChild.h"
- #include "mozilla/StaticPtr.h"
- #include "mozilla/Unused.h"
- #include "nsDataHashtable.h"
- #include "nsIXULRuntime.h"
- // These constants may be adjusted to modify the proportion of the Child ID
- // allocated to the content ID vs proportion allocated to the unique ID. They
- // must always sum to 31, ie. the width of a 32-bit integer less the sign bit.
- // NB: kNumContentProcessIDBits must be large enough to successfully hold the
- // maximum permitted number of e10s content processes. If the e10s maximum
- // number of content processes changes, then kNumContentProcessIDBits must also
- // be updated if necessary to accommodate that new value!
- static const uint32_t kNumContentProcessIDBits = 7UL;
- static const uint32_t kNumUniqueIDBits = (31UL - kNumContentProcessIDBits);
- static_assert(kNumContentProcessIDBits + kNumUniqueIDBits == 31,
- "Allocation of Content ID bits and Unique ID bits must sum to 31");
- namespace mozilla {
- namespace a11y {
- namespace detail {
- typedef nsDataHashtable<nsUint64HashKey, uint32_t> ContentParentIdMap;
- #pragma pack(push, 1)
- union MsaaID
- {
- int32_t mInt32;
- uint32_t mUInt32;
- struct
- {
- uint32_t mUniqueID:kNumUniqueIDBits;
- uint32_t mContentProcessID:kNumContentProcessIDBits;
- uint32_t mSignBit:1;
- }
- mCracked;
- };
- #pragma pack(pop)
- static uint32_t
- BuildMsaaID(const uint32_t aID, const uint32_t aContentProcessID)
- {
- MsaaID id;
- id.mCracked.mSignBit = 0;
- id.mCracked.mUniqueID = aID;
- id.mCracked.mContentProcessID = aContentProcessID;
- return ~id.mUInt32;
- }
- class MsaaIDCracker
- {
- public:
- explicit MsaaIDCracker(const uint32_t aMsaaID)
- {
- mID.mUInt32 = ~aMsaaID;
- }
- uint32_t GetContentProcessId()
- {
- return mID.mCracked.mContentProcessID;
- }
- uint32_t GetUniqueId()
- {
- return mID.mCracked.mUniqueID;
- }
- private:
- MsaaID mID;
- };
- } // namespace detail
- MsaaIdGenerator::MsaaIdGenerator()
- : mIDSet(kNumUniqueIDBits)
- {}
- uint32_t
- MsaaIdGenerator::GetID()
- {
- uint32_t id = mIDSet.GetID();
- MOZ_ASSERT(id <= ((1UL << kNumUniqueIDBits) - 1UL));
- return detail::BuildMsaaID(id, ResolveContentProcessID());
- }
- void
- MsaaIdGenerator::ReleaseID(AccessibleWrap* aAccWrap)
- {
- MOZ_ASSERT(aAccWrap);
- uint32_t id = aAccWrap->GetExistingID();
- MOZ_ASSERT(id != AccessibleWrap::kNoID);
- detail::MsaaIDCracker cracked(id);
- if (cracked.GetContentProcessId() != ResolveContentProcessID()) {
- // This may happen if chrome holds a proxy whose ID was originally generated
- // by a content process. Since ReleaseID only has meaning in the process
- // that originally generated that ID, we ignore ReleaseID calls for any ID
- // that did not come from the current process.
- MOZ_ASSERT(aAccWrap->IsProxy());
- return;
- }
- mIDSet.ReleaseID(cracked.GetUniqueId());
- }
- bool
- MsaaIdGenerator::IsChromeID(uint32_t aID)
- {
- detail::MsaaIDCracker cracked(aID);
- return cracked.GetContentProcessId() == 0;
- }
- bool
- MsaaIdGenerator::IsIDForThisContentProcess(uint32_t aID)
- {
- MOZ_ASSERT(XRE_IsContentProcess());
- detail::MsaaIDCracker cracked(aID);
- return cracked.GetContentProcessId() == ResolveContentProcessID();
- }
- bool
- MsaaIdGenerator::IsIDForContentProcess(uint32_t aID,
- dom::ContentParentId aIPCContentProcessId)
- {
- MOZ_ASSERT(XRE_IsParentProcess());
- detail::MsaaIDCracker cracked(aID);
- return cracked.GetContentProcessId() ==
- GetContentProcessIDFor(aIPCContentProcessId);
- }
- bool
- MsaaIdGenerator::IsSameContentProcessFor(uint32_t aFirstID, uint32_t aSecondID)
- {
- detail::MsaaIDCracker firstCracked(aFirstID);
- detail::MsaaIDCracker secondCracked(aSecondID);
- return firstCracked.GetContentProcessId() ==
- secondCracked.GetContentProcessId();
- }
- uint32_t
- MsaaIdGenerator::ResolveContentProcessID()
- {
- if (XRE_IsParentProcess()) {
- return 0;
- }
- dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
- uint32_t result = contentChild->GetMsaaID();
- MOZ_ASSERT(result);
- return result;
- }
- /**
- * Each dom::ContentParent has a 64-bit ID. This ID is monotonically increasing
- * with each new content process, so those IDs are effectively single-use. OTOH,
- * MSAA requires 32-bit IDs. Since we only allocate kNumContentProcessIDBits for
- * the content process ID component, the MSAA content process ID value must be
- * reusable. sContentParentIdMap holds the current associations between
- * dom::ContentParent IDs and the MSAA content parent IDs that have been
- * allocated to them.
- */
- static StaticAutoPtr<detail::ContentParentIdMap> sContentParentIdMap;
- static const uint32_t kBitsPerByte = 8UL;
- // Set sContentProcessIdBitmap[0] to 1 to reserve the Chrome process's id
- static uint64_t sContentProcessIdBitmap[(1UL << kNumContentProcessIDBits) /
- (sizeof(uint64_t) * kBitsPerByte)] = {1ULL};
- static const uint32_t kBitsPerElement = sizeof(sContentProcessIdBitmap[0]) *
- kBitsPerByte;
- uint32_t
- MsaaIdGenerator::GetContentProcessIDFor(dom::ContentParentId aIPCContentProcessID)
- {
- MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread());
- if (!sContentParentIdMap) {
- sContentParentIdMap = new detail::ContentParentIdMap();
- ClearOnShutdown(&sContentParentIdMap);
- }
- uint32_t value = 0;
- if (sContentParentIdMap->Get(aIPCContentProcessID, &value)) {
- return value;
- }
- uint32_t index = 0;
- for (; index < ArrayLength(sContentProcessIdBitmap); ++index) {
- if (sContentProcessIdBitmap[index] == UINT64_MAX) {
- continue;
- }
- uint32_t bitIndex = CountTrailingZeroes64(~sContentProcessIdBitmap[index]);
- MOZ_ASSERT(!(sContentProcessIdBitmap[index] & (1ULL << bitIndex)));
- MOZ_ASSERT(bitIndex != 0 || index != 0);
- sContentProcessIdBitmap[index] |= (1ULL << bitIndex);
- value = index * kBitsPerElement + bitIndex;
- break;
- }
- // If we run out of content process IDs, we're in trouble
- MOZ_RELEASE_ASSERT(index < ArrayLength(sContentProcessIdBitmap));
- sContentParentIdMap->Put(aIPCContentProcessID, value);
- return value;
- }
- void
- MsaaIdGenerator::ReleaseContentProcessIDFor(dom::ContentParentId aIPCContentProcessID)
- {
- MOZ_ASSERT(XRE_IsParentProcess() && NS_IsMainThread());
- if (!sContentParentIdMap) {
- // Since Content IDs are generated lazily, ContentParent might attempt
- // to release an ID that was never allocated to begin with.
- return;
- }
- Maybe<uint32_t> mapping = sContentParentIdMap->GetAndRemove(aIPCContentProcessID);
- if (!mapping) {
- // Since Content IDs are generated lazily, ContentParent might attempt
- // to release an ID that was never allocated to begin with.
- return;
- }
- uint32_t index = mapping.ref() / kBitsPerElement;
- MOZ_ASSERT(index < ArrayLength(sContentProcessIdBitmap));
- uint64_t mask = 1ULL << (mapping.ref() % kBitsPerElement);
- MOZ_ASSERT(sContentProcessIdBitmap[index] & mask);
- sContentProcessIdBitmap[index] &= ~mask;
- }
- } // namespace a11y
- } // namespace mozilla
|