Home | History | Annotate | Download | only in ui
      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 <ui/FenceTime.h>
     18 
     19 #define LOG_TAG "FenceTime"
     20 
     21 #include <cutils/compiler.h>  // For CC_[UN]LIKELY
     22 #include <utils/Log.h>
     23 #include <inttypes.h>
     24 #include <stdlib.h>
     25 
     26 #include <memory>
     27 
     28 namespace android {
     29 
     30 // ============================================================================
     31 // FenceTime
     32 // ============================================================================
     33 
     34 const auto FenceTime::NO_FENCE = std::make_shared<FenceTime>(Fence::NO_FENCE);
     35 
     36 void* FenceTime::operator new(size_t byteCount) noexcept {
     37     void *p = nullptr;
     38     if (posix_memalign(&p, alignof(FenceTime), byteCount)) {
     39         return nullptr;
     40     }
     41     return p;
     42 }
     43 
     44 void FenceTime::operator delete(void *p) {
     45     free(p);
     46 }
     47 
     48 FenceTime::FenceTime(const sp<Fence>& fence)
     49   : mState(((fence.get() != nullptr) && fence->isValid()) ?
     50             State::VALID : State::INVALID),
     51     mFence(fence),
     52     mSignalTime(mState == State::INVALID ?
     53             Fence::SIGNAL_TIME_INVALID : Fence::SIGNAL_TIME_PENDING) {
     54 }
     55 
     56 FenceTime::FenceTime(sp<Fence>&& fence)
     57   : mState(((fence.get() != nullptr) && fence->isValid()) ?
     58             State::VALID : State::INVALID),
     59     mFence(std::move(fence)),
     60     mSignalTime(mState == State::INVALID ?
     61             Fence::SIGNAL_TIME_INVALID : Fence::SIGNAL_TIME_PENDING) {
     62 }
     63 
     64 FenceTime::FenceTime(nsecs_t signalTime)
     65   : mState(Fence::isValidTimestamp(signalTime) ? State::VALID : State::INVALID),
     66     mFence(nullptr),
     67     mSignalTime(signalTime) {
     68     if (CC_UNLIKELY(mSignalTime == Fence::SIGNAL_TIME_PENDING)) {
     69         ALOGE("Pending signal time not allowed after signal.");
     70         mSignalTime = Fence::SIGNAL_TIME_INVALID;
     71     }
     72 }
     73 
     74 void FenceTime::applyTrustedSnapshot(const Snapshot& src) {
     75     if (CC_UNLIKELY(src.state != Snapshot::State::SIGNAL_TIME)) {
     76         // Applying Snapshot::State::FENCE, could change the valid state of the
     77         // FenceTime, which is not allowed. Callers should create a new
     78         // FenceTime from the snapshot instead.
     79         ALOGE("applyTrustedSnapshot: Unexpected fence.");
     80         return;
     81     }
     82 
     83     if (src.state == Snapshot::State::EMPTY) {
     84         return;
     85     }
     86 
     87     nsecs_t signalTime = mSignalTime.load(std::memory_order_relaxed);
     88     if (signalTime != Fence::SIGNAL_TIME_PENDING) {
     89         // We should always get the same signalTime here that we did in
     90         // getSignalTime(). This check races with getSignalTime(), but it is
     91         // only a sanity check so that's okay.
     92         if (CC_UNLIKELY(signalTime != src.signalTime)) {
     93             ALOGE("FenceTime::applyTrustedSnapshot: signalTime mismatch. "
     94                     "(%" PRId64 " (old) != %" PRId64 " (new))",
     95                     signalTime, src.signalTime);
     96         }
     97         return;
     98     }
     99 
    100     std::lock_guard<std::mutex> lock(mMutex);
    101     mFence.clear();
    102     mSignalTime.store(src.signalTime, std::memory_order_relaxed);
    103 }
    104 
    105 bool FenceTime::isValid() const {
    106     // We store the valid state in the constructors and return it here.
    107     // This lets release code remember the valid state even after the
    108     // underlying fence is destroyed.
    109     return mState != State::INVALID;
    110 }
    111 
    112 nsecs_t FenceTime::getSignalTime() {
    113     // See if we already have a cached value we can return.
    114     nsecs_t signalTime = mSignalTime.load(std::memory_order_relaxed);
    115     if (signalTime != Fence::SIGNAL_TIME_PENDING) {
    116         return signalTime;
    117     }
    118 
    119     // Hold a reference to the fence on the stack in case the class'
    120     // reference is removed by another thread. This prevents the
    121     // fence from being destroyed until the end of this method, where
    122     // we conveniently do not have the lock held.
    123     sp<Fence> fence;
    124     {
    125         // With the lock acquired this time, see if we have the cached
    126         // value or if we need to poll the fence.
    127         std::lock_guard<std::mutex> lock(mMutex);
    128         if (!mFence.get()) {
    129             // Another thread set the signal time just before we added the
    130             // reference to mFence.
    131             return mSignalTime.load(std::memory_order_relaxed);
    132         }
    133         fence = mFence;
    134     }
    135 
    136     // Make the system call without the lock held.
    137     signalTime = fence->getSignalTime();
    138 
    139     // Allow tests to override SIGNAL_TIME_INVALID behavior, since tests
    140     // use invalid underlying Fences without real file descriptors.
    141     if (CC_UNLIKELY(mState == State::FORCED_VALID_FOR_TEST)) {
    142         if (signalTime == Fence::SIGNAL_TIME_INVALID) {
    143             signalTime = Fence::SIGNAL_TIME_PENDING;
    144         }
    145     }
    146 
    147     // Make the signal time visible to everyone if it is no longer pending
    148     // and remove the class' reference to the fence.
    149     if (signalTime != Fence::SIGNAL_TIME_PENDING) {
    150         std::lock_guard<std::mutex> lock(mMutex);
    151         mFence.clear();
    152         mSignalTime.store(signalTime, std::memory_order_relaxed);
    153     }
    154 
    155     return signalTime;
    156 }
    157 
    158 nsecs_t FenceTime::getCachedSignalTime() const {
    159     // memory_order_acquire since we don't have a lock fallback path
    160     // that will do an acquire.
    161     return mSignalTime.load(std::memory_order_acquire);
    162 }
    163 
    164 FenceTime::Snapshot FenceTime::getSnapshot() const {
    165     // Quick check without the lock.
    166     nsecs_t signalTime = mSignalTime.load(std::memory_order_relaxed);
    167     if (signalTime != Fence::SIGNAL_TIME_PENDING) {
    168         return Snapshot(signalTime);
    169     }
    170 
    171     // Do the full check with the lock.
    172     std::lock_guard<std::mutex> lock(mMutex);
    173     signalTime = mSignalTime.load(std::memory_order_relaxed);
    174     if (signalTime != Fence::SIGNAL_TIME_PENDING) {
    175         return Snapshot(signalTime);
    176     }
    177     return Snapshot(mFence);
    178 }
    179 
    180 // For tests only. If forceValidForTest is true, then getSignalTime will
    181 // never return SIGNAL_TIME_INVALID and isValid will always return true.
    182 FenceTime::FenceTime(const sp<Fence>& fence, bool forceValidForTest)
    183   : mState(forceValidForTest ?
    184             State::FORCED_VALID_FOR_TEST : State::INVALID),
    185     mFence(fence),
    186     mSignalTime(mState == State::INVALID ?
    187             Fence::SIGNAL_TIME_INVALID : Fence::SIGNAL_TIME_PENDING) {
    188 }
    189 
    190 void FenceTime::signalForTest(nsecs_t signalTime) {
    191     // To be realistic, this should really set a hidden value that
    192     // gets picked up in the next call to getSignalTime, but this should
    193     // be good enough.
    194     std::lock_guard<std::mutex> lock(mMutex);
    195     mFence.clear();
    196     mSignalTime.store(signalTime, std::memory_order_relaxed);
    197 }
    198 
    199 // ============================================================================
    200 // FenceTime::Snapshot
    201 // ============================================================================
    202 FenceTime::Snapshot::Snapshot(const sp<Fence>& srcFence)
    203     : state(State::FENCE), fence(srcFence) {
    204 }
    205 
    206 FenceTime::Snapshot::Snapshot(nsecs_t srcSignalTime)
    207     : state(State::SIGNAL_TIME), signalTime(srcSignalTime) {
    208 }
    209 
    210 size_t FenceTime::Snapshot::getFlattenedSize() const {
    211     constexpr size_t min = sizeof(state);
    212     switch (state) {
    213         case State::EMPTY:
    214             return min;
    215         case State::FENCE:
    216             return min + fence->getFlattenedSize();
    217         case State::SIGNAL_TIME:
    218             return min + sizeof(signalTime);
    219     }
    220     return 0;
    221 }
    222 
    223 size_t FenceTime::Snapshot::getFdCount() const {
    224     return state == State::FENCE ? fence->getFdCount() : 0u;
    225 }
    226 
    227 status_t FenceTime::Snapshot::flatten(
    228         void*& buffer, size_t& size, int*& fds, size_t& count) const {
    229     if (size < getFlattenedSize()) {
    230         return NO_MEMORY;
    231     }
    232 
    233     FlattenableUtils::write(buffer, size, state);
    234     switch (state) {
    235         case State::EMPTY:
    236             return NO_ERROR;
    237         case State::FENCE:
    238             return fence->flatten(buffer, size, fds, count);
    239         case State::SIGNAL_TIME:
    240             FlattenableUtils::write(buffer, size, signalTime);
    241             return NO_ERROR;
    242     }
    243 
    244     return NO_ERROR;
    245 }
    246 
    247 status_t FenceTime::Snapshot::unflatten(
    248         void const*& buffer, size_t& size, int const*& fds, size_t& count) {
    249     if (size < sizeof(state)) {
    250         return NO_MEMORY;
    251     }
    252 
    253     FlattenableUtils::read(buffer, size, state);
    254     switch (state) {
    255         case State::EMPTY:
    256             return NO_ERROR;
    257         case State::FENCE:
    258             fence = new Fence;
    259             return fence->unflatten(buffer, size, fds, count);
    260         case State::SIGNAL_TIME:
    261             if (size < sizeof(signalTime)) {
    262                 return NO_MEMORY;
    263             }
    264             FlattenableUtils::read(buffer, size, signalTime);
    265             return NO_ERROR;
    266     }
    267 
    268     return NO_ERROR;
    269 }
    270 
    271 // ============================================================================
    272 // FenceTimeline
    273 // ============================================================================
    274 void FenceTimeline::push(const std::shared_ptr<FenceTime>& fence) {
    275     std::lock_guard<std::mutex> lock(mMutex);
    276     while (mQueue.size() >= MAX_ENTRIES) {
    277         // This is a sanity check to make sure the queue doesn't grow unbounded.
    278         // MAX_ENTRIES should be big enough not to trigger this path.
    279         // In case this path is taken though, users of FenceTime must make sure
    280         // not to rely solely on FenceTimeline to get the final timestamp and
    281         // should eventually call Fence::getSignalTime on their own.
    282         std::shared_ptr<FenceTime> front = mQueue.front().lock();
    283         if (front) {
    284             // Make a last ditch effort to get the signalTime here since
    285             // we are removing it from the timeline.
    286             front->getSignalTime();
    287         }
    288         mQueue.pop();
    289     }
    290     mQueue.push(fence);
    291 }
    292 
    293 void FenceTimeline::updateSignalTimes() {
    294     while (!mQueue.empty()) {
    295         std::lock_guard<std::mutex> lock(mMutex);
    296         std::shared_ptr<FenceTime> fence = mQueue.front().lock();
    297         if (!fence) {
    298             // The shared_ptr no longer exists and no one cares about the
    299             // timestamp anymore.
    300             mQueue.pop();
    301             continue;
    302         } else if (fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) {
    303             // The fence has signaled and we've removed the sp<Fence> ref.
    304             mQueue.pop();
    305             continue;
    306         } else {
    307             // The fence didn't signal yet. Break since the later ones
    308             // shouldn't have signaled either.
    309             break;
    310         }
    311     }
    312 }
    313 
    314 // ============================================================================
    315 // FenceToFenceTimeMap
    316 // ============================================================================
    317 std::shared_ptr<FenceTime> FenceToFenceTimeMap::createFenceTimeForTest(
    318         const sp<Fence>& fence) {
    319     std::lock_guard<std::mutex> lock(mMutex);
    320     // Always garbage collecting isn't efficient, but this is only for testing.
    321     garbageCollectLocked();
    322     std::shared_ptr<FenceTime> fenceTime(new FenceTime(fence, true));
    323     mMap[fence.get()].push_back(fenceTime);
    324     return fenceTime;
    325 }
    326 
    327 void FenceToFenceTimeMap::signalAllForTest(
    328         const sp<Fence>& fence, nsecs_t signalTime) {
    329     bool signaled = false;
    330 
    331     std::lock_guard<std::mutex> lock(mMutex);
    332     auto it = mMap.find(fence.get());
    333     if (it != mMap.end()) {
    334         for (auto& weakFenceTime : it->second) {
    335             std::shared_ptr<FenceTime> fenceTime = weakFenceTime.lock();
    336             if (!fenceTime) {
    337                 continue;
    338             }
    339             ALOGE_IF(!fenceTime->isValid(),
    340                     "signalAllForTest: Signaling invalid fence.");
    341             fenceTime->signalForTest(signalTime);
    342             signaled = true;
    343         }
    344     }
    345 
    346     ALOGE_IF(!signaled, "signalAllForTest: Nothing to signal.");
    347 }
    348 
    349 void FenceToFenceTimeMap::garbageCollectLocked() {
    350     for (auto& it : mMap) {
    351         // Erase all expired weak pointers from the vector.
    352         auto& vect = it.second;
    353         vect.erase(
    354                 std::remove_if(vect.begin(), vect.end(),
    355                         [](const std::weak_ptr<FenceTime>& ft) {
    356                             return ft.expired();
    357                         }),
    358                 vect.end());
    359 
    360         // Also erase the map entry if the vector is now empty.
    361         if (vect.empty()) {
    362             mMap.erase(it.first);
    363         }
    364     }
    365 }
    366 
    367 } // namespace android
    368