blob: 24ac682cb1a7aa44dc29d3adaec0f0cb3c79abc7 [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
56TranscodingJobScheduler::Job* TranscodingJobScheduler::getTopJob_l() {
57 if (mJobMap.empty()) {
58 return nullptr;
59 }
Chong Zhang7ae4e2f2020-04-17 15:24:34 -070060 uid_t topUid = *mUidSortedList.begin();
61 JobKeyType topJobKey = *mJobQueues[topUid].begin();
Chong Zhang6d58e4b2020-03-31 09:41:10 -070062 return &mJobMap[topJobKey];
63}
64
65void TranscodingJobScheduler::updateCurrentJob_l() {
66 Job* topJob = getTopJob_l();
67 Job* curJob = mCurrentJob;
68 ALOGV("updateCurrentJob: topJob is %s, curJob is %s",
69 topJob == nullptr ? "null" : jobToString(topJob->key).c_str(),
70 curJob == nullptr ? "null" : jobToString(curJob->key).c_str());
71
72 // If we found a topJob that should be run, and it's not already running,
73 // take some actions to ensure it's running.
74 if (topJob != nullptr && (topJob != curJob || topJob->state != Job::RUNNING)) {
75 // If another job is currently running, pause it first.
76 if (curJob != nullptr && curJob->state == Job::RUNNING) {
77 mTranscoder->pause(curJob->key.first, curJob->key.second);
78 curJob->state = Job::PAUSED;
79 }
80 // If we are not experiencing resource loss, we can start or resume
81 // the topJob now.
82 if (!mResourceLost) {
83 if (topJob->state == Job::NOT_STARTED) {
Chong Zhang66469272020-06-04 16:51:55 -070084 mTranscoder->start(topJob->key.first, topJob->key.second, topJob->request,
85 topJob->callback.lock());
Chong Zhang6d58e4b2020-03-31 09:41:10 -070086 } else if (topJob->state == Job::PAUSED) {
Chong Zhangb55c5452020-06-26 14:32:12 -070087 mTranscoder->resume(topJob->key.first, topJob->key.second, topJob->request,
88 topJob->callback.lock());
Chong Zhang6d58e4b2020-03-31 09:41:10 -070089 }
90 topJob->state = Job::RUNNING;
91 }
92 }
93 mCurrentJob = topJob;
94}
95
96void TranscodingJobScheduler::removeJob_l(const JobKeyType& jobKey) {
97 ALOGV("%s: job %s", __FUNCTION__, jobToString(jobKey).c_str());
98
99 if (mJobMap.count(jobKey) == 0) {
100 ALOGE("job %s doesn't exist", jobToString(jobKey).c_str());
101 return;
102 }
103
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700104 // Remove job from uid's queue.
105 const uid_t uid = mJobMap[jobKey].uid;
106 JobQueueType& jobQueue = mJobQueues[uid];
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700107 auto it = std::find(jobQueue.begin(), jobQueue.end(), jobKey);
108 if (it == jobQueue.end()) {
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700109 ALOGE("couldn't find job %s in queue for uid %d", jobToString(jobKey).c_str(), uid);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700110 return;
111 }
112 jobQueue.erase(it);
113
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700114 // If this is the last job in a real-time queue, remove this uid's queue.
115 if (uid != OFFLINE_UID && jobQueue.empty()) {
116 mUidSortedList.remove(uid);
117 mJobQueues.erase(uid);
Chong Zhangacb33502020-04-20 11:04:48 -0700118 mUidPolicy->unregisterMonitorUid(uid);
119
120 std::unordered_set<uid_t> topUids = mUidPolicy->getTopUids();
121 moveUidsToTop_l(topUids, false /*preserveTopUid*/);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700122 }
123
124 // Clear current job.
125 if (mCurrentJob == &mJobMap[jobKey]) {
126 mCurrentJob = nullptr;
127 }
128
129 // Remove job from job map.
130 mJobMap.erase(jobKey);
131}
132
Chong Zhangacb33502020-04-20 11:04:48 -0700133/**
134 * Moves the set of uids to the front of mUidSortedList (which is used to pick
135 * the next job to run).
136 *
137 * This is called when 1) we received a onTopUidsChanged() callbcak from UidPolicy,
138 * or 2) we removed the job queue for a uid because it becomes empty.
139 *
140 * In case of 1), if there are multiple uids in the set, and the current front
141 * uid in mUidSortedList is still in the set, we try to keep that uid at front
142 * so that current job run is not interrupted. (This is not a concern for case 2)
143 * because the queue for a uid was just removed entirely.)
144 */
145void TranscodingJobScheduler::moveUidsToTop_l(const std::unordered_set<uid_t>& uids,
146 bool preserveTopUid) {
147 // If uid set is empty, nothing to do. Do not change the queue status.
148 if (uids.empty()) {
149 return;
150 }
151
152 // Save the current top uid.
153 uid_t curTopUid = *mUidSortedList.begin();
154 bool pushCurTopToFront = false;
155 int32_t numUidsMoved = 0;
156
157 // Go through the sorted uid list once, and move the ones in top set to front.
158 for (auto it = mUidSortedList.begin(); it != mUidSortedList.end();) {
159 uid_t uid = *it;
160
161 if (uid != OFFLINE_UID && uids.count(uid) > 0) {
162 it = mUidSortedList.erase(it);
163
164 // If this is the top we're preserving, don't push it here, push
165 // it after the for-loop.
166 if (uid == curTopUid && preserveTopUid) {
167 pushCurTopToFront = true;
168 } else {
169 mUidSortedList.push_front(uid);
170 }
171
172 // If we found all uids in the set, break out.
173 if (++numUidsMoved == uids.size()) {
174 break;
175 }
176 } else {
177 ++it;
178 }
179 }
180
181 if (pushCurTopToFront) {
182 mUidSortedList.push_front(curTopUid);
183 }
184}
185
Chong Zhang3fa408f2020-04-30 11:04:28 -0700186bool TranscodingJobScheduler::submit(ClientIdType clientId, JobIdType jobId, uid_t uid,
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700187 const TranscodingRequestParcel& request,
188 const std::weak_ptr<ITranscodingClientCallback>& callback) {
189 JobKeyType jobKey = std::make_pair(clientId, jobId);
190
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700191 ALOGV("%s: job %s, uid %d, prioirty %d", __FUNCTION__, jobToString(jobKey).c_str(), uid,
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700192 (int32_t)request.priority);
193
194 std::scoped_lock lock{mLock};
195
196 if (mJobMap.count(jobKey) > 0) {
197 ALOGE("job %s already exists", jobToString(jobKey).c_str());
198 return false;
199 }
200
201 // TODO(chz): only support offline vs real-time for now. All kUnspecified jobs
202 // go to offline queue.
203 if (request.priority == TranscodingJobPriority::kUnspecified) {
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700204 uid = OFFLINE_UID;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700205 }
206
207 // Add job to job map.
208 mJobMap[jobKey].key = jobKey;
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700209 mJobMap[jobKey].uid = uid;
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700210 mJobMap[jobKey].state = Job::NOT_STARTED;
211 mJobMap[jobKey].request = request;
212 mJobMap[jobKey].callback = callback;
213
214 // If it's an offline job, the queue was already added in constructor.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700215 // If it's a real-time jobs, check if a queue is already present for the uid,
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700216 // and add a new queue if needed.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700217 if (uid != OFFLINE_UID) {
218 if (mJobQueues.count(uid) == 0) {
Chong Zhangacb33502020-04-20 11:04:48 -0700219 mUidPolicy->registerMonitorUid(uid);
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700220 if (mUidPolicy->isUidOnTop(uid)) {
221 mUidSortedList.push_front(uid);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700222 } else {
223 // Shouldn't be submitting real-time requests from non-top app,
224 // put it in front of the offline queue.
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700225 mUidSortedList.insert(mOfflineUidIterator, uid);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700226 }
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700227 } else if (uid != *mUidSortedList.begin()) {
228 if (mUidPolicy->isUidOnTop(uid)) {
229 mUidSortedList.remove(uid);
230 mUidSortedList.push_front(uid);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700231 }
232 }
233 }
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700234 // Append this job to the uid's queue.
235 mJobQueues[uid].push_back(jobKey);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700236
237 updateCurrentJob_l();
238
239 validateState_l();
240 return true;
241}
242
Chong Zhang3fa408f2020-04-30 11:04:28 -0700243bool TranscodingJobScheduler::cancel(ClientIdType clientId, JobIdType jobId) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700244 JobKeyType jobKey = std::make_pair(clientId, jobId);
245
246 ALOGV("%s: job %s", __FUNCTION__, jobToString(jobKey).c_str());
247
Chong Zhang15c192a2020-05-05 16:24:00 -0700248 std::list<JobKeyType> jobsToRemove;
249
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700250 std::scoped_lock lock{mLock};
251
Chong Zhang15c192a2020-05-05 16:24:00 -0700252 if (jobId < 0) {
253 for (auto it = mJobMap.begin(); it != mJobMap.end(); ++it) {
254 if (it->first.first == clientId && it->second.uid != OFFLINE_UID) {
255 jobsToRemove.push_back(it->first);
256 }
257 }
258 } else {
259 if (mJobMap.count(jobKey) == 0) {
260 ALOGE("job %s doesn't exist", jobToString(jobKey).c_str());
261 return false;
262 }
263 jobsToRemove.push_back(jobKey);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700264 }
265
Chong Zhang15c192a2020-05-05 16:24:00 -0700266 for (auto it = jobsToRemove.begin(); it != jobsToRemove.end(); ++it) {
Chong Zhang00feca22020-05-08 15:02:06 -0700267 // If the job has ever been started, stop it now.
268 // Note that stop() is needed even if the job is currently paused. This instructs
269 // the transcoder to discard any states for the job, otherwise the states may
270 // never be discarded.
271 if (mJobMap[*it].state != Job::NOT_STARTED) {
272 mTranscoder->stop(it->first, it->second);
Chong Zhang15c192a2020-05-05 16:24:00 -0700273 }
274
275 // Remove the job.
276 removeJob_l(*it);
277 }
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700278
279 // Start next job.
280 updateCurrentJob_l();
281
282 validateState_l();
283 return true;
284}
285
Chong Zhang3fa408f2020-04-30 11:04:28 -0700286bool TranscodingJobScheduler::getJob(ClientIdType clientId, JobIdType jobId,
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700287 TranscodingRequestParcel* request) {
288 JobKeyType jobKey = std::make_pair(clientId, jobId);
289
290 std::scoped_lock lock{mLock};
291
292 if (mJobMap.count(jobKey) == 0) {
293 ALOGE("job %s doesn't exist", jobToString(jobKey).c_str());
294 return false;
295 }
296
297 *(TranscodingRequest*)request = mJobMap[jobKey].request;
298 return true;
299}
300
Chong Zhangde60f062020-06-11 17:05:10 -0700301void TranscodingJobScheduler::notifyClient(ClientIdType clientId, JobIdType jobId,
302 const char* reason,
303 std::function<void(const JobKeyType&)> func) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700304 JobKeyType jobKey = std::make_pair(clientId, jobId);
305
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700306 std::scoped_lock lock{mLock};
307
308 if (mJobMap.count(jobKey) == 0) {
Chong Zhangde60f062020-06-11 17:05:10 -0700309 ALOGW("%s: ignoring %s for job %s that doesn't exist", __FUNCTION__, reason,
310 jobToString(jobKey).c_str());
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700311 return;
312 }
313
314 // Only ignore if job was never started. In particular, propagate the status
315 // to client if the job is paused. Transcoder could have posted finish when
316 // we're pausing it, and the finish arrived after we changed current job.
317 if (mJobMap[jobKey].state == Job::NOT_STARTED) {
Chong Zhangde60f062020-06-11 17:05:10 -0700318 ALOGW("%s: ignoring %s for job %s that was never started", __FUNCTION__, reason,
319 jobToString(jobKey).c_str());
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700320 return;
321 }
322
Chong Zhangde60f062020-06-11 17:05:10 -0700323 ALOGV("%s: job %s %s", __FUNCTION__, jobToString(jobKey).c_str(), reason);
324 func(jobKey);
325}
326
327void TranscodingJobScheduler::onStarted(ClientIdType clientId, JobIdType jobId) {
328 notifyClient(clientId, jobId, "started", [=](const JobKeyType& jobKey) {
329 auto callback = mJobMap[jobKey].callback.lock();
330 if (callback != nullptr) {
331 callback->onTranscodingStarted(jobId);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700332 }
Chong Zhangde60f062020-06-11 17:05:10 -0700333 });
334}
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700335
Chong Zhangde60f062020-06-11 17:05:10 -0700336void TranscodingJobScheduler::onPaused(ClientIdType clientId, JobIdType jobId) {
337 notifyClient(clientId, jobId, "paused", [=](const JobKeyType& jobKey) {
338 auto callback = mJobMap[jobKey].callback.lock();
339 if (callback != nullptr) {
340 callback->onTranscodingPaused(jobId);
341 }
342 });
343}
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700344
Chong Zhangde60f062020-06-11 17:05:10 -0700345void TranscodingJobScheduler::onResumed(ClientIdType clientId, JobIdType jobId) {
346 notifyClient(clientId, jobId, "resumed", [=](const JobKeyType& jobKey) {
347 auto callback = mJobMap[jobKey].callback.lock();
348 if (callback != nullptr) {
349 callback->onTranscodingResumed(jobId);
350 }
351 });
352}
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700353
Chong Zhangde60f062020-06-11 17:05:10 -0700354void TranscodingJobScheduler::onFinish(ClientIdType clientId, JobIdType jobId) {
355 notifyClient(clientId, jobId, "finish", [=](const JobKeyType& jobKey) {
356 {
357 auto clientCallback = mJobMap[jobKey].callback.lock();
358 if (clientCallback != nullptr) {
Chong Zhang66469272020-06-04 16:51:55 -0700359 clientCallback->onTranscodingFinished(
hkuang0bd73742020-06-24 12:57:09 -0700360 jobId, TranscodingResultParcel({jobId, -1 /*actualBitrateBps*/,
361 std::nullopt /*jobStats*/}));
Chong Zhangde60f062020-06-11 17:05:10 -0700362 }
363 }
364
365 // Remove the job.
366 removeJob_l(jobKey);
367
368 // Start next job.
369 updateCurrentJob_l();
370
371 validateState_l();
372 });
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700373}
374
Chong Zhang3fa408f2020-04-30 11:04:28 -0700375void TranscodingJobScheduler::onError(ClientIdType clientId, JobIdType jobId,
376 TranscodingErrorCode err) {
Chong Zhangde60f062020-06-11 17:05:10 -0700377 notifyClient(clientId, jobId, "error", [=](const JobKeyType& jobKey) {
378 {
379 auto clientCallback = mJobMap[jobKey].callback.lock();
380 if (clientCallback != nullptr) {
381 clientCallback->onTranscodingFailed(jobId, err);
382 }
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700383 }
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700384
Chong Zhangde60f062020-06-11 17:05:10 -0700385 // Remove the job.
386 removeJob_l(jobKey);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700387
Chong Zhangde60f062020-06-11 17:05:10 -0700388 // Start next job.
389 updateCurrentJob_l();
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700390
Chong Zhangde60f062020-06-11 17:05:10 -0700391 validateState_l();
392 });
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700393}
394
Chong Zhang3fa408f2020-04-30 11:04:28 -0700395void TranscodingJobScheduler::onProgressUpdate(ClientIdType clientId, JobIdType jobId,
396 int32_t progress) {
Chong Zhangde60f062020-06-11 17:05:10 -0700397 notifyClient(clientId, jobId, "progress", [=](const JobKeyType& jobKey) {
398 auto callback = mJobMap[jobKey].callback.lock();
399 if (callback != nullptr) {
400 callback->onProgressUpdate(jobId, progress);
Chong Zhangacb33502020-04-20 11:04:48 -0700401 }
Chong Zhangde60f062020-06-11 17:05:10 -0700402 });
Chong Zhangacb33502020-04-20 11:04:48 -0700403}
404
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700405void TranscodingJobScheduler::onResourceLost() {
Chong Zhangf9077512020-09-21 21:02:06 -0700406 ALOGI("%s", __FUNCTION__);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700407
408 std::scoped_lock lock{mLock};
409
Chong Zhangf9077512020-09-21 21:02:06 -0700410 if (mResourceLost) {
411 return;
412 }
413
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700414 // If we receive a resource loss event, the TranscoderLibrary already paused
415 // the transcoding, so we don't need to call onPaused to notify it to pause.
416 // Only need to update the job state here.
417 if (mCurrentJob != nullptr && mCurrentJob->state == Job::RUNNING) {
418 mCurrentJob->state = Job::PAUSED;
Chong Zhangf9077512020-09-21 21:02:06 -0700419 // Notify the client as a paused event.
420 auto clientCallback = mCurrentJob->callback.lock();
421 if (clientCallback != nullptr) {
422 clientCallback->onTranscodingPaused(mCurrentJob->key.second);
423 }
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700424 }
425 mResourceLost = true;
426
427 validateState_l();
428}
429
Chong Zhangacb33502020-04-20 11:04:48 -0700430void TranscodingJobScheduler::onTopUidsChanged(const std::unordered_set<uid_t>& uids) {
431 if (uids.empty()) {
432 ALOGW("%s: ignoring empty uids", __FUNCTION__);
433 return;
434 }
435
436 std::string uidStr;
437 for (auto it = uids.begin(); it != uids.end(); it++) {
438 if (!uidStr.empty()) {
439 uidStr += ", ";
440 }
441 uidStr += std::to_string(*it);
442 }
443
444 ALOGD("%s: topUids: size %zu, uids: %s", __FUNCTION__, uids.size(), uidStr.c_str());
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700445
446 std::scoped_lock lock{mLock};
447
Chong Zhangacb33502020-04-20 11:04:48 -0700448 moveUidsToTop_l(uids, true /*preserveTopUid*/);
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700449
450 updateCurrentJob_l();
451
452 validateState_l();
453}
454
455void TranscodingJobScheduler::onResourceAvailable() {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700456 std::scoped_lock lock{mLock};
457
Chong Zhangf9077512020-09-21 21:02:06 -0700458 if (!mResourceLost) {
459 return;
460 }
461
462 ALOGI("%s", __FUNCTION__);
463
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700464 mResourceLost = false;
465 updateCurrentJob_l();
466
467 validateState_l();
468}
469
470void TranscodingJobScheduler::validateState_l() {
471#ifdef VALIDATE_STATE
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700472 LOG_ALWAYS_FATAL_IF(mJobQueues.count(OFFLINE_UID) != 1,
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700473 "mJobQueues offline queue number is not 1");
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700474 LOG_ALWAYS_FATAL_IF(*mOfflineUidIterator != OFFLINE_UID,
475 "mOfflineUidIterator not pointing to offline uid");
476 LOG_ALWAYS_FATAL_IF(mUidSortedList.size() != mJobQueues.size(),
477 "mUidList and mJobQueues size mismatch");
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700478
479 int32_t totalJobs = 0;
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700480 for (auto uidIt = mUidSortedList.begin(); uidIt != mUidSortedList.end(); uidIt++) {
481 LOG_ALWAYS_FATAL_IF(mJobQueues.count(*uidIt) != 1, "mJobQueues count for uid %d is not 1",
482 *uidIt);
483 for (auto jobIt = mJobQueues[*uidIt].begin(); jobIt != mJobQueues[*uidIt].end(); jobIt++) {
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700484 LOG_ALWAYS_FATAL_IF(mJobMap.count(*jobIt) != 1, "mJobs count for job %s is not 1",
485 jobToString(*jobIt).c_str());
486 }
487
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700488 totalJobs += mJobQueues[*uidIt].size();
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700489 }
490 LOG_ALWAYS_FATAL_IF(mJobMap.size() != totalJobs,
Chong Zhang7ae4e2f2020-04-17 15:24:34 -0700491 "mJobs size doesn't match total jobs counted from uid queues");
Chong Zhang6d58e4b2020-03-31 09:41:10 -0700492#endif // VALIDATE_STATE
493}
494
495} // namespace android