FrameTimestamps.cpp revision 3d4039d7a291cd9b6f2dd4b46fcdb576f2db3356
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("ConsumerFrameEventHistory::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("ConsumerFrameEventHistory::addPreComposition: "
364              "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("ConsumerFrameEventHistory::addPostComposition: "
381              "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("ConsumerFrameEventHistory::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    size_t i = static_cast<size_t>(std::distance(mFrames.begin(), frame));
424    if (mFramesDirty[i].anyDirty()) {
425        delta->mDeltas.emplace_back(i, *frame, mFramesDirty[i]);
426        mFramesDirty[i].reset();
427    }
428}
429
430void ConsumerFrameEventHistory::getAndResetDelta(
431        FrameEventHistoryDelta* delta) {
432    // Write these in order of frame number so that it is easy to
433    // add them to a FenceTimeline in the proper order producer side.
434    delta->mDeltas.reserve(mFramesDirty.size());
435    auto earliestFrame = std::min_element(
436            mFrames.begin(), mFrames.end(), &FrameNumberLessThan);
437    for (auto frame = earliestFrame; frame != mFrames.end(); ++frame) {
438        getFrameDelta(delta, frame);
439    }
440    for (auto frame = mFrames.begin(); frame != earliestFrame; ++frame) {
441        getFrameDelta(delta, frame);
442    }
443}
444
445
446// ============================================================================
447// FrameEventsDelta
448// ============================================================================
449
450FrameEventsDelta::FrameEventsDelta(
451        size_t index,
452        const FrameEvents& frameTimestamps,
453        const FrameEventDirtyFields& dirtyFields)
454    : mIndex(index),
455      mFrameNumber(frameTimestamps.frameNumber),
456      mAddPostCompositeCalled(frameTimestamps.addPostCompositeCalled),
457      mAddRetireCalled(frameTimestamps.addRetireCalled),
458      mAddReleaseCalled(frameTimestamps.addReleaseCalled),
459      mPostedTime(frameTimestamps.postedTime),
460      mRequestedPresentTime(frameTimestamps.requestedPresentTime),
461      mLatchTime(frameTimestamps.latchTime),
462      mFirstRefreshStartTime(frameTimestamps.firstRefreshStartTime),
463      mLastRefreshStartTime(frameTimestamps.lastRefreshStartTime) {
464    if (dirtyFields.isDirty<FrameEvent::GL_COMPOSITION_DONE>()) {
465        mGpuCompositionDoneFence =
466                frameTimestamps.gpuCompositionDoneFence->getSnapshot();
467    }
468    if (dirtyFields.isDirty<FrameEvent::DISPLAY_PRESENT>()) {
469        mDisplayPresentFence =
470                frameTimestamps.displayPresentFence->getSnapshot();
471    }
472    if (dirtyFields.isDirty<FrameEvent::DISPLAY_RETIRE>()) {
473        mDisplayRetireFence = frameTimestamps.displayRetireFence->getSnapshot();
474    }
475    if (dirtyFields.isDirty<FrameEvent::RELEASE>()) {
476        mReleaseFence = frameTimestamps.releaseFence->getSnapshot();
477    }
478}
479
480size_t FrameEventsDelta::minFlattenedSize() {
481    constexpr size_t min =
482            sizeof(FrameEventsDelta::mFrameNumber) +
483            sizeof(uint8_t) + // mIndex
484            sizeof(uint8_t) + // mAddPostCompositeCalled
485            sizeof(uint8_t) + // mAddRetireCalled
486            sizeof(uint8_t) + // mAddReleaseCalled
487            sizeof(FrameEventsDelta::mPostedTime) +
488            sizeof(FrameEventsDelta::mRequestedPresentTime) +
489            sizeof(FrameEventsDelta::mLatchTime) +
490            sizeof(FrameEventsDelta::mFirstRefreshStartTime) +
491            sizeof(FrameEventsDelta::mLastRefreshStartTime);
492    return min;
493}
494
495// Flattenable implementation
496size_t FrameEventsDelta::getFlattenedSize() const {
497    auto fences = allFences(this);
498    return minFlattenedSize() +
499            std::accumulate(fences.begin(), fences.end(), size_t(0),
500                    [](size_t a, const FenceTime::Snapshot* fence) {
501                            return a + fence->getFlattenedSize();
502                    });
503}
504
505size_t FrameEventsDelta::getFdCount() const {
506    auto fences = allFences(this);
507    return std::accumulate(fences.begin(), fences.end(), size_t(0),
508            [](size_t a, const FenceTime::Snapshot* fence) {
509                return a + fence->getFdCount();
510            });
511}
512
513status_t FrameEventsDelta::flatten(void*& buffer, size_t& size, int*& fds,
514            size_t& count) const {
515    if (size < getFlattenedSize() || count < getFdCount()) {
516        return NO_MEMORY;
517    }
518
519    if (mIndex >= FrameEventHistory::MAX_FRAME_HISTORY ||
520            mIndex > std::numeric_limits<uint8_t>::max()) {
521        return BAD_VALUE;
522    }
523
524    FlattenableUtils::write(buffer, size, mFrameNumber);
525
526    // These are static_cast to uint8_t for alignment.
527    FlattenableUtils::write(buffer, size, static_cast<uint8_t>(mIndex));
528    FlattenableUtils::write(
529            buffer, size, static_cast<uint8_t>(mAddPostCompositeCalled));
530    FlattenableUtils::write(
531            buffer, size, static_cast<uint8_t>(mAddRetireCalled));
532    FlattenableUtils::write(
533            buffer, size, static_cast<uint8_t>(mAddReleaseCalled));
534
535    FlattenableUtils::write(buffer, size, mPostedTime);
536    FlattenableUtils::write(buffer, size, mRequestedPresentTime);
537    FlattenableUtils::write(buffer, size, mLatchTime);
538    FlattenableUtils::write(buffer, size, mFirstRefreshStartTime);
539    FlattenableUtils::write(buffer, size, mLastRefreshStartTime);
540
541    // Fences
542    for (auto fence : allFences(this)) {
543        status_t status = fence->flatten(buffer, size, fds, count);
544        if (status != NO_ERROR) {
545            return status;
546        }
547    }
548    return NO_ERROR;
549}
550
551status_t FrameEventsDelta::unflatten(void const*& buffer, size_t& size,
552            int const*& fds, size_t& count) {
553    if (size < minFlattenedSize()) {
554        return NO_MEMORY;
555    }
556
557    FlattenableUtils::read(buffer, size, mFrameNumber);
558
559    // These were written as uint8_t for alignment.
560    uint8_t temp = 0;
561    FlattenableUtils::read(buffer, size, temp);
562    mIndex = temp;
563    if (mIndex >= FrameEventHistory::MAX_FRAME_HISTORY) {
564        return BAD_VALUE;
565    }
566    FlattenableUtils::read(buffer, size, temp);
567    mAddPostCompositeCalled = static_cast<bool>(temp);
568    FlattenableUtils::read(buffer, size, temp);
569    mAddRetireCalled = static_cast<bool>(temp);
570    FlattenableUtils::read(buffer, size, temp);
571    mAddReleaseCalled = static_cast<bool>(temp);
572
573    FlattenableUtils::read(buffer, size, mPostedTime);
574    FlattenableUtils::read(buffer, size, mRequestedPresentTime);
575    FlattenableUtils::read(buffer, size, mLatchTime);
576    FlattenableUtils::read(buffer, size, mFirstRefreshStartTime);
577    FlattenableUtils::read(buffer, size, mLastRefreshStartTime);
578
579    // Fences
580    for (auto fence : allFences(this)) {
581        status_t status = fence->unflatten(buffer, size, fds, count);
582        if (status != NO_ERROR) {
583            return status;
584        }
585    }
586    return NO_ERROR;
587}
588
589
590// ============================================================================
591// FrameEventHistoryDelta
592// ============================================================================
593
594FrameEventHistoryDelta& FrameEventHistoryDelta::operator=(
595        FrameEventHistoryDelta&& src) {
596    if (CC_UNLIKELY(!mDeltas.empty())) {
597        ALOGE("FrameEventHistoryDelta: Clobbering history.");
598    }
599    mDeltas = std::move(src.mDeltas);
600    ALOGE_IF(src.mDeltas.empty(), "Source mDeltas not empty.");
601    return *this;
602}
603
604size_t FrameEventHistoryDelta::minFlattenedSize() {
605    return sizeof(uint32_t);
606}
607
608size_t FrameEventHistoryDelta::getFlattenedSize() const {
609    return minFlattenedSize() +
610            std::accumulate(mDeltas.begin(), mDeltas.end(), size_t(0),
611                    [](size_t a, const FrameEventsDelta& delta) {
612                            return a + delta.getFlattenedSize();
613                    });
614}
615
616size_t FrameEventHistoryDelta::getFdCount() const {
617    return std::accumulate(mDeltas.begin(), mDeltas.end(), size_t(0),
618            [](size_t a, const FrameEventsDelta& delta) {
619                    return a + delta.getFdCount();
620            });
621}
622
623status_t FrameEventHistoryDelta::flatten(
624            void*& buffer, size_t& size, int*& fds, size_t& count) const {
625    if (mDeltas.size() > FrameEventHistory::MAX_FRAME_HISTORY) {
626        return BAD_VALUE;
627    }
628    if (size < getFlattenedSize()) {
629        return NO_MEMORY;
630    }
631
632    FlattenableUtils::write(
633            buffer, size, static_cast<uint32_t>(mDeltas.size()));
634    for (auto& d : mDeltas) {
635        status_t status = d.flatten(buffer, size, fds, count);
636        if (status != NO_ERROR) {
637            return status;
638        }
639    }
640    return NO_ERROR;
641}
642
643status_t FrameEventHistoryDelta::unflatten(
644            void const*& buffer, size_t& size, int const*& fds, size_t& count) {
645    if (size < minFlattenedSize()) {
646        return NO_MEMORY;
647    }
648
649    uint32_t deltaCount = 0;
650    FlattenableUtils::read(buffer, size, deltaCount);
651    if (deltaCount > FrameEventHistory::MAX_FRAME_HISTORY) {
652        return BAD_VALUE;
653    }
654    mDeltas.resize(deltaCount);
655    for (auto& d : mDeltas) {
656        status_t status = d.unflatten(buffer, size, fds, count);
657        if (status != NO_ERROR) {
658            return status;
659        }
660    }
661    return NO_ERROR;
662}
663
664
665} // namespace android
666