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