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
20 #include <binder/ActivityManager.h>
21
22 #include "../utils/ClientManager.h"
23 #include <gtest/gtest.h>
24
25 using namespace android::resource_policy;
26 using namespace android;
27
28 struct TestClient {
TestClientTestClient29 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
makeDescFromTestClient(const TestClient & tc)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, /*oomScoreOffset*/0);
48 }
49
50 class TestClientManager : public ClientManager<int, TestClient> {
51 public:
TestClientManager()52 TestClientManager() {}
~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.
TEST(ClientManagerTest,SingleOwnerMultipleCamera)61 TEST(ClientManagerTest, SingleOwnerMultipleCamera) {
62
63 TestClientManager cm;
64 TestClient cam0Client(/*ID*/0, /*cost*/100, /*conflicts*/{1},
65 /*ownerId*/ 1000, PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ,
66 ActivityManager::PROCESS_STATE_PERSISTENT_UI, /*isVendorClient*/ false);
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},
72 /*ownerId*/ 1000, PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ,
73 ActivityManager::PROCESS_STATE_PERSISTENT_UI, /*isVendorClient*/ false);
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*/{},
84 /*ownerId*/ 1000, PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ,
85 ActivityManager::PROCESS_STATE_PERSISTENT_UI, /*isVendorClient*/ false);
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*/{},
91 /*ownerId*/ 1000, PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ,
92 ActivityManager::PROCESS_STATE_PERSISTENT_UI, /*isVendorClient*/ false);
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},
107 /*ownerId*/ 1000, PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ,
108 ActivityManager::PROCESS_STATE_PERSISTENT_UI, /*isVendorClient*/ false);
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";
115
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 }
146