Merge "Camera: Treat decreasing timestamp as BUFFER_ERROR"
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
index 73ed8c3..1558e8b 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp
@@ -118,9 +118,9 @@
status_t ClearKeyCasPlugin::closeSession(const CasSessionId &sessionId) {
ALOGV("closeSession: sessionId=%s", sessionIdToString(sessionId).string());
- sp<ClearKeyCasSession> session =
+ std::shared_ptr<ClearKeyCasSession> session =
ClearKeySessionLibrary::get()->findSession(sessionId);
- if (session == NULL) {
+ if (session.get() == nullptr) {
return ERROR_CAS_SESSION_NOT_OPENED;
}
@@ -132,9 +132,9 @@
const CasSessionId &sessionId, const CasData & /*data*/) {
ALOGV("setSessionPrivateData: sessionId=%s",
sessionIdToString(sessionId).string());
- sp<ClearKeyCasSession> session =
+ std::shared_ptr<ClearKeyCasSession> session =
ClearKeySessionLibrary::get()->findSession(sessionId);
- if (session == NULL) {
+ if (session.get() == nullptr) {
return ERROR_CAS_SESSION_NOT_OPENED;
}
return OK;
@@ -143,9 +143,9 @@
status_t ClearKeyCasPlugin::processEcm(
const CasSessionId &sessionId, const CasEcm& ecm) {
ALOGV("processEcm: sessionId=%s", sessionIdToString(sessionId).string());
- sp<ClearKeyCasSession> session =
+ std::shared_ptr<ClearKeyCasSession> session =
ClearKeySessionLibrary::get()->findSession(sessionId);
- if (session == NULL) {
+ if (session.get() == nullptr) {
return ERROR_CAS_SESSION_NOT_OPENED;
}
@@ -418,15 +418,15 @@
const CasSessionId &sessionId) {
ALOGV("setMediaCasSession: sessionId=%s", sessionIdToString(sessionId).string());
- sp<ClearKeyCasSession> session =
+ std::shared_ptr<ClearKeyCasSession> session =
ClearKeySessionLibrary::get()->findSession(sessionId);
- if (session == NULL) {
+ if (session.get() == nullptr) {
ALOGE("ClearKeyDescramblerPlugin: session not found");
return ERROR_CAS_SESSION_NOT_OPENED;
}
- mCASSession = session;
+ std::atomic_store(&mCASSession, session);
return OK;
}
@@ -447,12 +447,14 @@
subSamplesToString(subSamples, numSubSamples).string(),
srcPtr, dstPtr, srcOffset, dstOffset);
- if (mCASSession == NULL) {
+ std::shared_ptr<ClearKeyCasSession> session = std::atomic_load(&mCASSession);
+
+ if (session.get() == nullptr) {
ALOGE("Uninitialized CAS session!");
return ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED;
}
- return mCASSession->decrypt(
+ return session->decrypt(
secure, scramblingControl,
numSubSamples, subSamples,
(uint8_t*)srcPtr + srcOffset,
diff --git a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
index 42cfb8f..389e172 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
+++ b/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.h
@@ -120,7 +120,7 @@
AString *errorDetailMsg) override;
private:
- sp<ClearKeyCasSession> mCASSession;
+ std::shared_ptr<ClearKeyCasSession> mCASSession;
String8 subSamplesToString(
SubSample const *subSamples,
diff --git a/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.cpp b/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.cpp
index 4b4051d..3bb1176 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.cpp
+++ b/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.cpp
@@ -56,7 +56,7 @@
Mutex::Autolock lock(mSessionsLock);
- sp<ClearKeyCasSession> session = new ClearKeyCasSession(plugin);
+ std::shared_ptr<ClearKeyCasSession> session(new ClearKeyCasSession(plugin));
uint8_t *byteArray = (uint8_t *) &mNextSessionId;
sessionId->push_back(byteArray[3]);
@@ -69,7 +69,7 @@
return OK;
}
-sp<ClearKeyCasSession> ClearKeySessionLibrary::findSession(
+std::shared_ptr<ClearKeyCasSession> ClearKeySessionLibrary::findSession(
const CasSessionId& sessionId) {
Mutex::Autolock lock(mSessionsLock);
@@ -88,7 +88,7 @@
return;
}
- sp<ClearKeyCasSession> session = mIDToSessionMap.valueAt(index);
+ std::shared_ptr<ClearKeyCasSession> session = mIDToSessionMap.valueAt(index);
mIDToSessionMap.removeItemsAt(index);
}
@@ -96,7 +96,7 @@
Mutex::Autolock lock(mSessionsLock);
for (ssize_t index = (ssize_t)mIDToSessionMap.size() - 1; index >= 0; index--) {
- sp<ClearKeyCasSession> session = mIDToSessionMap.valueAt(index);
+ std::shared_ptr<ClearKeyCasSession> session = mIDToSessionMap.valueAt(index);
if (session->getPlugin() == plugin) {
mIDToSessionMap.removeItemsAt(index);
}
diff --git a/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.h b/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.h
index 01f5f47..a537e63 100644
--- a/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.h
+++ b/drm/mediacas/plugins/clearkey/ClearKeySessionLibrary.h
@@ -32,6 +32,10 @@
class ClearKeyCasSession : public RefBase {
public:
+ explicit ClearKeyCasSession(CasPlugin *plugin);
+
+ virtual ~ClearKeyCasSession();
+
ssize_t decrypt(
bool secure,
DescramblerPlugin::ScramblingControl scramblingControl,
@@ -58,8 +62,6 @@
friend class ClearKeySessionLibrary;
- explicit ClearKeyCasSession(CasPlugin *plugin);
- virtual ~ClearKeyCasSession();
CasPlugin* getPlugin() const { return mPlugin; }
status_t decryptPayload(
const AES_KEY& key, size_t length, size_t offset, char* buffer) const;
@@ -73,7 +75,7 @@
status_t addSession(CasPlugin *plugin, CasSessionId *sessionId);
- sp<ClearKeyCasSession> findSession(const CasSessionId& sessionId);
+ std::shared_ptr<ClearKeyCasSession> findSession(const CasSessionId& sessionId);
void destroySession(const CasSessionId& sessionId);
@@ -85,7 +87,7 @@
Mutex mSessionsLock;
uint32_t mNextSessionId;
- KeyedVector<CasSessionId, sp<ClearKeyCasSession>> mIDToSessionMap;
+ KeyedVector<CasSessionId, std::shared_ptr<ClearKeyCasSession>> mIDToSessionMap;
ClearKeySessionLibrary();
DISALLOW_EVIL_CONSTRUCTORS(ClearKeySessionLibrary);
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index d51e29d..3b61085 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -245,11 +245,29 @@
setPlayPolicy();
std::vector<uint8_t> keySetId;
+ keySetId.clear();
+
Status status = session->provideKeyResponse(response);
if (status == Status::OK) {
- // This is for testing AMediaDrm_setOnEventListener only.
- sendEvent(EventType::VENDOR_DEFINED, 0, scope);
- keySetId.clear();
+ // Test calling AMediaDrm listeners.
+ sendEvent(EventType::VENDOR_DEFINED, toVector(scope), toVector(scope));
+
+ sendExpirationUpdate(toVector(scope), 100);
+
+ std::vector<KeyStatus> keysStatus;
+ KeyStatus keyStatus;
+
+ std::vector<uint8_t> keyId1 = { 0xA, 0xB, 0xC };
+ keyStatus.keyId = keyId1;
+ keyStatus.type = V1_0::KeyStatusType::USABLE;
+ keysStatus.push_back(keyStatus);
+
+ std::vector<uint8_t> keyId2 = { 0xD, 0xE, 0xF };
+ keyStatus.keyId = keyId2;
+ keyStatus.type = V1_0::KeyStatusType::EXPIRED;
+ keysStatus.push_back(keyStatus);
+
+ sendKeysChange(toVector(scope), keysStatus, true);
}
installSecureStop(scope);
diff --git a/media/libnblog/NBLog.cpp b/media/libnblog/NBLog.cpp
index f1d7523..f73e2ae 100644
--- a/media/libnblog/NBLog.cpp
+++ b/media/libnblog/NBLog.cpp
@@ -68,7 +68,7 @@
}
const uint8_t type = EntryIterator(ptr)->type;
switch (type) {
- case EVENT_START_FMT:
+ case EVENT_FMT_START:
return std::make_unique<FormatEntry>(FormatEntry(ptr));
case EVENT_AUDIO_STATE:
case EVENT_HISTOGRAM_ENTRY_TS:
@@ -107,7 +107,7 @@
++it; // skip timestamp
++it; // skip hash
// Skip author if present
- if (it->type == EVENT_AUTHOR) {
+ if (it->type == EVENT_FMT_AUTHOR) {
++it;
}
return it;
@@ -138,7 +138,7 @@
++it; // skip timestamp
++it; // skip hash
// if there is an author entry, return it, return -1 otherwise
- return it->type == EVENT_AUTHOR ? it.payload<int>() : -1;
+ return it->type == EVENT_FMT_AUTHOR ? it.payload<int>() : -1;
}
NBLog::EntryIterator NBLog::FormatEntry::copyWithAuthor(
@@ -151,14 +151,14 @@
// insert author entry
size_t authorEntrySize = Entry::kOverhead + sizeof(author);
uint8_t authorEntry[authorEntrySize];
- authorEntry[offsetof(entry, type)] = EVENT_AUTHOR;
+ authorEntry[offsetof(entry, type)] = EVENT_FMT_AUTHOR;
authorEntry[offsetof(entry, length)] =
authorEntry[authorEntrySize + Entry::kPreviousLengthOffset] =
sizeof(author);
*(int*) (&authorEntry[offsetof(entry, data)]) = author;
dst->write(authorEntry, authorEntrySize);
// copy rest of entries
- while ((++it)->type != EVENT_END_FMT) {
+ while ((++it)->type != EVENT_FMT_END) {
it.copyTo(dst);
}
it.copyTo(dst);
@@ -394,46 +394,12 @@
if (!mEnabled) {
return;
}
- int64_t ts = get_monotonic_ns();
- if (ts > 0) {
+ struct timespec ts;
+ if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
log(EVENT_TIMESTAMP, &ts, sizeof(ts));
- } else {
- ALOGE("Failed to get timestamp");
}
}
-void NBLog::Writer::logTimestamp(const int64_t ts)
-{
- if (!mEnabled) {
- return;
- }
- log(EVENT_TIMESTAMP, &ts, sizeof(ts));
-}
-
-void NBLog::Writer::logInteger(const int x)
-{
- if (!mEnabled) {
- return;
- }
- log(EVENT_INTEGER, &x, sizeof(x));
-}
-
-void NBLog::Writer::logFloat(const float x)
-{
- if (!mEnabled) {
- return;
- }
- log(EVENT_FLOAT, &x, sizeof(x));
-}
-
-void NBLog::Writer::logPID()
-{
- if (!mEnabled) {
- return;
- }
- log(EVENT_PID, mPidTag, mPidTagSize);
-}
-
void NBLog::Writer::logStart(const char *fmt)
{
if (!mEnabled) {
@@ -443,24 +409,20 @@
if (length > Entry::kMaxLength) {
length = Entry::kMaxLength;
}
- log(EVENT_START_FMT, fmt, length);
+ log(EVENT_FMT_START, fmt, length);
}
-void NBLog::Writer::logEnd()
+void NBLog::Writer::logTimestampFormat()
{
if (!mEnabled) {
return;
}
- Entry entry = Entry(EVENT_END_FMT, NULL, 0);
- log(entry, true);
-}
-
-void NBLog::Writer::logHash(log_hash_t hash)
-{
- if (!mEnabled) {
- return;
+ int64_t ts = get_monotonic_ns();
+ if (ts > 0) {
+ log(EVENT_FMT_TIMESTAMP, &ts, sizeof(ts));
+ } else {
+ ALOGE("Failed to get timestamp");
}
- log(EVENT_HASH, &hash, sizeof(hash));
}
void NBLog::Writer::logEventHistTs(Event event, log_hash_t hash)
@@ -478,22 +440,6 @@
}
}
-void NBLog::Writer::logLatency(double latencyMs)
-{
- if (!mEnabled) {
- return;
- }
- log(EVENT_LATENCY, &latencyMs, sizeof(latencyMs));
-}
-
-void NBLog::Writer::logMonotonicCycleTime(uint32_t monotonicNs)
-{
- if (!mEnabled) {
- return;
- }
- log(EVENT_MONOTONIC_CYCLE_TIME, &monotonicNs, sizeof(monotonicNs));
-}
-
void NBLog::Writer::logFormat(const char *fmt, log_hash_t hash, ...)
{
if (!mEnabled) {
@@ -512,11 +458,13 @@
}
Writer::logStart(fmt);
int i;
- double f;
+ double d;
+ float f;
char* s;
+ size_t length;
int64_t t;
- Writer::logTimestamp();
- Writer::logHash(hash);
+ Writer::logTimestampFormat();
+ log(EVENT_FMT_HASH, &hash, sizeof(hash));
for (const char *p = fmt; *p != '\0'; p++) {
// TODO: implement more complex formatting such as %.3f
if (*p != '%') {
@@ -525,26 +473,31 @@
switch(*++p) {
case 's': // string
s = va_arg(argp, char *);
- Writer::log(s);
+ length = strlen(s);
+ if (length > Entry::kMaxLength) {
+ length = Entry::kMaxLength;
+ }
+ log(EVENT_FMT_STRING, s, length);
break;
case 't': // timestamp
t = va_arg(argp, int64_t);
- Writer::logTimestamp(t);
+ log(EVENT_FMT_TIMESTAMP, &t, sizeof(t));
break;
case 'd': // integer
i = va_arg(argp, int);
- Writer::logInteger(i);
+ log(EVENT_FMT_INTEGER, &i, sizeof(i));
break;
case 'f': // float
- f = va_arg(argp, double); // float arguments are promoted to double in vararg lists
- Writer::logFloat((float)f);
+ d = va_arg(argp, double); // float arguments are promoted to double in vararg lists
+ f = (float)d;
+ log(EVENT_FMT_FLOAT, &f, sizeof(f));
break;
case 'p': // pid
- Writer::logPID();
+ log(EVENT_FMT_PID, mPidTag, mPidTagSize);
break;
// the "%\0" case finishes parsing
@@ -560,7 +513,8 @@
break;
}
}
- Writer::logEnd();
+ Entry etr(EVENT_FMT_END, nullptr, 0);
+ log(etr, true);
}
void NBLog::Writer::log(Event event, const void *data, size_t length)
@@ -630,79 +584,6 @@
{
}
-void NBLog::LockedWriter::log(const char *string)
-{
- Mutex::Autolock _l(mLock);
- Writer::log(string);
-}
-
-void NBLog::LockedWriter::logf(const char *fmt, ...)
-{
- // FIXME should not take the lock until after formatting is done
- Mutex::Autolock _l(mLock);
- va_list ap;
- va_start(ap, fmt);
- Writer::logvf(fmt, ap);
- va_end(ap);
-}
-
-void NBLog::LockedWriter::logvf(const char *fmt, va_list ap)
-{
- // FIXME should not take the lock until after formatting is done
- Mutex::Autolock _l(mLock);
- Writer::logvf(fmt, ap);
-}
-
-void NBLog::LockedWriter::logTimestamp()
-{
- // FIXME should not take the lock until after the clock_gettime() syscall
- Mutex::Autolock _l(mLock);
- Writer::logTimestamp();
-}
-
-void NBLog::LockedWriter::logTimestamp(const int64_t ts)
-{
- Mutex::Autolock _l(mLock);
- Writer::logTimestamp(ts);
-}
-
-void NBLog::LockedWriter::logInteger(const int x)
-{
- Mutex::Autolock _l(mLock);
- Writer::logInteger(x);
-}
-
-void NBLog::LockedWriter::logFloat(const float x)
-{
- Mutex::Autolock _l(mLock);
- Writer::logFloat(x);
-}
-
-void NBLog::LockedWriter::logPID()
-{
- Mutex::Autolock _l(mLock);
- Writer::logPID();
-}
-
-void NBLog::LockedWriter::logStart(const char *fmt)
-{
- Mutex::Autolock _l(mLock);
- Writer::logStart(fmt);
-}
-
-
-void NBLog::LockedWriter::logEnd()
-{
- Mutex::Autolock _l(mLock);
- Writer::logEnd();
-}
-
-void NBLog::LockedWriter::logHash(log_hash_t hash)
-{
- Mutex::Autolock _l(mLock);
- Writer::logHash(hash);
-}
-
bool NBLog::LockedWriter::isEnabled() const
{
Mutex::Autolock _l(mLock);
@@ -715,21 +596,47 @@
return Writer::setEnabled(enabled);
}
+void NBLog::LockedWriter::log(const Entry &entry, bool trusted) {
+ Mutex::Autolock _l(mLock);
+ Writer::log(entry, trusted);
+}
+
// ---------------------------------------------------------------------------
-const std::unordered_set<NBLog::Event> NBLog::Reader::startingTypes {
- NBLog::Event::EVENT_START_FMT,
- NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS,
- NBLog::Event::EVENT_AUDIO_STATE,
- NBLog::Event::EVENT_LATENCY,
- NBLog::Event::EVENT_MONOTONIC_CYCLE_TIME
+// We make a set of the invalid types rather than the valid types when aligning
+// Snapshot EntryIterators to valid entries during log corruption checking.
+// This is done in order to avoid the maintenance overhead of adding a new NBLog::Event
+// type to the two sets below whenever a new NBLog::Event type is created, as it is
+// very likely that new types added will be valid types.
+// Currently, invalidBeginTypes and invalidEndTypes are used to handle the special
+// case of a Format Entry, which consists of a variable number of simple log entries.
+// If a new NBLog::Event is added that consists of a variable number of simple log entries,
+// then these sets need to be updated.
+
+// We want the beginning of a Snapshot to point to an entry that is not in
+// the middle of a formatted entry and not an FMT_END.
+const std::unordered_set<NBLog::Event> NBLog::Reader::invalidBeginTypes {
+ NBLog::Event::EVENT_FMT_TIMESTAMP,
+ NBLog::Event::EVENT_FMT_HASH,
+ NBLog::Event::EVENT_FMT_STRING,
+ NBLog::Event::EVENT_FMT_INTEGER,
+ NBLog::Event::EVENT_FMT_FLOAT,
+ NBLog::Event::EVENT_FMT_PID,
+ NBLog::Event::EVENT_FMT_AUTHOR,
+ NBLog::Event::EVENT_FMT_END
};
-const std::unordered_set<NBLog::Event> NBLog::Reader::endingTypes {
- NBLog::Event::EVENT_END_FMT,
- NBLog::Event::EVENT_HISTOGRAM_ENTRY_TS,
- NBLog::Event::EVENT_AUDIO_STATE,
- NBLog::Event::EVENT_LATENCY,
- NBLog::Event::EVENT_MONOTONIC_CYCLE_TIME
+
+// We want the end of a Snapshot to point to an entry that is not in
+// the middle of a formatted entry and not a FMT_START.
+const std::unordered_set<NBLog::Event> NBLog::Reader::invalidEndTypes {
+ NBLog::Event::EVENT_FMT_START,
+ NBLog::Event::EVENT_FMT_TIMESTAMP,
+ NBLog::Event::EVENT_FMT_HASH,
+ NBLog::Event::EVENT_FMT_STRING,
+ NBLog::Event::EVENT_FMT_INTEGER,
+ NBLog::Event::EVENT_FMT_FLOAT,
+ NBLog::Event::EVENT_FMT_PID,
+ NBLog::Event::EVENT_FMT_AUTHOR
};
NBLog::Reader::Reader(const void *shared, size_t size, const std::string &name)
@@ -754,17 +661,22 @@
delete mFifo;
}
-const uint8_t *NBLog::Reader::findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
- const std::unordered_set<Event> &types) {
+const uint8_t *NBLog::Reader::findLastValidEntry(const uint8_t *front, const uint8_t *back,
+ const std::unordered_set<Event> &invalidTypes) {
+ if (front == nullptr || back == nullptr) {
+ return nullptr;
+ }
while (back + Entry::kPreviousLengthOffset >= front) {
const uint8_t *prev = back - back[Entry::kPreviousLengthOffset] - Entry::kOverhead;
- if (prev < front || prev + prev[offsetof(entry, length)] +
- Entry::kOverhead != back) {
-
+ const Event type = (const Event)prev[offsetof(entry, type)];
+ if (prev < front
+ || prev + prev[offsetof(entry, length)] + Entry::kOverhead != back
+ || type <= NBLog::EVENT_RESERVED || type >= NBLog::EVENT_UPPER_BOUND) {
// prev points to an out of limits or inconsistent entry
return nullptr;
}
- if (types.find((const Event) prev[offsetof(entry, type)]) != types.end()) {
+ // if invalidTypes does not contain the type, then the type is valid.
+ if (invalidTypes.find(type) == invalidTypes.end()) {
return prev;
}
back = prev;
@@ -778,7 +690,7 @@
std::unique_ptr<NBLog::Snapshot> NBLog::Reader::getSnapshot()
{
if (mFifoReader == NULL) {
- return std::make_unique<Snapshot>();
+ return std::unique_ptr<Snapshot>(new Snapshot());
}
// This emulates the behaviour of audio_utils_fifo_reader::read, but without incrementing the
@@ -808,9 +720,20 @@
if (availToRead <= 0) {
ALOGW_IF(availToRead < 0, "NBLog Reader %s failed to catch up with Writer", mName.c_str());
- return std::make_unique<Snapshot>();
+ return std::unique_ptr<Snapshot>(new Snapshot());
}
+ // Change to #if 1 for debugging. This statement is useful for checking buffer fullness levels
+ // (as seen by reader) and how much data was lost. If you find that the fullness level is
+ // getting close to full, or that data loss is happening to often, then you should
+ // probably try some of the following:
+ // - log less data
+ // - log less often
+ // - increase the initial shared memory allocation for the buffer
+#if 0
+ ALOGD("getSnapshot name=%s, availToRead=%zd, capacity=%zu, fullness=%.3f, lost=%zu",
+ name().c_str(), availToRead, capacity, (double)availToRead / (double)capacity, lost);
+#endif
std::unique_ptr<Snapshot> snapshot(new Snapshot(availToRead));
memcpy(snapshot->mData, (const char *) mFifo->buffer() + iovec[0].mOffset, iovec[0].mLength);
if (iovec[1].mLength > 0) {
@@ -821,28 +744,28 @@
// Handle corrupted buffer
// Potentially, a buffer has corrupted data on both beginning (due to overflow) and end
// (due to incomplete format entry). But even if the end format entry is incomplete,
- // it ends in a complete entry (which is not an END_FMT). So is safe to traverse backwards.
+ // it ends in a complete entry (which is not an FMT_END). So is safe to traverse backwards.
// TODO: handle client corruption (in the middle of a buffer)
const uint8_t *back = snapshot->mData + availToRead;
const uint8_t *front = snapshot->mData;
- // Find last END_FMT. <back> is sitting on an entry which might be the middle of a FormatEntry.
- // We go backwards until we find an EVENT_END_FMT.
- const uint8_t *lastEnd = findLastEntryOfTypes(front, back, endingTypes);
+ // Find last FMT_END. <back> is sitting on an entry which might be the middle of a FormatEntry.
+ // We go backwards until we find an EVENT_FMT_END.
+ const uint8_t *lastEnd = findLastValidEntry(front, back, invalidEndTypes);
if (lastEnd == nullptr) {
snapshot->mEnd = snapshot->mBegin = EntryIterator(front);
} else {
- // end of snapshot points to after last END_FMT entry
+ // end of snapshot points to after last FMT_END entry
snapshot->mEnd = EntryIterator(lastEnd).next();
- // find first START_FMT
+ // find first FMT_START
const uint8_t *firstStart = nullptr;
const uint8_t *firstStartTmp = snapshot->mEnd;
- while ((firstStartTmp = findLastEntryOfTypes(front, firstStartTmp, startingTypes))
+ while ((firstStartTmp = findLastValidEntry(front, firstStartTmp, invalidBeginTypes))
!= nullptr) {
firstStart = firstStartTmp;
}
- // firstStart is null if no START_FMT entry was found before lastEnd
+ // firstStart is null if no FMT_START entry was found before lastEnd
if (firstStart == nullptr) {
snapshot->mBegin = snapshot->mEnd;
} else {
@@ -861,43 +784,30 @@
// writes the data to a map of class PerformanceAnalysis, based on their thread ID.
void NBLog::MergeReader::getAndProcessSnapshot(NBLog::Snapshot &snapshot, int author)
{
- for (const entry &etr : snapshot) {
- switch (etr.type) {
+ // We don't do "auto it" because it reduces readability in this case.
+ for (EntryIterator it = snapshot.begin(); it != snapshot.end(); ++it) {
+ switch (it->type) {
case EVENT_HISTOGRAM_ENTRY_TS: {
- HistTsEntry *data = (HistTsEntry *) (etr.data);
- // TODO This memcpies are here to avoid unaligned memory access crash.
- // There's probably a more efficient way to do it
- log_hash_t hash;
- memcpy(&hash, &(data->hash), sizeof(hash));
- int64_t ts;
- memcpy(&ts, &data->ts, sizeof(ts));
+ HistTsEntry payload = it.payload<HistTsEntry>();
// TODO: hash for histogram ts and audio state need to match
// and correspond to audio production source file location
- mThreadPerformanceAnalysis[author][0 /*hash*/].logTsEntry(ts);
+ mThreadPerformanceAnalysis[author][0 /*hash*/].logTsEntry(payload.ts);
} break;
case EVENT_AUDIO_STATE: {
- HistTsEntry *data = (HistTsEntry *) (etr.data);
- // TODO This memcpies are here to avoid unaligned memory access crash.
- // There's probably a more efficient way to do it
- log_hash_t hash;
- memcpy(&hash, &(data->hash), sizeof(hash));
mThreadPerformanceAnalysis[author][0 /*hash*/].handleStateChange();
} break;
case EVENT_LATENCY: {
- double latencyMs;
- memcpy(&latencyMs, etr.data, sizeof(latencyMs));
+ double latencyMs = it.payload<double>();
mPerformanceData.addLatencyEntry(author, latencyMs);
} break;
- case EVENT_MONOTONIC_CYCLE_TIME: {
- uint32_t monotonicNs;
- memcpy(&monotonicNs, etr.data, sizeof(monotonicNs));
+ case EVENT_WORK_TIME: {
+ uint64_t monotonicNs = it.payload<uint64_t>();
const double monotonicMs = monotonicNs * 1e-6;
mPerformanceData.addCycleTimeEntry(author, monotonicMs);
} break;
- case EVENT_END_FMT:
case EVENT_RESERVED:
case EVENT_UPPER_BOUND:
- ALOGW("warning: unexpected event %d", etr.type);
+ ALOGW("warning: unexpected event %d", it->type);
default:
break;
}
@@ -940,22 +850,20 @@
String8 timestamp, body;
// TODO all logged types should have a printable format.
- for (auto it = snapshot->begin(); it != snapshot->end(); ++it) {
+ for (EntryIterator it = snapshot->begin(); it != snapshot->end(); ++it) {
switch (it->type) {
- case EVENT_START_FMT:
+ case EVENT_FMT_START:
it = handleFormat(FormatEntry(it), ×tamp, &body);
break;
- case EVENT_MONOTONIC_CYCLE_TIME: {
- uint32_t monotonicNs;
- memcpy(&monotonicNs, it->data, sizeof(monotonicNs));
- body.appendFormat("Thread cycle: %u ns", monotonicNs);
+ case EVENT_WORK_TIME: {
+ uint64_t monotonicNs = it.payload<uint64_t>();
+ body.appendFormat("Thread cycle: %lu ns", (unsigned long)monotonicNs);
} break;
case EVENT_LATENCY: {
- double latencyMs;
- memcpy(&latencyMs, it->data, sizeof(latencyMs));
+ double latencyMs = it.payload<double>();
body.appendFormat("latency: %.3f ms", latencyMs);
} break;
- case EVENT_END_FMT:
+ case EVENT_FMT_END:
case EVENT_RESERVED:
case EVENT_UPPER_BOUND:
body.appendFormat("warning: unexpected event %d", it->type);
@@ -1078,7 +986,7 @@
// TODO check length for event type is correct
- if (event == EVENT_END_FMT) {
+ if (event == EVENT_FMT_END) {
break;
}
@@ -1087,31 +995,31 @@
switch(fmt[fmt_offset])
{
case 's': // string
- ALOGW_IF(event != EVENT_STRING,
+ ALOGW_IF(event != EVENT_FMT_STRING,
"NBLog Reader incompatible event for string specifier: %d", event);
body->append((const char*) datum, length);
break;
case 't': // timestamp
- ALOGW_IF(event != EVENT_TIMESTAMP,
+ ALOGW_IF(event != EVENT_FMT_TIMESTAMP,
"NBLog Reader incompatible event for timestamp specifier: %d", event);
appendTimestamp(body, datum);
break;
case 'd': // integer
- ALOGW_IF(event != EVENT_INTEGER,
+ ALOGW_IF(event != EVENT_FMT_INTEGER,
"NBLog Reader incompatible event for integer specifier: %d", event);
appendInt(body, datum);
break;
case 'f': // float
- ALOGW_IF(event != EVENT_FLOAT,
+ ALOGW_IF(event != EVENT_FMT_FLOAT,
"NBLog Reader incompatible event for float specifier: %d", event);
appendFloat(body, datum);
break;
case 'p': // pid
- ALOGW_IF(event != EVENT_PID,
+ ALOGW_IF(event != EVENT_FMT_PID,
"NBLog Reader incompatible event for pid specifier: %d", event);
appendPID(body, datum, length);
break;
@@ -1121,7 +1029,7 @@
}
++arg;
}
- ALOGW_IF(arg->type != EVENT_END_FMT, "Expected end of format, got %d", arg->type);
+ ALOGW_IF(arg->type != EVENT_FMT_END, "Expected end of format, got %d", arg->type);
return arg;
}
diff --git a/media/libnblog/include/media/nblog/NBLog.h b/media/libnblog/include/media/nblog/NBLog.h
index 763d743..561e8c7 100644
--- a/media/libnblog/include/media/nblog/NBLog.h
+++ b/media/libnblog/include/media/nblog/NBLog.h
@@ -20,6 +20,7 @@
#define ANDROID_MEDIA_NBLOG_H
#include <map>
+#include <type_traits>
#include <unordered_set>
#include <vector>
@@ -45,33 +46,58 @@
class Writer;
class Reader;
+ // TODO have a comment somewhere explaining the whole process for adding a new EVENT_
+
+ // NBLog Event types. The Events are named to provide contextual meaning for what is logged.
+ // If adding a new standalone Event here, update the event-to-type mapping by adding a
+ // MAP_EVENT_TO_TYPE statement below.
enum Event : uint8_t {
EVENT_RESERVED,
EVENT_STRING, // ASCII string, not NUL-terminated
// TODO: make timestamp optional
EVENT_TIMESTAMP, // clock_gettime(CLOCK_MONOTONIC)
- EVENT_INTEGER, // integer value entry
- EVENT_FLOAT, // floating point value entry
- EVENT_PID, // process ID and process name
- EVENT_AUTHOR, // author index (present in merged logs) tracks entry's
- // original log
- EVENT_START_FMT, // logFormat start event: entry includes format string,
+
+ // Types for Format Entry, i.e. formatted entry
+ EVENT_FMT_START, // logFormat start event: entry includes format string,
// following entries contain format arguments
- EVENT_HASH, // unique HASH of log origin, originates from hash of file name
+ // format arguments
+ EVENT_FMT_TIMESTAMP, // timestamp value entry
+ EVENT_FMT_HASH, // unique HASH of log origin, originates from hash of file name
// and line number
+ EVENT_FMT_STRING, // string value entry
+ EVENT_FMT_INTEGER, // integer value entry
+ EVENT_FMT_FLOAT, // floating point value entry
+ EVENT_FMT_PID, // process ID and process name
+ EVENT_FMT_AUTHOR, // author index (present in merged logs) tracks entry's
+ // original log
+ // end of format arguments
+ EVENT_FMT_END, // end of logFormat argument list
+
+ // Types for wakeup timestamp histograms
EVENT_HISTOGRAM_ENTRY_TS, // single datum for timestamp histogram
EVENT_AUDIO_STATE, // audio on/off event: logged on FastMixer::onStateChange call
- EVENT_END_FMT, // end of logFormat argument list
// Types representing audio performance metrics
- EVENT_LATENCY, // TODO classify specifically what this is
- EVENT_CPU_FREQUENCY, // instantaneous CPU frequency in kHz
- EVENT_MONOTONIC_CYCLE_TIME, // thread per-cycle monotonic time
- EVENT_CPU_CYCLE_TIME, // thread per-cycle cpu time
+ EVENT_LATENCY, // difference between frames presented by HAL and frames
+ // written to HAL output sink, divided by sample rate.
+ EVENT_WORK_TIME, // the time a thread takes to do work, e.g. read, write, etc.
EVENT_UPPER_BOUND, // to check for invalid events
};
+ template <Event E> struct get_mapped;
+#define MAP_EVENT_TO_TYPE(E, T) \
+ template<> struct get_mapped<E> { \
+ static_assert(std::is_trivially_copyable<T>::value \
+ && !std::is_pointer<T>::value, \
+ "NBLog::Event must map to trivially copyable, non-pointer type."); \
+ typedef T type; \
+ }
+
+ // Maps an NBLog Event type to a C++ POD type.
+ MAP_EVENT_TO_TYPE(EVENT_LATENCY, double);
+ MAP_EVENT_TO_TYPE(EVENT_WORK_TIME, uint64_t);
+
private:
// ---------------------------------------------------------------------------
@@ -119,10 +145,24 @@
void copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
void copyData(uint8_t *dst) const;
+ // memcpy preferred to reinterpret_cast to avoid potentially unsupported
+ // unaligned memory access.
+#if 0
template<typename T>
inline const T& payload() {
return *reinterpret_cast<const T *>(mPtr + offsetof(entry, data));
}
+#else
+ template<typename T>
+ inline T payload() {
+ static_assert(std::is_trivially_copyable<T>::value
+ && !std::is_pointer<T>::value,
+ "NBLog::EntryIterator payload must be trivially copyable, non-pointer type.");
+ T payload;
+ memcpy(&payload, mPtr + offsetof(entry, data), sizeof(payload));
+ return payload;
+ }
+#endif
inline operator const uint8_t*() const {
return mPtr;
@@ -169,14 +209,14 @@
// API for handling format entry operations
// a formatted entry has the following structure:
- // * START_FMT entry, containing the format string
+ // * FMT_START entry, containing the format string
// * TIMESTAMP entry
// * HASH entry
// * author entry of the thread that generated it (optional, present in merged log)
// * format arg1
// * format arg2
// * ...
- // * END_FMT entry
+ // * FMT_END entry
class FormatEntry : public AbstractEntry {
public:
// explicit FormatEntry(const EntryIterator &it);
@@ -262,6 +302,7 @@
offsetof(ending, length);
};
+ // TODO move these somewhere else
struct HistTsEntry {
log_hash_t hash;
int64_t ts;
@@ -320,6 +361,8 @@
};
// ---------------------------------------------------------------------------
+ // NBLog Writer API
+ // ---------------------------------------------------------------------------
// Writer is thread-safe with respect to Reader, but not with respect to multiple threads
// calling Writer methods. If you need multi-thread safety for writing, use LockedWriter.
@@ -335,24 +378,22 @@
virtual ~Writer();
// FIXME needs comments, and some should be private
- virtual void log(const char *string);
- virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
- virtual void logvf(const char *fmt, va_list ap);
- virtual void logTimestamp();
- virtual void logTimestamp(const int64_t ts);
- virtual void logInteger(const int x);
- virtual void logFloat(const float x);
- virtual void logPID();
- virtual void logStart(const char *fmt);
- virtual void logEnd();
- virtual void logHash(log_hash_t hash);
- // The functions below are not in LockedWriter yet.
- virtual void logFormat(const char *fmt, log_hash_t hash, ...);
- virtual void logVFormat(const char *fmt, log_hash_t hash, va_list ap);
- virtual void logEventHistTs(Event event, log_hash_t hash);
- virtual void logLatency(double latencyMs);
- virtual void logMonotonicCycleTime(uint32_t monotonicNs);
- // End of functions that are not in LockedWriter yet.
+ void log(const char *string);
+ void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+ void logTimestamp();
+ void logFormat(const char *fmt, log_hash_t hash, ...);
+ void logEventHistTs(Event event, log_hash_t hash);
+
+ // Log data related to Event E. See the event-to-type mapping for the type of data
+ // corresponding to the event. For example, if you see a mapping statement:
+ // MAP_TYPE_TO_EVENT(E, T);
+ // then the usage of this method would be:
+ // T data = doComputation();
+ // tlNBLogWriter->log<NBLog::E>(data);
+ template<Event E>
+ void log(typename get_mapped<E>::type data) {
+ log(E, &data, sizeof(data));
+ }
virtual bool isEnabled() const;
@@ -363,12 +404,24 @@
sp<IMemory> getIMemory() const { return mIMemory; }
+ // Public logging function implementations should always use one of the
+ // two log() function calls below to write to shared memory.
+ protected:
+ // Writes a single Entry to the FIFO if the writer is enabled.
+ // This is protected and virtual because LockedWriter uses a lock to protect
+ // writing to the FIFO before writing to this function.
+ virtual void log(const Entry &entry, bool trusted = false);
+
private:
// 0 <= length <= kMaxLength
- // writes a single Entry to the FIFO
+ // Log a single Entry with corresponding event, data, and length.
void log(Event event, const void *data, size_t length);
- // checks validity of an event before calling log above this one
- void log(const Entry &entry, bool trusted = false);
+
+ void logvf(const char *fmt, va_list ap);
+ // helper functions for logging parts of a formatted entry
+ void logStart(const char *fmt);
+ void logTimestampFormat();
+ void logVFormat(const char *fmt, log_hash_t hash, va_list ap);
Shared* const mShared; // raw pointer to shared memory
sp<IMemory> mIMemory; // ref-counted version, initialized in constructor
@@ -393,54 +446,20 @@
LockedWriter();
LockedWriter(void *shared, size_t size);
- virtual void log(const char *string);
- virtual void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
- virtual void logvf(const char *fmt, va_list ap);
- virtual void logTimestamp();
- virtual void logTimestamp(const int64_t ts);
- virtual void logInteger(const int x);
- virtual void logFloat(const float x);
- virtual void logPID();
- virtual void logStart(const char *fmt);
- virtual void logEnd();
- virtual void logHash(log_hash_t hash);
-
- virtual bool isEnabled() const;
- virtual bool setEnabled(bool enabled);
+ bool isEnabled() const override;
+ bool setEnabled(bool enabled) override;
private:
+ // Lock needs to be obtained before writing to FIFO.
+ void log(const Entry &entry, bool trusted = false) override;
mutable Mutex mLock;
};
// ---------------------------------------------------------------------------
+ // NBLog Reader API
+ // ---------------------------------------------------------------------------
- // A snapshot of a readers buffer
- // This is raw data. No analysis has been done on it
- class Snapshot {
- public:
- Snapshot() = default;
-
- explicit Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
-
- ~Snapshot() { delete[] mData; }
-
- // amount of data lost (given by audio_utils_fifo_reader)
- size_t lost() const { return mLost; }
-
- // iterator to beginning of readable segment of snapshot
- // data between begin and end has valid entries
- EntryIterator begin() const { return mBegin; }
-
- // iterator to end of readable segment of snapshot
- EntryIterator end() const { return mEnd; }
-
- private:
- friend class Reader;
- uint8_t * const mData{};
- size_t mLost{0};
- EntryIterator mBegin;
- EntryIterator mEnd;
- };
+ class Snapshot; // Forward declaration needed for Reader::getSnapshot()
class Reader : public RefBase {
public:
@@ -456,10 +475,12 @@
const std::string &name() const { return mName; }
private:
+ // Amount of tries for reader to catch up with writer in getSnapshot().
static constexpr int kMaxObtainTries = 3;
- // startingTypes and endingTypes are used to check for log corruption.
- static const std::unordered_set<Event> startingTypes;
- static const std::unordered_set<Event> endingTypes;
+ // invalidBeginTypes and invalidEndTypes are used to align the Snapshot::begin() and
+ // Snapshot::end() EntryIterators to valid entries.
+ static const std::unordered_set<Event> invalidBeginTypes;
+ static const std::unordered_set<Event> invalidEndTypes;
// declared as const because audio_utils_fifo() constructor
sp<IMemory> mIMemory; // ref-counted version, assigned only in constructor
@@ -470,12 +491,39 @@
audio_utils_fifo_reader * const mFifoReader; // used to read from FIFO,
// non-NULL unless constructor fails
- // Searches for the last entry of type <type> in the range [front, back)
+ // Searches for the last valid entry in the range [front, back)
// back has to be entry-aligned. Returns nullptr if none enconuntered.
- static const uint8_t *findLastEntryOfTypes(const uint8_t *front, const uint8_t *back,
- const std::unordered_set<Event> &types);
+ static const uint8_t *findLastValidEntry(const uint8_t *front, const uint8_t *back,
+ const std::unordered_set<Event> &invalidTypes);
};
+ // A snapshot of a readers buffer
+ // This is raw data. No analysis has been done on it
+ class Snapshot {
+ public:
+ ~Snapshot() { delete[] mData; }
+
+ // amount of data lost (given by audio_utils_fifo_reader)
+ size_t lost() const { return mLost; }
+
+ // iterator to beginning of readable segment of snapshot
+ // data between begin and end has valid entries
+ EntryIterator begin() const { return mBegin; }
+
+ // iterator to end of readable segment of snapshot
+ EntryIterator end() const { return mEnd; }
+
+ private:
+ Snapshot() = default;
+ explicit Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
+ friend std::unique_ptr<Snapshot> Reader::getSnapshot();
+ uint8_t * const mData = nullptr;
+ size_t mLost = 0;
+ EntryIterator mBegin;
+ EntryIterator mEnd;
+ };
+
+ // TODO move this to MediaLogService?
class DumpReader : public Reader {
public:
DumpReader(const void *shared, size_t size, const std::string &name)
@@ -491,7 +539,7 @@
static void appendFloat(String8 *body, const void *data);
static void appendPID(String8 *body, const void *data, size_t length);
static void appendTimestamp(String8 *body, const void *data);
- //static size_t fmtEntryLength(const uint8_t *data); // TODO Eric remove if not used
+ // The bufferDump functions are used for debugging only.
static String8 bufferDump(const uint8_t *buffer, size_t size);
static String8 bufferDump(const EntryIterator &it);
};
diff --git a/media/libstagefright/TEST_MAPPING b/media/libstagefright/TEST_MAPPING
new file mode 100644
index 0000000..96818eb
--- /dev/null
+++ b/media/libstagefright/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "postsubmit": [
+ {
+ "name": "CtsMediaTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.RequiresDevice"
+ }
+ ]
+ }
+ ]
+}
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 5597488..2552073 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -17,6 +17,8 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "NdkMediaDrm"
+#include <inttypes.h>
+
#include <media/NdkMediaDrm.h>
#include <cutils/properties.h>
@@ -40,10 +42,32 @@
{
private:
AMediaDrm *mObj;
- AMediaDrmEventListener mListener;
+ AMediaDrmEventListener mEventListener;
+ AMediaDrmExpirationUpdateListener mExpirationUpdateListener;
+ AMediaDrmKeysChangeListener mKeysChangeListener;
public:
- DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj), mListener(listener) {}
+ DrmListener(AMediaDrm *obj, AMediaDrmEventListener listener) : mObj(obj),
+ mEventListener(listener), mExpirationUpdateListener(NULL), mKeysChangeListener(NULL) {}
+
+ DrmListener(AMediaDrm *obj, AMediaDrmExpirationUpdateListener listener) : mObj(obj),
+ mEventListener(NULL), mExpirationUpdateListener(listener), mKeysChangeListener(NULL) {}
+
+ DrmListener(AMediaDrm *obj, AMediaDrmKeysChangeListener listener) : mObj(obj),
+ mEventListener(NULL), mExpirationUpdateListener(NULL), mKeysChangeListener(listener) {}
+
+ void setEventListener(AMediaDrmEventListener listener) {
+ mEventListener = listener;
+ }
+
+ void setExpirationUpdateListener(AMediaDrmExpirationUpdateListener listener) {
+ mExpirationUpdateListener = listener;
+ }
+
+ void setKeysChangeListener(AMediaDrmKeysChangeListener listener) {
+ mKeysChangeListener = listener;
+ }
+
void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj);
};
@@ -62,27 +86,75 @@
};
void DrmListener::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
- if (!mListener) {
+ if (!mEventListener && !mExpirationUpdateListener && !mKeysChangeListener) {
+ ALOGE("No listeners are specified");
return;
}
+ obj->setDataPosition(0);
+
AMediaDrmSessionId sessionId = {NULL, 0};
int32_t sessionIdSize = obj->readInt32();
- if (sessionIdSize) {
- uint8_t *sessionIdData = new uint8_t[sessionIdSize];
- sessionId.ptr = sessionIdData;
- sessionId.length = sessionIdSize;
- obj->read(sessionIdData, sessionId.length);
+ if (sessionIdSize <= 0) {
+ ALOGE("Invalid session id size");
+ return;
}
- int32_t dataSize = obj->readInt32();
- uint8_t *data = NULL;
- if (dataSize) {
- data = new uint8_t[dataSize];
- obj->read(data, dataSize);
+ std::unique_ptr<uint8_t[]> sessionIdData(new uint8_t[sessionIdSize]);
+ sessionId.ptr = sessionIdData.get();
+ sessionId.length = sessionIdSize;
+ status_t err = obj->read(sessionIdData.get(), sessionId.length);
+ if (err != OK) {
+ ALOGE("Failed to read session id, error=%d", err);
+ return;
}
- // translate DrmPlugin event types into their NDK equivalents
+ if (DrmPlugin::kDrmPluginEventExpirationUpdate == eventType) {
+ int64_t expiryTimeInMS = obj->readInt64();
+ if (expiryTimeInMS >= 0) {
+ (*mExpirationUpdateListener)(mObj, &sessionId, expiryTimeInMS);
+ } else {
+ ALOGE("Failed to read expiry time, status=%" PRId64 "", expiryTimeInMS);
+ }
+ return;
+ } else if (DrmPlugin::kDrmPluginEventKeysChange == eventType) {
+ int32_t numKeys = 0;
+ err = obj->readInt32(&numKeys);
+ if (err != OK) {
+ ALOGE("Failed to read number of keys status, error=%d", err);
+ return;
+ }
+
+ Vector<AMediaDrmKeyStatus> keysStatus;
+ std::vector<std::unique_ptr<uint8_t[]> > dataPointers;
+ AMediaDrmKeyStatus keyStatus;
+
+ for (size_t i = 0; i < numKeys; ++i) {
+ keyStatus.keyId.ptr = nullptr;
+ keyStatus.keyId.length = 0;
+ int32_t idSize = obj->readInt32();
+ if (idSize > 0) {
+ std::unique_ptr<uint8_t[]> data(new uint8_t[idSize]);
+ err = obj->read(data.get(), idSize);
+ if (err != OK) {
+ ALOGE("Failed to read key data, error=%d", err);
+ return;
+ }
+ keyStatus.keyId.ptr = data.get();
+ keyStatus.keyId.length = idSize;
+ dataPointers.push_back(std::move(data));
+ }
+ keyStatus.keyType = static_cast<AMediaDrmKeyStatusType>(obj->readInt32());
+ keysStatus.push(keyStatus);
+ }
+
+ bool hasNewUsableKey = obj->readInt32();
+ (*mKeysChangeListener)(mObj, &sessionId, keysStatus.array(), numKeys, hasNewUsableKey);
+ return;
+ }
+
+ // Handles AMediaDrmEventListener below:
+ // translates DrmPlugin event types into their NDK equivalents
AMediaDrmEventType ndkEventType;
switch(eventType) {
case DrmPlugin::kDrmPluginEventProvisionRequired:
@@ -97,19 +169,30 @@
case DrmPlugin::kDrmPluginEventVendorDefined:
ndkEventType = EVENT_VENDOR_DEFINED;
break;
+ case DrmPlugin::kDrmPluginEventSessionReclaimed:
+ ndkEventType = EVENT_SESSION_RECLAIMED;
+ break;
default:
ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
- goto cleanup;
+ return;
}
- (*mListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize);
-
- cleanup:
- delete [] sessionId.ptr;
- delete [] data;
+ int32_t dataSize = obj->readInt32();
+ uint8_t *data = NULL;
+ if (dataSize > 0) {
+ data = new uint8_t[dataSize];
+ err = obj->read(data, dataSize);
+ if (err == OK) {
+ (*mEventListener)(mObj, &sessionId, ndkEventType, extra, data, dataSize);
+ } else {
+ ALOGE("Failed to read event data, error=%d", err);
+ }
+ delete [] data;
+ } else {
+ ALOGE("Error reading parcel: invalid event data size=%d", dataSize);
+ }
}
-
extern "C" {
static media_status_t translateStatus(status_t status) {
@@ -198,6 +281,8 @@
AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) {
AMediaDrm *mObj = new AMediaDrm();
mObj->mDrm = CreateDrmFromUUID(uuid);
+
+ mObj->mListener.clear();
return mObj;
}
@@ -216,11 +301,47 @@
if (!mObj || mObj->mDrm == NULL) {
return AMEDIA_ERROR_INVALID_OBJECT;
}
- mObj->mListener = new DrmListener(mObj, listener);
+
+ if (mObj->mListener.get()) {
+ mObj->mListener->setEventListener(listener);
+ } else {
+ mObj->mListener = new DrmListener(mObj, listener);
+ }
mObj->mDrm->setListener(mObj->mListener);
return AMEDIA_OK;
}
+EXPORT
+media_status_t AMediaDrm_setOnExpirationUpdateListener(AMediaDrm *mObj,
+ AMediaDrmExpirationUpdateListener listener) {
+ if (!mObj || mObj->mDrm == NULL) {
+ return AMEDIA_ERROR_INVALID_OBJECT;
+ }
+
+ if (mObj->mListener.get()) {
+ mObj->mListener->setExpirationUpdateListener(listener);
+ } else {
+ mObj->mListener = new DrmListener(mObj, listener);
+ }
+ mObj->mDrm->setListener(mObj->mListener);
+ return AMEDIA_OK;
+}
+
+EXPORT
+media_status_t AMediaDrm_setOnKeysChangeListener(AMediaDrm *mObj,
+ AMediaDrmKeysChangeListener listener) {
+ if (!mObj || mObj->mDrm == NULL) {
+ return AMEDIA_ERROR_INVALID_OBJECT;
+ }
+
+ if (mObj->mListener.get()) {
+ mObj->mListener->setKeysChangeListener(listener);
+ } else {
+ mObj->mListener = new DrmListener(mObj, listener);
+ }
+ mObj->mDrm->setListener(mObj->mListener);
+ return AMEDIA_OK;
+}
static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) {
for (iter = mObj->mIds.begin(); iter != mObj->mIds.end(); ++iter) {
diff --git a/media/ndk/include/media/NdkMediaDrm.h b/media/ndk/include/media/NdkMediaDrm.h
index 0209681..2e438d9 100644
--- a/media/ndk/include/media/NdkMediaDrm.h
+++ b/media/ndk/include/media/NdkMediaDrm.h
@@ -56,6 +56,7 @@
typedef AMediaDrmByteArray AMediaDrmScope;
typedef AMediaDrmByteArray AMediaDrmKeySetId;
typedef AMediaDrmByteArray AMediaDrmSecureStop;
+typedef AMediaDrmByteArray AMediaDrmKeyId;
typedef enum AMediaDrmEventType {
/**
@@ -81,12 +82,89 @@
* This event may indicate some specific vendor-defined condition, see your
* DRM provider documentation for details
*/
- EVENT_VENDOR_DEFINED = 4
+ EVENT_VENDOR_DEFINED = 4,
+
+ /**
+ * This event indicates that a session opened by the app has been reclaimed
+ * by the resource manager.
+ */
+ EVENT_SESSION_RECLAIMED = 5,
} AMediaDrmEventType;
+typedef enum AMediaDrmKeyType {
+ /**
+ * This key request type specifies that the keys will be for online use, they will
+ * not be saved to the device for subsequent use when the device is not connected
+ * to a network.
+ */
+ KEY_TYPE_STREAMING = 1,
+
+ /**
+ * This key request type specifies that the keys will be for offline use, they
+ * will be saved to the device for use when the device is not connected to a network.
+ */
+ KEY_TYPE_OFFLINE = 2,
+
+ /**
+ * This key request type specifies that previously saved offline keys should be released.
+ */
+ KEY_TYPE_RELEASE = 3
+} AMediaDrmKeyType;
+
+/**
+ * Data type containing {key, value} pair
+ */
+typedef struct AMediaDrmKeyValuePair {
+ const char *mKey;
+ const char *mValue;
+} AMediaDrmKeyValue;
+
+typedef enum AMediaKeyStatusType {
+ /**
+ * The key is currently usable to decrypt media data.
+ */
+ KEY_STATUS_TYPE_USABLE,
+
+ /**
+ * The key is no longer usable to decrypt media data because its expiration
+ * time has passed.
+ */
+ KEY_STATUS_TYPE_EXPIRED,
+
+ /**
+ * The key is not currently usable to decrypt media data because its output
+ * requirements cannot currently be met.
+ */
+ KEY_STATUS_TYPE_OUTPUTNOTALLOWED,
+
+ /**
+ * The status of the key is not yet known and is being determined.
+ */
+ KEY_STATUS_TYPE_STATUSPENDING,
+
+ /**
+ * The key is not currently usable to decrypt media data because of an
+ * internal error in processing unrelated to input parameters.
+ */
+ KEY_STATUS_TYPE_INTERNALERROR,
+
+} AMediaDrmKeyStatusType;
+
+typedef struct AMediaDrmKeyStatus {
+ AMediaDrmKeyId keyId;
+ AMediaDrmKeyStatusType keyType;
+} AMediaDrmKeyStatus;
+
typedef void (*AMediaDrmEventListener)(AMediaDrm *, const AMediaDrmSessionId *sessionId,
AMediaDrmEventType eventType, int extra, const uint8_t *data, size_t dataSize);
+typedef void (*AMediaDrmExpirationUpdateListener)(AMediaDrm *,
+ const AMediaDrmSessionId *sessionId, int64_t expiryTimeInMS);
+
+typedef void (*AMediaDrmKeysChangeListener)(AMediaDrm *,
+ const AMediaDrmSessionId *sessionId, const AMediaDrmKeyStatus *keyStatus,
+ size_t numKeys, bool hasNewUsableKey);
+
#if __ANDROID_API__ >= 21
/**
@@ -120,6 +198,22 @@
AMediaDrmEventListener listener) __INTRODUCED_IN(21);
/**
+ * Register a callback to be invoked when an expiration update event occurs
+ *
+ * listener is the callback that will be invoked on event
+ */
+media_status_t AMediaDrm_setOnExpirationUpdateListener(AMediaDrm *,
+ AMediaDrmExpirationUpdateListener listener) __INTRODUCED_IN(29);
+
+/**
+ * Register a callback to be invoked when a key status change event occurs
+ *
+ * listener is the callback that will be invoked on event
+ */
+media_status_t AMediaDrm_setOnKeysChangeListener(AMediaDrm *,
+ AMediaDrmKeysChangeListener listener) __INTRODUCED_IN(29);
+
+/**
* Open a new session with the MediaDrm object. A session ID is returned.
*
* returns MEDIADRM_NOT_PROVISIONED_ERROR if provisioning is needed
@@ -135,34 +229,6 @@
media_status_t AMediaDrm_closeSession(AMediaDrm *,
const AMediaDrmSessionId *sessionId) __INTRODUCED_IN(21);
-typedef enum AMediaDrmKeyType {
- /**
- * This key request type species that the keys will be for online use, they will
- * not be saved to the device for subsequent use when the device is not connected
- * to a network.
- */
- KEY_TYPE_STREAMING = 1,
-
- /**
- * This key request type specifies that the keys will be for offline use, they
- * will be saved to the device for use when the device is not connected to a network.
- */
- KEY_TYPE_OFFLINE = 2,
-
- /**
- * This key request type specifies that previously saved offline keys should be released.
- */
- KEY_TYPE_RELEASE = 3
-} AMediaDrmKeyType;
-
-/**
- * Data type containing {key, value} pair
- */
-typedef struct AMediaDrmKeyValuePair {
- const char *mKey;
- const char *mValue;
-} AMediaDrmKeyValue;
-
/**
* A key request/response exchange occurs between the app and a license server
* to obtain or release keys used to decrypt encrypted content.
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index c4c742e..6cab441 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1157,7 +1157,8 @@
{
sp<ThreadBase> thread = mThread.promote();
if (thread != 0 &&
- (thread->type() == ThreadBase::OFFLOAD || thread->type() == ThreadBase::DIRECT)) {
+ (thread->type() == ThreadBase::OFFLOAD || thread->type() == ThreadBase::DIRECT) &&
+ !isNonOffloadableEnabled_l()) {
PlaybackThread *t = (PlaybackThread *)thread.get();
float vol_l = (float)left / (1 << 24);
float vol_r = (float)right / (1 << 24);
@@ -2552,6 +2553,11 @@
bool AudioFlinger::EffectChain::isNonOffloadableEnabled()
{
Mutex::Autolock _l(mLock);
+ return isNonOffloadableEnabled_l();
+}
+
+bool AudioFlinger::EffectChain::isNonOffloadableEnabled_l()
+{
size_t size = mEffects.size();
for (size_t i = 0; i < size; i++) {
if (mEffects[i]->isEnabled() && !mEffects[i]->isOffloadable()) {
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index e04ee8e..15a26ea 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -378,6 +378,7 @@
// At least one non offloadable effect in the chain is enabled
bool isNonOffloadableEnabled();
+ bool isNonOffloadableEnabled_l();
void syncHalEffectsState();
diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp
index e587026..6f223df 100644
--- a/services/audioflinger/FastThread.cpp
+++ b/services/audioflinger/FastThread.cpp
@@ -339,7 +339,7 @@
// these stores #1, #2, #3 are not atomic with respect to each other,
// or with respect to store #4 below
mDumpState->mMonotonicNs[i] = monotonicNs;
- LOG_MONOTONIC_CYCLE_TIME(monotonicNs);
+ LOG_WORK_TIME(monotonicNs);
mDumpState->mLoadNs[i] = loadNs;
#ifdef CPU_FREQUENCY_STATISTICS
mDumpState->mCpukHz[i] = kHz;
diff --git a/services/audioflinger/TypedLogger.h b/services/audioflinger/TypedLogger.h
index 736ac60..6677470 100644
--- a/services/audioflinger/TypedLogger.h
+++ b/services/audioflinger/TypedLogger.h
@@ -97,13 +97,15 @@
#define LOG_AUDIO_STATE() do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
x->logEventHistTs(NBLog::EVENT_AUDIO_STATE, hash(__FILE__, __LINE__)); } while(0)
-// Record a typed entry that represents a thread's cycle time in nanoseconds.
+// Record a typed entry that represents a thread's work time in nanoseconds.
// Parameter ns should be of type uint32_t.
-#define LOG_MONOTONIC_CYCLE_TIME(ns) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
- x->logMonotonicCycleTime(ns); } while (0)
+#define LOG_WORK_TIME(ns) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+ x->log<NBLog::EVENT_WORK_TIME>(ns); } while (0)
+// Log the difference bewteen frames presented by HAL and frames written to HAL output sink,
+// divided by the sample rate. Parameter ms is of type double.
#define LOG_LATENCY(ms) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
- x->logLatency(ms); } while (0)
+ x->log<NBLog::EVENT_LATENCY>(ms); } while (0)
namespace android {
extern "C" {
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 04fee13..b1854bf 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -140,9 +140,8 @@
}
sp<AAudioServiceEndpoint> AAudioEndpointManager::openEndpoint(AAudioService &audioService,
- const aaudio::AAudioStreamRequest &request,
- aaudio_sharing_mode_t sharingMode) {
- if (sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE) {
+ const aaudio::AAudioStreamRequest &request) {
+ if (request.getConstantConfiguration().getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
return openExclusiveEndpoint(audioService, request);
} else {
return openSharedEndpoint(audioService, request);
diff --git a/services/oboeservice/AAudioEndpointManager.h b/services/oboeservice/AAudioEndpointManager.h
index 193bdee..ba17853 100644
--- a/services/oboeservice/AAudioEndpointManager.h
+++ b/services/oboeservice/AAudioEndpointManager.h
@@ -56,8 +56,7 @@
* @return endpoint or null
*/
android::sp<AAudioServiceEndpoint> openEndpoint(android::AAudioService &audioService,
- const aaudio::AAudioStreamRequest &request,
- aaudio_sharing_mode_t sharingMode);
+ const aaudio::AAudioStreamRequest &request);
void closeEndpoint(android::sp<AAudioServiceEndpoint> serviceEndpoint);
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 94440b1..53ee145 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -118,11 +118,16 @@
}
}
- // if SHARED requested or if EXCLUSIVE failed
- if (sharingMode == AAUDIO_SHARING_MODE_SHARED
- || (serviceStream.get() == nullptr && !sharingModeMatchRequired)) {
+ // If SHARED requested or if EXCLUSIVE failed.
+ if (sharingMode == AAUDIO_SHARING_MODE_SHARED) {
serviceStream = new AAudioServiceStreamShared(*this);
result = serviceStream->open(request);
+ } else if (serviceStream.get() == nullptr && !sharingModeMatchRequired) {
+ aaudio::AAudioStreamRequest modifiedRequest = request;
+ // Overwrite the original EXCLUSIVE mode with SHARED.
+ modifiedRequest.getConfiguration().setSharingMode(AAUDIO_SHARING_MODE_SHARED);
+ serviceStream = new AAudioServiceStreamShared(*this);
+ result = serviceStream->open(modifiedRequest);
}
if (result != AAUDIO_OK) {
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index f30f9bb..01caee4 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -210,9 +210,6 @@
uid_t audioServiceUid = getuid();
if ((mMmapClient.clientUid != audioServiceUid) &&
getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
- // Fallback is handled by caller but indicate what is possible in case
- // this is used in the future
- setSharingMode(AAUDIO_SHARING_MODE_SHARED);
ALOGW("%s() - exclusive FD cannot be used by client", __func__);
result = AAUDIO_ERROR_UNAVAILABLE;
goto error;
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 9af8af3..12be4a3 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -81,8 +81,7 @@
return result.str();
}
-aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request,
- aaudio_sharing_mode_t sharingMode) {
+aaudio_result_t AAudioServiceStreamBase::open(const aaudio::AAudioStreamRequest &request) {
AAudioEndpointManager &mEndpointManager = AAudioEndpointManager::getInstance();
aaudio_result_t result = AAUDIO_OK;
@@ -109,8 +108,7 @@
// referenced until the service returns a handle to the client.
// So only one thread can open a stream.
mServiceEndpoint = mEndpointManager.openEndpoint(mAudioService,
- request,
- sharingMode);
+ request);
if (mServiceEndpoint == nullptr) {
ALOGE("%s() openEndpoint() failed", __func__);
result = AAUDIO_ERROR_UNAVAILABLE;
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index c845309..9377945 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -64,8 +64,13 @@
sp<AAudioServiceStreamMMAP> keep(this);
- aaudio_result_t result = AAudioServiceStreamBase::open(request,
- AAUDIO_SHARING_MODE_EXCLUSIVE);
+ if (request.getConstantConfiguration().getSharingMode() != AAUDIO_SHARING_MODE_EXCLUSIVE) {
+ ALOGE("%s() sharingMode mismatch %d", __func__,
+ request.getConstantConfiguration().getSharingMode());
+ return AAUDIO_ERROR_INTERNAL;
+ }
+
+ aaudio_result_t result = AAudioServiceStreamBase::open(request);
if (result != AAUDIO_OK) {
return result;
}
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 05c5735..b645c69 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -120,7 +120,13 @@
sp<AAudioServiceStreamShared> keep(this);
- aaudio_result_t result = AAudioServiceStreamBase::open(request, AAUDIO_SHARING_MODE_SHARED);
+ if (request.getConstantConfiguration().getSharingMode() != AAUDIO_SHARING_MODE_SHARED) {
+ ALOGE("%s() sharingMode mismatch %d", __func__,
+ request.getConstantConfiguration().getSharingMode());
+ return AAUDIO_ERROR_INTERNAL;
+ }
+
+ aaudio_result_t result = AAudioServiceStreamBase::open(request);
if (result != AAUDIO_OK) {
ALOGE("%s() returned %d", __func__, result);
return result;