transcoding: drop transcoding request when uid is gone
bug: 184181113
test: transcoding unit tests;
manually testing kill Yelp app during long transcoding,
verify in log that session is cancelled after app kill.
Change-Id: I721c1d4cbf8ae9d6ff328766e4b9fd725f86f8b8
diff --git a/media/libmediatranscoding/TranscodingSessionController.cpp b/media/libmediatranscoding/TranscodingSessionController.cpp
index 2518e70..68e2875 100644
--- a/media/libmediatranscoding/TranscodingSessionController.cpp
+++ b/media/libmediatranscoding/TranscodingSessionController.cpp
@@ -195,6 +195,7 @@
bool onSessionStarted(uid_t uid);
void onSessionCompleted(uid_t uid, std::chrono::microseconds runningTime);
+ void onSessionCancelled(uid_t uid);
private:
// Threshold of time between finish/start below which a back-to-back start is counted.
@@ -267,6 +268,18 @@
mUidHistoryMap[uid].lastCompletedTime = std::chrono::steady_clock::now();
}
+void TranscodingSessionController::Pacer::onSessionCancelled(uid_t uid) {
+ if (mUidHistoryMap.find(uid) == mUidHistoryMap.end()) {
+ ALOGV("Pacer::onSessionCancelled: uid %d: not present", uid);
+ return;
+ }
+ // This is only called if a uid is removed from a session (due to it being killed
+ // or the original submitting client was gone but session was kept for offline use).
+ // Since the uid is going to miss the onSessionCompleted(), we can't track this
+ // session, and have to check back at next onSessionStarted().
+ mUidHistoryMap[uid].sessionActive = false;
+}
+
///////////////////////////////////////////////////////////////////////////////
TranscodingSessionController::TranscodingSessionController(
@@ -539,8 +552,9 @@
mSessionQueues[clientUid].push_back(sessionKey);
}
-void TranscodingSessionController::removeSession_l(const SessionKeyType& sessionKey,
- Session::State finalState, bool keepForOffline) {
+void TranscodingSessionController::removeSession_l(
+ const SessionKeyType& sessionKey, Session::State finalState,
+ const std::shared_ptr<std::function<bool(uid_t uid)>>& keepUid) {
ALOGV("%s: session %s", __FUNCTION__, sessionToString(sessionKey).c_str());
if (mSessionMap.count(sessionKey) == 0) {
@@ -550,9 +564,17 @@
// Remove session from uid's queue.
bool uidQueueRemoved = false;
+ std::unordered_set<uid_t> remainingUids;
for (uid_t uid : mSessionMap[sessionKey].allClientUids) {
- if (keepForOffline && uid == OFFLINE_UID) {
- continue;
+ if (keepUid != nullptr) {
+ if ((*keepUid)(uid)) {
+ remainingUids.insert(uid);
+ continue;
+ }
+ // If we have uids to keep, the session is not going to any final
+ // state we can't use onSessionCompleted as the running time will
+ // not be valid. Only notify pacer to stop tracking this session.
+ mPacer->onSessionCancelled(uid);
}
SessionQueueType& sessionQueue = mSessionQueues[uid];
auto it = std::find(sessionQueue.begin(), sessionQueue.end(), sessionKey);
@@ -578,8 +600,8 @@
moveUidsToTop_l(topUids, false /*preserveTopUid*/);
}
- if (keepForOffline) {
- mSessionMap[sessionKey].allClientUids = {OFFLINE_UID};
+ if (keepUid != nullptr) {
+ mSessionMap[sessionKey].allClientUids = remainingUids;
return;
}
@@ -590,10 +612,10 @@
setSessionState_l(&mSessionMap[sessionKey], finalState);
- if (finalState == Session::FINISHED || finalState == Session::ERROR) {
- for (uid_t uid : mSessionMap[sessionKey].allClientUids) {
- mPacer->onSessionCompleted(uid, mSessionMap[sessionKey].runningTime);
- }
+ // We can use onSessionCompleted() even for CANCELLED, because runningTime is
+ // now updated by setSessionState_l().
+ for (uid_t uid : mSessionMap[sessionKey].allClientUids) {
+ mPacer->onSessionCompleted(uid, mSessionMap[sessionKey].runningTime);
}
mSessionHistory.push_back(mSessionMap[sessionKey]);
@@ -743,8 +765,10 @@
removeSession_l(*it, Session::CANCELED);
}
+ auto keepUid = std::make_shared<std::function<bool(uid_t)>>(
+ [](uid_t uid) { return uid == OFFLINE_UID; });
for (auto it = sessionsForOffline.begin(); it != sessionsForOffline.end(); ++it) {
- removeSession_l(*it, Session::CANCELED, true /*keepForOffline*/);
+ removeSession_l(*it, Session::CANCELED, keepUid);
}
// Start next session.
@@ -990,6 +1014,58 @@
validateState_l();
}
+void TranscodingSessionController::onUidGone(uid_t goneUid) {
+ ALOGD("%s: gone uid %u", __FUNCTION__, goneUid);
+
+ std::list<SessionKeyType> sessionsToRemove, sessionsForOtherUids;
+
+ std::scoped_lock lock{mLock};
+
+ for (auto it = mSessionMap.begin(); it != mSessionMap.end(); ++it) {
+ if (it->second.allClientUids.count(goneUid) > 0) {
+ // If goneUid is the only uid, remove the session; otherwise, only
+ // remove the uid from the session.
+ if (it->second.allClientUids.size() > 1) {
+ sessionsForOtherUids.push_back(it->first);
+ } else {
+ sessionsToRemove.push_back(it->first);
+ }
+ }
+ }
+
+ for (auto it = sessionsToRemove.begin(); it != sessionsToRemove.end(); ++it) {
+ // If the session has ever been started, stop it now.
+ // Note that stop() is needed even if the session is currently paused. This instructs
+ // the transcoder to discard any states for the session, otherwise the states may
+ // never be discarded.
+ if (mSessionMap[*it].getState() != Session::NOT_STARTED) {
+ mTranscoder->stop(it->first, it->second);
+ }
+
+ {
+ auto clientCallback = mSessionMap[*it].callback.lock();
+ if (clientCallback != nullptr) {
+ clientCallback->onTranscodingFailed(it->second,
+ TranscodingErrorCode::kUidGoneCancelled);
+ }
+ }
+
+ // Remove the session.
+ removeSession_l(*it, Session::CANCELED);
+ }
+
+ auto keepUid = std::make_shared<std::function<bool(uid_t)>>(
+ [goneUid](uid_t uid) { return uid != goneUid; });
+ for (auto it = sessionsForOtherUids.begin(); it != sessionsForOtherUids.end(); ++it) {
+ removeSession_l(*it, Session::CANCELED, keepUid);
+ }
+
+ // Start next session.
+ updateCurrentSession_l();
+
+ validateState_l();
+}
+
void TranscodingSessionController::onResourceAvailable() {
std::scoped_lock lock{mLock};
diff --git a/media/libmediatranscoding/TranscodingUidPolicy.cpp b/media/libmediatranscoding/TranscodingUidPolicy.cpp
index b5eb028..0a1ffbc 100644
--- a/media/libmediatranscoding/TranscodingUidPolicy.cpp
+++ b/media/libmediatranscoding/TranscodingUidPolicy.cpp
@@ -141,38 +141,34 @@
}
void TranscodingUidPolicy::onUidStateChanged(uid_t uid, int32_t procState) {
- ALOGV("onUidStateChanged: %u, procState %d", uid, procState);
+ ALOGV("onUidStateChanged: uid %u, procState %d", uid, procState);
bool topUidSetChanged = false;
+ bool isUidGone = false;
std::unordered_set<uid_t> topUids;
{
Mutex::Autolock _l(mUidLock);
auto it = mUidStateMap.find(uid);
if (it != mUidStateMap.end() && it->second != procState) {
- // Top set changed if 1) the uid is in the current top uid set, or 2) the
- // new procState is at least the same priority as the current top uid state.
- bool isUidCurrentTop =
- mTopUidState != IMPORTANCE_UNKNOWN && mStateUidMap[mTopUidState].count(uid) > 0;
- bool isNewStateHigherThanTop =
- procState != IMPORTANCE_UNKNOWN &&
- (procState <= mTopUidState || mTopUidState == IMPORTANCE_UNKNOWN);
- topUidSetChanged = (isUidCurrentTop || isNewStateHigherThanTop);
+ isUidGone = (procState == AACTIVITYMANAGER_IMPORTANCE_GONE);
+
+ topUids = mStateUidMap[mTopUidState];
// Move uid to the new procState.
mStateUidMap[it->second].erase(uid);
mStateUidMap[procState].insert(uid);
it->second = procState;
- if (topUidSetChanged) {
- updateTopUid_l();
-
+ updateTopUid_l();
+ if (topUids != mStateUidMap[mTopUidState]) {
// Make a copy of the uid set for callback.
topUids = mStateUidMap[mTopUidState];
+ topUidSetChanged = true;
}
}
}
- ALOGV("topUidSetChanged: %d", topUidSetChanged);
+ ALOGV("topUidSetChanged: %d, isUidGone %d", topUidSetChanged, isUidGone);
if (topUidSetChanged) {
auto callback = mUidPolicyCallback.lock();
@@ -180,6 +176,12 @@
callback->onTopUidsChanged(topUids);
}
}
+ if (isUidGone) {
+ auto callback = mUidPolicyCallback.lock();
+ if (callback != nullptr) {
+ callback->onUidGone(uid);
+ }
+ }
}
void TranscodingUidPolicy::updateTopUid_l() {
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl
index 5349fe1..fdd86c7 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingErrorCode.aidl
@@ -38,4 +38,5 @@
kErrorIO = kPrivateErrorFirst + 5,
kInsufficientResources = kPrivateErrorFirst + 6,
kWatchdogTimeout = kPrivateErrorFirst + 7,
+ kUidGoneCancelled = kPrivateErrorFirst + 8,
}
\ No newline at end of file
diff --git a/media/libmediatranscoding/include/media/TranscodingSessionController.h b/media/libmediatranscoding/include/media/TranscodingSessionController.h
index 05234f4..2691201 100644
--- a/media/libmediatranscoding/include/media/TranscodingSessionController.h
+++ b/media/libmediatranscoding/include/media/TranscodingSessionController.h
@@ -73,6 +73,7 @@
// UidPolicyCallbackInterface
void onTopUidsChanged(const std::unordered_set<uid_t>& uids) override;
+ void onUidGone(uid_t goneUid) override;
// ~UidPolicyCallbackInterface
// ResourcePolicyCallbackInterface
@@ -189,7 +190,7 @@
void updateCurrentSession_l();
void addUidToSession_l(uid_t uid, const SessionKeyType& sessionKey);
void removeSession_l(const SessionKeyType& sessionKey, Session::State finalState,
- bool keepForOffline = false);
+ const std::shared_ptr<std::function<bool(uid_t uid)>>& keepUid = nullptr);
void moveUidsToTop_l(const std::unordered_set<uid_t>& uids, bool preserveTopUid);
void setSessionState_l(Session* session, Session::State state);
void notifyClient(ClientIdType clientId, SessionIdType sessionId, const char* reason,
diff --git a/media/libmediatranscoding/include/media/UidPolicyInterface.h b/media/libmediatranscoding/include/media/UidPolicyInterface.h
index 05d8db0..445a2ff 100644
--- a/media/libmediatranscoding/include/media/UidPolicyInterface.h
+++ b/media/libmediatranscoding/include/media/UidPolicyInterface.h
@@ -48,6 +48,9 @@
// has changed. The receiver of this callback should adjust accordingly.
virtual void onTopUidsChanged(const std::unordered_set<uid_t>& uids) = 0;
+ // Called when a uid is gone.
+ virtual void onUidGone(uid_t goneUid) = 0;
+
protected:
virtual ~UidPolicyCallbackInterface() = default;
};
diff --git a/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp b/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
index 2be9e7d..9e7fa95 100644
--- a/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
+++ b/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
@@ -915,6 +915,52 @@
EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), SESSION(0)));
}
+TEST_F(TranscodingSessionControllerTest, TestUidGone) {
+ ALOGD("TestUidGone");
+
+ mUidPolicy->setTop(UID(0));
+ // Start with unspecified top UID.
+ // Submit real-time sessions to CLIENT(0), session should start immediately.
+ mController->submit(CLIENT(0), SESSION(0), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(0)));
+
+ mController->submit(CLIENT(0), SESSION(1), UID(0), UID(0), mRealtimeRequest, mClientCallback0);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+ EXPECT_TRUE(mController->addClientUid(CLIENT(0), SESSION(1), UID(1)));
+
+ // Submit real-time session to CLIENT(1), should not start.
+ mController->submit(CLIENT(1), SESSION(0), UID(1), UID(1), mOfflineRequest, mClientCallback1);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
+ EXPECT_TRUE(mController->addClientUid(CLIENT(1), SESSION(0), UID(1)));
+
+ // Tell the controller that UID(0) is gone.
+ mUidPolicy->setTop(UID(1));
+ // CLIENT(0)'s SESSION(1) should start, SESSION(0) should be cancelled.
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), SESSION(1)));
+ mController->onUidGone(UID(0));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Stop(CLIENT(0), SESSION(0)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), SESSION(0)));
+ EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kUidGoneCancelled);
+
+ std::vector<int32_t> clientUids;
+ EXPECT_FALSE(mController->getClientUids(CLIENT(0), SESSION(0), &clientUids));
+ EXPECT_TRUE(mController->getClientUids(CLIENT(0), SESSION(1), &clientUids));
+ EXPECT_EQ(clientUids.size(), 1);
+ EXPECT_EQ(clientUids[0], UID(1));
+
+ // Tell the controller that UID(1) is gone too.
+ mController->onUidGone(UID(1));
+ // CLIENT(1)'s SESSION(0) should start, CLIENT(0)'s SESSION(1) should be cancelled.
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Stop(CLIENT(0), SESSION(1)));
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), SESSION(1)));
+ EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kUidGoneCancelled);
+ EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), SESSION(0)));
+ // CLIENT(1) SESSION(0) should not have any client uids as it's only kept for offline.
+ EXPECT_TRUE(mController->getClientUids(CLIENT(1), SESSION(0), &clientUids));
+ EXPECT_EQ(clientUids.size(), 0);
+}
+
TEST_F(TranscodingSessionControllerTest, TestAddGetClientUids) {
ALOGD("TestAddGetClientUids");