| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #ifndef ANDROID_HARDWARE_HIDL_CACHE_H |
| #define ANDROID_HARDWARE_HIDL_CACHE_H |
| |
| #include <utils/Log.h> |
| |
| namespace android { |
| namespace hardware { |
| |
| // A generic cache to map Key to sp<Value>. The cache records are kept with |
| // wp<Value>, so that it does not block the Value to be garbage collected |
| // when there's no other sp<> externally. |
| template <class Key, class Value, class Compare = std::less<Key>> |
| class HidlCache : public virtual RefBase { |
| using Mutex = std::mutex; |
| using Lock = std::lock_guard<Mutex>; |
| |
| public: |
| // A RAII class to manage lock/unlock HidlCache. |
| class HidlCacheLock : public virtual RefBase { |
| public: |
| HidlCacheLock(sp<HidlCache> cache, const Key& key) : mCache(cache), mKey(key) { |
| mCache->lock(mKey); |
| } |
| ~HidlCacheLock() { mCache->unlock(mKey); } |
| |
| private: |
| sp<HidlCache> mCache; |
| const Key mKey; |
| }; |
| // lock the IMemory refered by key and keep it alive even if there's no |
| // other memory block refers to. |
| virtual bool lock(const Key& key); |
| virtual sp<Value> unlock(const Key& key); |
| virtual bool flush(const Key& key); |
| // fetch the sp<Value> with key from cache, |
| // make a new instance with fill() if it does not present currently. |
| virtual sp<Value> fetch(const Key& key); |
| virtual sp<HidlCacheLock> lockGuard(const Key& key) { return new HidlCacheLock(this, key); } |
| |
| virtual ~HidlCache() {} |
| |
| protected: |
| friend void HidlCacheWhiteBoxTest(); |
| // This method shall be called with a lock held |
| virtual sp<Value> fillLocked(const Key& key) = 0; |
| |
| // @return nullptr if it does not present currently. |
| // @note This method shall be called with a lock held |
| virtual sp<Value> getCachedLocked(const Key& key); |
| bool cached(Key key) const { return mCached.count(key) > 0; } |
| bool locked(Key key) const { return mLocked.count(key) > 0; } |
| Mutex mMutex; |
| |
| std::map<Key, wp<Value>, Compare> mCached; |
| std::map<Key, sp<Value>, Compare> mLocked; |
| }; |
| |
| template <class Key, class Value, class Compare> |
| bool HidlCache<Key, Value, Compare>::lock(const Key& key) { |
| { |
| Lock lock(mMutex); |
| if (cached(key)) { |
| sp<Value> im = mCached[key].promote(); |
| if (im != nullptr) { |
| mLocked[key] = im; |
| return true; |
| } else { |
| mCached.erase(key); |
| } |
| } |
| } |
| sp<Value> value = fetch(key); |
| if (value == nullptr) { |
| return false; |
| } else { |
| Lock lock(mMutex); |
| mLocked[key] = value; |
| return true; |
| } |
| } |
| |
| template <class Key, class Value, class Compare> |
| sp<Value> HidlCache<Key, Value, Compare>::unlock(const Key& key) { |
| Lock lock(mMutex); |
| if (locked(key) > 0) { |
| sp<Value> v = mLocked[key]; |
| mLocked.erase(key); |
| return v; |
| } |
| return nullptr; |
| } |
| |
| template <class Key, class Value, class Compare> |
| bool HidlCache<Key, Value, Compare>::flush(const Key& key) { |
| Lock lock(mMutex); |
| bool contain = cached(key); |
| mCached.erase(key); |
| return contain; |
| } |
| |
| template <class Key, class Value, class Compare> |
| sp<Value> HidlCache<Key, Value, Compare>::getCachedLocked(const Key& key) { |
| if (cached(key)) { |
| wp<Value> cache = mCached[key]; |
| sp<Value> mem = cache.promote(); |
| if (mem != nullptr) { |
| return mem; |
| } else { |
| mCached.erase(key); |
| } |
| } |
| return nullptr; |
| } |
| |
| template <class Key, class Value, class Compare> |
| sp<Value> HidlCache<Key, Value, Compare>::fetch(const Key& key) { |
| Lock lock(mMutex); |
| sp<Value> value = getCachedLocked(key); |
| |
| if (value == nullptr) { |
| value = fillLocked(key); |
| } |
| return value; |
| } |
| |
| } // namespace hardware |
| } // namespace android |
| #endif |