blob: adb16a21c7f8ce75b089cb8c8f0acb12b6a71eba [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
Chong Zhang75222182020-04-29 14:43:42 -070087 void setCallback(const std::shared_ptr<TranscoderCallbackInterface>& /*cb*/) override {}
88
Chong Zhang6d58e4b2020-03-31 09:41:10 -070089 void start(int64_t clientId, int32_t jobId) override {
90 mEventQueue.push_back(Start(clientId, jobId));
91 }
92 void pause(int64_t clientId, int32_t jobId) override {
93 mEventQueue.push_back(Pause(clientId, jobId));
94 }
95 void resume(int64_t clientId, int32_t jobId) override {
96 mEventQueue.push_back(Resume(clientId, jobId));
97 }
98
Chong Zhang6d58e4b2020-03-31 09:41:10 -070099 void onFinished(int64_t clientId, int32_t jobId) {
100 mEventQueue.push_back(Finished(clientId, jobId));
101 }
102
103 void onFailed(int64_t clientId, int32_t jobId, TranscodingErrorCode err) {
104 mLastError = err;
105 mEventQueue.push_back(Failed(clientId, jobId));
106 }
107
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700108 TranscodingErrorCode getLastError() {
109 TranscodingErrorCode result = mLastError;
110 mLastError = TranscodingErrorCode::kUnknown;
111 return result;
112 }
113
114 struct Event {
115 enum { NoEvent, Start, Pause, Resume, Finished, Failed } type;
116 int64_t clientId;
117 int32_t jobId;
118 };
119
120 static constexpr Event NoEvent = {Event::NoEvent, 0, 0};
121
122#define DECLARE_EVENT(action) \
123 static Event action(int64_t clientId, int32_t jobId) { \
124 return {Event::action, clientId, jobId}; \
125 }
126
127 DECLARE_EVENT(Start);
128 DECLARE_EVENT(Pause);
129 DECLARE_EVENT(Resume);
130 DECLARE_EVENT(Finished);
131 DECLARE_EVENT(Failed);
132
133 const Event& popEvent() {
134 if (mEventQueue.empty()) {
135 mPoppedEvent = NoEvent;
136 } else {
137 mPoppedEvent = *mEventQueue.begin();
138 mEventQueue.pop_front();
139 }
140 return mPoppedEvent;
141 }
142
143private:
144 Event mPoppedEvent;
145 std::list<Event> mEventQueue;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700146 TranscodingErrorCode mLastError;
147};
148
Chong Zhangacb33502020-04-20 11:04:48 -0700149bool operator==(const TestTranscoder::Event& lhs, const TestTranscoder::Event& rhs) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700150 return lhs.type == rhs.type && lhs.clientId == rhs.clientId && lhs.jobId == rhs.jobId;
151}
152
153struct TestClientCallback : public BnTranscodingClientCallback {
Chong Zhangacb33502020-04-20 11:04:48 -0700154 TestClientCallback(TestTranscoder* owner, int64_t clientId)
155 : mOwner(owner), mClientId(clientId) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700156 ALOGD("TestClient Created");
157 }
158
159 Status onTranscodingFinished(int32_t in_jobId,
160 const TranscodingResultParcel& in_result) override {
161 EXPECT_EQ(in_jobId, in_result.jobId);
Chong Zhang75222182020-04-29 14:43:42 -0700162 ALOGD("TestClientCallback: received onTranscodingFinished");
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700163 mOwner->onFinished(mClientId, in_jobId);
164 return Status::ok();
165 }
166
167 Status onTranscodingFailed(int32_t in_jobId, TranscodingErrorCode in_errorCode) override {
168 mOwner->onFailed(mClientId, in_jobId, in_errorCode);
169 return Status::ok();
170 }
171
172 Status onAwaitNumberOfJobsChanged(int32_t /* in_jobId */, int32_t /* in_oldAwaitNumber */,
173 int32_t /* in_newAwaitNumber */) override {
174 return Status::ok();
175 }
176
177 Status onProgressUpdate(int32_t /* in_jobId */, int32_t /* in_progress */) override {
178 return Status::ok();
179 }
180
181 virtual ~TestClientCallback() { ALOGI("TestClient destroyed"); };
182
183private:
Chong Zhangacb33502020-04-20 11:04:48 -0700184 TestTranscoder* mOwner;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700185 int64_t mClientId;
186 TestClientCallback(const TestClientCallback&) = delete;
187 TestClientCallback& operator=(const TestClientCallback&) = delete;
188};
189
190class TranscodingJobSchedulerTest : public ::testing::Test {
191public:
192 TranscodingJobSchedulerTest() { ALOGI("TranscodingJobSchedulerTest created"); }
193
194 void SetUp() override {
195 ALOGI("TranscodingJobSchedulerTest set up");
Chong Zhangacb33502020-04-20 11:04:48 -0700196 mTranscoder.reset(new TestTranscoder());
197 mUidPolicy.reset(new TestUidPolicy());
198 mScheduler.reset(new TranscodingJobScheduler(mTranscoder, mUidPolicy));
199 mUidPolicy->setCallback(mScheduler);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700200
201 // Set priority only, ignore other fields for now.
202 mOfflineRequest.priority = TranscodingJobPriority::kUnspecified;
203 mRealtimeRequest.priority = TranscodingJobPriority::kHigh;
204 mClientCallback0 =
Chong Zhangacb33502020-04-20 11:04:48 -0700205 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(0));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700206 mClientCallback1 =
Chong Zhangacb33502020-04-20 11:04:48 -0700207 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(1));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700208 mClientCallback2 =
Chong Zhangacb33502020-04-20 11:04:48 -0700209 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(2));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700210 mClientCallback3 =
Chong Zhangacb33502020-04-20 11:04:48 -0700211 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(3));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700212 }
213
214 void TearDown() override { ALOGI("TranscodingJobSchedulerTest tear down"); }
215
216 ~TranscodingJobSchedulerTest() { ALOGD("TranscodingJobSchedulerTest destroyed"); }
217
Chong Zhangacb33502020-04-20 11:04:48 -0700218 std::shared_ptr<TestTranscoder> mTranscoder;
219 std::shared_ptr<TestUidPolicy> mUidPolicy;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700220 std::shared_ptr<TranscodingJobScheduler> mScheduler;
221 TranscodingRequestParcel mOfflineRequest;
222 TranscodingRequestParcel mRealtimeRequest;
223 std::shared_ptr<TestClientCallback> mClientCallback0;
224 std::shared_ptr<TestClientCallback> mClientCallback1;
225 std::shared_ptr<TestClientCallback> mClientCallback2;
226 std::shared_ptr<TestClientCallback> mClientCallback3;
227};
228
229TEST_F(TranscodingJobSchedulerTest, TestSubmitJob) {
230 ALOGD("TestSubmitJob");
231
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700232 // Start with UID(1) on top.
Chong Zhangacb33502020-04-20 11:04:48 -0700233 mUidPolicy->setTop(UID(1));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700234
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700235 // Submit offline job to CLIENT(0) in UID(0).
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700236 // Should start immediately (because this is the only job).
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700237 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700238 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), 0));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700239
240 // Submit real-time job to CLIENT(0).
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700241 // Should pause offline job and start new job, even if UID(0) is not on top.
242 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700243 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
244 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700245
246 // Submit real-time job to CLIENT(0), should be queued after the previous job.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700247 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700248 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700249
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700250 // Submit real-time job to CLIENT(1) in same uid, should be queued after the previous job.
251 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mRealtimeRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700252 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700253
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700254 // Submit real-time job to CLIENT(2) in UID(1).
Chong Zhangacb33502020-04-20 11:04:48 -0700255 // Should pause previous job and start new job, because UID(1) is (has been) top.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700256 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700257 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
258 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700259
260 // Submit offline job, shouldn't generate any event.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700261 mScheduler->submit(CLIENT(2), JOB(1), UID(1), mOfflineRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700262 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700263
Chong Zhangacb33502020-04-20 11:04:48 -0700264 // Bring UID(0) to top.
265 mUidPolicy->setTop(UID(0));
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700266 // Should pause current job, and resume last job in UID(0).
Chong Zhangacb33502020-04-20 11:04:48 -0700267 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
268 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700269}
270
271TEST_F(TranscodingJobSchedulerTest, TestCancelJob) {
272 ALOGD("TestCancelJob");
273
274 // Submit real-time job JOB(0), should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700275 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700276 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700277
278 // Submit real-time job JOB(1), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700279 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700280 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700281
282 // Submit offline job JOB(2), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700283 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700284 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700285
286 // Cancel queued real-time job.
287 // Cancel real-time job JOB(1), should be cancelled.
288 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(1)));
289
290 // Cancel queued offline job.
291 // Cancel offline job JOB(2), should be cancelled.
292 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(2)));
293
294 // Submit offline job JOB(3), shouldn't cause any event.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700295 mScheduler->submit(CLIENT(0), JOB(3), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700296 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700297
298 // Cancel running real-time job JOB(0).
299 // - Should be paused first then cancelled.
300 // - Should also start offline job JOB(2) because real-time queue is empty.
301 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(0)));
Chong Zhangacb33502020-04-20 11:04:48 -0700302 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
303 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(3)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700304}
305
306TEST_F(TranscodingJobSchedulerTest, TestFinishJob) {
307 ALOGD("TestFinishJob");
308
Chong Zhangacb33502020-04-20 11:04:48 -0700309 // Start with unspecified top UID.
310 // Finish without any jobs submitted, should be ignored.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700311 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700312 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700313
314 // Submit offline job JOB(0), should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700315 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700316 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700317
318 // Submit real-time job JOB(1), should pause offline job and start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700319 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700320 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
321 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700322
323 // Submit real-time job JOB(2), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700324 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700325 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700326
Chong Zhangacb33502020-04-20 11:04:48 -0700327 // Finish when the job never started, should be ignored.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700328 mScheduler->onFinish(CLIENT(0), JOB(2));
Chong Zhangacb33502020-04-20 11:04:48 -0700329 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700330
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700331 // UID(1) moves to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700332 mUidPolicy->setTop(UID(1));
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700333 // Submit real-time job to CLIENT(1) in UID(1), should pause previous job and start new job.
334 mScheduler->submit(CLIENT(1), JOB(0), UID(1), mRealtimeRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700335 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
336 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700337
Chong Zhangacb33502020-04-20 11:04:48 -0700338 // Simulate Finish that arrived late, after pause issued by scheduler.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700339 // Should still be propagated to client, but shouldn't trigger any new start.
340 mScheduler->onFinish(CLIENT(0), JOB(1));
Chong Zhangacb33502020-04-20 11:04:48 -0700341 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700342
Chong Zhangacb33502020-04-20 11:04:48 -0700343 // Finish running real-time job, should start next real-time job in queue.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700344 mScheduler->onFinish(CLIENT(1), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700345 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(1), JOB(0)));
346 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(2)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700347
Chong Zhangacb33502020-04-20 11:04:48 -0700348 // Finish running real-time job, should resume next job (offline job) in queue.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700349 mScheduler->onFinish(CLIENT(0), JOB(2));
Chong Zhangacb33502020-04-20 11:04:48 -0700350 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(2)));
351 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700352
Chong Zhangacb33502020-04-20 11:04:48 -0700353 // Finish running offline job.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700354 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700355 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700356
Chong Zhangacb33502020-04-20 11:04:48 -0700357 // Duplicate finish for last job, should be ignored.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700358 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700359 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700360}
361
362TEST_F(TranscodingJobSchedulerTest, TestFailJob) {
363 ALOGD("TestFailJob");
364
Chong Zhangacb33502020-04-20 11:04:48 -0700365 // Start with unspecified top UID.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700366 // Fail without any jobs submitted, should be ignored.
367 mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700368 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700369
370 // Submit offline job JOB(0), should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700371 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700372 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700373
374 // Submit real-time job JOB(1), should pause offline job and start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700375 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700376 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
377 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700378
379 // Submit real-time job JOB(2), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700380 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700381 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700382
383 // Fail when the job never started, should be ignored.
384 mScheduler->onError(CLIENT(0), JOB(2), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700385 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700386
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700387 // UID(1) moves to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700388 mUidPolicy->setTop(UID(1));
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700389 // Submit real-time job to CLIENT(1) in UID(1), should pause previous job and start new job.
390 mScheduler->submit(CLIENT(1), JOB(0), UID(1), mRealtimeRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700391 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
392 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700393
394 // Simulate Fail that arrived late, after pause issued by scheduler.
395 // Should still be propagated to client, but shouldn't trigger any new start.
396 mScheduler->onError(CLIENT(0), JOB(1), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700397 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700398
399 // Fail running real-time job, should start next real-time job in queue.
400 mScheduler->onError(CLIENT(1), JOB(0), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700401 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(1), JOB(0)));
402 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(2)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700403
404 // Fail running real-time job, should resume next job (offline job) in queue.
405 mScheduler->onError(CLIENT(0), JOB(2), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700406 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(2)));
407 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700408
409 // Fail running offline job, and test error code propagation.
410 mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kInvalidBitstream);
Chong Zhangacb33502020-04-20 11:04:48 -0700411 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(0)));
412 EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kInvalidBitstream);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700413
414 // Duplicate fail for last job, should be ignored.
415 mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700416 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700417}
418
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700419TEST_F(TranscodingJobSchedulerTest, TestTopUidChanged) {
420 ALOGD("TestTopUidChanged");
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700421
Chong Zhangacb33502020-04-20 11:04:48 -0700422 // Start with unspecified top UID.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700423 // Submit real-time job to CLIENT(0), job should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700424 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700425 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700426
427 // Submit offline job to CLIENT(0), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700428 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700429 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700430
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700431 // Move UID(1) to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700432 mUidPolicy->setTop(UID(1));
433 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
434
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700435 // Submit real-time job to CLIENT(2) in different uid UID(1).
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700436 // Should pause previous job and start new job.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700437 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700438 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
439 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700440
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700441 // Bring UID(0) back to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700442 mUidPolicy->setTop(UID(0));
443 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
444 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700445
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700446 // Bring invalid uid to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700447 mUidPolicy->setTop(kInvalidUid);
448 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700449
450 // Finish job, next real-time job should resume.
451 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700452 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
453 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700454
455 // Finish job, offline job should start.
456 mScheduler->onFinish(CLIENT(2), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700457 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(2), JOB(0)));
458 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
459}
460
461TEST_F(TranscodingJobSchedulerTest, TestTopUidSetChanged) {
462 ALOGD("TestTopUidChanged_MultipleUids");
463
464 // Start with unspecified top UID.
465 // Submit real-time job to CLIENT(0), job should start immediately.
466 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
467 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
468
469 // Submit offline job to CLIENT(0), should not start.
470 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
471 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
472
473 // Set UID(0), UID(1) to top set.
474 // UID(0) should continue to run.
475 mUidPolicy->setTop({UID(0), UID(1)});
476 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
477
478 // Submit real-time job to CLIENT(2) in different uid UID(1).
479 // UID(0) should pause and UID(1) should start.
480 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
481 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
482 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
483
484 // Remove UID(0) from top set, and only leave UID(1) in the set.
485 // UID(1) should continue to run.
486 mUidPolicy->setTop(UID(1));
487 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
488
489 // Set UID(0), UID(2) to top set.
490 // UID(1) should continue to run.
491 mUidPolicy->setTop({UID(1), UID(2)});
492 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
493
494 // Bring UID(0) back to top.
495 mUidPolicy->setTop(UID(0));
496 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
497 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
498
499 // Bring invalid uid to top.
500 mUidPolicy->setTop(kInvalidUid);
501 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
502
503 // Finish job, next real-time job from UID(1) should resume, even if UID(1) no longer top.
504 mScheduler->onFinish(CLIENT(0), JOB(0));
505 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
506 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
507
508 // Finish job, offline job should start.
509 mScheduler->onFinish(CLIENT(2), JOB(0));
510 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(2), JOB(0)));
511 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700512}
513
514TEST_F(TranscodingJobSchedulerTest, TestResourceLost) {
515 ALOGD("TestResourceLost");
516
Chong Zhangacb33502020-04-20 11:04:48 -0700517 // Start with unspecified top UID.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700518 // Submit real-time job to CLIENT(0), job should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700519 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700520 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700521
522 // Submit offline job to CLIENT(0), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700523 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700524 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700525
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700526 // Move UID(1) to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700527 mUidPolicy->setTop(UID(1));
528 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700529
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700530 // Submit real-time job to CLIENT(2) in different uid UID(1).
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700531 // Should pause previous job and start new job.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700532 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700533 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
534 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700535
536 // Test 1: No queue change during resource loss.
537 // Signal resource lost.
538 mScheduler->onResourceLost();
Chong Zhangacb33502020-04-20 11:04:48 -0700539 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700540
541 // Signal resource available, CLIENT(2) should resume.
542 mScheduler->onResourceAvailable();
Chong Zhangacb33502020-04-20 11:04:48 -0700543 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700544
545 // Test 2: Change of queue order during resource loss.
546 // Signal resource lost.
547 mScheduler->onResourceLost();
Chong Zhangacb33502020-04-20 11:04:48 -0700548 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700549
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700550 // Move UID(0) back to top, should have no resume due to no resource.
Chong Zhangacb33502020-04-20 11:04:48 -0700551 mUidPolicy->setTop(UID(0));
552 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700553
554 // Signal resource available, CLIENT(0) should resume.
555 mScheduler->onResourceAvailable();
Chong Zhangacb33502020-04-20 11:04:48 -0700556 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700557
558 // Test 3: Adding new queue during resource loss.
559 // Signal resource lost.
560 mScheduler->onResourceLost();
Chong Zhangacb33502020-04-20 11:04:48 -0700561 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700562
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700563 // Move UID(2) to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700564 mUidPolicy->setTop(UID(2));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700565
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700566 // Submit real-time job to CLIENT(3) in UID(2), job shouldn't start due to no resource.
567 mScheduler->submit(CLIENT(3), JOB(0), UID(2), mRealtimeRequest, mClientCallback3);
Chong Zhangacb33502020-04-20 11:04:48 -0700568 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700569
570 // Signal resource available, CLIENT(3)'s job should start.
571 mScheduler->onResourceAvailable();
Chong Zhangacb33502020-04-20 11:04:48 -0700572 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(3), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700573}
574
575} // namespace android