transcoding: do not check bulk transcoding quota for MTP

bug: 185411130
test: media transcoding cts and unit tests; manual testing.
Change-Id: I103c383cecc9c4ca0c529dea7572c222f61e20b9
diff --git a/media/libmediatranscoding/TranscodingSessionController.cpp b/media/libmediatranscoding/TranscodingSessionController.cpp
index 68e2875..9705f3c 100644
--- a/media/libmediatranscoding/TranscodingSessionController.cpp
+++ b/media/libmediatranscoding/TranscodingSessionController.cpp
@@ -19,6 +19,7 @@
 
 #define VALIDATE_STATE 1
 
+#include <android/permission_manager.h>
 #include <inttypes.h>
 #include <media/TranscodingSessionController.h>
 #include <media/TranscodingUidPolicy.h>
@@ -193,7 +194,7 @@
 
     ~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);
 
@@ -212,9 +213,49 @@
         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{});
@@ -494,7 +535,7 @@
             // 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.
diff --git a/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp b/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
index 9e7fa95..ef9c4f8 100644
--- a/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
+++ b/media/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
@@ -339,19 +339,37 @@
         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, {},
-                        pauseLastSuccessSession);
+                        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, {},
+                        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);
             }
@@ -1294,8 +1312,7 @@
 
 TEST_F(TranscodingSessionControllerTest, TestTranscoderPacerWithPause) {
     ALOGD("TestTranscoderPacerDuringPause");
-    testPacerHelper(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/,
-                    true /*pauseLastSuccessSession*/);
+    testPacerHelperWithPause(12 /*numSubmits*/, 400 /*sessionDurationMs*/, 10 /*expectedSuccess*/);
 }
 
 /*
@@ -1305,17 +1322,26 @@
 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