Skip to content

Commit

Permalink
[GStreamer][EME] Reworked the reference counting of sessions
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=273490

Reviewed by Philippe Normand.

Now they are properly accounted for and disposed.

A fly-by is fixing the name of for the isKeyAvailable methods to make them code-style compliant.

* Source/WebCore/platform/encryptedmedia/CDMProxy.cpp:
(WebCore::KeyHandle::takeValueIfDifferent):
(WebCore::keyStoreBaseNextID):
(WebCore::ReferenceAwareKeyStore::unrefAllKeysFrom):
(WebCore::ReferenceAwareKeyStore::merge):
(WebCore::CDMProxy::tryWaitForKeyHandle const):
(WebCore::CDMProxy::isKeyAvailableUnlocked const):
(WebCore::CDMProxy::isKeyAvailable const):
(WebCore::CDMProxy::getOrWaitForKeyHandle const):
(WebCore::KeyStore::containsKeyID const): Deleted.
(WebCore::KeyStore::merge): Deleted.
(WebCore::KeyStore::allKeysAs const): Deleted.
(WebCore::KeyStore::addKeys): Deleted.
(WebCore::KeyStore::add): Deleted.
(WebCore::KeyStore::unrefAllKeysFrom): Deleted.
(WebCore::KeyStore::unrefAllKeys): Deleted.
(WebCore::KeyStore::unref): Deleted.
(WebCore::KeyStore::keyHandle const): Deleted.
(WebCore::KeyStore::convertToJSKeyStatusVector const): Deleted.
(WebCore::CDMProxy::keyAvailableUnlocked const): Deleted.
(WebCore::CDMProxy::keyAvailable const): Deleted.
* Source/WebCore/platform/encryptedmedia/CDMProxy.h:
(WebCore::KeyHandle::status const):
(WebCore::KeyHandle::operator==):
(WebCore::KeyHandle::KeyHandle):
(WebCore::KeyStoreBase::KeyStoreBase):
(WebCore::KeyStoreBase::add):
(WebCore::KeyStoreBase::addKeys):
(WebCore::KeyStoreBase::remove):
(WebCore::KeyStoreBase::clear):
(WebCore::KeyStoreBase::containsKeyID const):
(WebCore::KeyStoreBase::keyHandle const):
(WebCore::KeyStoreBase::allKeysAs const):
(WebCore::KeyStoreBase::convertToJSKeyStatusVector const):
(WebCore::KeyStoreBase::numKeys const):
(WebCore::KeyStoreBase::values const):
(WebCore::KeyStoreBase::id const):
(WebCore::ReferenceAwareKeyHandle::createFrom):
(WebCore::ReferenceAwareKeyHandle::updateKeyFrom):
(WebCore::ReferenceAwareKeyHandle::hasReferences const):
(WebCore::ReferenceAwareKeyHandle::ReferenceAwareKeyHandle):
(WebCore::ReferenceAwareKeyHandle::removeReference):
(WebCore::KeyHandle::mergeKeyInto): Deleted.
(WebCore::KeyHandle::operator<): Deleted.
(WebCore::KeyHandle::addSessionReference): Deleted.
(WebCore::KeyHandle::removeSessionReference): Deleted.
(WebCore::KeyHandle::numSessionReferences const): Deleted.
(WebCore::KeyHandle::hasReferences const): Deleted.
(WebCore::KeyStore::hasKeys const): Deleted.
(WebCore::KeyStore::numKeys const): Deleted.
(WebCore::KeyStore::isEmpty const): Deleted.
(WebCore::KeyStore::addSessionReferenceTo const): Deleted.
(WebCore::KeyStore::removeSessionReferenceFrom const): Deleted.
(WebCore::KeyStore::begin): Deleted.
(WebCore::KeyStore::begin const): Deleted.
(WebCore::KeyStore::end): Deleted.
(WebCore::KeyStore::end const): Deleted.
(WebCore::KeyStore::rbegin): Deleted.
(WebCore::KeyStore::rbegin const): Deleted.
(WebCore::KeyStore::rend): Deleted.
(WebCore::KeyStore::rend const): Deleted.
* Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.cpp:
(WebCore::CDMInstanceSessionClearKey::updateLicense):
(WebCore::CDMInstanceSessionClearKey::removeSessionData):
* Source/WebCore/platform/graphics/gstreamer/eme/CDMThunder.cpp:
(WebCore::CDMInstanceSessionThunder::closeSession):

Canonical link: https://commits.webkit.org/278272@main
  • Loading branch information
calvaris committed May 2, 2024
1 parent ec1b41b commit 38d5868
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 189 deletions.
160 changes: 36 additions & 124 deletions Source/WebCore/platform/encryptedmedia/CDMProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ Vector<CDMProxyFactory*> CDMProxyFactory::platformRegisterFactories()
}
#endif

bool KeyHandle::takeValueIfDifferent(KeyHandleValueVariant&& value)
{
if (m_value != value) {
m_value = WTFMove(value);
return true;
}
return false;
}

namespace {

static String vectorToHexString(const Vector<uint8_t>& vec)
Expand All @@ -100,135 +109,38 @@ String KeyHandle::idAsString() const
return makeString("[", vectorToHexString(m_id), "]");
}

bool KeyHandle::takeValueIfDifferent(KeyHandleValueVariant&& value)
{
if (m_value != value) {
m_value = WTFMove(value);
return true;
}
return false;
}

bool KeyStore::containsKeyID(const KeyIDType& keyID) const
{
return m_keys.findIf([&](const RefPtr<KeyHandle>& storedKey) {
return *storedKey == keyID;
}) != notFound;
}

void KeyStore::merge(const KeyStore& other)
KeyStoreIDType keyStoreBaseNextID()
{
static KeyStoreIDType nextID = 1;
ASSERT(isMainThread());
LOG(EME, "EME - CDMProxy - merging %u new keys into a key store of %u keys", other.numKeys(), numKeys());
for (const auto& key : other)
add(key.copyRef());

#if !LOG_DISABLED
LOG(EME, "EME - CDMProxy - key store now has %u keys", numKeys());
for (const auto& key : m_keys)
LOG(EME, "\tEME - CDMProxy - Key ID: %s", key->idAsString().ascii().data());
#endif // !LOG_DISABLED
}

CDMInstanceSession::KeyStatusVector KeyStore::allKeysAs(CDMInstanceSession::KeyStatus status) const
{
CDMInstanceSession::KeyStatusVector keyStatusVector = convertToJSKeyStatusVector();
for (auto& keyStatus : keyStatusVector)
keyStatus.second = status;
return keyStatusVector;
return nextID++;
}

bool KeyStore::addKeys(Vector<RefPtr<KeyHandle>>&& newKeys)
void ReferenceAwareKeyStore::unrefAllKeysFrom(const KeyStore& otherStore)
{
bool didKeyStoreChange = false;
for (auto& key : newKeys) {
if (add(WTFMove(key)))
didKeyStoreChange = true;
for (const auto& otherKey : otherStore.values()) {
auto findingResult = m_keys.find(otherKey->id());
if (findingResult == m_keys.end())
continue;
const RefPtr<ReferenceAwareKeyHandle>& key = findingResult->value;
RELEASE_ASSERT(key);
key->removeReference(otherStore.id());
if (!key->hasReferences())
remove(key);
}
return didKeyStoreChange;
}

bool KeyStore::add(RefPtr<KeyHandle>&& key)
void ReferenceAwareKeyStore::merge(const KeyStore& otherStore)
{
bool didStoreChange = false;
size_t keyWithMatchingKeyIDIndex = m_keys.findIf([&] (const RefPtr<KeyHandle>& storedKey) {
return *key == *storedKey;
});

addSessionReferenceTo(key);
if (keyWithMatchingKeyIDIndex != notFound) {
auto& keyWithMatchingKeyID = m_keys[keyWithMatchingKeyIDIndex];
didStoreChange = keyWithMatchingKeyID != key;
if (didStoreChange)
keyWithMatchingKeyID->mergeKeyInto(WTFMove(key));
} else {
LOG(EME, "EME - ClearKey - New key with ID %s getting added to key store", key->idAsString().ascii().data());
m_keys.append(WTFMove(key));
didStoreChange = true;
}

if (didStoreChange) {
// Sort the keys lexicographically.
// NOTE: This is not as pathological as it may seem, for all
// practical purposes the store has a maximum of 2 keys.
std::sort(m_keys.begin(), m_keys.end(),
[](const RefPtr<KeyHandle>& a, const RefPtr<KeyHandle>& b) {
return *a < *b;
});
}

return didStoreChange;
}

void KeyStore::unrefAllKeysFrom(const KeyStore& other)
{
for (const auto& key : other)
unref(key);
}

void KeyStore::unrefAllKeys()
{
KeyStore store(*this);
unrefAllKeysFrom(store);
}

bool KeyStore::unref(const RefPtr<KeyHandle>& key)
{
bool storeChanged = false;

size_t keyWithMatchingKeyIDIndex = m_keys.find(key);
LOG(EME, "EME - ClearKey - requested to unref key with ID %s and %d session references", key->idAsString().ascii().data(), key->numSessionReferences());

if (keyWithMatchingKeyIDIndex != notFound) {
auto& keyWithMatchingKeyID = m_keys[keyWithMatchingKeyIDIndex];
removeSessionReferenceFrom(keyWithMatchingKeyID);
if (!keyWithMatchingKeyID->hasReferences()) {
LOG(EME, "EME - ClearKey - unref key with ID %s", keyWithMatchingKeyID->idAsString().ascii().data());
m_keys.remove(keyWithMatchingKeyIDIndex);
storeChanged = true;
}
} else
LOG(EME, "EME - ClearKey - attempt to unref key with ID %s ignored, does not exist", key->idAsString().ascii().data());

return storeChanged;
}

const RefPtr<KeyHandle>& KeyStore::keyHandle(const KeyIDType& keyID) const
{
for (const auto& key : m_keys) {
if (*key == keyID)
return key;
ASSERT(isMainThread());
for (const auto& otherKey : otherStore.values()) {
RefPtr<ReferenceAwareKeyHandle> key = keyHandle(otherKey->id());
auto otherReferenceAwareKey = ReferenceAwareKeyHandle::createFrom(otherKey, otherStore.id());
if (key)
key->updateKeyFrom(WTFMove(otherReferenceAwareKey));
else
add(WTFMove(otherReferenceAwareKey));
}

RELEASE_ASSERT(false && "key must exist to call this method");
UNREACHABLE();
}

CDMInstanceSession::KeyStatusVector KeyStore::convertToJSKeyStatusVector() const
{
return m_keys.map([](auto& key) {
return std::pair { key->idAsSharedBuffer(), key->status() };
});
}

void CDMProxy::updateKeyStore(const KeyStore& newKeyStore)
Expand Down Expand Up @@ -306,7 +218,7 @@ std::optional<Ref<KeyHandle>> CDMProxy::tryWaitForKeyHandle(const KeyIDType& key
assertIsHeld(m_keysLock);
if (!client || client->isAborting())
return true;
wasKeyAvailable = keyAvailableUnlocked(keyID);
wasKeyAvailable = isKeyAvailableUnlocked(keyID);
return wasKeyAvailable;
});
}
Expand All @@ -321,20 +233,20 @@ std::optional<Ref<KeyHandle>> CDMProxy::tryWaitForKeyHandle(const KeyIDType& key
return std::nullopt;
}

bool CDMProxy::keyAvailableUnlocked(const KeyIDType& keyID) const
bool CDMProxy::isKeyAvailableUnlocked(const KeyIDType& keyID) const
{
return m_keyStore.containsKeyID(keyID);
}

bool CDMProxy::keyAvailable(const KeyIDType& keyID) const
bool CDMProxy::isKeyAvailable(const KeyIDType& keyID) const
{
Locker locker { m_keysLock };
return keyAvailableUnlocked(keyID);
return isKeyAvailableUnlocked(keyID);
}

std::optional<Ref<KeyHandle>> CDMProxy::getOrWaitForKeyHandle(const KeyIDType& keyID, WeakPtr<CDMProxyDecryptionClient>&& client) const
{
if (!keyAvailable(keyID)) {
if (!isKeyAvailable(keyID)) {
LOG(EME, "EME - CDMProxy key cache does not contain key ID %s", vectorToHexString(keyID).ascii().data());
return tryWaitForKeyHandle(keyID, WTFMove(client));
}
Expand Down
Loading

0 comments on commit 38d5868

Please sign in to comment.