blob: 25321e362851d362014267b3a2746ebd852cc251 [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;
Chong Zhang00feca22020-05-08 15:02:06 -070042using aidl::android::media::TranscodingRequestParcel;
Chong Zhang6d58e4b2020-03-31 09:41:10 -070043
Chong Zhang3fa408f2020-04-30 11:04:28 -070044constexpr ClientIdType kClientId = 1000;
45constexpr JobIdType kClientJobId = 0;
Chong Zhang7ae4e2f2020-04-17 15:24:34 -070046constexpr uid_t kClientUid = 5000;
47constexpr uid_t kInvalidUid = (uid_t)-1;
Chong Zhang6d58e4b2020-03-31 09:41:10 -070048
49#define CLIENT(n) (kClientId + (n))
50#define JOB(n) (kClientJobId + (n))
Chong Zhang7ae4e2f2020-04-17 15:24:34 -070051#define UID(n) (kClientUid + (n))
Chong Zhang6d58e4b2020-03-31 09:41:10 -070052
Chong Zhangacb33502020-04-20 11:04:48 -070053class TestUidPolicy : public UidPolicyInterface {
Chong Zhang6d58e4b2020-03-31 09:41:10 -070054public:
Chong Zhangacb33502020-04-20 11:04:48 -070055 TestUidPolicy() = default;
56 virtual ~TestUidPolicy() = default;
57
58 // UidPolicyInterface
59 void registerMonitorUid(uid_t /*uid*/) override {}
60 void unregisterMonitorUid(uid_t /*uid*/) override {}
61 bool isUidOnTop(uid_t uid) override { return mTopUids.count(uid) > 0; }
62 std::unordered_set<uid_t> getTopUids() const override { return mTopUids; }
63 void setCallback(const std::shared_ptr<UidPolicyCallbackInterface>& cb) override {
64 mUidPolicyCallback = cb;
65 }
66 void setTop(uid_t uid) {
67 std::unordered_set<uid_t> uids = {uid};
68 setTop(uids);
69 }
70 void setTop(const std::unordered_set<uid_t>& uids) {
71 mTopUids = uids;
72 auto uidPolicyCb = mUidPolicyCallback.lock();
73 if (uidPolicyCb != nullptr) {
74 uidPolicyCb->onTopUidsChanged(mTopUids);
75 }
76 }
77
78 std::unordered_set<uid_t> mTopUids;
79 std::weak_ptr<UidPolicyCallbackInterface> mUidPolicyCallback;
80};
81
82class TestTranscoder : public TranscoderInterface {
83public:
84 TestTranscoder() : mLastError(TranscodingErrorCode::kUnknown) {}
85 virtual ~TestTranscoder() {}
Chong Zhang6d58e4b2020-03-31 09:41:10 -070086
87 // TranscoderInterface
Chong Zhang75222182020-04-29 14:43:42 -070088 void setCallback(const std::shared_ptr<TranscoderCallbackInterface>& /*cb*/) override {}
89
Chong Zhang00feca22020-05-08 15:02:06 -070090 void start(ClientIdType clientId, JobIdType jobId,
91 const TranscodingRequestParcel& /*request*/) override {
Chong Zhang6d58e4b2020-03-31 09:41:10 -070092 mEventQueue.push_back(Start(clientId, jobId));
93 }
Chong Zhang3fa408f2020-04-30 11:04:28 -070094 void pause(ClientIdType clientId, JobIdType jobId) override {
Chong Zhang6d58e4b2020-03-31 09:41:10 -070095 mEventQueue.push_back(Pause(clientId, jobId));
96 }
Chong Zhang3fa408f2020-04-30 11:04:28 -070097 void resume(ClientIdType clientId, JobIdType jobId) override {
Chong Zhang6d58e4b2020-03-31 09:41:10 -070098 mEventQueue.push_back(Resume(clientId, jobId));
99 }
Chong Zhang00feca22020-05-08 15:02:06 -0700100 void stop(ClientIdType clientId, JobIdType jobId) override {
101 mEventQueue.push_back(Stop(clientId, jobId));
102 }
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700103
Chong Zhang3fa408f2020-04-30 11:04:28 -0700104 void onFinished(ClientIdType clientId, JobIdType jobId) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700105 mEventQueue.push_back(Finished(clientId, jobId));
106 }
107
Chong Zhang3fa408f2020-04-30 11:04:28 -0700108 void onFailed(ClientIdType clientId, JobIdType jobId, TranscodingErrorCode err) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700109 mLastError = err;
110 mEventQueue.push_back(Failed(clientId, jobId));
111 }
112
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700113 TranscodingErrorCode getLastError() {
114 TranscodingErrorCode result = mLastError;
115 mLastError = TranscodingErrorCode::kUnknown;
116 return result;
117 }
118
119 struct Event {
Chong Zhang00feca22020-05-08 15:02:06 -0700120 enum { NoEvent, Start, Pause, Resume, Stop, Finished, Failed } type;
Chong Zhang3fa408f2020-04-30 11:04:28 -0700121 ClientIdType clientId;
122 JobIdType jobId;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700123 };
124
125 static constexpr Event NoEvent = {Event::NoEvent, 0, 0};
126
Chong Zhang3fa408f2020-04-30 11:04:28 -0700127#define DECLARE_EVENT(action) \
128 static Event action(ClientIdType clientId, JobIdType jobId) { \
129 return {Event::action, clientId, jobId}; \
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700130 }
131
132 DECLARE_EVENT(Start);
133 DECLARE_EVENT(Pause);
134 DECLARE_EVENT(Resume);
Chong Zhang00feca22020-05-08 15:02:06 -0700135 DECLARE_EVENT(Stop);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700136 DECLARE_EVENT(Finished);
137 DECLARE_EVENT(Failed);
138
139 const Event& popEvent() {
140 if (mEventQueue.empty()) {
141 mPoppedEvent = NoEvent;
142 } else {
143 mPoppedEvent = *mEventQueue.begin();
144 mEventQueue.pop_front();
145 }
146 return mPoppedEvent;
147 }
148
149private:
150 Event mPoppedEvent;
151 std::list<Event> mEventQueue;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700152 TranscodingErrorCode mLastError;
153};
154
Chong Zhangacb33502020-04-20 11:04:48 -0700155bool operator==(const TestTranscoder::Event& lhs, const TestTranscoder::Event& rhs) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700156 return lhs.type == rhs.type && lhs.clientId == rhs.clientId && lhs.jobId == rhs.jobId;
157}
158
159struct TestClientCallback : public BnTranscodingClientCallback {
Chong Zhangacb33502020-04-20 11:04:48 -0700160 TestClientCallback(TestTranscoder* owner, int64_t clientId)
161 : mOwner(owner), mClientId(clientId) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700162 ALOGD("TestClient Created");
163 }
164
165 Status onTranscodingFinished(int32_t in_jobId,
166 const TranscodingResultParcel& in_result) override {
167 EXPECT_EQ(in_jobId, in_result.jobId);
Chong Zhang75222182020-04-29 14:43:42 -0700168 ALOGD("TestClientCallback: received onTranscodingFinished");
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700169 mOwner->onFinished(mClientId, in_jobId);
170 return Status::ok();
171 }
172
173 Status onTranscodingFailed(int32_t in_jobId, TranscodingErrorCode in_errorCode) override {
174 mOwner->onFailed(mClientId, in_jobId, in_errorCode);
175 return Status::ok();
176 }
177
178 Status onAwaitNumberOfJobsChanged(int32_t /* in_jobId */, int32_t /* in_oldAwaitNumber */,
179 int32_t /* in_newAwaitNumber */) override {
180 return Status::ok();
181 }
182
183 Status onProgressUpdate(int32_t /* in_jobId */, int32_t /* in_progress */) override {
184 return Status::ok();
185 }
186
187 virtual ~TestClientCallback() { ALOGI("TestClient destroyed"); };
188
189private:
Chong Zhangacb33502020-04-20 11:04:48 -0700190 TestTranscoder* mOwner;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700191 int64_t mClientId;
192 TestClientCallback(const TestClientCallback&) = delete;
193 TestClientCallback& operator=(const TestClientCallback&) = delete;
194};
195
196class TranscodingJobSchedulerTest : public ::testing::Test {
197public:
198 TranscodingJobSchedulerTest() { ALOGI("TranscodingJobSchedulerTest created"); }
199
200 void SetUp() override {
201 ALOGI("TranscodingJobSchedulerTest set up");
Chong Zhangacb33502020-04-20 11:04:48 -0700202 mTranscoder.reset(new TestTranscoder());
203 mUidPolicy.reset(new TestUidPolicy());
204 mScheduler.reset(new TranscodingJobScheduler(mTranscoder, mUidPolicy));
205 mUidPolicy->setCallback(mScheduler);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700206
207 // Set priority only, ignore other fields for now.
208 mOfflineRequest.priority = TranscodingJobPriority::kUnspecified;
209 mRealtimeRequest.priority = TranscodingJobPriority::kHigh;
210 mClientCallback0 =
Chong Zhangacb33502020-04-20 11:04:48 -0700211 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(0));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700212 mClientCallback1 =
Chong Zhangacb33502020-04-20 11:04:48 -0700213 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(1));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700214 mClientCallback2 =
Chong Zhangacb33502020-04-20 11:04:48 -0700215 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(2));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700216 mClientCallback3 =
Chong Zhangacb33502020-04-20 11:04:48 -0700217 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(3));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700218 }
219
220 void TearDown() override { ALOGI("TranscodingJobSchedulerTest tear down"); }
221
222 ~TranscodingJobSchedulerTest() { ALOGD("TranscodingJobSchedulerTest destroyed"); }
223
Chong Zhangacb33502020-04-20 11:04:48 -0700224 std::shared_ptr<TestTranscoder> mTranscoder;
225 std::shared_ptr<TestUidPolicy> mUidPolicy;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700226 std::shared_ptr<TranscodingJobScheduler> mScheduler;
227 TranscodingRequestParcel mOfflineRequest;
228 TranscodingRequestParcel mRealtimeRequest;
229 std::shared_ptr<TestClientCallback> mClientCallback0;
230 std::shared_ptr<TestClientCallback> mClientCallback1;
231 std::shared_ptr<TestClientCallback> mClientCallback2;
232 std::shared_ptr<TestClientCallback> mClientCallback3;
233};
234
235TEST_F(TranscodingJobSchedulerTest, TestSubmitJob) {
236 ALOGD("TestSubmitJob");
237
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700238 // Start with UID(1) on top.
Chong Zhangacb33502020-04-20 11:04:48 -0700239 mUidPolicy->setTop(UID(1));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700240
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700241 // Submit offline job to CLIENT(0) in UID(0).
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700242 // Should start immediately (because this is the only job).
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700243 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700244 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), 0));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700245
246 // Submit real-time job to CLIENT(0).
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700247 // Should pause offline job and start new job, even if UID(0) is not on top.
248 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700249 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
250 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700251
252 // Submit real-time job to CLIENT(0), should be queued after the previous job.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700253 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700254 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700255
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700256 // Submit real-time job to CLIENT(1) in same uid, should be queued after the previous job.
257 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mRealtimeRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700258 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700259
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700260 // Submit real-time job to CLIENT(2) in UID(1).
Chong Zhangacb33502020-04-20 11:04:48 -0700261 // Should pause previous job and start new job, because UID(1) is (has been) top.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700262 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700263 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
264 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700265
266 // Submit offline job, shouldn't generate any event.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700267 mScheduler->submit(CLIENT(2), JOB(1), UID(1), mOfflineRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700268 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700269
Chong Zhangacb33502020-04-20 11:04:48 -0700270 // Bring UID(0) to top.
271 mUidPolicy->setTop(UID(0));
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700272 // Should pause current job, and resume last job in UID(0).
Chong Zhangacb33502020-04-20 11:04:48 -0700273 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
274 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700275}
276
277TEST_F(TranscodingJobSchedulerTest, TestCancelJob) {
278 ALOGD("TestCancelJob");
279
280 // Submit real-time job JOB(0), should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700281 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700282 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700283
284 // Submit real-time job JOB(1), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700285 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700286 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700287
288 // Submit offline job JOB(2), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700289 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700290 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700291
292 // Cancel queued real-time job.
293 // Cancel real-time job JOB(1), should be cancelled.
294 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(1)));
295
296 // Cancel queued offline job.
297 // Cancel offline job JOB(2), should be cancelled.
298 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(2)));
299
300 // Submit offline job JOB(3), shouldn't cause any event.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700301 mScheduler->submit(CLIENT(0), JOB(3), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700302 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700303
304 // Cancel running real-time job JOB(0).
Chong Zhang00feca22020-05-08 15:02:06 -0700305 // - Should be stopped first then cancelled.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700306 // - Should also start offline job JOB(2) because real-time queue is empty.
307 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(0)));
Chong Zhang00feca22020-05-08 15:02:06 -0700308 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Stop(CLIENT(0), JOB(0)));
Chong Zhangacb33502020-04-20 11:04:48 -0700309 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(3)));
Chong Zhang00feca22020-05-08 15:02:06 -0700310
311 // Submit real-time job JOB(4), offline JOB(3) should pause and JOB(4) should start.
312 mScheduler->submit(CLIENT(0), JOB(4), UID(0), mRealtimeRequest, mClientCallback0);
313 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(3)));
314 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(4)));
315
316 // Cancel paused JOB(3). JOB(3) should be stopped.
317 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(3)));
318 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Stop(CLIENT(0), JOB(3)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700319}
320
321TEST_F(TranscodingJobSchedulerTest, TestFinishJob) {
322 ALOGD("TestFinishJob");
323
Chong Zhangacb33502020-04-20 11:04:48 -0700324 // Start with unspecified top UID.
325 // Finish without any jobs submitted, should be ignored.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700326 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700327 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700328
329 // Submit offline job JOB(0), should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700330 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700331 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700332
333 // Submit real-time job JOB(1), should pause offline job and start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700334 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700335 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
336 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700337
338 // Submit real-time job JOB(2), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700339 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700340 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700341
Chong Zhangacb33502020-04-20 11:04:48 -0700342 // Finish when the job never started, should be ignored.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700343 mScheduler->onFinish(CLIENT(0), JOB(2));
Chong Zhangacb33502020-04-20 11:04:48 -0700344 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700345
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700346 // UID(1) moves to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700347 mUidPolicy->setTop(UID(1));
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700348 // Submit real-time job to CLIENT(1) in UID(1), should pause previous job and start new job.
349 mScheduler->submit(CLIENT(1), JOB(0), UID(1), mRealtimeRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700350 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
351 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700352
Chong Zhangacb33502020-04-20 11:04:48 -0700353 // Simulate Finish that arrived late, after pause issued by scheduler.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700354 // Should still be propagated to client, but shouldn't trigger any new start.
355 mScheduler->onFinish(CLIENT(0), JOB(1));
Chong Zhangacb33502020-04-20 11:04:48 -0700356 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700357
Chong Zhangacb33502020-04-20 11:04:48 -0700358 // Finish running real-time job, should start next real-time job in queue.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700359 mScheduler->onFinish(CLIENT(1), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700360 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(1), JOB(0)));
361 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(2)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700362
Chong Zhangacb33502020-04-20 11:04:48 -0700363 // Finish running real-time job, should resume next job (offline job) in queue.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700364 mScheduler->onFinish(CLIENT(0), JOB(2));
Chong Zhangacb33502020-04-20 11:04:48 -0700365 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(2)));
366 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700367
Chong Zhangacb33502020-04-20 11:04:48 -0700368 // Finish running offline job.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700369 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700370 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700371
Chong Zhangacb33502020-04-20 11:04:48 -0700372 // Duplicate finish for last job, should be ignored.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700373 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700374 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700375}
376
377TEST_F(TranscodingJobSchedulerTest, TestFailJob) {
378 ALOGD("TestFailJob");
379
Chong Zhangacb33502020-04-20 11:04:48 -0700380 // Start with unspecified top UID.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700381 // Fail without any jobs submitted, should be ignored.
382 mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700383 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700384
385 // Submit offline job JOB(0), should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700386 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700387 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700388
389 // Submit real-time job JOB(1), should pause offline job and start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700390 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700391 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
392 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700393
394 // Submit real-time job JOB(2), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700395 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700396 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700397
398 // Fail when the job never started, should be ignored.
399 mScheduler->onError(CLIENT(0), JOB(2), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700400 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700401
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700402 // UID(1) moves to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700403 mUidPolicy->setTop(UID(1));
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700404 // Submit real-time job to CLIENT(1) in UID(1), should pause previous job and start new job.
405 mScheduler->submit(CLIENT(1), JOB(0), UID(1), mRealtimeRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700406 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
407 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700408
409 // Simulate Fail that arrived late, after pause issued by scheduler.
410 // Should still be propagated to client, but shouldn't trigger any new start.
411 mScheduler->onError(CLIENT(0), JOB(1), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700412 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700413
414 // Fail running real-time job, should start next real-time job in queue.
415 mScheduler->onError(CLIENT(1), JOB(0), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700416 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(1), JOB(0)));
417 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(2)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700418
419 // Fail running real-time job, should resume next job (offline job) in queue.
420 mScheduler->onError(CLIENT(0), JOB(2), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700421 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(2)));
422 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700423
424 // Fail running offline job, and test error code propagation.
425 mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kInvalidBitstream);
Chong Zhangacb33502020-04-20 11:04:48 -0700426 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(0)));
427 EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kInvalidBitstream);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700428
429 // Duplicate fail for last job, should be ignored.
430 mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700431 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700432}
433
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700434TEST_F(TranscodingJobSchedulerTest, TestTopUidChanged) {
435 ALOGD("TestTopUidChanged");
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700436
Chong Zhangacb33502020-04-20 11:04:48 -0700437 // Start with unspecified top UID.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700438 // Submit real-time job to CLIENT(0), job should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700439 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700440 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700441
442 // Submit offline job to CLIENT(0), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700443 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700444 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700445
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700446 // Move UID(1) to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700447 mUidPolicy->setTop(UID(1));
448 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
449
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700450 // Submit real-time job to CLIENT(2) in different uid UID(1).
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700451 // Should pause previous job and start new job.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700452 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700453 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
454 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700455
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700456 // Bring UID(0) back to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700457 mUidPolicy->setTop(UID(0));
458 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
459 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700460
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700461 // Bring invalid uid to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700462 mUidPolicy->setTop(kInvalidUid);
463 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700464
465 // Finish job, next real-time job should resume.
466 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700467 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
468 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700469
470 // Finish job, offline job should start.
471 mScheduler->onFinish(CLIENT(2), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700472 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(2), JOB(0)));
473 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
474}
475
476TEST_F(TranscodingJobSchedulerTest, TestTopUidSetChanged) {
477 ALOGD("TestTopUidChanged_MultipleUids");
478
479 // Start with unspecified top UID.
480 // Submit real-time job to CLIENT(0), job should start immediately.
481 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
482 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
483
484 // Submit offline job to CLIENT(0), should not start.
485 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
486 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
487
488 // Set UID(0), UID(1) to top set.
489 // UID(0) should continue to run.
490 mUidPolicy->setTop({UID(0), UID(1)});
491 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
492
493 // Submit real-time job to CLIENT(2) in different uid UID(1).
494 // UID(0) should pause and UID(1) should start.
495 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
496 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
497 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
498
499 // Remove UID(0) from top set, and only leave UID(1) in the set.
500 // UID(1) should continue to run.
501 mUidPolicy->setTop(UID(1));
502 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
503
504 // Set UID(0), UID(2) to top set.
505 // UID(1) should continue to run.
506 mUidPolicy->setTop({UID(1), UID(2)});
507 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
508
509 // Bring UID(0) back to top.
510 mUidPolicy->setTop(UID(0));
511 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
512 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
513
514 // Bring invalid uid to top.
515 mUidPolicy->setTop(kInvalidUid);
516 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
517
518 // Finish job, next real-time job from UID(1) should resume, even if UID(1) no longer top.
519 mScheduler->onFinish(CLIENT(0), JOB(0));
520 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
521 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
522
523 // Finish job, offline job should start.
524 mScheduler->onFinish(CLIENT(2), JOB(0));
525 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(2), JOB(0)));
526 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700527}
528
529TEST_F(TranscodingJobSchedulerTest, TestResourceLost) {
530 ALOGD("TestResourceLost");
531
Chong Zhangacb33502020-04-20 11:04:48 -0700532 // Start with unspecified top UID.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700533 // Submit real-time job to CLIENT(0), job should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700534 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700535 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700536
537 // Submit offline job to CLIENT(0), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700538 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700539 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700540
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700541 // Move UID(1) to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700542 mUidPolicy->setTop(UID(1));
543 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700544
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700545 // Submit real-time job to CLIENT(2) in different uid UID(1).
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700546 // Should pause previous job and start new job.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700547 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700548 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
549 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700550
551 // Test 1: No queue change during resource loss.
552 // Signal resource lost.
553 mScheduler->onResourceLost();
Chong Zhangacb33502020-04-20 11:04:48 -0700554 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700555
556 // Signal resource available, CLIENT(2) should resume.
557 mScheduler->onResourceAvailable();
Chong Zhangacb33502020-04-20 11:04:48 -0700558 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700559
560 // Test 2: Change of queue order during resource loss.
561 // Signal resource lost.
562 mScheduler->onResourceLost();
Chong Zhangacb33502020-04-20 11:04:48 -0700563 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700564
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700565 // Move UID(0) back to top, should have no resume due to no resource.
Chong Zhangacb33502020-04-20 11:04:48 -0700566 mUidPolicy->setTop(UID(0));
567 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700568
569 // Signal resource available, CLIENT(0) should resume.
570 mScheduler->onResourceAvailable();
Chong Zhangacb33502020-04-20 11:04:48 -0700571 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700572
573 // Test 3: Adding new queue during resource loss.
574 // Signal resource lost.
575 mScheduler->onResourceLost();
Chong Zhangacb33502020-04-20 11:04:48 -0700576 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700577
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700578 // Move UID(2) to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700579 mUidPolicy->setTop(UID(2));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700580
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700581 // Submit real-time job to CLIENT(3) in UID(2), job shouldn't start due to no resource.
582 mScheduler->submit(CLIENT(3), JOB(0), UID(2), mRealtimeRequest, mClientCallback3);
Chong Zhangacb33502020-04-20 11:04:48 -0700583 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700584
585 // Signal resource available, CLIENT(3)'s job should start.
586 mScheduler->onResourceAvailable();
Chong Zhangacb33502020-04-20 11:04:48 -0700587 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(3), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700588}
589
590} // namespace android