| Yin-Chia Yeh | 8dfe464 | 2020-06-01 11:57:45 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2020 The Android Open Source Project | 
|  | 3 | * | 
|  | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | * you may not use this file except in compliance with the License. | 
|  | 6 | * You may obtain a copy of the License at | 
|  | 7 | * | 
|  | 8 | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | * | 
|  | 10 | * Unless required by applicable law or agreed to in writing, software | 
|  | 11 | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | * See the License for the specific language governing permissions and | 
|  | 14 | * limitations under the License. | 
|  | 15 | */ | 
|  | 16 |  | 
|  | 17 | #define LOG_NDEBUG 0 | 
|  | 18 | #define LOG_TAG "ClientManagerTest" | 
|  | 19 |  | 
| Eino-Ville Talvala | 7c602c3 | 2021-03-20 17:00:18 -0700 | [diff] [blame] | 20 | #include <binder/ActivityManager.h> | 
|  | 21 |  | 
| Yin-Chia Yeh | 8dfe464 | 2020-06-01 11:57:45 -0700 | [diff] [blame] | 22 | #include "../utils/ClientManager.h" | 
|  | 23 | #include <gtest/gtest.h> | 
|  | 24 |  | 
|  | 25 | using namespace android::resource_policy; | 
| Eino-Ville Talvala | 7c602c3 | 2021-03-20 17:00:18 -0700 | [diff] [blame] | 26 | using namespace android; | 
| Yin-Chia Yeh | 8dfe464 | 2020-06-01 11:57:45 -0700 | [diff] [blame] | 27 |  | 
|  | 28 | struct TestClient { | 
|  | 29 | TestClient(int id, int32_t cost, const std::set<int>& conflictingKeys, int32_t ownerId, | 
|  | 30 | int32_t score, int32_t state, bool isVendorClient) : | 
|  | 31 | mId(id), mCost(cost), mConflictingKeys(conflictingKeys), | 
|  | 32 | mOwnerId(ownerId), mScore(score), mState(state), mIsVendorClient(isVendorClient) {}; | 
|  | 33 | int mId; | 
|  | 34 | int32_t mCost;    // Int 0..100 | 
|  | 35 | std::set<int> mConflictingKeys; | 
|  | 36 | int32_t mOwnerId; // PID | 
|  | 37 | int32_t mScore;   // Priority | 
|  | 38 | int32_t mState;   // Foreground/background etc | 
|  | 39 | bool mIsVendorClient; | 
|  | 40 | }; | 
|  | 41 |  | 
|  | 42 | using TestClientDescriptor = ClientDescriptor<int, TestClient>; | 
|  | 43 | using TestDescriptorPtr = std::shared_ptr<TestClientDescriptor>; | 
|  | 44 |  | 
|  | 45 | TestDescriptorPtr makeDescFromTestClient(const TestClient& tc) { | 
|  | 46 | return std::make_shared<TestClientDescriptor>(/*ID*/tc.mId, tc, tc.mCost, tc.mConflictingKeys, | 
|  | 47 | tc.mScore, tc.mOwnerId, tc.mState, tc.mIsVendorClient); | 
|  | 48 | } | 
|  | 49 |  | 
|  | 50 | class TestClientManager : public ClientManager<int, TestClient> { | 
|  | 51 | public: | 
|  | 52 | TestClientManager() {} | 
|  | 53 | virtual ~TestClientManager() {} | 
|  | 54 | }; | 
|  | 55 |  | 
|  | 56 |  | 
|  | 57 | // Test ClientMager behavior when there is only one single owner | 
|  | 58 | // The expected behavior is that if one owner (application or vendor) is trying | 
|  | 59 | // to open second camera, it may succeed or not, but the first opened camera | 
|  | 60 | // should never be evicted. | 
|  | 61 | TEST(ClientManagerTest, SingleOwnerMultipleCamera) { | 
|  | 62 |  | 
|  | 63 | TestClientManager cm; | 
|  | 64 | TestClient cam0Client(/*ID*/0, /*cost*/100, /*conflicts*/{1}, | 
| Eino-Ville Talvala | 7c602c3 | 2021-03-20 17:00:18 -0700 | [diff] [blame] | 65 | /*ownerId*/ 1000, PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, | 
|  | 66 | ActivityManager::PROCESS_STATE_PERSISTENT_UI, /*isVendorClient*/ false); | 
| Yin-Chia Yeh | 8dfe464 | 2020-06-01 11:57:45 -0700 | [diff] [blame] | 67 | auto cam0Desc = makeDescFromTestClient(cam0Client); | 
|  | 68 | auto evicted = cm.addAndEvict(cam0Desc); | 
|  | 69 | ASSERT_EQ(evicted.size(), 0u) << "Evicted list must be empty"; | 
|  | 70 |  | 
|  | 71 | TestClient cam1Client(/*ID*/1, /*cost*/100, /*conflicts*/{0}, | 
| Eino-Ville Talvala | 7c602c3 | 2021-03-20 17:00:18 -0700 | [diff] [blame] | 72 | /*ownerId*/ 1000, PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, | 
|  | 73 | ActivityManager::PROCESS_STATE_PERSISTENT_UI, /*isVendorClient*/ false); | 
| Yin-Chia Yeh | 8dfe464 | 2020-06-01 11:57:45 -0700 | [diff] [blame] | 74 | auto cam1Desc = makeDescFromTestClient(cam1Client); | 
|  | 75 |  | 
|  | 76 | // 1. Check with conflicting devices, new client would be evicted | 
|  | 77 | auto wouldBeEvicted = cm.wouldEvict(cam1Desc); | 
|  | 78 | ASSERT_EQ(wouldBeEvicted.size(), 1u) << "Evicted list length must be 1"; | 
|  | 79 | ASSERT_EQ(wouldBeEvicted[0]->getKey(), cam1Desc->getKey()) << "cam1 must be evicted"; | 
|  | 80 |  | 
|  | 81 | cm.removeAll(); | 
|  | 82 |  | 
|  | 83 | TestClient cam2Client(/*ID*/2, /*cost*/100, /*conflicts*/{}, | 
| Eino-Ville Talvala | 7c602c3 | 2021-03-20 17:00:18 -0700 | [diff] [blame] | 84 | /*ownerId*/ 1000, PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, | 
|  | 85 | ActivityManager::PROCESS_STATE_PERSISTENT_UI, /*isVendorClient*/ false); | 
| Yin-Chia Yeh | 8dfe464 | 2020-06-01 11:57:45 -0700 | [diff] [blame] | 86 | auto cam2Desc = makeDescFromTestClient(cam2Client); | 
|  | 87 | evicted = cm.addAndEvict(cam2Desc); | 
|  | 88 | ASSERT_EQ(evicted.size(), 0u) << "Evicted list must be empty"; | 
|  | 89 |  | 
|  | 90 | TestClient cam3Client(/*ID*/3, /*cost*/100, /*conflicts*/{}, | 
| Eino-Ville Talvala | 7c602c3 | 2021-03-20 17:00:18 -0700 | [diff] [blame] | 91 | /*ownerId*/ 1000, PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, | 
|  | 92 | ActivityManager::PROCESS_STATE_PERSISTENT_UI, /*isVendorClient*/ false); | 
| Yin-Chia Yeh | 8dfe464 | 2020-06-01 11:57:45 -0700 | [diff] [blame] | 93 | auto cam3Desc = makeDescFromTestClient(cam3Client); | 
|  | 94 |  | 
|  | 95 | // 2. Check without conflicting devices, the pre-existing client won't be evicted | 
|  | 96 | // In this case, the new client would be granted, but could later be rejected by HAL due to | 
|  | 97 | // resource cost. | 
|  | 98 | wouldBeEvicted = cm.wouldEvict(cam3Desc); | 
|  | 99 | ASSERT_EQ(wouldBeEvicted.size(), 0u) << "Evicted list must be empty"; | 
|  | 100 |  | 
|  | 101 | cm.removeAll(); | 
|  | 102 |  | 
|  | 103 | evicted = cm.addAndEvict(cam0Desc); | 
|  | 104 | ASSERT_EQ(evicted.size(), 0u) << "Evicted list must be empty"; | 
|  | 105 |  | 
|  | 106 | TestClient cam0ClientNew(/*ID*/0, /*cost*/100, /*conflicts*/{1}, | 
| Eino-Ville Talvala | 7c602c3 | 2021-03-20 17:00:18 -0700 | [diff] [blame] | 107 | /*ownerId*/ 1000, PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ, | 
|  | 108 | ActivityManager::PROCESS_STATE_PERSISTENT_UI, /*isVendorClient*/ false); | 
| Yin-Chia Yeh | 8dfe464 | 2020-06-01 11:57:45 -0700 | [diff] [blame] | 109 | auto cam0DescNew = makeDescFromTestClient(cam0ClientNew); | 
|  | 110 | wouldBeEvicted = cm.wouldEvict(cam0DescNew); | 
|  | 111 |  | 
|  | 112 | // 3. Check opening the same camera twice will evict the older client | 
|  | 113 | ASSERT_EQ(wouldBeEvicted.size(), 1u) << "Evicted list length must be 1"; | 
|  | 114 | ASSERT_EQ(wouldBeEvicted[0], cam0Desc) << "cam0 (old) must be evicted"; | 
| Yin-Chia Yeh | 8dfe464 | 2020-06-01 11:57:45 -0700 | [diff] [blame] | 115 |  | 
| Eino-Ville Talvala | 7c602c3 | 2021-03-20 17:00:18 -0700 | [diff] [blame] | 116 | // 4. Check that an invalid client (dead process) will be evicted | 
|  | 117 |  | 
|  | 118 | cm.removeAll(); | 
|  | 119 |  | 
|  | 120 | TestClient camDeadClient(/*ID*/ 0, /*cost*/100, /*conflicts*/{}, | 
|  | 121 | /*ownerId*/ 1000, INVALID_ADJ, | 
|  | 122 | ActivityManager::PROCESS_STATE_NONEXISTENT, /*isVendorClient*/ false); | 
|  | 123 | auto camDeadDesc = makeDescFromTestClient(camDeadClient); | 
|  | 124 | evicted = cm.addAndEvict(camDeadDesc); | 
|  | 125 | wouldBeEvicted = cm.wouldEvict(cam0Desc); | 
|  | 126 |  | 
|  | 127 | ASSERT_EQ(evicted.size(), 0u) << "Evicted list must be empty"; | 
|  | 128 | ASSERT_EQ(wouldBeEvicted.size(), 1u) << "Evicted list length must be 1"; | 
|  | 129 | ASSERT_EQ(wouldBeEvicted[0], camDeadDesc) << "dead cam must be evicted"; | 
|  | 130 |  | 
|  | 131 | // 5. Check that a more important client will win | 
|  | 132 |  | 
|  | 133 | TestClient cam0ForegroundClient(/*ID*/0, /*cost*/100, /*conflicts*/{1}, | 
|  | 134 | /*ownerId*/ 1000, FOREGROUND_APP_ADJ, | 
|  | 135 | ActivityManager::PROCESS_STATE_PERSISTENT_UI, /*isVendorClient*/ false); | 
|  | 136 | auto cam0FgDesc = makeDescFromTestClient(cam0ForegroundClient); | 
|  | 137 |  | 
|  | 138 | cm.removeAll(); | 
|  | 139 | evicted = cm.addAndEvict(cam0Desc); | 
|  | 140 | wouldBeEvicted = cm.wouldEvict(cam0FgDesc); | 
|  | 141 |  | 
|  | 142 | ASSERT_EQ(evicted.size(), 0u); | 
|  | 143 | ASSERT_EQ(wouldBeEvicted.size(), 1u); | 
|  | 144 | ASSERT_EQ(wouldBeEvicted[0],cam0Desc) << "less important cam0 must be evicted"; | 
|  | 145 | } |