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