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