blob: d4fd4830281ae89420cd7eeb036919c02484bfb0 [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
hkuang19253092020-06-01 09:10:49 -0700165 Status openFileDescriptor(const std::string& /*in_fileUri*/, const std::string& /*in_mode*/,
166 ::ndk::ScopedFileDescriptor* /*_aidl_return*/) override {
167 return Status::ok();
168 }
169
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700170 Status onTranscodingFinished(int32_t in_jobId,
171 const TranscodingResultParcel& in_result) override {
172 EXPECT_EQ(in_jobId, in_result.jobId);
Chong Zhang75222182020-04-29 14:43:42 -0700173 ALOGD("TestClientCallback: received onTranscodingFinished");
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700174 mOwner->onFinished(mClientId, in_jobId);
175 return Status::ok();
176 }
177
178 Status onTranscodingFailed(int32_t in_jobId, TranscodingErrorCode in_errorCode) override {
179 mOwner->onFailed(mClientId, in_jobId, in_errorCode);
180 return Status::ok();
181 }
182
183 Status onAwaitNumberOfJobsChanged(int32_t /* in_jobId */, int32_t /* in_oldAwaitNumber */,
184 int32_t /* in_newAwaitNumber */) override {
185 return Status::ok();
186 }
187
188 Status onProgressUpdate(int32_t /* in_jobId */, int32_t /* in_progress */) override {
189 return Status::ok();
190 }
191
192 virtual ~TestClientCallback() { ALOGI("TestClient destroyed"); };
193
194private:
Chong Zhangacb33502020-04-20 11:04:48 -0700195 TestTranscoder* mOwner;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700196 int64_t mClientId;
197 TestClientCallback(const TestClientCallback&) = delete;
198 TestClientCallback& operator=(const TestClientCallback&) = delete;
199};
200
201class TranscodingJobSchedulerTest : public ::testing::Test {
202public:
203 TranscodingJobSchedulerTest() { ALOGI("TranscodingJobSchedulerTest created"); }
204
205 void SetUp() override {
206 ALOGI("TranscodingJobSchedulerTest set up");
Chong Zhangacb33502020-04-20 11:04:48 -0700207 mTranscoder.reset(new TestTranscoder());
208 mUidPolicy.reset(new TestUidPolicy());
209 mScheduler.reset(new TranscodingJobScheduler(mTranscoder, mUidPolicy));
210 mUidPolicy->setCallback(mScheduler);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700211
212 // Set priority only, ignore other fields for now.
213 mOfflineRequest.priority = TranscodingJobPriority::kUnspecified;
214 mRealtimeRequest.priority = TranscodingJobPriority::kHigh;
215 mClientCallback0 =
Chong Zhangacb33502020-04-20 11:04:48 -0700216 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(0));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700217 mClientCallback1 =
Chong Zhangacb33502020-04-20 11:04:48 -0700218 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(1));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700219 mClientCallback2 =
Chong Zhangacb33502020-04-20 11:04:48 -0700220 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(2));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700221 mClientCallback3 =
Chong Zhangacb33502020-04-20 11:04:48 -0700222 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(3));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700223 }
224
225 void TearDown() override { ALOGI("TranscodingJobSchedulerTest tear down"); }
226
227 ~TranscodingJobSchedulerTest() { ALOGD("TranscodingJobSchedulerTest destroyed"); }
228
Chong Zhangacb33502020-04-20 11:04:48 -0700229 std::shared_ptr<TestTranscoder> mTranscoder;
230 std::shared_ptr<TestUidPolicy> mUidPolicy;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700231 std::shared_ptr<TranscodingJobScheduler> mScheduler;
232 TranscodingRequestParcel mOfflineRequest;
233 TranscodingRequestParcel mRealtimeRequest;
234 std::shared_ptr<TestClientCallback> mClientCallback0;
235 std::shared_ptr<TestClientCallback> mClientCallback1;
236 std::shared_ptr<TestClientCallback> mClientCallback2;
237 std::shared_ptr<TestClientCallback> mClientCallback3;
238};
239
240TEST_F(TranscodingJobSchedulerTest, TestSubmitJob) {
241 ALOGD("TestSubmitJob");
242
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700243 // Start with UID(1) on top.
Chong Zhangacb33502020-04-20 11:04:48 -0700244 mUidPolicy->setTop(UID(1));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700245
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700246 // Submit offline job to CLIENT(0) in UID(0).
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700247 // Should start immediately (because this is the only job).
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700248 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700249 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), 0));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700250
251 // Submit real-time job to CLIENT(0).
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700252 // Should pause offline job and start new job, even if UID(0) is not on top.
253 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700254 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
255 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700256
257 // Submit real-time job to CLIENT(0), should be queued after the previous job.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700258 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700259 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700260
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700261 // Submit real-time job to CLIENT(1) in same uid, should be queued after the previous job.
262 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mRealtimeRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700263 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700264
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700265 // Submit real-time job to CLIENT(2) in UID(1).
Chong Zhangacb33502020-04-20 11:04:48 -0700266 // Should pause previous job and start new job, because UID(1) is (has been) top.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700267 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700268 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
269 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700270
271 // Submit offline job, shouldn't generate any event.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700272 mScheduler->submit(CLIENT(2), JOB(1), UID(1), mOfflineRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700273 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700274
Chong Zhangacb33502020-04-20 11:04:48 -0700275 // Bring UID(0) to top.
276 mUidPolicy->setTop(UID(0));
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700277 // Should pause current job, and resume last job in UID(0).
Chong Zhangacb33502020-04-20 11:04:48 -0700278 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
279 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700280}
281
282TEST_F(TranscodingJobSchedulerTest, TestCancelJob) {
283 ALOGD("TestCancelJob");
284
285 // Submit real-time job JOB(0), should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700286 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700287 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700288
289 // Submit real-time job JOB(1), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700290 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700291 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700292
293 // Submit offline job JOB(2), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700294 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700295 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700296
297 // Cancel queued real-time job.
298 // Cancel real-time job JOB(1), should be cancelled.
299 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(1)));
300
301 // Cancel queued offline job.
302 // Cancel offline job JOB(2), should be cancelled.
303 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(2)));
304
305 // Submit offline job JOB(3), shouldn't cause any event.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700306 mScheduler->submit(CLIENT(0), JOB(3), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700307 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700308
309 // Cancel running real-time job JOB(0).
Chong Zhang00feca22020-05-08 15:02:06 -0700310 // - Should be stopped first then cancelled.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700311 // - Should also start offline job JOB(2) because real-time queue is empty.
312 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(0)));
Chong Zhang00feca22020-05-08 15:02:06 -0700313 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Stop(CLIENT(0), JOB(0)));
Chong Zhangacb33502020-04-20 11:04:48 -0700314 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(3)));
Chong Zhang00feca22020-05-08 15:02:06 -0700315
316 // Submit real-time job JOB(4), offline JOB(3) should pause and JOB(4) should start.
317 mScheduler->submit(CLIENT(0), JOB(4), UID(0), mRealtimeRequest, mClientCallback0);
318 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(3)));
319 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(4)));
320
321 // Cancel paused JOB(3). JOB(3) should be stopped.
322 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(3)));
323 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Stop(CLIENT(0), JOB(3)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700324}
325
326TEST_F(TranscodingJobSchedulerTest, TestFinishJob) {
327 ALOGD("TestFinishJob");
328
Chong Zhangacb33502020-04-20 11:04:48 -0700329 // Start with unspecified top UID.
330 // Finish without any jobs submitted, should be ignored.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700331 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700332 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700333
334 // Submit offline job JOB(0), should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700335 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700336 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700337
338 // Submit real-time job JOB(1), should pause offline job and start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700339 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700340 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
341 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700342
343 // Submit real-time job JOB(2), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700344 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700345 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700346
Chong Zhangacb33502020-04-20 11:04:48 -0700347 // Finish when the job never started, should be ignored.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700348 mScheduler->onFinish(CLIENT(0), JOB(2));
Chong Zhangacb33502020-04-20 11:04:48 -0700349 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700350
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700351 // UID(1) moves to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700352 mUidPolicy->setTop(UID(1));
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700353 // Submit real-time job to CLIENT(1) in UID(1), should pause previous job and start new job.
354 mScheduler->submit(CLIENT(1), JOB(0), UID(1), mRealtimeRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700355 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
356 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700357
Chong Zhangacb33502020-04-20 11:04:48 -0700358 // Simulate Finish that arrived late, after pause issued by scheduler.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700359 // Should still be propagated to client, but shouldn't trigger any new start.
360 mScheduler->onFinish(CLIENT(0), JOB(1));
Chong Zhangacb33502020-04-20 11:04:48 -0700361 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700362
Chong Zhangacb33502020-04-20 11:04:48 -0700363 // Finish running real-time job, should start next real-time job in queue.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700364 mScheduler->onFinish(CLIENT(1), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700365 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(1), JOB(0)));
366 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(2)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700367
Chong Zhangacb33502020-04-20 11:04:48 -0700368 // Finish running real-time job, should resume next job (offline job) in queue.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700369 mScheduler->onFinish(CLIENT(0), JOB(2));
Chong Zhangacb33502020-04-20 11:04:48 -0700370 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(2)));
371 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700372
Chong Zhangacb33502020-04-20 11:04:48 -0700373 // Finish running offline job.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700374 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700375 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700376
Chong Zhangacb33502020-04-20 11:04:48 -0700377 // Duplicate finish for last job, should be ignored.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700378 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700379 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700380}
381
382TEST_F(TranscodingJobSchedulerTest, TestFailJob) {
383 ALOGD("TestFailJob");
384
Chong Zhangacb33502020-04-20 11:04:48 -0700385 // Start with unspecified top UID.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700386 // Fail without any jobs submitted, should be ignored.
387 mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700388 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700389
390 // Submit offline job JOB(0), should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700391 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700392 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700393
394 // Submit real-time job JOB(1), should pause offline job and start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700395 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700396 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
397 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700398
399 // Submit real-time job JOB(2), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700400 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700401 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700402
403 // Fail when the job never started, should be ignored.
404 mScheduler->onError(CLIENT(0), JOB(2), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700405 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700406
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700407 // UID(1) moves to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700408 mUidPolicy->setTop(UID(1));
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700409 // Submit real-time job to CLIENT(1) in UID(1), should pause previous job and start new job.
410 mScheduler->submit(CLIENT(1), JOB(0), UID(1), mRealtimeRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700411 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
412 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700413
414 // Simulate Fail that arrived late, after pause issued by scheduler.
415 // Should still be propagated to client, but shouldn't trigger any new start.
416 mScheduler->onError(CLIENT(0), JOB(1), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700417 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700418
419 // Fail running real-time job, should start next real-time job in queue.
420 mScheduler->onError(CLIENT(1), JOB(0), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700421 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(1), JOB(0)));
422 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(2)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700423
424 // Fail running real-time job, should resume next job (offline job) in queue.
425 mScheduler->onError(CLIENT(0), JOB(2), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700426 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(2)));
427 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700428
429 // Fail running offline job, and test error code propagation.
430 mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kInvalidBitstream);
Chong Zhangacb33502020-04-20 11:04:48 -0700431 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(0)));
432 EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kInvalidBitstream);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700433
434 // Duplicate fail for last job, should be ignored.
435 mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700436 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700437}
438
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700439TEST_F(TranscodingJobSchedulerTest, TestTopUidChanged) {
440 ALOGD("TestTopUidChanged");
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700441
Chong Zhangacb33502020-04-20 11:04:48 -0700442 // Start with unspecified top UID.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700443 // Submit real-time job to CLIENT(0), job should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700444 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700445 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700446
447 // Submit offline job to CLIENT(0), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700448 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700449 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700450
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700451 // Move UID(1) to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700452 mUidPolicy->setTop(UID(1));
453 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
454
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700455 // Submit real-time job to CLIENT(2) in different uid UID(1).
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700456 // Should pause previous job and start new job.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700457 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700458 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
459 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700460
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700461 // Bring UID(0) back to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700462 mUidPolicy->setTop(UID(0));
463 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
464 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700465
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700466 // Bring invalid uid to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700467 mUidPolicy->setTop(kInvalidUid);
468 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700469
470 // Finish job, next real-time job should resume.
471 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700472 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
473 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700474
475 // Finish job, offline job should start.
476 mScheduler->onFinish(CLIENT(2), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700477 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(2), JOB(0)));
478 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
479}
480
481TEST_F(TranscodingJobSchedulerTest, TestTopUidSetChanged) {
482 ALOGD("TestTopUidChanged_MultipleUids");
483
484 // Start with unspecified top UID.
485 // Submit real-time job to CLIENT(0), job should start immediately.
486 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
487 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
488
489 // Submit offline job to CLIENT(0), should not start.
490 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
491 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
492
493 // Set UID(0), UID(1) to top set.
494 // UID(0) should continue to run.
495 mUidPolicy->setTop({UID(0), UID(1)});
496 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
497
498 // Submit real-time job to CLIENT(2) in different uid UID(1).
499 // UID(0) should pause and UID(1) should start.
500 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
501 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
502 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
503
504 // Remove UID(0) from top set, and only leave UID(1) in the set.
505 // UID(1) should continue to run.
506 mUidPolicy->setTop(UID(1));
507 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
508
509 // Set UID(0), UID(2) to top set.
510 // UID(1) should continue to run.
511 mUidPolicy->setTop({UID(1), UID(2)});
512 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
513
514 // Bring UID(0) back to top.
515 mUidPolicy->setTop(UID(0));
516 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
517 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
518
519 // Bring invalid uid to top.
520 mUidPolicy->setTop(kInvalidUid);
521 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
522
523 // Finish job, next real-time job from UID(1) should resume, even if UID(1) no longer top.
524 mScheduler->onFinish(CLIENT(0), JOB(0));
525 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
526 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
527
528 // Finish job, offline job should start.
529 mScheduler->onFinish(CLIENT(2), JOB(0));
530 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(2), JOB(0)));
531 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700532}
533
534TEST_F(TranscodingJobSchedulerTest, TestResourceLost) {
535 ALOGD("TestResourceLost");
536
Chong Zhangacb33502020-04-20 11:04:48 -0700537 // Start with unspecified top UID.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700538 // Submit real-time job to CLIENT(0), job should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700539 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700540 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700541
542 // Submit offline job to CLIENT(0), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700543 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700544 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700545
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700546 // Move UID(1) to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700547 mUidPolicy->setTop(UID(1));
548 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700549
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700550 // Submit real-time job to CLIENT(2) in different uid UID(1).
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700551 // Should pause previous job and start new job.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700552 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700553 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
554 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700555
556 // Test 1: No queue change during resource loss.
557 // Signal resource lost.
558 mScheduler->onResourceLost();
Chong Zhangacb33502020-04-20 11:04:48 -0700559 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700560
561 // Signal resource available, CLIENT(2) should resume.
562 mScheduler->onResourceAvailable();
Chong Zhangacb33502020-04-20 11:04:48 -0700563 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700564
565 // Test 2: Change of queue order during resource loss.
566 // Signal resource lost.
567 mScheduler->onResourceLost();
Chong Zhangacb33502020-04-20 11:04:48 -0700568 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700569
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700570 // Move UID(0) back to top, should have no resume due to no resource.
Chong Zhangacb33502020-04-20 11:04:48 -0700571 mUidPolicy->setTop(UID(0));
572 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700573
574 // Signal resource available, CLIENT(0) should resume.
575 mScheduler->onResourceAvailable();
Chong Zhangacb33502020-04-20 11:04:48 -0700576 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700577
578 // Test 3: Adding new queue during resource loss.
579 // Signal resource lost.
580 mScheduler->onResourceLost();
Chong Zhangacb33502020-04-20 11:04:48 -0700581 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700582
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700583 // Move UID(2) to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700584 mUidPolicy->setTop(UID(2));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700585
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700586 // Submit real-time job to CLIENT(3) in UID(2), job shouldn't start due to no resource.
587 mScheduler->submit(CLIENT(3), JOB(0), UID(2), mRealtimeRequest, mClientCallback3);
Chong Zhangacb33502020-04-20 11:04:48 -0700588 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700589
590 // Signal resource available, CLIENT(3)'s job should start.
591 mScheduler->onResourceAvailable();
Chong Zhangacb33502020-04-20 11:04:48 -0700592 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(3), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700593}
594
595} // namespace android