Loading media/libmediatranscoding/TranscodingSessionController.cpp +44 −3 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #define VALIDATE_STATE 1 #include <android/permission_manager.h> #include <inttypes.h> #include <media/TranscodingSessionController.h> #include <media/TranscodingUidPolicy.h> Loading Loading @@ -193,7 +194,7 @@ struct TranscodingSessionController::Pacer { ~Pacer() = default; bool onSessionStarted(uid_t uid); bool onSessionStarted(uid_t uid, uid_t callingUid); void onSessionCompleted(uid_t uid, std::chrono::microseconds runningTime); void onSessionCancelled(uid_t uid); Loading @@ -212,9 +213,49 @@ private: std::chrono::steady_clock::time_point lastCompletedTime; }; std::map<uid_t, UidHistoryEntry> mUidHistoryMap; std::unordered_set<uid_t> mMtpUids; std::unordered_set<uid_t> mNonMtpUids; bool isSubjectToQuota(uid_t uid, uid_t callingUid); }; bool TranscodingSessionController::Pacer::onSessionStarted(uid_t uid) { bool TranscodingSessionController::Pacer::isSubjectToQuota(uid_t uid, uid_t callingUid) { // Submitting with self uid is not limited (which can only happen if it's used as an // app-facing API). MediaProvider usage always submit on behalf of other uids. if (uid == callingUid) { return false; } if (mMtpUids.find(uid) != mMtpUids.end()) { return false; } if (mNonMtpUids.find(uid) != mNonMtpUids.end()) { return true; } // We don't have MTP permission info about this uid yet, check permission and save the result. int32_t result; if (__builtin_available(android __TRANSCODING_MIN_API__, *)) { if (APermissionManager_checkPermission("android.permission.ACCESS_MTP", -1 /*pid*/, uid, &result) == PERMISSION_MANAGER_STATUS_OK && result == PERMISSION_MANAGER_PERMISSION_GRANTED) { mMtpUids.insert(uid); return false; } } mNonMtpUids.insert(uid); return true; } bool TranscodingSessionController::Pacer::onSessionStarted(uid_t uid, uid_t callingUid) { if (!isSubjectToQuota(uid, callingUid)) { ALOGI("Pacer::onSessionStarted: uid %d (caling uid: %d): not subject to quota", uid, callingUid); return true; } // If uid doesn't exist, only insert the entry and mark session active. Skip quota checking. if (mUidHistoryMap.find(uid) == mUidHistoryMap.end()) { mUidHistoryMap.emplace(uid, UidHistoryEntry{}); Loading Loading @@ -494,7 +535,7 @@ void TranscodingSessionController::updateCurrentSession_l() { // Check if at least one client has quota to start the session. bool keepForClient = false; for (uid_t uid : topSession->allClientUids) { if (mPacer->onSessionStarted(uid)) { if (mPacer->onSessionStarted(uid, topSession->callingUid)) { keepForClient = true; // DO NOT break here, because book-keeping still needs to happen // for the other uids. Loading media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp +41 −15 Original line number Diff line number Diff line Loading @@ -339,19 +339,37 @@ public: EXPECT_EQ(mTranscoder.use_count(), 2); } void testPacerHelper(int numSubmits, int sessionDurationMs, int expectedSuccess, bool pauseLastSuccessSession = false) { void testPacerHelper(int numSubmits, int sessionDurationMs, int expectedSuccess) { testPacerHelper(numSubmits, sessionDurationMs, expectedSuccess, mClientCallback0, {}, false /*pauseLastSuccessSession*/, true /*useRealCallingUid*/); } void testPacerHelperWithPause(int numSubmits, int sessionDurationMs, int expectedSuccess) { testPacerHelper(numSubmits, sessionDurationMs, expectedSuccess, mClientCallback0, {}, true /*pauseLastSuccessSession*/, true /*useRealCallingUid*/); } void testPacerHelperWithMultipleUids(int numSubmits, int sessionDurationMs, int expectedSuccess, const std::shared_ptr<TestClientCallback>& client, const std::vector<int>& additionalClientUids) { testPacerHelper(numSubmits, sessionDurationMs, expectedSuccess, client, additionalClientUids, false /*pauseLastSuccessSession*/, true /*useRealCallingUid*/); } void testPacerHelperWithSelfUid(int numSubmits, int sessionDurationMs, int expectedSuccess) { testPacerHelper(numSubmits, sessionDurationMs, expectedSuccess, mClientCallback0, {}, pauseLastSuccessSession); false /*pauseLastSuccessSession*/, false /*useRealCallingUid*/); } void testPacerHelper(int numSubmits, int sessionDurationMs, int expectedSuccess, const std::shared_ptr<TestClientCallback>& client, const std::vector<int>& additionalClientUids, bool pauseLastSuccessSession) { const std::vector<int>& additionalClientUids, bool pauseLastSuccessSession, bool useRealCallingUid) { uid_t callingUid = useRealCallingUid ? ::getuid() : client->clientUid(); for (int i = 0; i < numSubmits; i++) { mController->submit(client->clientId(), SESSION(i), client->clientUid(), client->clientUid(), mRealtimeRequest, client); mController->submit(client->clientId(), SESSION(i), callingUid, client->clientUid(), mRealtimeRequest, client); for (int additionalUid : additionalClientUids) { mController->addClientUid(client->clientId(), SESSION(i), additionalUid); } Loading Loading @@ -1294,8 +1312,7 @@ TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerOverQuota) { TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerWithPause) { ALOGD("TestTranscoderPacerDuringPause"); testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/, true /*pauseLastSuccessSession*/); testPacerHelperWithPause(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/); } /* Loading @@ -1305,17 +1322,26 @@ TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerWithPause) { TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerMultipleUids) { ALOGD("TestTranscoderPacerMultipleUids"); // First, run mClientCallback0 to the point of no quota. testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/, mClientCallback0, {}, false /*pauseLastSuccessSession*/); testPacerHelperWithMultipleUids(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/, mClientCallback0, {}); // Make UID(0) block on Client1's sessions too, Client1's quota should not be affected. testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/, mClientCallback1, {UID(0)}, false /*pauseLastSuccessSession*/); testPacerHelperWithMultipleUids(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/, mClientCallback1, {UID(0)}); // Make UID(10) block on Client2's sessions. We expect to see 11 succeeds (instead of 10), // because the addClientUid() is called after the submit, and first session is already // started by the time UID(10) is added. UID(10) allowed us to run the 11th session, // after that both UID(10) and UID(2) are out of quota. testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 11 /*expectedSuccess*/, mClientCallback2, {UID(10)}, false /*pauseLastSuccessSession*/); testPacerHelperWithMultipleUids(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 11 /*expectedSuccess*/, mClientCallback2, {UID(10)}); } /* * Use same uid for clientUid and callingUid, should not be limited by quota. */ TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerSelfUid) { ALOGD("TestTranscoderPacerSelfUid"); testPacerHelperWithSelfUid(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 12 /*expectedSuccess*/); } } // namespace android Loading
media/libmediatranscoding/TranscodingSessionController.cpp +44 −3 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #define VALIDATE_STATE 1 #include <android/permission_manager.h> #include <inttypes.h> #include <media/TranscodingSessionController.h> #include <media/TranscodingUidPolicy.h> Loading Loading @@ -193,7 +194,7 @@ struct TranscodingSessionController::Pacer { ~Pacer() = default; bool onSessionStarted(uid_t uid); bool onSessionStarted(uid_t uid, uid_t callingUid); void onSessionCompleted(uid_t uid, std::chrono::microseconds runningTime); void onSessionCancelled(uid_t uid); Loading @@ -212,9 +213,49 @@ private: std::chrono::steady_clock::time_point lastCompletedTime; }; std::map<uid_t, UidHistoryEntry> mUidHistoryMap; std::unordered_set<uid_t> mMtpUids; std::unordered_set<uid_t> mNonMtpUids; bool isSubjectToQuota(uid_t uid, uid_t callingUid); }; bool TranscodingSessionController::Pacer::onSessionStarted(uid_t uid) { bool TranscodingSessionController::Pacer::isSubjectToQuota(uid_t uid, uid_t callingUid) { // Submitting with self uid is not limited (which can only happen if it's used as an // app-facing API). MediaProvider usage always submit on behalf of other uids. if (uid == callingUid) { return false; } if (mMtpUids.find(uid) != mMtpUids.end()) { return false; } if (mNonMtpUids.find(uid) != mNonMtpUids.end()) { return true; } // We don't have MTP permission info about this uid yet, check permission and save the result. int32_t result; if (__builtin_available(android __TRANSCODING_MIN_API__, *)) { if (APermissionManager_checkPermission("android.permission.ACCESS_MTP", -1 /*pid*/, uid, &result) == PERMISSION_MANAGER_STATUS_OK && result == PERMISSION_MANAGER_PERMISSION_GRANTED) { mMtpUids.insert(uid); return false; } } mNonMtpUids.insert(uid); return true; } bool TranscodingSessionController::Pacer::onSessionStarted(uid_t uid, uid_t callingUid) { if (!isSubjectToQuota(uid, callingUid)) { ALOGI("Pacer::onSessionStarted: uid %d (caling uid: %d): not subject to quota", uid, callingUid); return true; } // If uid doesn't exist, only insert the entry and mark session active. Skip quota checking. if (mUidHistoryMap.find(uid) == mUidHistoryMap.end()) { mUidHistoryMap.emplace(uid, UidHistoryEntry{}); Loading Loading @@ -494,7 +535,7 @@ void TranscodingSessionController::updateCurrentSession_l() { // Check if at least one client has quota to start the session. bool keepForClient = false; for (uid_t uid : topSession->allClientUids) { if (mPacer->onSessionStarted(uid)) { if (mPacer->onSessionStarted(uid, topSession->callingUid)) { keepForClient = true; // DO NOT break here, because book-keeping still needs to happen // for the other uids. Loading
media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp +41 −15 Original line number Diff line number Diff line Loading @@ -339,19 +339,37 @@ public: EXPECT_EQ(mTranscoder.use_count(), 2); } void testPacerHelper(int numSubmits, int sessionDurationMs, int expectedSuccess, bool pauseLastSuccessSession = false) { void testPacerHelper(int numSubmits, int sessionDurationMs, int expectedSuccess) { testPacerHelper(numSubmits, sessionDurationMs, expectedSuccess, mClientCallback0, {}, false /*pauseLastSuccessSession*/, true /*useRealCallingUid*/); } void testPacerHelperWithPause(int numSubmits, int sessionDurationMs, int expectedSuccess) { testPacerHelper(numSubmits, sessionDurationMs, expectedSuccess, mClientCallback0, {}, true /*pauseLastSuccessSession*/, true /*useRealCallingUid*/); } void testPacerHelperWithMultipleUids(int numSubmits, int sessionDurationMs, int expectedSuccess, const std::shared_ptr<TestClientCallback>& client, const std::vector<int>& additionalClientUids) { testPacerHelper(numSubmits, sessionDurationMs, expectedSuccess, client, additionalClientUids, false /*pauseLastSuccessSession*/, true /*useRealCallingUid*/); } void testPacerHelperWithSelfUid(int numSubmits, int sessionDurationMs, int expectedSuccess) { testPacerHelper(numSubmits, sessionDurationMs, expectedSuccess, mClientCallback0, {}, pauseLastSuccessSession); false /*pauseLastSuccessSession*/, false /*useRealCallingUid*/); } void testPacerHelper(int numSubmits, int sessionDurationMs, int expectedSuccess, const std::shared_ptr<TestClientCallback>& client, const std::vector<int>& additionalClientUids, bool pauseLastSuccessSession) { const std::vector<int>& additionalClientUids, bool pauseLastSuccessSession, bool useRealCallingUid) { uid_t callingUid = useRealCallingUid ? ::getuid() : client->clientUid(); for (int i = 0; i < numSubmits; i++) { mController->submit(client->clientId(), SESSION(i), client->clientUid(), client->clientUid(), mRealtimeRequest, client); mController->submit(client->clientId(), SESSION(i), callingUid, client->clientUid(), mRealtimeRequest, client); for (int additionalUid : additionalClientUids) { mController->addClientUid(client->clientId(), SESSION(i), additionalUid); } Loading Loading @@ -1294,8 +1312,7 @@ TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerOverQuota) { TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerWithPause) { ALOGD("TestTranscoderPacerDuringPause"); testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/, true /*pauseLastSuccessSession*/); testPacerHelperWithPause(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/); } /* Loading @@ -1305,17 +1322,26 @@ TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerWithPause) { TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerMultipleUids) { ALOGD("TestTranscoderPacerMultipleUids"); // First, run mClientCallback0 to the point of no quota. testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/, mClientCallback0, {}, false /*pauseLastSuccessSession*/); testPacerHelperWithMultipleUids(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/, mClientCallback0, {}); // Make UID(0) block on Client1's sessions too, Client1's quota should not be affected. testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/, mClientCallback1, {UID(0)}, false /*pauseLastSuccessSession*/); testPacerHelperWithMultipleUids(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/, mClientCallback1, {UID(0)}); // Make UID(10) block on Client2's sessions. We expect to see 11 succeeds (instead of 10), // because the addClientUid() is called after the submit, and first session is already // started by the time UID(10) is added. UID(10) allowed us to run the 11th session, // after that both UID(10) and UID(2) are out of quota. testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 11 /*expectedSuccess*/, mClientCallback2, {UID(10)}, false /*pauseLastSuccessSession*/); testPacerHelperWithMultipleUids(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 11 /*expectedSuccess*/, mClientCallback2, {UID(10)}); } /* * Use same uid for clientUid and callingUid, should not be limited by quota. */ TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerSelfUid) { ALOGD("TestTranscoderPacerSelfUid"); testPacerHelperWithSelfUid(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 12 /*expectedSuccess*/); } } // namespace android