blob: 804504350a898ea301ee1fa9e2470db1afa258f0 [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
Chong Zhangacb33502020-04-20 11:04:48 -070017//#define LOG_NDEBUG 0
Chong Zhang6d58e4b2020-03-31 09:41:10 -070018#define LOG_TAG "TranscodingJobScheduler"
19
20#define VALIDATE_STATE 1
21
22#include <inttypes.h>
23#include <media/TranscodingJobScheduler.h>
24#include <utils/Log.h>
25
26#include <utility>
27
28namespace android {
29
Chong Zhang15c192a2020-05-05 16:24:00 -070030static_assert((JobIdType)-1 < 0, "JobIdType should be signed");
31
Chong Zhang7ae4e2f2020-04-17 15:24:34 -070032constexpr static uid_t OFFLINE_UID = -1;
Chong Zhang6d58e4b2020-03-31 09:41:10 -070033
34//static
35String8 TranscodingJobScheduler::jobToString(const JobKeyType& jobKey) {
36 return String8::format("{client:%lld, job:%d}", (long long)jobKey.first, jobKey.second);
37}
38
39TranscodingJobScheduler::TranscodingJobScheduler(
40 const std::shared_ptr<TranscoderInterface>& transcoder,
Chong Zhangf9077512020-09-21 21:02:06 -070041 const std::shared_ptr<UidPolicyInterface>& uidPolicy,
42 const std::shared_ptr<ResourcePolicyInterface>& resourcePolicy)
43 : mTranscoder(transcoder),
44 mUidPolicy(uidPolicy),
45 mResourcePolicy(resourcePolicy),
46 mCurrentJob(nullptr),
47 mResourceLost(false) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -070048 // Only push empty offline queue initially. Realtime queues are added when requests come in.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -070049 mUidSortedList.push_back(OFFLINE_UID);
50 mOfflineUidIterator = mUidSortedList.begin();
51 mJobQueues.emplace(OFFLINE_UID, JobQueueType());
Chong Zhang6d58e4b2020-03-31 09:41:10 -070052}
53
54TranscodingJobScheduler::~TranscodingJobScheduler() {}
55
hkuangff778692020-10-02 15:40:56 -070056void TranscodingJobScheduler::dumpAllJobs(int fd, const Vector<String16>& args __unused) {
57 String8 result;
58
59 const size_t SIZE = 256;
60 char buffer[SIZE];
61 std::scoped_lock lock{mLock};
62
63 snprintf(buffer, SIZE, " \n\n Total num of Jobs: %zu\n", mJobMap.size());
64 result.append(buffer);
65
66 if (mJobMap.size() > 0) {
67 snprintf(buffer, SIZE, "========== Dumping all jobs =========\n");
68 result.append(buffer);
69 }
70
71 for (auto uidIt = mUidSortedList.begin(); uidIt != mUidSortedList.end(); uidIt++) {
72 for (auto jobIt = mJobQueues[*uidIt].begin(); jobIt != mJobQueues[*uidIt].end(); jobIt++) {
73 if (mJobMap.count(*jobIt) != 0) {
74 TranscodingRequestParcel& request = mJobMap[*jobIt].request;
75 snprintf(buffer, SIZE, "Job: %s Client: %d\n", request.sourceFilePath.c_str(),
76 request.clientUid);
77
78 } else {
79 snprintf(buffer, SIZE, "Failed to look up Job %s \n", jobToString(*jobIt).c_str());
80 }
81 result.append(buffer);
82 }
83 }
84
85 write(fd, result.string(), result.size());
86}
87
Chong Zhang6d58e4b2020-03-31 09:41:10 -070088TranscodingJobScheduler::Job* TranscodingJobScheduler::getTopJob_l() {
89 if (mJobMap.empty()) {
90 return nullptr;
91 }
Chong Zhang7ae4e2f2020-04-17 15:24:34 -070092 uid_t topUid = *mUidSortedList.begin();
93 JobKeyType topJobKey = *mJobQueues[topUid].begin();
Chong Zhang6d58e4b2020-03-31 09:41:10 -070094 return &mJobMap[topJobKey];
95}
96
97void TranscodingJobScheduler::updateCurrentJob_l() {
98 Job* topJob = getTopJob_l();
99 Job* curJob = mCurrentJob;
100 ALOGV("updateCurrentJob: topJob is %s, curJob is %s",
101 topJob == nullptr ? "null" : jobToString(topJob->key).c_str(),
102 curJob == nullptr ? "null" : jobToString(curJob->key).c_str());
103
104 // If we found a topJob that should be run, and it's not already running,
105 // take some actions to ensure it's running.
106 if (topJob != nullptr && (topJob != curJob || topJob->state != Job::RUNNING)) {
107 // If another job is currently running, pause it first.
108 if (curJob != nullptr && curJob->state == Job::RUNNING) {
109 mTranscoder->pause(curJob->key.first, curJob->key.second);
110 curJob->state = Job::PAUSED;
111 }
112 // If we are not experiencing resource loss, we can start or resume
113 // the topJob now.
114 if (!mResourceLost) {
115 if (topJob->state == Job::NOT_STARTED) {
Chong Zhang66469272020-06-04 16:51:55 -0700116 mTranscoder->start(topJob->key.first, topJob->key.second, topJob->request,
117 topJob->callback.lock());
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700118 } else if (topJob->state == Job::PAUSED) {
Chong Zhangb55c5452020-06-26 14:32:12 -0700119 mTranscoder->resume(topJob->key.first, topJob->key.second, topJob->request,
120 topJob->callback.lock());
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700121 }
122 topJob->state = Job::RUNNING;
123 }
124 }
125 mCurrentJob = topJob;
126}
127
128void TranscodingJobScheduler::removeJob_l(const JobKeyType& jobKey) {
129 ALOGV("%s: job %s", __FUNCTION__, jobToString(jobKey).c_str());
130
131 if (mJobMap.count(jobKey) == 0) {
132 ALOGE("job %s doesn't exist", jobToString(jobKey).c_str());
133 return;
134 }
135
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700136 // Remove job from uid's queue.
137 const uid_t uid = mJobMap[jobKey].uid;
138 JobQueueType& jobQueue = mJobQueues[uid];
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700139 auto it = std::find(jobQueue.begin(), jobQueue.end(), jobKey);
140 if (it == jobQueue.end()) {
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700141 ALOGE("couldn't find job %s in queue for uid %d", jobToString(jobKey).c_str(), uid);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700142 return;
143 }
144 jobQueue.erase(it);
145
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700146 // If this is the last job in a real-time queue, remove this uid's queue.
147 if (uid != OFFLINE_UID && jobQueue.empty()) {
148 mUidSortedList.remove(uid);
149 mJobQueues.erase(uid);
Chong Zhangacb33502020-04-20 11:04:48 -0700150 mUidPolicy->unregisterMonitorUid(uid);
151
152 std::unordered_set<uid_t> topUids = mUidPolicy->getTopUids();
153 moveUidsToTop_l(topUids, false /*preserveTopUid*/);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700154 }
155
156 // Clear current job.
157 if (mCurrentJob == &mJobMap[jobKey]) {
158 mCurrentJob = nullptr;
159 }
160
161 // Remove job from job map.
162 mJobMap.erase(jobKey);
163}
164
Chong Zhangacb33502020-04-20 11:04:48 -0700165/**
166 * Moves the set of uids to the front of mUidSortedList (which is used to pick
167 * the next job to run).
168 *
169 * This is called when 1) we received a onTopUidsChanged() callbcak from UidPolicy,
170 * or 2) we removed the job queue for a uid because it becomes empty.
171 *
172 * In case of 1), if there are multiple uids in the set, and the current front
173 * uid in mUidSortedList is still in the set, we try to keep that uid at front
174 * so that current job run is not interrupted. (This is not a concern for case 2)
175 * because the queue for a uid was just removed entirely.)
176 */
177void TranscodingJobScheduler::moveUidsToTop_l(const std::unordered_set<uid_t>& uids,
178 bool preserveTopUid) {
179 // If uid set is empty, nothing to do. Do not change the queue status.
180 if (uids.empty()) {
181 return;
182 }
183
184 // Save the current top uid.
185 uid_t curTopUid = *mUidSortedList.begin();
186 bool pushCurTopToFront = false;
187 int32_t numUidsMoved = 0;
188
189 // Go through the sorted uid list once, and move the ones in top set to front.
190 for (auto it = mUidSortedList.begin(); it != mUidSortedList.end();) {
191 uid_t uid = *it;
192
193 if (uid != OFFLINE_UID && uids.count(uid) > 0) {
194 it = mUidSortedList.erase(it);
195
196 // If this is the top we're preserving, don't push it here, push
197 // it after the for-loop.
198 if (uid == curTopUid && preserveTopUid) {
199 pushCurTopToFront = true;
200 } else {
201 mUidSortedList.push_front(uid);
202 }
203
204 // If we found all uids in the set, break out.
205 if (++numUidsMoved == uids.size()) {
206 break;
207 }
208 } else {
209 ++it;
210 }
211 }
212
213 if (pushCurTopToFront) {
214 mUidSortedList.push_front(curTopUid);
215 }
216}
217
Chong Zhang3fa408f2020-04-30 11:04:28 -0700218bool TranscodingJobScheduler::submit(ClientIdType clientId, JobIdType jobId, uid_t uid,
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700219 const TranscodingRequestParcel& request,
220 const std::weak_ptr<ITranscodingClientCallback>& callback) {
221 JobKeyType jobKey = std::make_pair(clientId, jobId);
222
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700223 ALOGV("%s: job %s, uid %d, prioirty %d", __FUNCTION__, jobToString(jobKey).c_str(), uid,
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700224 (int32_t)request.priority);
225
226 std::scoped_lock lock{mLock};
227
228 if (mJobMap.count(jobKey) > 0) {
229 ALOGE("job %s already exists", jobToString(jobKey).c_str());
230 return false;
231 }
232
233 // TODO(chz): only support offline vs real-time for now. All kUnspecified jobs
234 // go to offline queue.
235 if (request.priority == TranscodingJobPriority::kUnspecified) {
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700236 uid = OFFLINE_UID;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700237 }
238
239 // Add job to job map.
240 mJobMap[jobKey].key = jobKey;
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700241 mJobMap[jobKey].uid = uid;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700242 mJobMap[jobKey].state = Job::NOT_STARTED;
243 mJobMap[jobKey].request = request;
244 mJobMap[jobKey].callback = callback;
245
246 // If it's an offline job, the queue was already added in constructor.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700247 // If it's a real-time jobs, check if a queue is already present for the uid,
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700248 // and add a new queue if needed.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700249 if (uid != OFFLINE_UID) {
250 if (mJobQueues.count(uid) == 0) {
Chong Zhangacb33502020-04-20 11:04:48 -0700251 mUidPolicy->registerMonitorUid(uid);
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700252 if (mUidPolicy->isUidOnTop(uid)) {
253 mUidSortedList.push_front(uid);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700254 } else {
255 // Shouldn't be submitting real-time requests from non-top app,
256 // put it in front of the offline queue.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700257 mUidSortedList.insert(mOfflineUidIterator, uid);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700258 }
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700259 } else if (uid != *mUidSortedList.begin()) {
260 if (mUidPolicy->isUidOnTop(uid)) {
261 mUidSortedList.remove(uid);
262 mUidSortedList.push_front(uid);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700263 }
264 }
265 }
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700266 // Append this job to the uid's queue.
267 mJobQueues[uid].push_back(jobKey);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700268
269 updateCurrentJob_l();
270
271 validateState_l();
272 return true;
273}
274
Chong Zhang3fa408f2020-04-30 11:04:28 -0700275bool TranscodingJobScheduler::cancel(ClientIdType clientId, JobIdType jobId) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700276 JobKeyType jobKey = std::make_pair(clientId, jobId);
277
278 ALOGV("%s: job %s", __FUNCTION__, jobToString(jobKey).c_str());
279
Chong Zhang15c192a2020-05-05 16:24:00 -0700280 std::list<JobKeyType> jobsToRemove;
281
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700282 std::scoped_lock lock{mLock};
283
Chong Zhang15c192a2020-05-05 16:24:00 -0700284 if (jobId < 0) {
285 for (auto it = mJobMap.begin(); it != mJobMap.end(); ++it) {
286 if (it->first.first == clientId && it->second.uid != OFFLINE_UID) {
287 jobsToRemove.push_back(it->first);
288 }
289 }
290 } else {
291 if (mJobMap.count(jobKey) == 0) {
292 ALOGE("job %s doesn't exist", jobToString(jobKey).c_str());
293 return false;
294 }
295 jobsToRemove.push_back(jobKey);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700296 }
297
Chong Zhang15c192a2020-05-05 16:24:00 -0700298 for (auto it = jobsToRemove.begin(); it != jobsToRemove.end(); ++it) {
Chong Zhang00feca22020-05-08 15:02:06 -0700299 // If the job has ever been started, stop it now.
300 // Note that stop() is needed even if the job is currently paused. This instructs
301 // the transcoder to discard any states for the job, otherwise the states may
302 // never be discarded.
303 if (mJobMap[*it].state != Job::NOT_STARTED) {
304 mTranscoder->stop(it->first, it->second);
Chong Zhang15c192a2020-05-05 16:24:00 -0700305 }
306
307 // Remove the job.
308 removeJob_l(*it);
309 }
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700310
311 // Start next job.
312 updateCurrentJob_l();
313
314 validateState_l();
315 return true;
316}
317
Chong Zhang3fa408f2020-04-30 11:04:28 -0700318bool TranscodingJobScheduler::getJob(ClientIdType clientId, JobIdType jobId,
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700319 TranscodingRequestParcel* request) {
320 JobKeyType jobKey = std::make_pair(clientId, jobId);
321
322 std::scoped_lock lock{mLock};
323
324 if (mJobMap.count(jobKey) == 0) {
325 ALOGE("job %s doesn't exist", jobToString(jobKey).c_str());
326 return false;
327 }
328
329 *(TranscodingRequest*)request = mJobMap[jobKey].request;
330 return true;
331}
332
Chong Zhangde60f062020-06-11 17:05:10 -0700333void TranscodingJobScheduler::notifyClient(ClientIdType clientId, JobIdType jobId,
334 const char* reason,
335 std::function<void(const JobKeyType&)> func) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700336 JobKeyType jobKey = std::make_pair(clientId, jobId);
337
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700338 std::scoped_lock lock{mLock};
339
340 if (mJobMap.count(jobKey) == 0) {
Chong Zhangde60f062020-06-11 17:05:10 -0700341 ALOGW("%s: ignoring %s for job %s that doesn't exist", __FUNCTION__, reason,
342 jobToString(jobKey).c_str());
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700343 return;
344 }
345
346 // Only ignore if job was never started. In particular, propagate the status
347 // to client if the job is paused. Transcoder could have posted finish when
348 // we're pausing it, and the finish arrived after we changed current job.
349 if (mJobMap[jobKey].state == Job::NOT_STARTED) {
Chong Zhangde60f062020-06-11 17:05:10 -0700350 ALOGW("%s: ignoring %s for job %s that was never started", __FUNCTION__, reason,
351 jobToString(jobKey).c_str());
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700352 return;
353 }
354
Chong Zhangde60f062020-06-11 17:05:10 -0700355 ALOGV("%s: job %s %s", __FUNCTION__, jobToString(jobKey).c_str(), reason);
356 func(jobKey);
357}
358
359void TranscodingJobScheduler::onStarted(ClientIdType clientId, JobIdType jobId) {
360 notifyClient(clientId, jobId, "started", [=](const JobKeyType& jobKey) {
361 auto callback = mJobMap[jobKey].callback.lock();
362 if (callback != nullptr) {
363 callback->onTranscodingStarted(jobId);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700364 }
Chong Zhangde60f062020-06-11 17:05:10 -0700365 });
366}
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700367
Chong Zhangde60f062020-06-11 17:05:10 -0700368void TranscodingJobScheduler::onPaused(ClientIdType clientId, JobIdType jobId) {
369 notifyClient(clientId, jobId, "paused", [=](const JobKeyType& jobKey) {
370 auto callback = mJobMap[jobKey].callback.lock();
371 if (callback != nullptr) {
372 callback->onTranscodingPaused(jobId);
373 }
374 });
375}
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700376
Chong Zhangde60f062020-06-11 17:05:10 -0700377void TranscodingJobScheduler::onResumed(ClientIdType clientId, JobIdType jobId) {
378 notifyClient(clientId, jobId, "resumed", [=](const JobKeyType& jobKey) {
379 auto callback = mJobMap[jobKey].callback.lock();
380 if (callback != nullptr) {
381 callback->onTranscodingResumed(jobId);
382 }
383 });
384}
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700385
Chong Zhangde60f062020-06-11 17:05:10 -0700386void TranscodingJobScheduler::onFinish(ClientIdType clientId, JobIdType jobId) {
387 notifyClient(clientId, jobId, "finish", [=](const JobKeyType& jobKey) {
388 {
389 auto clientCallback = mJobMap[jobKey].callback.lock();
390 if (clientCallback != nullptr) {
Chong Zhang66469272020-06-04 16:51:55 -0700391 clientCallback->onTranscodingFinished(
hkuang0bd73742020-06-24 12:57:09 -0700392 jobId, TranscodingResultParcel({jobId, -1 /*actualBitrateBps*/,
393 std::nullopt /*jobStats*/}));
Chong Zhangde60f062020-06-11 17:05:10 -0700394 }
395 }
396
397 // Remove the job.
398 removeJob_l(jobKey);
399
400 // Start next job.
401 updateCurrentJob_l();
402
403 validateState_l();
404 });
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700405}
406
Chong Zhang3fa408f2020-04-30 11:04:28 -0700407void TranscodingJobScheduler::onError(ClientIdType clientId, JobIdType jobId,
408 TranscodingErrorCode err) {
Chong Zhangde60f062020-06-11 17:05:10 -0700409 notifyClient(clientId, jobId, "error", [=](const JobKeyType& jobKey) {
410 {
411 auto clientCallback = mJobMap[jobKey].callback.lock();
412 if (clientCallback != nullptr) {
413 clientCallback->onTranscodingFailed(jobId, err);
414 }
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700415 }
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700416
Chong Zhangde60f062020-06-11 17:05:10 -0700417 // Remove the job.
418 removeJob_l(jobKey);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700419
Chong Zhangde60f062020-06-11 17:05:10 -0700420 // Start next job.
421 updateCurrentJob_l();
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700422
Chong Zhangde60f062020-06-11 17:05:10 -0700423 validateState_l();
424 });
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700425}
426
Chong Zhang3fa408f2020-04-30 11:04:28 -0700427void TranscodingJobScheduler::onProgressUpdate(ClientIdType clientId, JobIdType jobId,
428 int32_t progress) {
Chong Zhangde60f062020-06-11 17:05:10 -0700429 notifyClient(clientId, jobId, "progress", [=](const JobKeyType& jobKey) {
430 auto callback = mJobMap[jobKey].callback.lock();
431 if (callback != nullptr) {
432 callback->onProgressUpdate(jobId, progress);
Chong Zhangacb33502020-04-20 11:04:48 -0700433 }
Chong Zhangde60f062020-06-11 17:05:10 -0700434 });
Chong Zhangacb33502020-04-20 11:04:48 -0700435}
436
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700437void TranscodingJobScheduler::onResourceLost() {
Chong Zhangf9077512020-09-21 21:02:06 -0700438 ALOGI("%s", __FUNCTION__);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700439
440 std::scoped_lock lock{mLock};
441
Chong Zhangf9077512020-09-21 21:02:06 -0700442 if (mResourceLost) {
443 return;
444 }
445
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700446 // If we receive a resource loss event, the TranscoderLibrary already paused
447 // the transcoding, so we don't need to call onPaused to notify it to pause.
448 // Only need to update the job state here.
449 if (mCurrentJob != nullptr && mCurrentJob->state == Job::RUNNING) {
450 mCurrentJob->state = Job::PAUSED;
Chong Zhangf9077512020-09-21 21:02:06 -0700451 // Notify the client as a paused event.
452 auto clientCallback = mCurrentJob->callback.lock();
453 if (clientCallback != nullptr) {
454 clientCallback->onTranscodingPaused(mCurrentJob->key.second);
455 }
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700456 }
457 mResourceLost = true;
458
459 validateState_l();
460}
461
Chong Zhangacb33502020-04-20 11:04:48 -0700462void TranscodingJobScheduler::onTopUidsChanged(const std::unordered_set<uid_t>& uids) {
463 if (uids.empty()) {
464 ALOGW("%s: ignoring empty uids", __FUNCTION__);
465 return;
466 }
467
468 std::string uidStr;
469 for (auto it = uids.begin(); it != uids.end(); it++) {
470 if (!uidStr.empty()) {
471 uidStr += ", ";
472 }
473 uidStr += std::to_string(*it);
474 }
475
476 ALOGD("%s: topUids: size %zu, uids: %s", __FUNCTION__, uids.size(), uidStr.c_str());
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700477
478 std::scoped_lock lock{mLock};
479
Chong Zhangacb33502020-04-20 11:04:48 -0700480 moveUidsToTop_l(uids, true /*preserveTopUid*/);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700481
482 updateCurrentJob_l();
483
484 validateState_l();
485}
486
487void TranscodingJobScheduler::onResourceAvailable() {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700488 std::scoped_lock lock{mLock};
489
Chong Zhangf9077512020-09-21 21:02:06 -0700490 if (!mResourceLost) {
491 return;
492 }
493
494 ALOGI("%s", __FUNCTION__);
495
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700496 mResourceLost = false;
497 updateCurrentJob_l();
498
499 validateState_l();
500}
501
502void TranscodingJobScheduler::validateState_l() {
503#ifdef VALIDATE_STATE
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700504 LOG_ALWAYS_FATAL_IF(mJobQueues.count(OFFLINE_UID) != 1,
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700505 "mJobQueues offline queue number is not 1");
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700506 LOG_ALWAYS_FATAL_IF(*mOfflineUidIterator != OFFLINE_UID,
507 "mOfflineUidIterator not pointing to offline uid");
508 LOG_ALWAYS_FATAL_IF(mUidSortedList.size() != mJobQueues.size(),
509 "mUidList and mJobQueues size mismatch");
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700510
511 int32_t totalJobs = 0;
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700512 for (auto uidIt = mUidSortedList.begin(); uidIt != mUidSortedList.end(); uidIt++) {
513 LOG_ALWAYS_FATAL_IF(mJobQueues.count(*uidIt) != 1, "mJobQueues count for uid %d is not 1",
514 *uidIt);
515 for (auto jobIt = mJobQueues[*uidIt].begin(); jobIt != mJobQueues[*uidIt].end(); jobIt++) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700516 LOG_ALWAYS_FATAL_IF(mJobMap.count(*jobIt) != 1, "mJobs count for job %s is not 1",
517 jobToString(*jobIt).c_str());
518 }
519
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700520 totalJobs += mJobQueues[*uidIt].size();
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700521 }
522 LOG_ALWAYS_FATAL_IF(mJobMap.size() != totalJobs,
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700523 "mJobs size doesn't match total jobs counted from uid queues");
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700524#endif // VALIDATE_STATE
525}
526
527} // namespace android