blob: 95edf1ddb47948d52a948a6324a0e1c604bf8dc1 [file] [log] [blame]
Chong Zhang6d58e4b2020-03-31 09:41:10 -07001/*
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// Unit Test for TranscodingJobScheduler
18
19// #define LOG_NDEBUG 0
20#define LOG_TAG "TranscodingJobSchedulerTest"
21
22#include <aidl/android/media/BnTranscodingClientCallback.h>
23#include <aidl/android/media/IMediaTranscodingService.h>
24#include <aidl/android/media/ITranscodingClient.h>
25#include <aidl/android/media/ITranscodingClientCallback.h>
26#include <android-base/logging.h>
27#include <android/binder_manager.h>
28#include <android/binder_process.h>
29#include <gtest/gtest.h>
30#include <media/TranscodingClientManager.h>
31#include <media/TranscodingJobScheduler.h>
32#include <utils/Log.h>
33
Chong Zhangacb33502020-04-20 11:04:48 -070034#include <unordered_set>
35
Chong Zhang6d58e4b2020-03-31 09:41:10 -070036namespace android {
37
38using Status = ::ndk::ScopedAStatus;
39using aidl::android::media::BnTranscodingClientCallback;
40using aidl::android::media::IMediaTranscodingService;
41using aidl::android::media::ITranscodingClient;
42
43constexpr int64_t kClientId = 1000;
44constexpr int32_t kClientJobId = 0;
Chong Zhang7ae4e2f2020-04-17 15:24:34 -070045constexpr uid_t kClientUid = 5000;
46constexpr uid_t kInvalidUid = (uid_t)-1;
Chong Zhang6d58e4b2020-03-31 09:41:10 -070047
48#define CLIENT(n) (kClientId + (n))
49#define JOB(n) (kClientJobId + (n))
Chong Zhang7ae4e2f2020-04-17 15:24:34 -070050#define UID(n) (kClientUid + (n))
Chong Zhang6d58e4b2020-03-31 09:41:10 -070051
Chong Zhangacb33502020-04-20 11:04:48 -070052class TestUidPolicy : public UidPolicyInterface {
Chong Zhang6d58e4b2020-03-31 09:41:10 -070053public:
Chong Zhangacb33502020-04-20 11:04:48 -070054 TestUidPolicy() = default;
55 virtual ~TestUidPolicy() = default;
56
57 // UidPolicyInterface
58 void registerMonitorUid(uid_t /*uid*/) override {}
59 void unregisterMonitorUid(uid_t /*uid*/) override {}
60 bool isUidOnTop(uid_t uid) override { return mTopUids.count(uid) > 0; }
61 std::unordered_set<uid_t> getTopUids() const override { return mTopUids; }
62 void setCallback(const std::shared_ptr<UidPolicyCallbackInterface>& cb) override {
63 mUidPolicyCallback = cb;
64 }
65 void setTop(uid_t uid) {
66 std::unordered_set<uid_t> uids = {uid};
67 setTop(uids);
68 }
69 void setTop(const std::unordered_set<uid_t>& uids) {
70 mTopUids = uids;
71 auto uidPolicyCb = mUidPolicyCallback.lock();
72 if (uidPolicyCb != nullptr) {
73 uidPolicyCb->onTopUidsChanged(mTopUids);
74 }
75 }
76
77 std::unordered_set<uid_t> mTopUids;
78 std::weak_ptr<UidPolicyCallbackInterface> mUidPolicyCallback;
79};
80
81class TestTranscoder : public TranscoderInterface {
82public:
83 TestTranscoder() : mLastError(TranscodingErrorCode::kUnknown) {}
84 virtual ~TestTranscoder() {}
Chong Zhang6d58e4b2020-03-31 09:41:10 -070085
86 // TranscoderInterface
87 void start(int64_t clientId, int32_t jobId) override {
88 mEventQueue.push_back(Start(clientId, jobId));
89 }
90 void pause(int64_t clientId, int32_t jobId) override {
91 mEventQueue.push_back(Pause(clientId, jobId));
92 }
93 void resume(int64_t clientId, int32_t jobId) override {
94 mEventQueue.push_back(Resume(clientId, jobId));
95 }
96
Chong Zhang6d58e4b2020-03-31 09:41:10 -070097 void onFinished(int64_t clientId, int32_t jobId) {
98 mEventQueue.push_back(Finished(clientId, jobId));
99 }
100
101 void onFailed(int64_t clientId, int32_t jobId, TranscodingErrorCode err) {
102 mLastError = err;
103 mEventQueue.push_back(Failed(clientId, jobId));
104 }
105
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700106 TranscodingErrorCode getLastError() {
107 TranscodingErrorCode result = mLastError;
108 mLastError = TranscodingErrorCode::kUnknown;
109 return result;
110 }
111
112 struct Event {
113 enum { NoEvent, Start, Pause, Resume, Finished, Failed } type;
114 int64_t clientId;
115 int32_t jobId;
116 };
117
118 static constexpr Event NoEvent = {Event::NoEvent, 0, 0};
119
120#define DECLARE_EVENT(action) \
121 static Event action(int64_t clientId, int32_t jobId) { \
122 return {Event::action, clientId, jobId}; \
123 }
124
125 DECLARE_EVENT(Start);
126 DECLARE_EVENT(Pause);
127 DECLARE_EVENT(Resume);
128 DECLARE_EVENT(Finished);
129 DECLARE_EVENT(Failed);
130
131 const Event& popEvent() {
132 if (mEventQueue.empty()) {
133 mPoppedEvent = NoEvent;
134 } else {
135 mPoppedEvent = *mEventQueue.begin();
136 mEventQueue.pop_front();
137 }
138 return mPoppedEvent;
139 }
140
141private:
142 Event mPoppedEvent;
143 std::list<Event> mEventQueue;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700144 TranscodingErrorCode mLastError;
145};
146
Chong Zhangacb33502020-04-20 11:04:48 -0700147bool operator==(const TestTranscoder::Event& lhs, const TestTranscoder::Event& rhs) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700148 return lhs.type == rhs.type && lhs.clientId == rhs.clientId && lhs.jobId == rhs.jobId;
149}
150
151struct TestClientCallback : public BnTranscodingClientCallback {
Chong Zhangacb33502020-04-20 11:04:48 -0700152 TestClientCallback(TestTranscoder* owner, int64_t clientId)
153 : mOwner(owner), mClientId(clientId) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700154 ALOGD("TestClient Created");
155 }
156
157 Status onTranscodingFinished(int32_t in_jobId,
158 const TranscodingResultParcel& in_result) override {
159 EXPECT_EQ(in_jobId, in_result.jobId);
160 mOwner->onFinished(mClientId, in_jobId);
161 return Status::ok();
162 }
163
164 Status onTranscodingFailed(int32_t in_jobId, TranscodingErrorCode in_errorCode) override {
165 mOwner->onFailed(mClientId, in_jobId, in_errorCode);
166 return Status::ok();
167 }
168
169 Status onAwaitNumberOfJobsChanged(int32_t /* in_jobId */, int32_t /* in_oldAwaitNumber */,
170 int32_t /* in_newAwaitNumber */) override {
171 return Status::ok();
172 }
173
174 Status onProgressUpdate(int32_t /* in_jobId */, int32_t /* in_progress */) override {
175 return Status::ok();
176 }
177
178 virtual ~TestClientCallback() { ALOGI("TestClient destroyed"); };
179
180private:
Chong Zhangacb33502020-04-20 11:04:48 -0700181 TestTranscoder* mOwner;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700182 int64_t mClientId;
183 TestClientCallback(const TestClientCallback&) = delete;
184 TestClientCallback& operator=(const TestClientCallback&) = delete;
185};
186
187class TranscodingJobSchedulerTest : public ::testing::Test {
188public:
189 TranscodingJobSchedulerTest() { ALOGI("TranscodingJobSchedulerTest created"); }
190
191 void SetUp() override {
192 ALOGI("TranscodingJobSchedulerTest set up");
Chong Zhangacb33502020-04-20 11:04:48 -0700193 mTranscoder.reset(new TestTranscoder());
194 mUidPolicy.reset(new TestUidPolicy());
195 mScheduler.reset(new TranscodingJobScheduler(mTranscoder, mUidPolicy));
196 mUidPolicy->setCallback(mScheduler);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700197
198 // Set priority only, ignore other fields for now.
199 mOfflineRequest.priority = TranscodingJobPriority::kUnspecified;
200 mRealtimeRequest.priority = TranscodingJobPriority::kHigh;
201 mClientCallback0 =
Chong Zhangacb33502020-04-20 11:04:48 -0700202 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(0));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700203 mClientCallback1 =
Chong Zhangacb33502020-04-20 11:04:48 -0700204 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(1));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700205 mClientCallback2 =
Chong Zhangacb33502020-04-20 11:04:48 -0700206 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(2));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700207 mClientCallback3 =
Chong Zhangacb33502020-04-20 11:04:48 -0700208 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(3));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700209 }
210
211 void TearDown() override { ALOGI("TranscodingJobSchedulerTest tear down"); }
212
213 ~TranscodingJobSchedulerTest() { ALOGD("TranscodingJobSchedulerTest destroyed"); }
214
Chong Zhangacb33502020-04-20 11:04:48 -0700215 std::shared_ptr<TestTranscoder> mTranscoder;
216 std::shared_ptr<TestUidPolicy> mUidPolicy;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700217 std::shared_ptr<TranscodingJobScheduler> mScheduler;
218 TranscodingRequestParcel mOfflineRequest;
219 TranscodingRequestParcel mRealtimeRequest;
220 std::shared_ptr<TestClientCallback> mClientCallback0;
221 std::shared_ptr<TestClientCallback> mClientCallback1;
222 std::shared_ptr<TestClientCallback> mClientCallback2;
223 std::shared_ptr<TestClientCallback> mClientCallback3;
224};
225
226TEST_F(TranscodingJobSchedulerTest, TestSubmitJob) {
227 ALOGD("TestSubmitJob");
228
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700229 // Start with UID(1) on top.
Chong Zhangacb33502020-04-20 11:04:48 -0700230 mUidPolicy->setTop(UID(1));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700231
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700232 // Submit offline job to CLIENT(0) in UID(0).
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700233 // Should start immediately (because this is the only job).
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700234 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700235 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), 0));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700236
237 // Submit real-time job to CLIENT(0).
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700238 // Should pause offline job and start new job, even if UID(0) is not on top.
239 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700240 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
241 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700242
243 // Submit real-time job to CLIENT(0), should be queued after the previous job.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700244 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700245 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700246
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700247 // Submit real-time job to CLIENT(1) in same uid, should be queued after the previous job.
248 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mRealtimeRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700249 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700250
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700251 // Submit real-time job to CLIENT(2) in UID(1).
Chong Zhangacb33502020-04-20 11:04:48 -0700252 // Should pause previous job and start new job, because UID(1) is (has been) top.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700253 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700254 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
255 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700256
257 // Submit offline job, shouldn't generate any event.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700258 mScheduler->submit(CLIENT(2), JOB(1), UID(1), mOfflineRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700259 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700260
Chong Zhangacb33502020-04-20 11:04:48 -0700261 // Bring UID(0) to top.
262 mUidPolicy->setTop(UID(0));
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700263 // Should pause current job, and resume last job in UID(0).
Chong Zhangacb33502020-04-20 11:04:48 -0700264 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
265 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700266}
267
268TEST_F(TranscodingJobSchedulerTest, TestCancelJob) {
269 ALOGD("TestCancelJob");
270
271 // Submit real-time job JOB(0), should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700272 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700273 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700274
275 // Submit real-time job JOB(1), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700276 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700277 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700278
279 // Submit offline job JOB(2), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700280 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700281 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700282
283 // Cancel queued real-time job.
284 // Cancel real-time job JOB(1), should be cancelled.
285 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(1)));
286
287 // Cancel queued offline job.
288 // Cancel offline job JOB(2), should be cancelled.
289 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(2)));
290
291 // Submit offline job JOB(3), shouldn't cause any event.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700292 mScheduler->submit(CLIENT(0), JOB(3), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700293 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700294
295 // Cancel running real-time job JOB(0).
296 // - Should be paused first then cancelled.
297 // - Should also start offline job JOB(2) because real-time queue is empty.
298 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(0)));
Chong Zhangacb33502020-04-20 11:04:48 -0700299 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
300 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(3)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700301}
302
303TEST_F(TranscodingJobSchedulerTest, TestFinishJob) {
304 ALOGD("TestFinishJob");
305
Chong Zhangacb33502020-04-20 11:04:48 -0700306 // Start with unspecified top UID.
307 // Finish without any jobs submitted, should be ignored.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700308 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700309 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700310
311 // Submit offline job JOB(0), should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700312 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700313 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700314
315 // Submit real-time job JOB(1), should pause offline job and start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700316 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700317 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
318 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700319
320 // Submit real-time job JOB(2), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700321 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700322 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700323
Chong Zhangacb33502020-04-20 11:04:48 -0700324 // Finish when the job never started, should be ignored.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700325 mScheduler->onFinish(CLIENT(0), JOB(2));
Chong Zhangacb33502020-04-20 11:04:48 -0700326 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700327
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700328 // UID(1) moves to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700329 mUidPolicy->setTop(UID(1));
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700330 // Submit real-time job to CLIENT(1) in UID(1), should pause previous job and start new job.
331 mScheduler->submit(CLIENT(1), JOB(0), UID(1), mRealtimeRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700332 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
333 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700334
Chong Zhangacb33502020-04-20 11:04:48 -0700335 // Simulate Finish that arrived late, after pause issued by scheduler.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700336 // Should still be propagated to client, but shouldn't trigger any new start.
337 mScheduler->onFinish(CLIENT(0), JOB(1));
Chong Zhangacb33502020-04-20 11:04:48 -0700338 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700339
Chong Zhangacb33502020-04-20 11:04:48 -0700340 // Finish running real-time job, should start next real-time job in queue.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700341 mScheduler->onFinish(CLIENT(1), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700342 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(1), JOB(0)));
343 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(2)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700344
Chong Zhangacb33502020-04-20 11:04:48 -0700345 // Finish running real-time job, should resume next job (offline job) in queue.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700346 mScheduler->onFinish(CLIENT(0), JOB(2));
Chong Zhangacb33502020-04-20 11:04:48 -0700347 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(2)));
348 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700349
Chong Zhangacb33502020-04-20 11:04:48 -0700350 // Finish running offline job.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700351 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700352 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700353
Chong Zhangacb33502020-04-20 11:04:48 -0700354 // Duplicate finish for last job, should be ignored.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700355 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700356 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700357}
358
359TEST_F(TranscodingJobSchedulerTest, TestFailJob) {
360 ALOGD("TestFailJob");
361
Chong Zhangacb33502020-04-20 11:04:48 -0700362 // Start with unspecified top UID.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700363 // Fail without any jobs submitted, should be ignored.
364 mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700365 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700366
367 // Submit offline job JOB(0), should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700368 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700369 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700370
371 // Submit real-time job JOB(1), should pause offline job and start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700372 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700373 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
374 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700375
376 // Submit real-time job JOB(2), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700377 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700378 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700379
380 // Fail when the job never started, should be ignored.
381 mScheduler->onError(CLIENT(0), JOB(2), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700382 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700383
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700384 // UID(1) moves to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700385 mUidPolicy->setTop(UID(1));
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700386 // Submit real-time job to CLIENT(1) in UID(1), should pause previous job and start new job.
387 mScheduler->submit(CLIENT(1), JOB(0), UID(1), mRealtimeRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700388 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
389 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700390
391 // Simulate Fail that arrived late, after pause issued by scheduler.
392 // Should still be propagated to client, but shouldn't trigger any new start.
393 mScheduler->onError(CLIENT(0), JOB(1), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700394 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700395
396 // Fail running real-time job, should start next real-time job in queue.
397 mScheduler->onError(CLIENT(1), JOB(0), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700398 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(1), JOB(0)));
399 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(2)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700400
401 // Fail running real-time job, should resume next job (offline job) in queue.
402 mScheduler->onError(CLIENT(0), JOB(2), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700403 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(2)));
404 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700405
406 // Fail running offline job, and test error code propagation.
407 mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kInvalidBitstream);
Chong Zhangacb33502020-04-20 11:04:48 -0700408 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(0)));
409 EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kInvalidBitstream);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700410
411 // Duplicate fail for last job, should be ignored.
412 mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700413 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700414}
415
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700416TEST_F(TranscodingJobSchedulerTest, TestTopUidChanged) {
417 ALOGD("TestTopUidChanged");
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700418
Chong Zhangacb33502020-04-20 11:04:48 -0700419 // Start with unspecified top UID.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700420 // Submit real-time job to CLIENT(0), job should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700421 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700422 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700423
424 // Submit offline job to CLIENT(0), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700425 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700426 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700427
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700428 // Move UID(1) to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700429 mUidPolicy->setTop(UID(1));
430 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
431
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700432 // Submit real-time job to CLIENT(2) in different uid UID(1).
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700433 // Should pause previous job and start new job.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700434 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700435 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
436 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700437
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700438 // Bring UID(0) back to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700439 mUidPolicy->setTop(UID(0));
440 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
441 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700442
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700443 // Bring invalid uid to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700444 mUidPolicy->setTop(kInvalidUid);
445 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700446
447 // Finish job, next real-time job should resume.
448 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700449 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
450 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700451
452 // Finish job, offline job should start.
453 mScheduler->onFinish(CLIENT(2), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700454 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(2), JOB(0)));
455 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
456}
457
458TEST_F(TranscodingJobSchedulerTest, TestTopUidSetChanged) {
459 ALOGD("TestTopUidChanged_MultipleUids");
460
461 // Start with unspecified top UID.
462 // Submit real-time job to CLIENT(0), job should start immediately.
463 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
464 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
465
466 // Submit offline job to CLIENT(0), should not start.
467 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
468 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
469
470 // Set UID(0), UID(1) to top set.
471 // UID(0) should continue to run.
472 mUidPolicy->setTop({UID(0), UID(1)});
473 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
474
475 // Submit real-time job to CLIENT(2) in different uid UID(1).
476 // UID(0) should pause and UID(1) should start.
477 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
478 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
479 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
480
481 // Remove UID(0) from top set, and only leave UID(1) in the set.
482 // UID(1) should continue to run.
483 mUidPolicy->setTop(UID(1));
484 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
485
486 // Set UID(0), UID(2) to top set.
487 // UID(1) should continue to run.
488 mUidPolicy->setTop({UID(1), UID(2)});
489 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
490
491 // Bring UID(0) back to top.
492 mUidPolicy->setTop(UID(0));
493 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
494 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
495
496 // Bring invalid uid to top.
497 mUidPolicy->setTop(kInvalidUid);
498 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
499
500 // Finish job, next real-time job from UID(1) should resume, even if UID(1) no longer top.
501 mScheduler->onFinish(CLIENT(0), JOB(0));
502 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
503 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
504
505 // Finish job, offline job should start.
506 mScheduler->onFinish(CLIENT(2), JOB(0));
507 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(2), JOB(0)));
508 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700509}
510
511TEST_F(TranscodingJobSchedulerTest, TestResourceLost) {
512 ALOGD("TestResourceLost");
513
Chong Zhangacb33502020-04-20 11:04:48 -0700514 // Start with unspecified top UID.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700515 // Submit real-time job to CLIENT(0), job should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700516 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700517 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700518
519 // Submit offline job to CLIENT(0), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700520 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700521 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700522
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700523 // Move UID(1) to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700524 mUidPolicy->setTop(UID(1));
525 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700526
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700527 // Submit real-time job to CLIENT(2) in different uid UID(1).
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700528 // Should pause previous job and start new job.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700529 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700530 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
531 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700532
533 // Test 1: No queue change during resource loss.
534 // Signal resource lost.
535 mScheduler->onResourceLost();
Chong Zhangacb33502020-04-20 11:04:48 -0700536 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700537
538 // Signal resource available, CLIENT(2) should resume.
539 mScheduler->onResourceAvailable();
Chong Zhangacb33502020-04-20 11:04:48 -0700540 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700541
542 // Test 2: Change of queue order during resource loss.
543 // Signal resource lost.
544 mScheduler->onResourceLost();
Chong Zhangacb33502020-04-20 11:04:48 -0700545 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700546
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700547 // Move UID(0) back to top, should have no resume due to no resource.
Chong Zhangacb33502020-04-20 11:04:48 -0700548 mUidPolicy->setTop(UID(0));
549 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700550
551 // Signal resource available, CLIENT(0) should resume.
552 mScheduler->onResourceAvailable();
Chong Zhangacb33502020-04-20 11:04:48 -0700553 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700554
555 // Test 3: Adding new queue during resource loss.
556 // Signal resource lost.
557 mScheduler->onResourceLost();
Chong Zhangacb33502020-04-20 11:04:48 -0700558 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700559
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700560 // Move UID(2) to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700561 mUidPolicy->setTop(UID(2));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700562
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700563 // Submit real-time job to CLIENT(3) in UID(2), job shouldn't start due to no resource.
564 mScheduler->submit(CLIENT(3), JOB(0), UID(2), mRealtimeRequest, mClientCallback3);
Chong Zhangacb33502020-04-20 11:04:48 -0700565 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700566
567 // Signal resource available, CLIENT(3)'s job should start.
568 mScheduler->onResourceAvailable();
Chong Zhangacb33502020-04-20 11:04:48 -0700569 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(3), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700570}
571
572} // namespace android