FrameTimestamps.cpp revision 3890c3995c4a52439844faeb80b5503d42b977d8
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(&frame.acquireFence, d.mAcquireFence); 305 applyFenceDelta( 306 &frame.gpuCompositionDoneFence, d.mGpuCompositionDoneFence); 307 applyFenceDelta(&frame.displayPresentFence, d.mDisplayPresentFence); 308 applyFenceDelta(&frame.displayRetireFence, d.mDisplayRetireFence); 309 applyFenceDelta(&frame.releaseFence, d.mReleaseFence); 310 } else { 311 // New frame. Overwrite. 312 frame.frameNumber = d.mFrameNumber; 313 314 frame.gpuCompositionDoneFence = d.mGpuCompositionDoneFence; 315 frame.displayPresentFence = d.mDisplayPresentFence; 316 frame.displayRetireFence = d.mDisplayRetireFence; 317 frame.releaseFence = d.mReleaseFence; 318 319 // Set aquire fence and time at this point. 320 frame.acquireTime = 0; 321 frame.acquireFence = d.mAcquireFence; 322 323 // Reset fence-related timestamps 324 frame.gpuCompositionDoneTime = 0; 325 frame.displayPresentTime = 0; 326 frame.displayRetireTime = 0; 327 frame.releaseTime = 0; 328 329 // The consumer only sends valid frames. 330 frame.valid = true; 331 } 332 } 333} 334 335 336// ============================================================================ 337// ConsumerFrameEventHistory 338// ============================================================================ 339 340ConsumerFrameEventHistory::~ConsumerFrameEventHistory() = default; 341 342void ConsumerFrameEventHistory::addQueue(const NewFrameEventsEntry& newEntry) { 343 // Overwrite all fields of the frame with default values unless set here. 344 FrameEvents newTimestamps; 345 newTimestamps.frameNumber = newEntry.frameNumber; 346 newTimestamps.postedTime = newEntry.postedTime; 347 newTimestamps.requestedPresentTime = newEntry.requestedPresentTime; 348 newTimestamps.acquireFence = newEntry.acquireFence; 349 newTimestamps.valid = true; 350 mFrames[mQueueOffset] = newTimestamps; 351 mFramesDirty[mQueueOffset].setDirty<FrameEvent::POSTED>(); 352 mFramesDirty[mQueueOffset].setDirty<FrameEvent::ACQUIRE>(); 353 354 mQueueOffset = (mQueueOffset + 1) % mFrames.size(); 355} 356 357void ConsumerFrameEventHistory::addLatch( 358 uint64_t frameNumber, nsecs_t latchTime) { 359 FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset); 360 if (frame == nullptr) { 361 ALOGE("ConsumerFrameEventHistory::addLatch: Did not find frame."); 362 return; 363 } 364 frame->latchTime = latchTime; 365 mFramesDirty[mCompositionOffset].setDirty<FrameEvent::LATCH>(); 366} 367 368void ConsumerFrameEventHistory::addPreComposition( 369 uint64_t frameNumber, nsecs_t refreshStartTime) { 370 FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset); 371 if (frame == nullptr) { 372 ALOGE("ConsumerFrameEventHistory::addPreComposition: " 373 "Did not find frame."); 374 return; 375 } 376 frame->lastRefreshStartTime = refreshStartTime; 377 mFramesDirty[mCompositionOffset].setDirty<FrameEvent::LAST_REFRESH_START>(); 378 if (!isValidTimestamp(frame->firstRefreshStartTime)) { 379 frame->firstRefreshStartTime = refreshStartTime; 380 mFramesDirty[mCompositionOffset].setDirty<FrameEvent::FIRST_REFRESH_START>(); 381 } 382} 383 384void ConsumerFrameEventHistory::addPostComposition(uint64_t frameNumber, 385 sp<Fence> gpuCompositionDone, sp<Fence> displayPresent) { 386 FrameEvents* frame = getFrame(frameNumber, &mCompositionOffset); 387 if (frame == nullptr) { 388 ALOGE("ConsumerFrameEventHistory::addPostComposition: " 389 "Did not find frame."); 390 return; 391 } 392 // Only get GPU and present info for the first composite. 393 if (!frame->addPostCompositeCalled) { 394 frame->addPostCompositeCalled = true; 395 frame->gpuCompositionDoneFence = gpuCompositionDone; 396 mFramesDirty[mCompositionOffset].setDirty<FrameEvent::GL_COMPOSITION_DONE>(); 397 if (!frame->displayPresentFence->isValid()) { 398 frame->displayPresentFence = displayPresent; 399 mFramesDirty[mCompositionOffset].setDirty<FrameEvent::DISPLAY_PRESENT>(); 400 } 401 } 402} 403 404void ConsumerFrameEventHistory::addRetire( 405 uint64_t frameNumber, sp<Fence> displayRetire) { 406 FrameEvents* frame = getFrame(frameNumber, &mRetireOffset); 407 if (frame == nullptr) { 408 ALOGE("ConsumerFrameEventHistory::addRetire: Did not find frame."); 409 return; 410 } 411 frame->addRetireCalled = true; 412 frame->displayRetireFence = displayRetire; 413 mFramesDirty[mRetireOffset].setDirty<FrameEvent::DISPLAY_RETIRE>(); 414} 415 416void ConsumerFrameEventHistory::addRelease( 417 uint64_t frameNumber, sp<Fence> release) { 418 FrameEvents* frame = getFrame(frameNumber, &mReleaseOffset); 419 if (frame == nullptr) { 420 ALOGE("ConsumerFrameEventHistory::addRelease: Did not find frame."); 421 return; 422 } 423 frame->addReleaseCalled = true; 424 frame->releaseFence = release; 425 mFramesDirty[mReleaseOffset].setDirty<FrameEvent::RELEASE>(); 426} 427 428void ConsumerFrameEventHistory::getAndResetDelta( 429 FrameEventHistoryDelta* delta) { 430 delta->mDeltas.reserve(mFramesDirty.size()); 431 for (size_t i = 0; i < mFramesDirty.size(); i++) { 432 if (mFramesDirty[i].anyDirty()) { 433 delta->mDeltas.push_back( 434 FrameEventsDelta(i, mFrames[i], mFramesDirty[i])); 435 mFramesDirty[i].reset(); 436 } 437 } 438} 439 440 441// ============================================================================ 442// FrameEventsDelta 443// ============================================================================ 444 445FrameEventsDelta::FrameEventsDelta( 446 size_t index, 447 const FrameEvents& frameTimestamps, 448 const FrameEventDirtyFields& dirtyFields) 449 : mIndex(index), 450 mFrameNumber(frameTimestamps.frameNumber), 451 mAddPostCompositeCalled(frameTimestamps.addPostCompositeCalled), 452 mAddRetireCalled(frameTimestamps.addRetireCalled), 453 mAddReleaseCalled(frameTimestamps.addReleaseCalled), 454 mPostedTime(frameTimestamps.postedTime), 455 mRequestedPresentTime(frameTimestamps.requestedPresentTime), 456 mLatchTime(frameTimestamps.latchTime), 457 mFirstRefreshStartTime(frameTimestamps.firstRefreshStartTime), 458 mLastRefreshStartTime(frameTimestamps.lastRefreshStartTime) { 459 mAcquireFence = dirtyFields.isDirty<FrameEvent::ACQUIRE>() ? 460 frameTimestamps.acquireFence : Fence::NO_FENCE; 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