FrameTimestamps.cpp revision 7c3ba8aa288755fad78ddbabcee0ad5a0610ac1c
1/* 2* Copyright 2016 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#include <gui/FrameTimestamps.h> 18 19#include <inttypes.h> 20#include <utils/String8.h> 21 22#include <algorithm> 23#include <limits> 24#include <numeric> 25 26namespace android { 27 28static inline bool isValidTimestamp(nsecs_t time) { 29 return time > 0 && time < INT64_MAX; 30} 31 32// ============================================================================ 33// FrameEvents 34// ============================================================================ 35 36bool FrameEvents::hasPostedInfo() const { 37 return isValidTimestamp(postedTime); 38} 39 40bool FrameEvents::hasRequestedPresentInfo() const { 41 return isValidTimestamp(requestedPresentTime); 42} 43 44bool FrameEvents::hasLatchInfo() const { 45 return isValidTimestamp(latchTime); 46} 47 48bool FrameEvents::hasFirstRefreshStartInfo() const { 49 return isValidTimestamp(firstRefreshStartTime); 50} 51 52bool FrameEvents::hasLastRefreshStartInfo() const { 53 // The last refresh start time may continue to update until a new frame 54 // is latched. We know we have the final value once the release or retire 55 // info is set. See ConsumerFrameEventHistory::addRetire/Release. 56 return addRetireCalled || addReleaseCalled; 57} 58 59bool FrameEvents::hasAcquireInfo() const { 60 return isValidTimestamp(acquireTime) || acquireFence->isValid(); 61} 62 63bool FrameEvents::hasGpuCompositionDoneInfo() const { 64 // We may not get a gpuCompositionDone in addPostComposite if 65 // client/gles compositing isn't needed. 66 return addPostCompositeCalled; 67} 68 69bool FrameEvents::hasDisplayPresentInfo() const { 70 // We may not get a displayPresent in addPostComposite for HWC1. 71 return addPostCompositeCalled; 72} 73 74bool FrameEvents::hasDisplayRetireInfo() const { 75 // We may not get a displayRetire in addRetire for HWC2. 76 return addRetireCalled; 77} 78 79bool FrameEvents::hasReleaseInfo() const { 80 return addReleaseCalled; 81} 82 83static void checkFenceForCompletion(sp<Fence>* fence, nsecs_t* dstTime) { 84 if ((*fence)->isValid()) { 85 nsecs_t time = (*fence)->getSignalTime(); 86 if (isValidTimestamp(time)) { 87 *dstTime = time; 88 *fence = Fence::NO_FENCE; 89 } 90 } 91} 92 93void FrameEvents::checkFencesForCompletion() { 94 checkFenceForCompletion(&acquireFence, &acquireTime); 95 checkFenceForCompletion(&gpuCompositionDoneFence, &gpuCompositionDoneTime); 96 checkFenceForCompletion(&displayPresentFence, &displayPresentTime); 97 checkFenceForCompletion(&displayRetireFence, &displayRetireTime); 98 checkFenceForCompletion(&releaseFence, &releaseTime); 99} 100 101void FrameEvents::dump(String8& outString) const 102{ 103 if (!valid) { 104 return; 105 } 106 107 outString.appendFormat("-- Frame %" PRIu64 "\n", frameNumber); 108 outString.appendFormat("--- Posted \t%" PRId64 "\n", postedTime); 109 outString.appendFormat("--- Req. Present\t%" PRId64 "\n", requestedPresentTime); 110 111 outString.appendFormat("--- Latched \t"); 112 if (isValidTimestamp(latchTime)) { 113 outString.appendFormat("%" PRId64 "\n", latchTime); 114 } else { 115 outString.appendFormat("Pending\n"); 116 } 117 118 outString.appendFormat("--- Refresh (First)\t"); 119 if (isValidTimestamp(firstRefreshStartTime)) { 120 outString.appendFormat("%" PRId64 "\n", firstRefreshStartTime); 121 } else { 122 outString.appendFormat("Pending\n"); 123 } 124 125 outString.appendFormat("--- Refresh (Last)\t"); 126 if (isValidTimestamp(lastRefreshStartTime)) { 127 outString.appendFormat("%" PRId64 "\n", lastRefreshStartTime); 128 } else { 129 outString.appendFormat("Pending\n"); 130 } 131 132 outString.appendFormat("--- Acquire \t"); 133 if (isValidTimestamp(acquireTime)) { 134 outString.appendFormat("%" PRId64 "\n", acquireTime); 135 } else { 136 outString.appendFormat("Pending\n"); 137 } 138 139 outString.appendFormat("--- GPU Composite Done\t"); 140 if (isValidTimestamp(gpuCompositionDoneTime)) { 141 outString.appendFormat("%" PRId64 "\n", gpuCompositionDoneTime); 142 } else if (!addPostCompositeCalled || gpuCompositionDoneFence->isValid()) { 143 outString.appendFormat("Pending\n"); 144 } else { 145 outString.appendFormat("N/A\n"); 146 } 147 148 outString.appendFormat("--- Display Present\t"); 149 if (isValidTimestamp(displayPresentTime)) { 150 outString.appendFormat("%" PRId64 "\n", displayPresentTime); 151 } else if (!addPostCompositeCalled || displayPresentFence->isValid()) { 152 outString.appendFormat("Pending\n"); 153 } else { 154 outString.appendFormat("N/A\n"); 155 } 156 157 outString.appendFormat("--- Display Retire\t"); 158 if (isValidTimestamp(displayRetireTime)) { 159 outString.appendFormat("%" PRId64 "\n", displayRetireTime); 160 } else if (!addRetireCalled || displayRetireFence->isValid()) { 161 outString.appendFormat("Pending\n"); 162 } else { 163 outString.appendFormat("N/A\n"); 164 } 165 166 outString.appendFormat("--- Release \t"); 167 if (isValidTimestamp(releaseTime)) { 168 outString.appendFormat("%" PRId64 "\n", releaseTime); 169 } else { 170 outString.appendFormat("Pending\n"); 171 } 172} 173 174 175// ============================================================================ 176// FrameEventHistory 177// ============================================================================ 178 179namespace { 180 181struct FrameNumberEqual { 182 FrameNumberEqual(uint64_t frameNumber) : mFrameNumber(frameNumber) {} 183 bool operator()(const FrameEvents& frame) { 184 return frame.valid && mFrameNumber == frame.frameNumber; 185 } 186 const uint64_t mFrameNumber; 187}; 188 189} // namespace 190 191FrameEventHistory::~FrameEventHistory() = default; 192 193FrameEvents* FrameEventHistory::getFrame(uint64_t frameNumber) { 194 auto frame = std::find_if( 195 mFrames.begin(), mFrames.end(), FrameNumberEqual(frameNumber)); 196 return frame == mFrames.end() ? nullptr : &(*frame); 197} 198 199FrameEvents* FrameEventHistory::getFrame(uint64_t frameNumber, size_t* iHint) { 200 *iHint = std::min(*iHint, mFrames.size()); 201 auto hint = mFrames.begin() + *iHint; 202 auto frame = std::find_if( 203 hint, mFrames.end(), FrameNumberEqual(frameNumber)); 204 if (frame == mFrames.end()) { 205 frame = std::find_if( 206 mFrames.begin(), hint, FrameNumberEqual(frameNumber)); 207 if (frame == hint) { 208 return nullptr; 209 } 210 } 211 *iHint = static_cast<size_t>(std::distance(mFrames.begin(), frame)); 212 return &(*frame); 213} 214 215void FrameEventHistory::checkFencesForCompletion() { 216 for (auto& frame : mFrames) { 217 frame.checkFencesForCompletion(); 218 } 219} 220 221// Uses !|valid| as the MSB. 222static bool FrameNumberLessThan( 223 const FrameEvents& lhs, const FrameEvents& rhs) { 224 if (lhs.valid == rhs.valid) { 225 return lhs.frameNumber < rhs.frameNumber; 226 } 227 return lhs.valid; 228} 229 230void FrameEventHistory::dump(String8& outString) const { 231 auto earliestFrame = std::min_element( 232 mFrames.begin(), mFrames.end(), &FrameNumberLessThan); 233 if (!earliestFrame->valid) { 234 outString.appendFormat("-- N/A\n"); 235 return; 236 } 237 for (auto frame = earliestFrame; frame != mFrames.end(); ++frame) { 238 frame->dump(outString); 239 } 240 for (auto frame = mFrames.begin(); frame != earliestFrame; ++frame) { 241 frame->dump(outString); 242 } 243} 244 245 246// ============================================================================ 247// ProducerFrameEventHistory 248// ============================================================================ 249 250ProducerFrameEventHistory::~ProducerFrameEventHistory() = default; 251 252void ProducerFrameEventHistory::updateAcquireFence( 253 uint64_t frameNumber, sp<Fence> acquire) { 254 FrameEvents* frame = getFrame(frameNumber, &mAcquireOffset); 255 if (frame == nullptr) { 256 ALOGE("ProducerFrameEventHistory::updateAcquireFence: " 257 "Did not find frame."); 258 return; 259 } 260 261 if (acquire->isValid()) { 262 frame->acquireFence = acquire; 263 } else { 264 // If there isn't an acquire fence, assume that buffer was 265 // ready for the consumer when posted. 266 frame->acquireTime = frame->postedTime; 267 } 268} 269 270static void applyFenceDelta(sp<Fence>* dst, const sp<Fence>& src) { 271 if (src->isValid()) { 272 if ((*dst)->isValid()) { 273 ALOGE("applyFenceDelta: Unexpected fence."); 274 } 275 *dst = src; 276 } 277} 278 279void ProducerFrameEventHistory::applyDelta( 280 const FrameEventHistoryDelta& delta) { 281 for (auto& d : delta.mDeltas) { 282 // Avoid out-of-bounds access. 283 if (d.mIndex >= mFrames.size()) { 284 ALOGE("ProducerFrameEventHistory::applyDelta: Bad index."); 285 return; 286 } 287 288 FrameEvents& frame = mFrames[d.mIndex]; 289 290 frame.addPostCompositeCalled = d.mAddPostCompositeCalled != 0; 291 frame.addRetireCalled = d.mAddRetireCalled != 0; 292 frame.addReleaseCalled = d.mAddReleaseCalled != 0; 293 294 frame.postedTime = d.mPostedTime; 295 frame.requestedPresentTime = d.mRequestedPresentTime; 296 frame.latchTime = d.mLatchTime; 297 frame.firstRefreshStartTime = d.mFirstRefreshStartTime; 298 frame.lastRefreshStartTime = d.mLastRefreshStartTime; 299 300 if (frame.frameNumber == d.mFrameNumber) { 301 // Existing frame. Merge. 302 // Consumer never sends timestamps of fences, only the fences 303 // themselves, so we never need to update the fence timestamps here. 304 applyFenceDelta( 305 &frame.gpuCompositionDoneFence, d.mGpuCompositionDoneFence); 306 applyFenceDelta(&frame.displayPresentFence, d.mDisplayPresentFence); 307 applyFenceDelta(&frame.displayRetireFence, d.mDisplayRetireFence); 308 applyFenceDelta(&frame.releaseFence, d.mReleaseFence); 309 } else { 310 // New frame. Overwrite. 311 frame.frameNumber = d.mFrameNumber; 312 313 frame.gpuCompositionDoneFence = d.mGpuCompositionDoneFence; 314 frame.displayPresentFence = d.mDisplayPresentFence; 315 frame.displayRetireFence = d.mDisplayRetireFence; 316 frame.releaseFence = d.mReleaseFence; 317 318 // Set aquire fence and time at this point. 319 frame.acquireTime = 0; 320 frame.acquireFence = Fence::NO_FENCE; 321 322 // Reset fence-related timestamps 323 frame.gpuCompositionDoneTime = 0; 324 frame.displayPresentTime = 0; 325 frame.displayRetireTime = 0; 326 frame.releaseTime = 0; 327 328 // The consumer only sends valid frames. 329 frame.valid = true; 330 } 331 } 332} 333 334 335// ============================================================================ 336// ConsumerFrameEventHistory 337// ============================================================================ 338 339ConsumerFrameEventHistory::~ConsumerFrameEventHistory() = default; 340 341void ConsumerFrameEventHistory::addQueue(const NewFrameEventsEntry& newEntry) { 342 // Overwrite all fields of the frame with default values unless set here. 343 FrameEvents newTimestamps; 344 newTimestamps.frameNumber = newEntry.frameNumber; 345 newTimestamps.postedTime = newEntry.postedTime; 346 newTimestamps.requestedPresentTime = newEntry.requestedPresentTime; 347 newTimestamps.acquireFence = newEntry.acquireFence; 348 newTimestamps.valid = true; 349 mFrames[mQueueOffset] = newTimestamps; 350 351 // Note: We avoid sending the acquire fence back to the caller since 352 // they have the original one already, so there is no need to set the 353 // acquire dirty bit. 354 mFramesDirty[mQueueOffset].setDirty<FrameEvent::POSTED>(); 355 356 mQueueOffset = (mQueueOffset + 1) % mFrames.size(); 357} 358 359void ConsumerFrameEventHistory::addLatch( 360 uint64_t frameNumber, nsecs_t latchTime) { 361 FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset); 362 if (frame == nullptr) { 363 ALOGE("ConsumerFrameEventHistory::addLatch: Did not find frame."); 364 return; 365 } 366 frame->latchTime = latchTime; 367 mFramesDirty[mCompositionOffset].setDirty<FrameEvent::LATCH>(); 368} 369 370void ConsumerFrameEventHistory::addPreComposition( 371 uint64_t frameNumber, nsecs_t refreshStartTime) { 372 FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset); 373 if (frame == nullptr) { 374 ALOGE("ConsumerFrameEventHistory::addPreComposition: " 375 "Did not find frame."); 376 return; 377 } 378 frame->lastRefreshStartTime = refreshStartTime; 379 mFramesDirty[mCompositionOffset].setDirty<FrameEvent::LAST_REFRESH_START>(); 380 if (!isValidTimestamp(frame->firstRefreshStartTime)) { 381 frame->firstRefreshStartTime = refreshStartTime; 382 mFramesDirty[mCompositionOffset].setDirty<FrameEvent::FIRST_REFRESH_START>(); 383 } 384} 385 386void ConsumerFrameEventHistory::addPostComposition(uint64_t frameNumber, 387 sp<Fence> gpuCompositionDone, sp<Fence> displayPresent) { 388 FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset); 389 if (frame == nullptr) { 390 ALOGE("ConsumerFrameEventHistory::addPostComposition: " 391 "Did not find frame."); 392 return; 393 } 394 // Only get GPU and present info for the first composite. 395 if (!frame->addPostCompositeCalled) { 396 frame->addPostCompositeCalled = true; 397 frame->gpuCompositionDoneFence = gpuCompositionDone; 398 mFramesDirty[mCompositionOffset].setDirty<FrameEvent::GL_COMPOSITION_DONE>(); 399 if (!frame->displayPresentFence->isValid()) { 400 frame->displayPresentFence = displayPresent; 401 mFramesDirty[mCompositionOffset].setDirty<FrameEvent::DISPLAY_PRESENT>(); 402 } 403 } 404} 405 406void ConsumerFrameEventHistory::addRetire( 407 uint64_t frameNumber, sp<Fence> displayRetire) { 408 FrameEvents* frame = getFrame(frameNumber, &mRetireOffset); 409 if (frame == nullptr) { 410 ALOGE("ConsumerFrameEventHistory::addRetire: Did not find frame."); 411 return; 412 } 413 frame->addRetireCalled = true; 414 frame->displayRetireFence = displayRetire; 415 mFramesDirty[mRetireOffset].setDirty<FrameEvent::DISPLAY_RETIRE>(); 416} 417 418void ConsumerFrameEventHistory::addRelease( 419 uint64_t frameNumber, sp<Fence> release) { 420 FrameEvents* frame = getFrame(frameNumber, &mReleaseOffset); 421 if (frame == nullptr) { 422 ALOGE("ConsumerFrameEventHistory::addRelease: Did not find frame."); 423 return; 424 } 425 frame->addReleaseCalled = true; 426 frame->releaseFence = release; 427 mFramesDirty[mReleaseOffset].setDirty<FrameEvent::RELEASE>(); 428} 429 430void ConsumerFrameEventHistory::getAndResetDelta( 431 FrameEventHistoryDelta* delta) { 432 delta->mDeltas.reserve(mFramesDirty.size()); 433 for (size_t i = 0; i < mFramesDirty.size(); i++) { 434 if (mFramesDirty[i].anyDirty()) { 435 delta->mDeltas.push_back( 436 FrameEventsDelta(i, mFrames[i], mFramesDirty[i])); 437 mFramesDirty[i].reset(); 438 } 439 } 440} 441 442 443// ============================================================================ 444// FrameEventsDelta 445// ============================================================================ 446 447FrameEventsDelta::FrameEventsDelta( 448 size_t index, 449 const FrameEvents& frameTimestamps, 450 const FrameEventDirtyFields& dirtyFields) 451 : mIndex(index), 452 mFrameNumber(frameTimestamps.frameNumber), 453 mAddPostCompositeCalled(frameTimestamps.addPostCompositeCalled), 454 mAddRetireCalled(frameTimestamps.addRetireCalled), 455 mAddReleaseCalled(frameTimestamps.addReleaseCalled), 456 mPostedTime(frameTimestamps.postedTime), 457 mRequestedPresentTime(frameTimestamps.requestedPresentTime), 458 mLatchTime(frameTimestamps.latchTime), 459 mFirstRefreshStartTime(frameTimestamps.firstRefreshStartTime), 460 mLastRefreshStartTime(frameTimestamps.lastRefreshStartTime) { 461 mGpuCompositionDoneFence = 462 dirtyFields.isDirty<FrameEvent::GL_COMPOSITION_DONE>() ? 463 frameTimestamps.gpuCompositionDoneFence : Fence::NO_FENCE; 464 mDisplayPresentFence = dirtyFields.isDirty<FrameEvent::DISPLAY_PRESENT>() ? 465 frameTimestamps.displayPresentFence : Fence::NO_FENCE; 466 mDisplayRetireFence = dirtyFields.isDirty<FrameEvent::DISPLAY_RETIRE>() ? 467 frameTimestamps.displayRetireFence : Fence::NO_FENCE; 468 mReleaseFence = dirtyFields.isDirty<FrameEvent::RELEASE>() ? 469 frameTimestamps.releaseFence : Fence::NO_FENCE; 470} 471 472size_t FrameEventsDelta::minFlattenedSize() { 473 constexpr size_t min = 474 sizeof(FrameEventsDelta::mFrameNumber) + 475 sizeof(uint8_t) + // mIndex 476 sizeof(uint8_t) + // mAddPostCompositeCalled 477 sizeof(uint8_t) + // mAddRetireCalled 478 sizeof(uint8_t) + // mAddReleaseCalled 479 sizeof(FrameEventsDelta::mPostedTime) + 480 sizeof(FrameEventsDelta::mRequestedPresentTime) + 481 sizeof(FrameEventsDelta::mLatchTime) + 482 sizeof(FrameEventsDelta::mFirstRefreshStartTime) + 483 sizeof(FrameEventsDelta::mLastRefreshStartTime); 484 return min; 485} 486 487// Flattenable implementation 488size_t FrameEventsDelta::getFlattenedSize() const { 489 auto fences = allFences(this); 490 return minFlattenedSize() + 491 std::accumulate(fences.begin(), fences.end(), size_t(0), 492 [](size_t a, const sp<Fence>* fence) { 493 return a + (*fence)->getFlattenedSize(); 494 }); 495} 496 497size_t FrameEventsDelta::getFdCount() const { 498 auto fences = allFences(this); 499 return std::accumulate(fences.begin(), fences.end(), size_t(0), 500 [](size_t a, const sp<Fence>* fence) { 501 return a + (*fence)->getFdCount(); 502 }); 503} 504 505status_t FrameEventsDelta::flatten(void*& buffer, size_t& size, int*& fds, 506 size_t& count) const { 507 if (size < getFlattenedSize() || count < getFdCount()) { 508 return NO_MEMORY; 509 } 510 511 if (mIndex >= FrameEventHistory::MAX_FRAME_HISTORY || 512 mIndex > std::numeric_limits<uint8_t>::max()) { 513 return BAD_VALUE; 514 } 515 516 FlattenableUtils::write(buffer, size, mFrameNumber); 517 518 // These are static_cast to uint8_t for alignment. 519 FlattenableUtils::write(buffer, size, static_cast<uint8_t>(mIndex)); 520 FlattenableUtils::write( 521 buffer, size, static_cast<uint8_t>(mAddPostCompositeCalled)); 522 FlattenableUtils::write( 523 buffer, size, static_cast<uint8_t>(mAddRetireCalled)); 524 FlattenableUtils::write( 525 buffer, size, static_cast<uint8_t>(mAddReleaseCalled)); 526 527 FlattenableUtils::write(buffer, size, mPostedTime); 528 FlattenableUtils::write(buffer, size, mRequestedPresentTime); 529 FlattenableUtils::write(buffer, size, mLatchTime); 530 FlattenableUtils::write(buffer, size, mFirstRefreshStartTime); 531 FlattenableUtils::write(buffer, size, mLastRefreshStartTime); 532 533 // Fences 534 for (auto fence : allFences(this)) { 535 status_t status = (*fence)->flatten(buffer, size, fds, count); 536 if (status != NO_ERROR) { 537 return status; 538 } 539 } 540 return NO_ERROR; 541} 542 543status_t FrameEventsDelta::unflatten(void const*& buffer, size_t& size, 544 int const*& fds, size_t& count) { 545 if (size < minFlattenedSize()) { 546 return NO_MEMORY; 547 } 548 549 FlattenableUtils::read(buffer, size, mFrameNumber); 550 551 // These were written as uint8_t for alignment. 552 uint8_t temp = 0; 553 FlattenableUtils::read(buffer, size, temp); 554 mIndex = temp; 555 if (mIndex >= FrameEventHistory::MAX_FRAME_HISTORY) { 556 return BAD_VALUE; 557 } 558 FlattenableUtils::read(buffer, size, temp); 559 mAddPostCompositeCalled = static_cast<bool>(temp); 560 FlattenableUtils::read(buffer, size, temp); 561 mAddRetireCalled = static_cast<bool>(temp); 562 FlattenableUtils::read(buffer, size, temp); 563 mAddReleaseCalled = static_cast<bool>(temp); 564 565 FlattenableUtils::read(buffer, size, mPostedTime); 566 FlattenableUtils::read(buffer, size, mRequestedPresentTime); 567 FlattenableUtils::read(buffer, size, mLatchTime); 568 FlattenableUtils::read(buffer, size, mFirstRefreshStartTime); 569 FlattenableUtils::read(buffer, size, mLastRefreshStartTime); 570 571 // Fences 572 for (auto fence : allFences(this)) { 573 *fence = new Fence; 574 status_t status = (*fence)->unflatten(buffer, size, fds, count); 575 if (status != NO_ERROR) { 576 return status; 577 } 578 } 579 return NO_ERROR; 580} 581 582 583// ============================================================================ 584// FrameEventHistoryDelta 585// ============================================================================ 586 587size_t FrameEventHistoryDelta::minFlattenedSize() { 588 return sizeof(uint32_t); 589} 590 591size_t FrameEventHistoryDelta::getFlattenedSize() const { 592 return minFlattenedSize() + 593 std::accumulate(mDeltas.begin(), mDeltas.end(), size_t(0), 594 [](size_t a, const FrameEventsDelta& delta) { 595 return a + delta.getFlattenedSize(); 596 }); 597} 598 599size_t FrameEventHistoryDelta::getFdCount() const { 600 return std::accumulate(mDeltas.begin(), mDeltas.end(), size_t(0), 601 [](size_t a, const FrameEventsDelta& delta) { 602 return a + delta.getFdCount(); 603 }); 604} 605 606status_t FrameEventHistoryDelta::flatten( 607 void*& buffer, size_t& size, int*& fds, size_t& count) const { 608 if (mDeltas.size() > FrameEventHistory::MAX_FRAME_HISTORY) { 609 return BAD_VALUE; 610 } 611 if (size < getFlattenedSize()) { 612 return NO_MEMORY; 613 } 614 615 FlattenableUtils::write( 616 buffer, size, static_cast<uint32_t>(mDeltas.size())); 617 for (auto& d : mDeltas) { 618 status_t status = d.flatten(buffer, size, fds, count); 619 if (status != NO_ERROR) { 620 return status; 621 } 622 } 623 return NO_ERROR; 624} 625 626status_t FrameEventHistoryDelta::unflatten( 627 void const*& buffer, size_t& size, int const*& fds, size_t& count) { 628 if (size < minFlattenedSize()) { 629 return NO_MEMORY; 630 } 631 632 uint32_t deltaCount = 0; 633 FlattenableUtils::read(buffer, size, deltaCount); 634 if (deltaCount > FrameEventHistory::MAX_FRAME_HISTORY) { 635 return BAD_VALUE; 636 } 637 mDeltas.resize(deltaCount); 638 for (auto& d : mDeltas) { 639 status_t status = d.unflatten(buffer, size, fds, count); 640 if (status != NO_ERROR) { 641 return status; 642 } 643 } 644 return NO_ERROR; 645} 646 647 648} // namespace android 649