blob: b9bebacc79b843fcf8959b2cfbd6f1f642ccb86d [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
hkuang96471b82020-06-08 11:12:46 -0700170 Status onTranscodingStarted(int32_t /*in_jobId*/) override { return Status::ok(); }
171
172 Status onTranscodingPaused(int32_t /*in_jobId*/) override { return Status::ok(); }
173
174 Status onTranscodingResumed(int32_t /*in_jobId*/) override { return Status::ok(); }
175
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700176 Status onTranscodingFinished(int32_t in_jobId,
177 const TranscodingResultParcel& in_result) override {
178 EXPECT_EQ(in_jobId, in_result.jobId);
Chong Zhang75222182020-04-29 14:43:42 -0700179 ALOGD("TestClientCallback: received onTranscodingFinished");
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700180 mOwner->onFinished(mClientId, in_jobId);
181 return Status::ok();
182 }
183
184 Status onTranscodingFailed(int32_t in_jobId, TranscodingErrorCode in_errorCode) override {
185 mOwner->onFailed(mClientId, in_jobId, in_errorCode);
186 return Status::ok();
187 }
188
189 Status onAwaitNumberOfJobsChanged(int32_t /* in_jobId */, int32_t /* in_oldAwaitNumber */,
190 int32_t /* in_newAwaitNumber */) override {
191 return Status::ok();
192 }
193
194 Status onProgressUpdate(int32_t /* in_jobId */, int32_t /* in_progress */) override {
195 return Status::ok();
196 }
197
198 virtual ~TestClientCallback() { ALOGI("TestClient destroyed"); };
199
200private:
Chong Zhangacb33502020-04-20 11:04:48 -0700201 TestTranscoder* mOwner;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700202 int64_t mClientId;
203 TestClientCallback(const TestClientCallback&) = delete;
204 TestClientCallback& operator=(const TestClientCallback&) = delete;
205};
206
207class TranscodingJobSchedulerTest : public ::testing::Test {
208public:
209 TranscodingJobSchedulerTest() { ALOGI("TranscodingJobSchedulerTest created"); }
210
211 void SetUp() override {
212 ALOGI("TranscodingJobSchedulerTest set up");
Chong Zhangacb33502020-04-20 11:04:48 -0700213 mTranscoder.reset(new TestTranscoder());
214 mUidPolicy.reset(new TestUidPolicy());
215 mScheduler.reset(new TranscodingJobScheduler(mTranscoder, mUidPolicy));
216 mUidPolicy->setCallback(mScheduler);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700217
218 // Set priority only, ignore other fields for now.
219 mOfflineRequest.priority = TranscodingJobPriority::kUnspecified;
220 mRealtimeRequest.priority = TranscodingJobPriority::kHigh;
221 mClientCallback0 =
Chong Zhangacb33502020-04-20 11:04:48 -0700222 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(0));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700223 mClientCallback1 =
Chong Zhangacb33502020-04-20 11:04:48 -0700224 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(1));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700225 mClientCallback2 =
Chong Zhangacb33502020-04-20 11:04:48 -0700226 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(2));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700227 mClientCallback3 =
Chong Zhangacb33502020-04-20 11:04:48 -0700228 ::ndk::SharedRefBase::make<TestClientCallback>(mTranscoder.get(), CLIENT(3));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700229 }
230
231 void TearDown() override { ALOGI("TranscodingJobSchedulerTest tear down"); }
232
233 ~TranscodingJobSchedulerTest() { ALOGD("TranscodingJobSchedulerTest destroyed"); }
234
Chong Zhangacb33502020-04-20 11:04:48 -0700235 std::shared_ptr<TestTranscoder> mTranscoder;
236 std::shared_ptr<TestUidPolicy> mUidPolicy;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700237 std::shared_ptr<TranscodingJobScheduler> mScheduler;
238 TranscodingRequestParcel mOfflineRequest;
239 TranscodingRequestParcel mRealtimeRequest;
240 std::shared_ptr<TestClientCallback> mClientCallback0;
241 std::shared_ptr<TestClientCallback> mClientCallback1;
242 std::shared_ptr<TestClientCallback> mClientCallback2;
243 std::shared_ptr<TestClientCallback> mClientCallback3;
244};
245
246TEST_F(TranscodingJobSchedulerTest, TestSubmitJob) {
247 ALOGD("TestSubmitJob");
248
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700249 // Start with UID(1) on top.
Chong Zhangacb33502020-04-20 11:04:48 -0700250 mUidPolicy->setTop(UID(1));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700251
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700252 // Submit offline job to CLIENT(0) in UID(0).
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700253 // Should start immediately (because this is the only job).
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700254 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700255 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), 0));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700256
257 // Submit real-time job to CLIENT(0).
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700258 // Should pause offline job and start new job, even if UID(0) is not on top.
259 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700260 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
261 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700262
263 // Submit real-time job to CLIENT(0), should be queued after the previous job.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700264 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700265 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700266
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700267 // Submit real-time job to CLIENT(1) in same uid, should be queued after the previous job.
268 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mRealtimeRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700269 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700270
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700271 // Submit real-time job to CLIENT(2) in UID(1).
Chong Zhangacb33502020-04-20 11:04:48 -0700272 // Should pause previous job and start new job, because UID(1) is (has been) top.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700273 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700274 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
275 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700276
277 // Submit offline job, shouldn't generate any event.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700278 mScheduler->submit(CLIENT(2), JOB(1), UID(1), mOfflineRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700279 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700280
Chong Zhangacb33502020-04-20 11:04:48 -0700281 // Bring UID(0) to top.
282 mUidPolicy->setTop(UID(0));
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700283 // Should pause current job, and resume last job in UID(0).
Chong Zhangacb33502020-04-20 11:04:48 -0700284 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
285 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700286}
287
288TEST_F(TranscodingJobSchedulerTest, TestCancelJob) {
289 ALOGD("TestCancelJob");
290
291 // Submit real-time job JOB(0), should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700292 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700293 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700294
295 // Submit real-time job JOB(1), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700296 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700297 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700298
299 // Submit offline job JOB(2), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700300 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700301 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700302
303 // Cancel queued real-time job.
304 // Cancel real-time job JOB(1), should be cancelled.
305 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(1)));
306
307 // Cancel queued offline job.
308 // Cancel offline job JOB(2), should be cancelled.
309 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(2)));
310
311 // Submit offline job JOB(3), shouldn't cause any event.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700312 mScheduler->submit(CLIENT(0), JOB(3), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700313 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700314
315 // Cancel running real-time job JOB(0).
Chong Zhang00feca22020-05-08 15:02:06 -0700316 // - Should be stopped first then cancelled.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700317 // - Should also start offline job JOB(2) because real-time queue is empty.
318 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(0)));
Chong Zhang00feca22020-05-08 15:02:06 -0700319 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Stop(CLIENT(0), JOB(0)));
Chong Zhangacb33502020-04-20 11:04:48 -0700320 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(3)));
Chong Zhang00feca22020-05-08 15:02:06 -0700321
322 // Submit real-time job JOB(4), offline JOB(3) should pause and JOB(4) should start.
323 mScheduler->submit(CLIENT(0), JOB(4), UID(0), mRealtimeRequest, mClientCallback0);
324 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(3)));
325 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(4)));
326
327 // Cancel paused JOB(3). JOB(3) should be stopped.
328 EXPECT_TRUE(mScheduler->cancel(CLIENT(0), JOB(3)));
329 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Stop(CLIENT(0), JOB(3)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700330}
331
332TEST_F(TranscodingJobSchedulerTest, TestFinishJob) {
333 ALOGD("TestFinishJob");
334
Chong Zhangacb33502020-04-20 11:04:48 -0700335 // Start with unspecified top UID.
336 // Finish without any jobs submitted, should be ignored.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700337 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700338 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700339
340 // Submit offline job JOB(0), should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700341 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700342 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700343
344 // Submit real-time job JOB(1), should pause offline job and start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700345 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700346 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
347 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700348
349 // Submit real-time job JOB(2), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700350 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700351 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700352
Chong Zhangacb33502020-04-20 11:04:48 -0700353 // Finish when the job never started, should be ignored.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700354 mScheduler->onFinish(CLIENT(0), JOB(2));
Chong Zhangacb33502020-04-20 11:04:48 -0700355 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700356
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700357 // UID(1) moves to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700358 mUidPolicy->setTop(UID(1));
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700359 // Submit real-time job to CLIENT(1) in UID(1), should pause previous job and start new job.
360 mScheduler->submit(CLIENT(1), JOB(0), UID(1), mRealtimeRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700361 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
362 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700363
Chong Zhangacb33502020-04-20 11:04:48 -0700364 // Simulate Finish that arrived late, after pause issued by scheduler.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700365 // Should still be propagated to client, but shouldn't trigger any new start.
366 mScheduler->onFinish(CLIENT(0), JOB(1));
Chong Zhangacb33502020-04-20 11:04:48 -0700367 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700368
Chong Zhangacb33502020-04-20 11:04:48 -0700369 // Finish running real-time job, should start next real-time job in queue.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700370 mScheduler->onFinish(CLIENT(1), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700371 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(1), JOB(0)));
372 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(2)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700373
Chong Zhangacb33502020-04-20 11:04:48 -0700374 // Finish running real-time job, should resume next job (offline job) in queue.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700375 mScheduler->onFinish(CLIENT(0), JOB(2));
Chong Zhangacb33502020-04-20 11:04:48 -0700376 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(2)));
377 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700378
Chong Zhangacb33502020-04-20 11:04:48 -0700379 // Finish running offline job.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700380 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700381 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700382
Chong Zhangacb33502020-04-20 11:04:48 -0700383 // Duplicate finish for last job, should be ignored.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700384 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700385 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700386}
387
388TEST_F(TranscodingJobSchedulerTest, TestFailJob) {
389 ALOGD("TestFailJob");
390
Chong Zhangacb33502020-04-20 11:04:48 -0700391 // Start with unspecified top UID.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700392 // Fail without any jobs submitted, should be ignored.
393 mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700394 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700395
396 // Submit offline job JOB(0), should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700397 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mOfflineRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700398 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700399
400 // Submit real-time job JOB(1), should pause offline job and start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700401 mScheduler->submit(CLIENT(0), JOB(1), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700402 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
403 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700404
405 // Submit real-time job JOB(2), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700406 mScheduler->submit(CLIENT(0), JOB(2), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700407 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700408
409 // Fail when the job never started, should be ignored.
410 mScheduler->onError(CLIENT(0), JOB(2), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700411 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700412
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700413 // UID(1) moves to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700414 mUidPolicy->setTop(UID(1));
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700415 // Submit real-time job to CLIENT(1) in UID(1), should pause previous job and start new job.
416 mScheduler->submit(CLIENT(1), JOB(0), UID(1), mRealtimeRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700417 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(1)));
418 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700419
420 // Simulate Fail that arrived late, after pause issued by scheduler.
421 // Should still be propagated to client, but shouldn't trigger any new start.
422 mScheduler->onError(CLIENT(0), JOB(1), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700423 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(1)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700424
425 // Fail running real-time job, should start next real-time job in queue.
426 mScheduler->onError(CLIENT(1), JOB(0), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700427 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(1), JOB(0)));
428 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(2)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700429
430 // Fail running real-time job, should resume next job (offline job) in queue.
431 mScheduler->onError(CLIENT(0), JOB(2), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700432 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(2)));
433 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700434
435 // Fail running offline job, and test error code propagation.
436 mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kInvalidBitstream);
Chong Zhangacb33502020-04-20 11:04:48 -0700437 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Failed(CLIENT(0), JOB(0)));
438 EXPECT_EQ(mTranscoder->getLastError(), TranscodingErrorCode::kInvalidBitstream);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700439
440 // Duplicate fail for last job, should be ignored.
441 mScheduler->onError(CLIENT(0), JOB(0), TranscodingErrorCode::kUnknown);
Chong Zhangacb33502020-04-20 11:04:48 -0700442 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700443}
444
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700445TEST_F(TranscodingJobSchedulerTest, TestTopUidChanged) {
446 ALOGD("TestTopUidChanged");
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700447
Chong Zhangacb33502020-04-20 11:04:48 -0700448 // Start with unspecified top UID.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700449 // Submit real-time job to CLIENT(0), job should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700450 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700451 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700452
453 // Submit offline job to CLIENT(0), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700454 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700455 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700456
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700457 // Move UID(1) to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700458 mUidPolicy->setTop(UID(1));
459 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
460
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700461 // Submit real-time job to CLIENT(2) in different uid UID(1).
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700462 // Should pause previous job and start new job.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700463 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700464 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
465 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700466
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700467 // Bring UID(0) back to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700468 mUidPolicy->setTop(UID(0));
469 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
470 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700471
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700472 // Bring invalid uid to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700473 mUidPolicy->setTop(kInvalidUid);
474 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700475
476 // Finish job, next real-time job should resume.
477 mScheduler->onFinish(CLIENT(0), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700478 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
479 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700480
481 // Finish job, offline job should start.
482 mScheduler->onFinish(CLIENT(2), JOB(0));
Chong Zhangacb33502020-04-20 11:04:48 -0700483 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(2), JOB(0)));
484 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
485}
486
487TEST_F(TranscodingJobSchedulerTest, TestTopUidSetChanged) {
488 ALOGD("TestTopUidChanged_MultipleUids");
489
490 // Start with unspecified top UID.
491 // Submit real-time job to CLIENT(0), job should start immediately.
492 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
493 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
494
495 // Submit offline job to CLIENT(0), should not start.
496 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
497 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
498
499 // Set UID(0), UID(1) to top set.
500 // UID(0) should continue to run.
501 mUidPolicy->setTop({UID(0), UID(1)});
502 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
503
504 // Submit real-time job to CLIENT(2) in different uid UID(1).
505 // UID(0) should pause and UID(1) should start.
506 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
507 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
508 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
509
510 // Remove UID(0) from top set, and only leave UID(1) in the set.
511 // UID(1) should continue to run.
512 mUidPolicy->setTop(UID(1));
513 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
514
515 // Set UID(0), UID(2) to top set.
516 // UID(1) should continue to run.
517 mUidPolicy->setTop({UID(1), UID(2)});
518 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
519
520 // Bring UID(0) back to top.
521 mUidPolicy->setTop(UID(0));
522 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(2), JOB(0)));
523 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
524
525 // Bring invalid uid to top.
526 mUidPolicy->setTop(kInvalidUid);
527 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
528
529 // Finish job, next real-time job from UID(1) should resume, even if UID(1) no longer top.
530 mScheduler->onFinish(CLIENT(0), JOB(0));
531 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(0), JOB(0)));
532 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
533
534 // Finish job, offline job should start.
535 mScheduler->onFinish(CLIENT(2), JOB(0));
536 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Finished(CLIENT(2), JOB(0)));
537 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(1), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700538}
539
540TEST_F(TranscodingJobSchedulerTest, TestResourceLost) {
541 ALOGD("TestResourceLost");
542
Chong Zhangacb33502020-04-20 11:04:48 -0700543 // Start with unspecified top UID.
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700544 // Submit real-time job to CLIENT(0), job should start immediately.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700545 mScheduler->submit(CLIENT(0), JOB(0), UID(0), mRealtimeRequest, mClientCallback0);
Chong Zhangacb33502020-04-20 11:04:48 -0700546 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700547
548 // Submit offline job to CLIENT(0), should not start.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700549 mScheduler->submit(CLIENT(1), JOB(0), UID(0), mOfflineRequest, mClientCallback1);
Chong Zhangacb33502020-04-20 11:04:48 -0700550 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700551
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700552 // Move UID(1) to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700553 mUidPolicy->setTop(UID(1));
554 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700555
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700556 // Submit real-time job to CLIENT(2) in different uid UID(1).
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700557 // Should pause previous job and start new job.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700558 mScheduler->submit(CLIENT(2), JOB(0), UID(1), mRealtimeRequest, mClientCallback2);
Chong Zhangacb33502020-04-20 11:04:48 -0700559 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Pause(CLIENT(0), JOB(0)));
560 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700561
562 // Test 1: No queue change during resource loss.
563 // Signal resource lost.
564 mScheduler->onResourceLost();
Chong Zhangacb33502020-04-20 11:04:48 -0700565 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700566
567 // Signal resource available, CLIENT(2) should resume.
568 mScheduler->onResourceAvailable();
Chong Zhangacb33502020-04-20 11:04:48 -0700569 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(2), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700570
571 // Test 2: Change of queue order during resource loss.
572 // Signal resource lost.
573 mScheduler->onResourceLost();
Chong Zhangacb33502020-04-20 11:04:48 -0700574 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700575
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700576 // Move UID(0) back to top, should have no resume due to no resource.
Chong Zhangacb33502020-04-20 11:04:48 -0700577 mUidPolicy->setTop(UID(0));
578 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700579
580 // Signal resource available, CLIENT(0) should resume.
581 mScheduler->onResourceAvailable();
Chong Zhangacb33502020-04-20 11:04:48 -0700582 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Resume(CLIENT(0), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700583
584 // Test 3: Adding new queue during resource loss.
585 // Signal resource lost.
586 mScheduler->onResourceLost();
Chong Zhangacb33502020-04-20 11:04:48 -0700587 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700588
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700589 // Move UID(2) to top.
Chong Zhangacb33502020-04-20 11:04:48 -0700590 mUidPolicy->setTop(UID(2));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700591
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700592 // Submit real-time job to CLIENT(3) in UID(2), job shouldn't start due to no resource.
593 mScheduler->submit(CLIENT(3), JOB(0), UID(2), mRealtimeRequest, mClientCallback3);
Chong Zhangacb33502020-04-20 11:04:48 -0700594 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::NoEvent);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700595
596 // Signal resource available, CLIENT(3)'s job should start.
597 mScheduler->onResourceAvailable();
Chong Zhangacb33502020-04-20 11:04:48 -0700598 EXPECT_EQ(mTranscoder->popEvent(), TestTranscoder::Start(CLIENT(3), JOB(0)));
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700599}
600
601} // namespace android