• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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 #ifndef ANDROID_HARDWARE_HIDL_CACHE_H
17 #define ANDROID_HARDWARE_HIDL_CACHE_H
18 
19 #include <utils/Log.h>
20 
21 namespace android {
22 namespace hardware {
23 
24 // A generic cache to map Key to sp<Value>. The cache records are kept with
25 // wp<Value>, so that it does not block the Value to be garbage collected
26 // when there's no other sp<> externally.
27 template <class Key, class Value, class Compare = std::less<Key>>
28 class HidlCache : public virtual RefBase {
29     using Mutex = std::mutex;
30     using Lock = std::lock_guard<Mutex>;
31 
32    public:
33     //  A RAII class to manage lock/unlock HidlCache.
34     class HidlCacheLock : public virtual RefBase {
35        public:
HidlCacheLock(sp<HidlCache> cache,const Key & key)36         HidlCacheLock(sp<HidlCache> cache, const Key& key) : mCache(cache), mKey(key) {
37             mCache->lock(mKey);
38         }
~HidlCacheLock()39         ~HidlCacheLock() { mCache->unlock(mKey); }
40 
41        private:
42         sp<HidlCache> mCache;
43         const Key mKey;
44     };
45     // lock the IMemory refered by key and keep it alive even if there's no
46     // other memory block refers to.
47     virtual bool lock(const Key& key);
48     virtual sp<Value> unlock(const Key& key);
49     virtual bool flush(const Key& key);
50     // fetch the sp<Value> with key from cache,
51     // make a new instance with fill() if it does not present currently.
52     virtual sp<Value> fetch(const Key& key);
lockGuard(const Key & key)53     virtual sp<HidlCacheLock> lockGuard(const Key& key) { return new HidlCacheLock(this, key); }
54 
~HidlCache()55     virtual ~HidlCache() {}
56 
57    protected:
58     friend void HidlCacheWhiteBoxTest();
59     // This method shall be called with a lock held
60     virtual sp<Value> fillLocked(const Key& key) = 0;
61 
62     // @return nullptr if it does not present currently.
63     // @note This method shall be called with a lock held
64     virtual sp<Value> getCachedLocked(const Key& key);
cached(Key key)65     bool cached(Key key) const { return mCached.count(key) > 0; }
locked(Key key)66     bool locked(Key key) const { return mLocked.count(key) > 0; }
67     Mutex mMutex;
68 
69     std::map<Key, wp<Value>, Compare> mCached;
70     std::map<Key, sp<Value>, Compare> mLocked;
71 };
72 
73 template <class Key, class Value, class Compare>
lock(const Key & key)74 bool HidlCache<Key, Value, Compare>::lock(const Key& key) {
75     {
76         Lock lock(mMutex);
77         if (cached(key)) {
78             sp<Value> im = mCached[key].promote();
79             if (im != nullptr) {
80                 mLocked[key] = im;
81                 return true;
82             } else {
83                 mCached.erase(key);
84             }
85         }
86     }
87     sp<Value> value = fetch(key);
88     if (value == nullptr) {
89         return false;
90     } else {
91         Lock lock(mMutex);
92         mLocked[key] = value;
93         return true;
94     }
95 }
96 
97 template <class Key, class Value, class Compare>
unlock(const Key & key)98 sp<Value> HidlCache<Key, Value, Compare>::unlock(const Key& key) {
99     Lock lock(mMutex);
100     if (locked(key)) {
101         sp<Value> v = mLocked[key];
102         mLocked.erase(key);
103         return v;
104     }
105     return nullptr;
106 }
107 
108 template <class Key, class Value, class Compare>
flush(const Key & key)109 bool HidlCache<Key, Value, Compare>::flush(const Key& key) {
110     Lock lock(mMutex);
111     bool contain = cached(key);
112     mCached.erase(key);
113     return contain;
114 }
115 
116 template <class Key, class Value, class Compare>
getCachedLocked(const Key & key)117 sp<Value> HidlCache<Key, Value, Compare>::getCachedLocked(const Key& key) {
118     if (cached(key)) {
119         wp<Value> cache = mCached[key];
120         sp<Value> mem = cache.promote();
121         if (mem != nullptr) {
122             return mem;
123         } else {
124             mCached.erase(key);
125         }
126     }
127     return nullptr;
128 }
129 
130 template <class Key, class Value, class Compare>
fetch(const Key & key)131 sp<Value> HidlCache<Key, Value, Compare>::fetch(const Key& key) {
132     Lock lock(mMutex);
133     sp<Value> value = getCachedLocked(key);
134 
135     if (value == nullptr) {
136         value = fillLocked(key);
137     }
138     return value;
139 }
140 
141 }  // namespace hardware
142 }  // namespace android
143 #endif
144