• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 package android.app;
18 
19 import static android.text.TextUtils.formatSimple;
20 
21 import static com.android.internal.util.Preconditions.checkArgumentPositive;
22 
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.os.Binder;
26 import android.os.Handler;
27 import android.os.Looper;
28 import android.os.Message;
29 import android.os.ParcelFileDescriptor;
30 import android.os.Process;
31 import android.os.SystemClock;
32 import android.os.SystemProperties;
33 import android.util.ArrayMap;
34 import android.util.ArraySet;
35 import android.util.Log;
36 import android.util.SparseArray;
37 import android.util.SparseBooleanArray;
38 import android.util.SystemPropertySetter;
39 
40 import com.android.internal.annotations.GuardedBy;
41 import com.android.internal.annotations.VisibleForTesting;
42 import com.android.internal.os.ApplicationSharedMemory;
43 import com.android.internal.os.BackgroundThread;
44 
45 import dalvik.annotation.optimization.CriticalNative;
46 import dalvik.annotation.optimization.FastNative;
47 import dalvik.annotation.optimization.NeverCompile;
48 
49 import java.io.ByteArrayOutputStream;
50 import java.io.FileOutputStream;
51 import java.io.IOException;
52 import java.io.PrintWriter;
53 import java.util.ArrayList;
54 import java.util.Arrays;
55 import java.util.HashSet;
56 import java.util.Iterator;
57 import java.util.LinkedHashMap;
58 import java.util.Map;
59 import java.util.Objects;
60 import java.util.Random;
61 import java.util.Set;
62 import java.util.WeakHashMap;
63 import java.util.concurrent.ConcurrentHashMap;
64 import java.util.concurrent.Semaphore;
65 import java.util.concurrent.TimeUnit;
66 import java.util.concurrent.atomic.AtomicLong;
67 
68 /**
69  * LRU cache that's invalidated when an opaque value in a property changes. Self-synchronizing,
70  * but doesn't hold a lock across data fetches on query misses.
71  *
72  * This interface is deprecated.  New clients should use {@link IpcDataCache} instead.  Internally,
73  * that class uses {@link PropertyInvalidatedCache} , but that design may change in the future.
74  *
75  * @param <Query> The class used to index cache entries: must be hashable and comparable
76  * @param <Result> The class holding cache entries; use a boxed primitive if possible
77  * @hide
78  */
79 @android.ravenwood.annotation.RavenwoodKeepWholeClass
80 public class PropertyInvalidatedCache<Query, Result> {
81     /**
82      * A method to report if the PermissionManager notifications can be separated from cache
83      * invalidation.  The feature relies on a series of flags; the dependency is captured in this
84      * method.
85      * @hide
86      */
separatePermissionNotificationsEnabled()87     public static boolean separatePermissionNotificationsEnabled() {
88         return isSharedMemoryAvailable()
89                 && Flags.picSeparatePermissionNotifications();
90     }
91 
92     /**
93      * This is a configuration class that customizes a cache instance.
94      * @hide
95      */
96     public static abstract class QueryHandler<Q,R> {
97         /**
98          * Compute a result given a query.  The semantics are those of Functor.
99          */
apply(@onNull Q query)100         public abstract @Nullable R apply(@NonNull Q query);
101 
102         /**
103          * Return true if a query should not use the cache. The default implementation returns true
104          * if the process UID differs from the calling UID. This is to prevent a binder caller from
105          * reading a cached value created due to a different binder caller, when processes are
106          * caching on behalf of other processes.
107          */
shouldBypassCache(@onNull Q query)108         public boolean shouldBypassCache(@NonNull Q query) {
109             return false;
110         }
111     };
112 
113     /**
114      * The system properties used by caches should be of the form <prefix>.<module>.<api>,
115      * where the prefix is "cache_key", the module is one of the constants below, and the
116      * api is any string.  The ability to write the property (which happens during
117      * invalidation) depends on SELinux rules; these rules are defined against
118      * <prefix>.<module>.  Therefore, the module chosen for a cache property must match
119      * the permissions granted to the processes that contain the corresponding caches.
120      * @hide
121      */
122 
123     /**
124      * The well-known key prefix.
125      * @hide
126      */
127     private static final String CACHE_KEY_PREFIX = "cache_key";
128 
129     /**
130      * The module used for unit tests and cts tests.  It is expected that no process in
131      * the system has permissions to write properties with this module.
132      * @hide
133      */
134     public static final String MODULE_TEST = "test";
135 
136     /**
137      * The module used for system server/framework caches.  This is not visible outside
138      * the system processes.
139      * @hide
140      */
141     public static final String MODULE_SYSTEM = "system_server";
142 
143     /**
144      * The module used for bluetooth caches.
145      * @hide
146      */
147     public static final String MODULE_BLUETOOTH = "bluetooth";
148 
149     /**
150      * The module used for telephony caches.
151      * @hide
152      */
153     public static final String MODULE_TELEPHONY = "telephony";
154 
155     /**
156      * Construct a system property that matches the rules described above.  The module is
157      * one of the permitted values above.  The API is a string that is a legal Java simple
158      * identifier.  The api is modified to conform to the system property style guide by
159      * replacing every upper case letter with an underscore and the lower case equivalent.
160      * (An initial upper case letter is not prefixed with an underscore).
161      * There is no requirement that the apiName be the name of an actual API.
162      *
163      * Be aware that SystemProperties has a maximum length which is private to the
164      * implementation.  The current maximum is 92 characters. If this method creates a
165      * property name that is too long, SystemProperties.set() will fail without a good
166      * error message.
167      * @hide
168      */
createPropertyName(@onNull String module, @NonNull String apiName)169     public static @NonNull String createPropertyName(@NonNull String module,
170             @NonNull String apiName) {
171         char[] api = apiName.toCharArray();
172         int upper = 0;
173         for (int i = 1; i < api.length; i++) {
174             if (Character.isUpperCase(api[i])) {
175                 upper++;
176             }
177         }
178         char[] suffix = new char[api.length + upper];
179         int j = 0;
180         for (int i = 0; i < api.length; i++) {
181             if (Character.isJavaIdentifierPart(api[i])) {
182                 if (Character.isUpperCase(api[i])) {
183                     if (i > 0) {
184                         suffix[j++] = '_';
185                     }
186                     suffix[j++] = Character.toLowerCase(api[i]);
187                 } else {
188                     suffix[j++] = api[i];
189                 }
190             } else {
191                 throw new IllegalArgumentException("invalid api name");
192             }
193         }
194 
195         return CACHE_KEY_PREFIX + "." + module + "." + new String(suffix);
196     }
197 
198     /**
199      * The list of known and legal modules.  The list is not sorted.
200      */
201     private static final String[] sValidModule = {
202         MODULE_SYSTEM, MODULE_BLUETOOTH, MODULE_TELEPHONY, MODULE_TEST,
203     };
204 
205     /**
206      * Verify that the module string is in the legal list.  Throw if it is not.
207      */
throwIfInvalidModule(@onNull String name)208     private static void throwIfInvalidModule(@NonNull String name) {
209         for (int i = 0; i < sValidModule.length; i++) {
210             if (sValidModule[i].equals(name)) return;
211         }
212         throw new IllegalArgumentException("invalid module: " + name);
213     }
214 
215     /**
216      * All legal keys start with one of the following strings.
217      */
218     private static final String[] sValidKeyPrefix = {
219         CACHE_KEY_PREFIX + "." + MODULE_SYSTEM + ".",
220         CACHE_KEY_PREFIX + "." + MODULE_BLUETOOTH + ".",
221         CACHE_KEY_PREFIX + "." + MODULE_TELEPHONY + ".",
222         CACHE_KEY_PREFIX + "." + MODULE_TEST + ".",
223     };
224 
225     /**
226      * Verify that the property name conforms to the standard and throw if this is not true.  Note
227      * that this is done only once for a given property name; it does not have to be very fast.
228      */
throwIfInvalidCacheKey(String name)229     private static void throwIfInvalidCacheKey(String name) {
230         for (int i = 0; i < sValidKeyPrefix.length; i++) {
231             if (name.startsWith(sValidKeyPrefix[i])) return;
232         }
233         throw new IllegalArgumentException("invalid cache name: " + name);
234     }
235 
236     /**
237      * Create a cache key for the system module.  The parameter is the API name.  This reduces
238      * some of the boilerplate in system caches.  It is not needed in other modules because other
239      * modules must use the {@link IpcDataCache} interfaces.
240      * @hide
241      */
242     @NonNull
createSystemCacheKey(@onNull String api)243     public static String createSystemCacheKey(@NonNull String api) {
244         return createPropertyName(MODULE_SYSTEM, api);
245     }
246 
247     /**
248      * Reserved nonce values.  Use isReservedNonce() to test for a reserved value.  Note that all
249      * reserved values cause the cache to be skipped.
250      */
251     // This is the initial value of all cache keys.  It is changed when a cache is invalidated.
252     @VisibleForTesting
253     static final int NONCE_UNSET = 0;
254     // This value is used in two ways.  First, it is used internally to indicate that the cache is
255     // disabled for the current query.  Secondly, it is used to globally disable the cache across
256     // the entire system.  Once a cache is disabled, there is no way to enable it again.  The
257     // global behavior is unused and will likely be removed in the future.
258     private static final int NONCE_DISABLED = 1;
259     // The cache is corked, which means that clients must act as though the cache is always
260     // invalid.  This is used when the server is processing updates that continuously invalidate
261     // caches.  Rather than issuing individual invalidations (which has a performance penalty),
262     // the server corks the caches at the start of the process and uncorks at the end of the
263     // process.
264     private static final int NONCE_CORKED = 2;
265     // The cache is bypassed for the current query.  Unlike UNSET and CORKED, this value is never
266     // written to global store.
267     private static final int NONCE_BYPASS = 3;
268 
269     // The largest reserved nonce value.  Update this whenever a reserved nonce is added.
270     private static final int MAX_RESERVED_NONCE = NONCE_BYPASS;
271 
isReservedNonce(long n)272     private static boolean isReservedNonce(long n) {
273         return n >= NONCE_UNSET && n <= MAX_RESERVED_NONCE;
274     }
275 
276     /**
277      * The names of the reserved nonces.
278      */
279     private static final String[] sNonceName =
280             new String[]{ "unset", "disabled", "corked", "bypass" };
281 
282     // The standard tag for logging.
283     private static final String TAG = "PropertyInvalidatedCache";
284 
285     // Set this true to enable very chatty logging.  Never commit this true.
286     private static final boolean DEBUG = false;
287 
288     // Set this true to enable cache verification.  On every cache hit, the cache will compare the
289     // cached value to a value pulled directly from the source.  This completely negates any
290     // performance advantage of the cache.  Enable it only to test if a particular cache is not
291     // being properly invalidated.
292     private static final boolean VERIFY = false;
293 
294     // The test mode. This is only used to ensure that the test functions setTestMode() and
295     // testPropertyName() are used correctly.
296     @GuardedBy("sGlobalLock")
297     private static boolean sTestMode = false;
298 
299     /**
300      * The object-private lock.
301      */
302     private final Object mLock = new Object();
303 
304     // Per-Cache performance counters.
305     @GuardedBy("mLock")
306     private long mHits = 0;
307 
308     @GuardedBy("mLock")
309     private long mMisses = 0;
310 
311     // This counter tracks the number of times {@link #recompute} returned a null value and the
312     // result was not cached.
313     @GuardedBy("mLock")
314     private long mNulls = 0;
315 
316     @GuardedBy("mLock")
317     private long[] mSkips = new long[MAX_RESERVED_NONCE + 1];
318 
319     @GuardedBy("mLock")
320     private long mMissOverflow = 0;
321 
322     @GuardedBy("mLock")
323     private long mHighWaterMark = 0;
324 
325     @GuardedBy("mLock")
326     private long mClears = 0;
327 
328     /**
329      * Protect objects that support corking.  mLock and sGlobalLock must never be taken while this
330      * is held.
331      */
332     private static final Object sCorkLock = new Object();
333 
334     /**
335      * A lock for the global list of caches and cache keys.  This must never be taken inside mLock
336      * or sCorkLock.
337      */
338     private static final Object sGlobalLock = new Object();
339 
340     /**
341      * A map of cache keys that have been disabled in the local process.  When a key is disabled
342      * locally, existing caches are disabled and the key is saved in this map.  Future cache
343      * instances that use the same key will be disabled in their constructor.  Note that "disabled"
344      * means the cache is not used in this process.  Invalidation still proceeds normally, because
345      * the cache may be used in other processes.
346      */
347     @GuardedBy("sGlobalLock")
348     private static final HashSet<String> sDisabledKeys = new HashSet<>();
349 
350     /**
351      * Weakly references all cache objects in the current process, allowing us to iterate over
352      * them all for purposes like issuing debug dumps and reacting to memory pressure.
353      */
354     @GuardedBy("sGlobalLock")
355     private static final WeakHashMap<PropertyInvalidatedCache, Void> sCaches = new WeakHashMap<>();
356 
357     /**
358      * If sEnabled is false then all cache operations are stubbed out.  Set
359      * it to false inside test processes.
360      */
361     private static boolean sEnabled = true;
362 
363     /**
364      * Name of the property that holds the unique value that we use to invalidate the cache.
365      */
366     private final String mPropertyName;
367 
368     /**
369      * The name by which this cache is known.  This should normally be the
370      * binder call that is being cached, but the constructors default it to
371      * the property name.
372      */
373     private final String mCacheName;
374 
375     /**
376      * True if nulls are valid returns from recompute().
377      */
378     private final boolean mCacheNullResults;
379 
380     /**
381      * The function that computes a Result, given a Query.  This function is called on a
382      * cache miss.
383      */
384     private QueryHandler<Query, Result> mComputer;
385 
386     /**
387      * A default function that delegates to the deprecated recompute() method.
388      */
389     private static class DefaultComputer<Query, Result> extends QueryHandler<Query, Result> {
390         final PropertyInvalidatedCache<Query, Result> mCache;
DefaultComputer(PropertyInvalidatedCache<Query, Result> cache)391         DefaultComputer(PropertyInvalidatedCache<Query, Result> cache) {
392             mCache = cache;
393         }
apply(Query query)394         public Result apply(Query query) {
395             return mCache.recompute(query);
396         }
397     }
398 
399     /**
400      * An array of hash maps, indexed by calling UID.  The class behaves a bit like a hash map
401      * except that it uses the calling UID internally.
402      */
403     private class CacheMap<Query, Result> {
404 
405         // Create a new map for a UID, using the parent's configuration for max size.
createMap()406         private LinkedHashMap<Query, Result> createMap() {
407             return new LinkedHashMap<Query, Result>(
408                 2 /* start small */,
409                 0.75f /* default load factor */,
410                 true /* LRU access order */) {
411                 @GuardedBy("mLock")
412                 @Override
413                 protected boolean removeEldestEntry(Map.Entry eldest) {
414                     final int size = size();
415                     if (size > mHighWaterMark) {
416                         mHighWaterMark = size;
417                     }
418                     if (size > mMaxEntries) {
419                         mMissOverflow++;
420                         return true;
421                     }
422                     return false;
423                 }
424             };
425         }
426 
427         // An array of maps, indexed by UID.
428         private final SparseArray<LinkedHashMap<Query, Result>> mCache = new SparseArray<>();
429 
430         // If true, isolate the hash entries by calling UID.  If this is false, allow the cache
431         // entries to be combined in a single hash map.
432         private final boolean mIsolated;
433 
434         // Collect statistics.
435         private final boolean mStatistics;
436 
437         // An array of booleans to indicate if a UID has been involved in a map access.  A value
438         // exists for every UID that was ever involved during cache access. This is updated only
439         // if statistics are being collected.
440         private final SparseBooleanArray mUidSeen;
441 
442         // A hash map that ignores the UID.  This is used in look-aside fashion just for hit/miss
443         // statistics.  This is updated only if statistics are being collected.
444         private final ArraySet<Query> mShadowCache;
445 
446         // Shadow statistics.  Only hits and misses need to be recorded.  These are updated only
447         // if statistics are being collected.  The "SelfHits" records hits when the UID is the
448         // process uid.
449         private int mShadowHits;
450         private int mShadowMisses;
451         private int mShadowSelfHits;
452 
453         // The process UID.
454         private final int mSelfUid;
455 
456         // True in test mode.  In test mode, the cache uses Binder.getWorkSource() as the UID.
457         private final boolean mTestMode;
458 
459         /**
460          * Create a CacheMap.  UID isolation is enabled if the input parameter is true and if the
461          * isolation feature is enabled.
462          */
CacheMap(boolean isolate, boolean testMode)463         CacheMap(boolean isolate, boolean testMode) {
464             mIsolated = Flags.picIsolateCacheByUid() && isolate;
465             mStatistics = Flags.picIsolatedCacheStatistics() && mIsolated;
466             if (mStatistics) {
467                 mUidSeen = new SparseBooleanArray();
468                 mShadowCache = new ArraySet<>();
469             } else {
470                 mUidSeen = null;
471                 mShadowCache = null;
472             }
473             mSelfUid = Process.myUid();
474             mTestMode = testMode;
475         }
476 
477         // Return the UID for this cache invocation.  If uid isolation is disabled, the value of 0
478         // is returned, which effectively places all entries in a single hash map.
callerUid()479         private int callerUid() {
480             if (!mIsolated) {
481                 return 0;
482             } else if (mTestMode) {
483                 return Binder.getCallingWorkSourceUid();
484             } else {
485                 return Binder.getCallingUid();
486             }
487         }
488 
489         /**
490          * Lookup an entry in the cache.
491          */
get(Query query)492         Result get(Query query) {
493             final int uid = callerUid();
494 
495             // Shadow statistics
496             if (mStatistics) {
497                 if (mShadowCache.contains(query)) {
498                     mShadowHits++;
499                     if (uid == mSelfUid) {
500                         mShadowSelfHits++;
501                     }
502                 } else {
503                     mShadowMisses++;
504                 }
505             }
506 
507             var map = mCache.get(uid);
508             if (map != null) {
509                 return map.get(query);
510             } else {
511                 return null;
512             }
513         }
514 
515         /**
516          * Return true if the entry is in the cache.
517          */
containsKey(Query query)518         boolean containsKey(Query query) {
519             final int uid = callerUid();
520             var map = mCache.get(uid);
521             if (map != null) {
522                 return map.containsKey(query);
523             } else {
524                 return false;
525             }
526         }
527 
528         /**
529          * Remove an entry from the cache.
530          */
remove(Query query)531         void remove(Query query) {
532             final int uid = callerUid();
533             if (mStatistics) {
534                 mShadowCache.remove(query);
535             }
536 
537             var map = mCache.get(uid);
538             if (map != null) {
539                 map.remove(query);
540             }
541         }
542 
543         /**
544          * Record an entry in the cache.
545          */
put(Query query, Result result)546         void put(Query query, Result result) {
547             final int uid = callerUid();
548             if (mStatistics) {
549                 mShadowCache.add(query);
550                 mUidSeen.put(uid, true);
551             }
552 
553             var map = mCache.get(uid);
554             if (map == null) {
555                 map = createMap();
556                 mCache.put(uid, map);
557             }
558             map.put(query, result);
559         }
560 
561         /**
562          * Return the number of entries in the cache.
563          */
size()564         int size() {
565             int total = 0;
566             for (int i = 0; i < mCache.size(); i++) {
567                 var map = mCache.valueAt(i);
568                 total += map.size();
569             }
570             return total;
571         }
572 
573         /**
574          * Clear the entries in the cache.  Update the shadow statistics.
575          */
clear()576         void clear() {
577             if (mStatistics) {
578                 mShadowCache.clear();
579             }
580 
581             mCache.clear();
582         }
583 
584         // Dump basic statistics, if any are collected.  Do nothing if statistics are not enabled.
dump(PrintWriter pw)585         void dump(PrintWriter pw) {
586             if (mStatistics) {
587                 pw.println(formatSimple("    ShadowHits: %d, ShadowMisses: %d, ShadowSize: %d",
588                                 mShadowHits, mShadowMisses, mShadowCache.size()));
589                 pw.println(formatSimple("    ShadowUids: %d, SelfUid: %d",
590                                 mUidSeen.size(), mShadowSelfHits));
591             }
592         }
593 
594         // Dump detailed statistics
dumpDetailed(PrintWriter pw)595         void dumpDetailed(PrintWriter pw) {
596             for (int i = 0; i < mCache.size(); i++) {
597                 int uid = mCache.keyAt(i);
598                 var map = mCache.valueAt(i);
599 
600                 Set<Map.Entry<Query, Result>> cacheEntries = map.entrySet();
601                 if (cacheEntries.size() == 0) {
602                     break;
603                 }
604 
605                 pw.println("    Contents:");
606                 pw.println(formatSimple("      Uid: %d\n", uid));
607                 for (Map.Entry<Query, Result> entry : cacheEntries) {
608                     String key = Objects.toString(entry.getKey());
609                     String value = Objects.toString(entry.getValue());
610 
611                     pw.println(formatSimple("      Key: %s\n      Value: %s\n", key, value));
612                 }
613             }
614         }
615     }
616 
617     @GuardedBy("mLock")
618     private final CacheMap<Query, Result> mCache;
619 
620     /**
621      * The nonce handler for this cache.
622      */
623     @GuardedBy("mLock")
624     private final NonceHandler mNonce;
625 
626     /**
627      * The last nonce value that was observed.
628      */
629     @GuardedBy("mLock")
630     private long mLastSeenNonce = NONCE_UNSET;
631 
632     /**
633      * Whether we've disabled the cache in this process.
634      */
635     private boolean mDisabled = false;
636 
637     /**
638      * Maximum number of entries the cache will maintain.
639      */
640     private final int mMaxEntries;
641 
642     /**
643      * A class to manage cache keys.  There is a single instance of this class for each unique key
644      * that is shared by all cache instances that use that key.  This class is abstract; subclasses
645      * use different storage mechanisms for the nonces.
646      */
647     private static abstract class NonceHandler {
648         // The name of the nonce.
649         final String mName;
650 
651         // A lock to synchronize corking and invalidation.
652         protected final Object mLock = new Object();
653 
654         // Count the number of times the property name was invalidated.
655         @GuardedBy("mLock")
656         private int mInvalidated = 0;
657 
658         // Count the number of times invalidate or cork calls were nops because the cache was
659         // already corked.
660         @GuardedBy("mLock")
661         private int mCorkedInvalidates = 0;
662 
663         // Count the number of corks against this property name.  This is not a statistic.  It
664         // increases when the property is corked and decreases when the property is uncorked.
665         // Invalidation requests are ignored when the cork count is greater than zero.
666         @GuardedBy("mLock")
667         private int mCorks = 0;
668 
669         // True if this handler is in test mode.  If it is in test mode, then nonces are stored
670         // and retrieved from mTestNonce.
671         @GuardedBy("mLock")
672         private boolean mTestMode;
673 
674         // This is the local value of the nonce, as last set by the NonceHandler.  It is always
675         // updated by the setNonce() operation.  The getNonce() operation returns this value in
676         // NonceLocal handlers and handlers in test mode.
677         @GuardedBy("mLock")
678         protected long mShadowNonce = NONCE_UNSET;
679 
680         // A list of watchers to be notified of changes.  This is null until at least one watcher
681         // registers.  Checking for null is meant to be the fastest way the handler can determine
682         // that there are no watchers to be notified.
683         @GuardedBy("mLock")
684         private ArrayList<Semaphore> mWatchers;
685 
686         /**
687          * The methods to get and set a nonce from whatever storage is being used.  mLock may be
688          * held when these methods are called.  Implementations that take locks must behave as
689          * though mLock could be held.
690          */
691         abstract long getNonceInternal();
692         abstract void setNonceInternal(long value);
693 
694         NonceHandler(@NonNull String name) {
695             mName = name;
696             synchronized (sGlobalLock) {
697                 mTestMode = sTestMode;
698             }
699         }
700 
701         /**
702          * Get a nonce from storage.  If the handler is in test mode, the nonce is returned from
703          * the local mShadowNonce.
704          */
705         long getNonce() {
706             synchronized (mLock) {
707                 if (mTestMode) return mShadowNonce;
708             }
709             return getNonceInternal();
710         }
711 
712         /**
713          * Write a nonce to storage.  The nonce is always written to the local mShadowNonce.  If
714          * the handler is not in test mode the nonce is also written to storage.
715          */
716         void setNonce(long val) {
717             synchronized (mLock) {
718                 mShadowNonce = val;
719                 if (!mTestMode) {
720                     setNonceInternal(val);
721                 }
722                 wakeAllWatchersLocked();
723             }
724         }
725 
726         @GuardedBy("mLock")
727         private void wakeAllWatchersLocked() {
728             if (mWatchers != null) {
729                 for (int i = 0; i < mWatchers.size(); i++) {
730                     mWatchers.get(i).release();
731                 }
732             }
733         }
734 
735         /**
736          * Register a watcher to be notified when a nonce changes.  There is no check for
737          * duplicates.  In general, this method is called only from {@link NonceWatcher}.
738          */
739         void registerWatcher(Semaphore s) {
740             synchronized (mLock) {
741                 if (mWatchers == null) {
742                     mWatchers = new ArrayList<>();
743                 }
744                 mWatchers.add(s);
745             }
746         }
747 
748         /**
749          * Unregister a watcher.  Nothing happens if the watcher is not registered.
750          */
751         void unregisterWatcher(Semaphore s) {
752             synchronized (mLock) {
753                 if (mWatchers != null) {
754                     mWatchers.remove(s);
755                 }
756             }
757         }
758 
759         /**
760          * Write the invalidation nonce for the property.
761          */
762         void invalidate() {
763             if (!sEnabled) {
764                 if (DEBUG) {
765                     Log.d(TAG, formatSimple("cache invalidate %s suppressed", mName));
766                 }
767                 return;
768             }
769 
770             synchronized (mLock) {
771                 if (mCorks > 0) {
772                     if (DEBUG) {
773                         Log.d(TAG, "ignoring invalidation due to cork: " + mName);
774                     }
775                     mCorkedInvalidates++;
776                     return;
777                 }
778 
779                 final long nonce = getNonce();
780                 if (nonce == NONCE_DISABLED) {
781                     if (DEBUG) {
782                         Log.d(TAG, "refusing to invalidate disabled cache: " + mName);
783                     }
784                     return;
785                 }
786 
787                 long newValue;
788                 do {
789                     newValue = NoPreloadHolder.next();
790                 } while (isReservedNonce(newValue));
791                 if (DEBUG) {
792                     Log.d(TAG, formatSimple(
793                         "invalidating cache [%s]: [%s] -> [%s]",
794                         mName, nonce, Long.toString(newValue)));
795                 }
796                 // There is a small race with concurrent disables here.  A compare-and-exchange
797                 // property operation would be required to eliminate the race condition.
798                 setNonce(newValue);
799                 mInvalidated++;
800             }
801         }
802 
803         void cork() {
804             if (!sEnabled) {
805                 if (DEBUG) {
806                     Log.d(TAG, formatSimple("cache corking %s suppressed", mName));
807                 }
808                 return;
809             }
810 
811             synchronized (mLock) {
812                 int numberCorks = mCorks;
813                 if (DEBUG) {
814                     Log.d(TAG, formatSimple(
815                         "corking %s: numberCorks=%s", mName, numberCorks));
816                 }
817 
818                 // If we're the first ones to cork this cache, set the cache to the corked state so
819                 // existing caches talk directly to their services while we've corked updates.
820                 // Make sure we don't clobber a disabled cache value.
821 
822                 // TODO: we can skip this property write and leave the cache enabled if the
823                 // caller promises not to make observable changes to the cache backing state before
824                 // uncorking the cache, e.g., by holding a read lock across the cork-uncork pair.
825                 // Implement this more dangerous mode of operation if necessary.
826                 if (numberCorks == 0) {
827                     final long nonce = getNonce();
828                     if (nonce != NONCE_UNSET && nonce != NONCE_DISABLED) {
829                         setNonce(NONCE_CORKED);
830                     }
831                 } else {
832                     mCorkedInvalidates++;
833                 }
834                 mCorks++;
835                 if (DEBUG) {
836                     Log.d(TAG, "corked: " + mName);
837                 }
838             }
839         }
840 
841         void uncork() {
842             if (!sEnabled) {
843                 if (DEBUG) {
844                     Log.d(TAG, formatSimple("cache uncorking %s suppressed", mName));
845                 }
846                 return;
847             }
848 
849             synchronized (mLock) {
850                 int numberCorks = --mCorks;
851                 if (DEBUG) {
852                     Log.d(TAG, formatSimple(
853                         "uncorking %s: numberCorks=%s", mName, numberCorks));
854                 }
855 
856                 if (numberCorks < 0) {
857                     throw new AssertionError("cork underflow: " + mName);
858                 }
859                 if (numberCorks == 0) {
860                     // The property is fully uncorked and can be invalidated normally.
861                     invalidate();
862                     if (DEBUG) {
863                         Log.d(TAG, "uncorked: " + mName);
864                     }
865                 }
866             }
867         }
868 
869         /**
870          * Globally (that is, system-wide) disable all caches that use this key.  There is no way
871          * to re-enable these caches.
872          */
873         void disable() {
874             if (!sEnabled) {
875                 return;
876             }
877             synchronized (mLock) {
878                 setNonce(NONCE_DISABLED);
879             }
880         }
881 
882         /**
883          * Put this handler in or out of test mode.  Regardless of the current and next mode, the
884          * test nonce variable is reset to UNSET.
885          */
886         void setTestMode(boolean mode) {
887             synchronized (mLock) {
888                 mTestMode = mode;
889                 mShadowNonce = NONCE_UNSET;
890             }
891         }
892 
893         /**
894          * Return the statistics associated with the key.  These statistics are not associated
895          * with any individual cache.
896          */
897         record Stats(int invalidated, int corkedInvalidates) {}
898         Stats getStats() {
899             synchronized (mLock) {
900                 return new Stats(mInvalidated, mCorkedInvalidates);
901             }
902         }
903     }
904 
905     /**
906      * Manage nonces that are stored in a system property.
907      */
908     private static final class NonceSysprop extends NonceHandler {
909         // A handle to the property, for fast lookups.
910         private volatile SystemProperties.Handle mHandle;
911 
912         NonceSysprop(@NonNull String name) {
913             super(name);
914         }
915 
916         /**
917          * Retrieve the nonce from the system property.  If the handle is null, this method
918          * attempts to create a handle.  If handle creation fails, the method returns UNSET.  If
919          * the handle is not null, the method returns a value read via the handle.  This read
920          * occurs outside any lock.
921          */
922         @Override
923         long getNonceInternal() {
924             if (mHandle == null) {
925                 synchronized (mLock) {
926                     if (mHandle == null) {
927                         mHandle = SystemProperties.find(mName);
928                         if (mHandle == null) {
929                             return NONCE_UNSET;
930                         }
931                     }
932                 }
933             }
934             return mHandle.getLong(NONCE_UNSET);
935         }
936 
937         /**
938          * Write a nonce to a system property.
939          */
940         @Override
941         void setNonceInternal(long value) {
942             final String str = Long.toString(value);
943             SystemPropertySetter.setWithRetry(mName, str);
944         }
945     }
946 
947     /**
948      * Manage nonces that are stored in shared memory.
949      */
950     private static final class NonceSharedMem extends NonceHandler {
951         // The shared memory.
952         private volatile NonceStore mStore;
953 
954         // The index of the nonce in shared memory.  This changes from INVALID only when the local
955         // object is completely initialized.
956         private volatile int mHandle = NonceStore.INVALID_NONCE_INDEX;
957 
958         // A short name that is saved in shared memory.  This is the portion of the property name
959         // that follows the prefix.
960         private final String mShortName;
961 
962         NonceSharedMem(@NonNull String name, @Nullable String prefix) {
963             super(name);
964             if ((prefix != null) && name.startsWith(prefix)) {
965                 mShortName = name.substring(prefix.length());
966             } else {
967                 mShortName = name;
968             }
969         }
970 
971         // Initialize the mStore and mHandle variables.  This function does nothing if the
972         // variables are already initialized.  Synchronization ensures that initialization happens
973         // no more than once.  The function returns the new value of mHandle.
974         //
975         // If the "update" boolean is true, then the property is registered with the nonce store
976         // before the associated handle is fetched.
977         private int initialize(boolean update) {
978             synchronized (mLock) {
979                 int handle = mHandle;
980                 if (handle == NonceStore.INVALID_NONCE_INDEX) {
981                     if (mStore == null) {
982                         mStore = NonceStore.getInstance();
983                         if (mStore == null) {
984                             return NonceStore.INVALID_NONCE_INDEX;
985                         }
986                     }
987                     if (update) {
988                         mStore.storeName(mShortName);
989                     }
990                     handle = mStore.getHandleForName(mShortName);
991                     if (handle == NonceStore.INVALID_NONCE_INDEX) {
992                         return NonceStore.INVALID_NONCE_INDEX;
993                     }
994                     // The handle must be valid.
995                     mHandle = handle;
996                 }
997                 return handle;
998             }
999         }
1000 
1001         // Fetch the nonce from shared memory.  If the shared memory is not available, return
1002         // UNSET.  If the shared memory is available but the nonce name is not known (it may not
1003         // have been invalidated by the server yet), return UNSET.
1004         @Override
1005         long getNonceInternal() {
1006             int handle = mHandle;
1007             if (handle == NonceStore.INVALID_NONCE_INDEX) {
1008                 handle = initialize(false);
1009                 if (handle == NonceStore.INVALID_NONCE_INDEX) {
1010                     return NONCE_UNSET;
1011                 }
1012             }
1013             return mStore.getNonce(handle);
1014         }
1015 
1016         // Set the nonce in shared memory.  If the shared memory is not available or if the nonce
1017         // cannot be registered in shared memory, throw an exception.
1018         @Override
1019         void setNonceInternal(long value) {
1020             int handle = mHandle;
1021             if (handle == NonceStore.INVALID_NONCE_INDEX) {
1022                 handle = initialize(true);
1023                 if (handle == NonceStore.INVALID_NONCE_INDEX) {
1024                     throw new IllegalStateException("unable to assign nonce handle: " + mName);
1025                 }
1026             }
1027             mStore.setNonce(handle, value);
1028         }
1029     }
1030 
1031     /**
1032      * SystemProperties and shared storage are protected and cannot be written by random
1033      * processes.  So, for testing purposes, the NonceLocal handler stores the nonce locally.  The
1034      * NonceLocal uses the mShadowNonce in the superclass, regardless of test mode.
1035      */
1036     private static class NonceLocal extends NonceHandler {
1037         // The saved nonce.
1038         private long mValue;
1039 
1040         NonceLocal(@NonNull String name) {
1041             super(name);
1042         }
1043 
1044         @Override
1045         long getNonceInternal() {
1046             return mShadowNonce;
1047         }
1048 
1049         @Override
1050         void setNonceInternal(long value) {
1051             mShadowNonce = value;
1052         }
1053     }
1054 
1055     /**
1056      * A NonceWatcher lets an external client test if a nonce value has changed from the last time
1057      * the watcher was checked.
1058      * @hide
1059      */
1060     public static class NonceWatcher implements AutoCloseable {
1061         // The handler for the key.
1062         private final NonceHandler mHandler;
1063 
1064         // The last-seen value.  This is initialized to "unset".
1065         private long mLastSeen = NONCE_UNSET;
1066 
1067         // The semaphore that the watcher waits on.  A permit is released every time the nonce
1068         // changes.  Permits are acquired in the wait method.
1069         private final Semaphore mSem = new Semaphore(0);
1070 
1071         /**
1072          * Create a watcher for a handler.  The last-seen value is not set here and will be
1073          * "unset".  Therefore, a call to isChanged() will return true if the nonce has ever been
1074          * set, no matter when the watcher is first created.  Clients may want to flush that
1075          * change by calling isChanged() immediately after constructing the object.
1076          */
1077         private NonceWatcher(@NonNull NonceHandler handler) {
1078             mHandler = handler;
1079             mHandler.registerWatcher(mSem);
1080         }
1081 
1082         /**
1083          * Unregister to be notified when a nonce changes.  NonceHandler allows a call to
1084          * unregisterWatcher with a semaphore that is not registered, so there is no check inside
1085          * this method to guard against multiple closures.
1086          */
1087         @Override
1088         public void close() {
1089             mHandler.unregisterWatcher(mSem);
1090         }
1091 
1092         /**
1093          * Return the last seen value of the nonce.  This does not update that value.  Only
1094          * {@link #isChanged()} updates the value.
1095          */
1096         public long lastSeen() {
1097             return mLastSeen;
1098         }
1099 
1100         /**
1101          * Return true if the nonce has changed from the last time isChanged() was called.  The
1102          * method is not thread safe.
1103          * @hide
1104          */
1105         public boolean isChanged() {
1106             long current = mHandler.getNonce();
1107             if (current != mLastSeen) {
1108                 mLastSeen = current;
1109                 return true;
1110             }
1111             return false;
1112         }
1113 
1114         /**
1115          * Wait for the nonce value to change.  It is not guaranteed that the nonce has changed when
1116          * this returns: clients must confirm with {@link #isChanged}. The wait operation is only
1117          * effective in a process that writes the nonces.  The function returns the number of times
1118          * the nonce had changed since the last call to the method.
1119          * @hide
1120          */
1121         public int waitForChange() throws InterruptedException {
1122             mSem.acquire(1);
1123             return 1 + mSem.drainPermits();
1124         }
1125 
1126         /**
1127          * Wait for the nonce value to change.  It is not guaranteed that the nonce has changed when
1128          * this returns: clients must confirm with {@link #isChanged}. The wait operation is only
1129          * effective in a process that writes the nonces.  The function returns the number of times
1130          * the nonce changed since the last call to the method.  A return value of zero means the
1131          * timeout expired.  Beware that a timeout of 0 means the function will not wait at all.
1132          * @hide
1133          */
1134         public int waitForChange(long timeout, TimeUnit timeUnit) throws InterruptedException {
1135             if (mSem.tryAcquire(1, timeout, timeUnit)) {
1136                 return 1 + mSem.drainPermits();
1137             } else {
1138                 return 0;
1139             }
1140         }
1141 
1142         /**
1143          * Wake the watcher by releasing the semaphore.  This can be used to wake clients that are
1144          * blocked in {@link #waitForChange} without affecting the underlying nonce.
1145          * @hide
1146          */
1147         public void wakeUp() {
1148             mSem.release();
1149         }
1150     }
1151 
1152     /**
1153      * Return a NonceWatcher for the cache.
1154      * @hide
1155      */
1156     public NonceWatcher getNonceWatcher() {
1157         return new NonceWatcher(mNonce);
1158     }
1159 
1160     /**
1161      * Return a NonceWatcher for the given property.  If a handler does not exist for the
1162      * property, one is created.  This throws if the property name is not a valid cache key.
1163      * @hide
1164      */
1165     public static NonceWatcher getNonceWatcher(@NonNull String propertyName) {
1166         return new NonceWatcher(getNonceHandler(propertyName));
1167     }
1168 
1169     /**
1170      * Return the current cache nonce.
1171      * @hide
1172      */
1173     @VisibleForTesting
1174     public long getNonce() {
1175         synchronized (mLock) {
1176             return mNonce.getNonce();
1177         }
1178     }
1179 
1180     /**
1181      * Complete key prefixes.
1182      */
1183     private static final String PREFIX_TEST = CACHE_KEY_PREFIX + "." + MODULE_TEST + ".";
1184     private static final String PREFIX_SYSTEM = CACHE_KEY_PREFIX + "." + MODULE_SYSTEM + ".";
1185 
1186     /**
1187      * A static list of nonce handlers, indexed by name.  NonceHandlers can be safely shared by
1188      * multiple threads, and can therefore be shared by multiple instances of the same cache, and
1189      * with static calls (see {@link #invalidateCache}.  Addition and removal are guarded by the
1190      * global lock, to ensure that duplicates are not created.
1191      */
1192     private static final ConcurrentHashMap<String, NonceHandler> sHandlers
1193             = new ConcurrentHashMap<>();
1194 
1195     // True if shared memory is flag-enabled, false otherwise.  Read the flags exactly once.
1196     private static final boolean sSharedMemoryAvailable = isSharedMemoryAvailable();
1197 
1198     @android.ravenwood.annotation.RavenwoodReplace
1199     private static boolean isSharedMemoryAvailable() {
1200         return com.android.internal.os.Flags.applicationSharedMemoryEnabled()
1201                 && android.app.Flags.picUsesSharedMemory();
1202     }
1203 
1204     private static boolean isSharedMemoryAvailable$ravenwood() {
1205         return false; // Always disable shared memory on Ravenwood. (for now)
1206     }
1207 
1208     /**
1209      * Keys that cannot be put in shared memory yet.
1210      */
1211     private static boolean inSharedMemoryDenyList(@NonNull String name) {
1212         final String pkginfo = PREFIX_SYSTEM + "package_info";
1213         return name.equals(pkginfo);
1214     };
1215 
1216     // Return true if this cache can use shared memory for its nonce.  Shared memory may be used
1217     // if the module is the system.
1218     private static boolean sharedMemoryOkay(@NonNull String name) {
1219         return sSharedMemoryAvailable
1220                 && name.startsWith(PREFIX_SYSTEM)
1221                 && !inSharedMemoryDenyList(name);
1222     }
1223 
1224     /**
1225      * Return the proper nonce handler, based on the property name.  A handler is created if
1226      * necessary.  Before a handler is created, the name is checked, and an exception is thrown if
1227      * the name is not valid.
1228      */
1229     private static NonceHandler getNonceHandler(@NonNull String name) {
1230         NonceHandler h = sHandlers.get(name);
1231         if (h == null) {
1232             synchronized (sGlobalLock) {
1233                 throwIfInvalidCacheKey(name);
1234                 h = sHandlers.get(name);
1235                 if (h == null) {
1236                     if (sharedMemoryOkay(name)) {
1237                         h = new NonceSharedMem(name, PREFIX_SYSTEM);
1238                     } else if (name.startsWith(PREFIX_TEST)) {
1239                         h = new NonceLocal(name);
1240                     } else {
1241                         h = new NonceSysprop(name);
1242                     }
1243                     sHandlers.put(name, h);
1244                 }
1245             }
1246         }
1247         return h;
1248     }
1249 
1250     /**
1251      * A public argument builder to configure cache behavior.  The root instance requires a
1252      * module; this is immutable.  New instances are created with member methods.  It is important
1253      * to note that the member methods create new instances: they do not modify 'this'.  The api
1254      * is allowed to be null in the record constructor to facility reuse of Args instances.
1255      * @hide
1256      */
1257     public static record Args(@NonNull String mModule, @Nullable String mApi,
1258             int mMaxEntries, boolean mIsolateUids, boolean mTestMode, boolean mCacheNulls) {
1259 
1260         /**
1261          * Default values for fields.
1262          */
1263         public static final int DEFAULT_MAX_ENTRIES = 32;
1264         public static final boolean DEFAULT_ISOLATE_UIDS = true;
1265         public static final boolean DEFAULT_CACHE_NULLS = false;
1266 
1267         // Validation: the module must be one of the known module strings and the maxEntries must
1268         // be positive.
1269         public Args {
1270             throwIfInvalidModule(mModule);
1271             checkArgumentPositive(mMaxEntries, "max cache size must be positive");
1272         }
1273 
1274         // The base constructor must include the module.  Modules do not change in a source file,
1275         // so even if the Args is reused, the module will not/should not change.  The api is null,
1276         // which is not legal, but there is no reasonable default.  Clients must call the api
1277         // method to set the field properly.
1278         public Args(@NonNull String module) {
1279             this(module,
1280                     null,       // api
1281                     DEFAULT_MAX_ENTRIES,
1282                     DEFAULT_ISOLATE_UIDS,
1283                     false,      // testMode
1284                     DEFAULT_CACHE_NULLS
1285                  );
1286         }
1287 
1288         public Args api(@NonNull String api) {
1289             return new Args(mModule, api, mMaxEntries, mIsolateUids, mTestMode, mCacheNulls);
1290         }
1291 
1292         public Args maxEntries(int val) {
1293             return new Args(mModule, mApi, val, mIsolateUids, mTestMode, mCacheNulls);
1294         }
1295 
1296         public Args isolateUids(boolean val) {
1297             return new Args(mModule, mApi, mMaxEntries, val, mTestMode, mCacheNulls);
1298         }
1299 
1300         public Args testMode(boolean val) {
1301             return new Args(mModule, mApi, mMaxEntries, mIsolateUids, val, mCacheNulls);
1302         }
1303 
1304         public Args cacheNulls(boolean val) {
1305             return new Args(mModule, mApi, mMaxEntries, mIsolateUids, mTestMode, val);
1306         }
1307     }
1308 
1309     /**
1310      * Make a new property invalidated cache.  The key is computed from the module and api
1311      * parameters.
1312      *
1313      * @param args The cache configuration.
1314      * @param cacheName Name of this cache in debug and dumpsys
1315      * @param computer The code to compute values that are not in the cache.
1316      * @hide
1317      */
1318     public PropertyInvalidatedCache(@NonNull Args args, @NonNull String cacheName,
1319             @Nullable QueryHandler<Query, Result> computer) {
1320         mPropertyName = createPropertyName(args.mModule, args.mApi);
1321         mCacheName = cacheName;
1322         mCacheNullResults = args.mCacheNulls;
1323         mNonce = getNonceHandler(mPropertyName);
1324         mMaxEntries = args.mMaxEntries;
1325         mCache = new CacheMap<>(args.mIsolateUids, args.mTestMode);
1326         mComputer = (computer != null) ? computer : new DefaultComputer<>(this);
1327         registerCache();
1328     }
1329 
1330     /**
1331      * Burst a property name into module and api.  Throw if the key is invalid.  This method is
1332      * used to transition legacy cache constructors to the Args constructor.
1333      */
1334     private static Args argsFromProperty(@NonNull String name) {
1335         throwIfInvalidCacheKey(name);
1336         // Strip off the leading well-known prefix.
1337         String base = name.substring(CACHE_KEY_PREFIX.length() + 1);
1338         int dot = base.indexOf(".");
1339         String module = base.substring(0, dot);
1340         String api = base.substring(dot + 1);
1341         return new Args(module).api(api);
1342     }
1343 
1344     /**
1345      * Return the API porting of a legacy property.  This method is used to transition caches to
1346      * the Args constructor.
1347      * @hide
1348      */
1349     public static String apiFromProperty(@NonNull String name) {
1350         return argsFromProperty(name).mApi;
1351     }
1352 
1353     /**
1354      * Make a new property invalidated cache.  This constructor names the cache after the
1355      * property name.  New clients should prefer the constructor that takes an explicit
1356      * cache name.
1357      *
1358      * TODO(216112648): deprecate this as a public interface, in favor of the four-argument
1359      * constructor.
1360      *
1361      * @param maxEntries Maximum number of entries to cache; LRU discard
1362      * @param propertyName Name of the system property holding the cache invalidation nonce.
1363      *
1364      * @hide
1365      */
1366     @Deprecated
1367     public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName) {
1368         this(argsFromProperty(propertyName).maxEntries(maxEntries), propertyName, null);
1369     }
1370 
1371     /**
1372      * Make a new property invalidated cache.
1373      *
1374      * TODO(216112648): deprecate this as a public interface, in favor of the four-argument
1375      * constructor.
1376      *
1377      * @param maxEntries Maximum number of entries to cache; LRU discard
1378      * @param propertyName Name of the system property holding the cache invalidation nonce
1379      * @param cacheName Name of this cache in debug and dumpsys
1380      * @hide
1381      */
1382     @Deprecated
1383     public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName,
1384             @NonNull String cacheName) {
1385         this(argsFromProperty(propertyName).maxEntries(maxEntries), cacheName, null);
1386     }
1387 
1388     /**
1389      * Make a new property invalidated cache.  The key is computed from the module and api
1390      * parameters.
1391      *
1392      * @param maxEntries Maximum number of entries to cache; LRU discard
1393      * @param module The module under which the cache key should be placed.
1394      * @param api The api this cache front-ends.  The api must be a Java identifier but
1395      * need not be an actual api.
1396      * @param cacheName Name of this cache in debug and dumpsys
1397      * @param computer The code to compute values that are not in the cache.
1398      * @hide
1399      */
1400     public PropertyInvalidatedCache(int maxEntries, @NonNull String module, @NonNull String api,
1401             @NonNull String cacheName, @NonNull QueryHandler<Query, Result> computer) {
1402         this(new Args(module).maxEntries(maxEntries).api(api), cacheName, computer);
1403     }
1404 
1405     /**
1406      * Register the map in the global list.  If the cache is disabled globally, disable it
1407      * now.  This method is only ever called from the constructor, which means no other thread has
1408      * access to the object yet.  It can safely be modified outside any lock.
1409      */
1410     private void registerCache() {
1411         synchronized (sGlobalLock) {
1412             if (sDisabledKeys.contains(mCacheName)) {
1413                 disableInstance();
1414             }
1415             sCaches.put(this, null);
1416         }
1417     }
1418 
1419     /**
1420      * Throw if the current process is not allowed to use test APIs.
1421      */
1422     @android.ravenwood.annotation.RavenwoodReplace
1423     private static void throwIfNotTest() {
1424         final ActivityThread activityThread = ActivityThread.currentActivityThread();
1425         if (activityThread == null) {
1426             // Only tests can reach here.
1427             return;
1428         }
1429         final Instrumentation instrumentation = activityThread.getInstrumentation();
1430         if (instrumentation == null) {
1431             // Only tests can reach here.
1432             return;
1433         }
1434         if (instrumentation.isInstrumenting()) {
1435             return;
1436         }
1437         if (Flags.enforcePicTestmodeProtocol()) {
1438             throw new IllegalStateException("Test-only API called not from a test.");
1439         }
1440     }
1441 
1442     /**
1443      * Do not throw if running under ravenwood.
1444      */
1445     private static void throwIfNotTest$ravenwood() {
1446     }
1447 
1448     /**
1449      * Enable or disable test mode.  The protocol requires that the mode toggle: for instance, it is
1450      * illegal to clear the test mode if the test mode is already off.  Enabling test mode puts
1451      * all caches in the process into test mode; all nonces are initialized to UNSET and
1452      * subsequent reads and writes are to process memory.  This has the effect of disabling all
1453      * caches that are not local to the process.  Disabling test mode restores caches to normal
1454      * operation.
1455      * @param mode The desired test mode.
1456      * @throws IllegalStateException if the supplied mode is already set.
1457      * @throws IllegalStateException if the process is not running an instrumentation test.
1458      * @hide
1459      */
1460     @VisibleForTesting
1461     public static void setTestMode(boolean mode) {
1462         throwIfNotTest();
1463         synchronized (sGlobalLock) {
1464             if (sTestMode == mode) {
1465                 final String msg = "cannot set test mode redundantly: mode=" + mode;
1466                 if (Flags.enforcePicTestmodeProtocol()) {
1467                     throw new IllegalStateException(msg);
1468                 } else {
1469                     Log.e(TAG, msg);
1470                 }
1471             }
1472             sTestMode = mode;
1473             if (Flags.picTestMode() || !mode) {
1474                 setTestModeLocked(mode);
1475             }
1476         }
1477     }
1478 
1479     /**
1480      * Clean up when testing ends. All handlers are reset out of test mode.  NonceLocal handlers
1481      * (MODULE_TEST) are reset to the NONCE_UNSET state.  This has no effect on any other handlers
1482      * that were not originally in test mode.
1483      */
1484     @GuardedBy("sGlobalLock")
1485     private static void setTestModeLocked(boolean mode) {
1486         for (Iterator<String> e = sHandlers.keys().asIterator(); e.hasNext(); ) {
1487             String s = e.next();
1488             final NonceHandler h = sHandlers.get(s);
1489             h.setTestMode(mode);
1490         }
1491     }
1492 
1493     /**
1494      * Enable testing the specific cache key.  This API allows a test process to invalidate caches
1495      * for which it would not otherwise have permission.  Caches in test mode do NOT write their
1496      * values to the system properties.  The effect is local to the current process.  Test mode
1497      * must be true when this method is called.
1498      * @throws IllegalStateException if the process is not running an instrumentation test.
1499      * @hide
1500      */
1501     public void testPropertyName() {
1502         throwIfNotTest();
1503         synchronized (sGlobalLock) {
1504             if (sTestMode == false) {
1505                 throw new IllegalStateException("cannot test property name with test mode off");
1506             }
1507             mNonce.setTestMode(true);
1508         }
1509     }
1510 
1511     // Read the nonce associated with the current cache.
1512     @GuardedBy("mLock")
1513     private long getCurrentNonce() {
1514         return mNonce.getNonce();
1515     }
1516 
1517     /**
1518      * Forget all cached values.  This is used by a client when the server exits.  Since the
1519      * server has exited, the cache values are no longer valid, but the server is no longer
1520      * present to invalidate the cache.  Note that this is not necessary if the server is
1521      * system_server, because the entire operating system reboots if that process exits.
1522      * @hide
1523      */
1524     public final void clear() {
1525         synchronized (mLock) {
1526             if (DEBUG) {
1527                 Log.d(TAG, "clearing cache for " + mPropertyName);
1528             }
1529             mCache.clear();
1530             mClears++;
1531         }
1532     }
1533 
1534     /**
1535      * Fetch a result from scratch in case it's not in the cache at all.  Called unlocked: may
1536      * block. If this function returns null, the result of the cache query is null. There is no
1537      * "negative cache" in the query: we don't cache null results at all.
1538      * TODO(216112648): deprecate this as a public interface, in favor of an instance of
1539      * QueryHandler.
1540      * @hide
1541      */
1542     public Result recompute(@NonNull Query query) {
1543         return mComputer.apply(query);
1544     }
1545 
1546     /**
1547      * Return true if the query should bypass the cache.  The default behavior is to
1548      * always use the cache but the method can be overridden for a specific class.
1549      * TODO(216112648): deprecate this as a public interface, in favor of an instance of
1550      * QueryHandler.
1551      * @hide
1552      */
1553     public boolean bypass(@NonNull Query query) {
1554         return mComputer.shouldBypassCache(query);
1555     }
1556 
1557     /**
1558      * Determines if a pair of responses are considered equal. Used to determine whether
1559      * a cache is inadvertently returning stale results when VERIFY is set to true.
1560      * @hide
1561      */
1562     public boolean resultEquals(Result cachedResult, Result fetchedResult) {
1563         // If a service crashes and returns a null result, the cached value remains valid.
1564         if (fetchedResult != null) {
1565             return Objects.equals(cachedResult, fetchedResult);
1566         }
1567         return true;
1568     }
1569 
1570     /**
1571      * Make result up-to-date on a cache hit.  Called unlocked;
1572      * may block.
1573      *
1574      * Return either 1) oldResult itself (the same object, by reference equality), in which
1575      * case we just return oldResult as the result of the cache query, 2) a new object, which
1576      * replaces oldResult in the cache and which we return as the result of the cache query
1577      * after performing another property read to make sure that the result hasn't changed in
1578      * the meantime (if the nonce has changed in the meantime, we drop the cache and try the
1579      * whole query again), or 3) null, which causes the old value to be removed from the cache
1580      * and null to be returned as the result of the cache query.
1581      * @hide
1582      */
1583     protected Result refresh(Result oldResult, Query query) {
1584         return oldResult;
1585     }
1586 
1587     /**
1588      * Disable the use of this cache in this process.  This method is used internally and during
1589      * testing.  To disable a cache in normal code, use disableLocal().  A disabled cache cannot
1590      * be re-enabled.
1591      * @hide
1592      */
1593     @VisibleForTesting
1594     public void disableInstance() {
1595         synchronized (mLock) {
1596             mDisabled = true;
1597             clear();
1598         }
1599     }
1600 
1601     /**
1602      * Disable the local use of all caches with the same name.  All currently registered caches
1603      * with the name will be disabled now, and all future cache instances that use the name will
1604      * be disabled in their constructor.
1605      */
1606     private static final void disableLocal(@NonNull String name) {
1607         synchronized (sGlobalLock) {
1608             if (sDisabledKeys.contains(name)) {
1609                 // The key is already in recorded so there is no further work to be done.
1610                 return;
1611             }
1612             for (PropertyInvalidatedCache cache : sCaches.keySet()) {
1613                 if (name.equals(cache.mCacheName)) {
1614                     cache.disableInstance();
1615                 }
1616             }
1617             // Record the disabled key after the iteration.  If an exception occurs during the
1618             // iteration above, and the code is retried, the function should not exit early.
1619             sDisabledKeys.add(name);
1620         }
1621     }
1622 
1623     /**
1624      * Stop disabling local caches with a particular name.  Any caches that are currently
1625      * disabled remain disabled (the "disabled" setting is sticky).  However, new caches
1626      * with this name will not be disabled.  It is not an error if the cache name is not
1627      * found in the list of disabled caches.
1628      * @hide
1629      */
1630     @VisibleForTesting
1631     public void forgetDisableLocal() {
1632         synchronized (sGlobalLock) {
1633             sDisabledKeys.remove(mCacheName);
1634         }
1635     }
1636 
1637     /**
1638      * Disable this cache in the current process, and all other caches that use the same
1639      * name.  This does not affect caches that have a different name but use the same
1640      * property.
1641      * TODO(216112648) Remove this in favor of disableForCurrentProcess().
1642      * @hide
1643      */
1644     public void disableLocal() {
1645         disableForCurrentProcess();
1646     }
1647 
1648     /**
1649      * Disable this cache in the current process, and all other present and future caches that use
1650      * the same name.  This does not affect caches that have a different name but use the same
1651      * property.  Once disabled, a cache cannot be reenabled.
1652      * @hide
1653      */
1654     public void disableForCurrentProcess() {
1655         disableLocal(mCacheName);
1656     }
1657 
1658     /** @hide */
1659     public static void disableForCurrentProcess(@NonNull String cacheName) {
1660         disableLocal(cacheName);
1661     }
1662 
1663     /**
1664      * Return whether a cache instance is disabled.
1665      * @hide
1666      */
1667     @VisibleForTesting
1668     public boolean isDisabled() {
1669         return mDisabled || !sEnabled;
1670     }
1671 
1672     /**
1673      * Get a value from the cache or recompute it.
1674      * @hide
1675      */
1676     public @Nullable Result query(@NonNull Query query) {
1677         // Let access to mDisabled race: it's atomic anyway.
1678         long currentNonce = (!isDisabled()) ? getCurrentNonce() : NONCE_DISABLED;
1679         if (!isReservedNonce(currentNonce)
1680             && bypass(query)) {
1681             currentNonce = NONCE_BYPASS;
1682         }
1683         for (;;) {
1684             if (isReservedNonce(currentNonce)) {
1685                 if (!mDisabled) {
1686                     // Do not bother collecting statistics if the cache is
1687                     // locally disabled.
1688                     synchronized (mLock) {
1689                         mSkips[(int) currentNonce]++;
1690                     }
1691                 }
1692 
1693                 if (DEBUG) {
1694                     if (!mDisabled) {
1695                         Log.d(TAG, formatSimple(
1696                             "cache %s %s for %s",
1697                             cacheName(), sNonceName[(int) currentNonce], queryToString(query)));
1698                     }
1699                 }
1700                 return recompute(query);
1701             }
1702 
1703             final boolean cacheHit;
1704             final Result cachedResult;
1705             synchronized (mLock) {
1706                 if (currentNonce == mLastSeenNonce) {
1707                     cachedResult = mCache.get(query);
1708                     if (cachedResult == null) {
1709                         if (mCacheNullResults) {
1710                             cacheHit = mCache.containsKey(query);
1711                         } else {
1712                             cacheHit = false;
1713                         }
1714                     } else {
1715                         cacheHit = true;
1716                     }
1717                     if (cacheHit) {
1718                         mHits++;
1719                     }
1720                 } else {
1721                     if (DEBUG) {
1722                         Log.d(TAG, formatSimple(
1723                             "clearing cache %s of %d entries because nonce changed [%s] -> [%s]",
1724                             cacheName(), mCache.size(),
1725                             mLastSeenNonce, currentNonce));
1726                     }
1727                     clear();
1728                     mLastSeenNonce = currentNonce;
1729                     cacheHit = false;
1730                     cachedResult = null;
1731                 }
1732             }
1733 
1734             // Cache hit --- but we're not quite done yet.  A value in the cache might need to
1735             // be augmented in a "refresh" operation.  The refresh operation can combine the
1736             // old and the new nonce values.  In order to make sure the new parts of the value
1737             // are consistent with the old, possibly-reused parts, we check the property value
1738             // again after the refresh and do the whole fetch again if the property invalidated
1739             // us while we were refreshing.
1740             if (cacheHit) {
1741                 final Result refreshedResult = refresh(cachedResult, query);
1742                 if (refreshedResult != cachedResult) {
1743                     if (DEBUG) {
1744                         Log.d(TAG, "cache refresh for " + cacheName() + " " + queryToString(query));
1745                     }
1746                     final long afterRefreshNonce = getCurrentNonce();
1747                     if (currentNonce != afterRefreshNonce) {
1748                         currentNonce = afterRefreshNonce;
1749                         if (DEBUG) {
1750                             Log.d(TAG, formatSimple(
1751                                     "restarting %s %s because nonce changed in refresh",
1752                                     cacheName(),
1753                                     queryToString(query)));
1754                         }
1755                         continue;
1756                     }
1757                     synchronized (mLock) {
1758                         if (currentNonce != mLastSeenNonce) {
1759                             // Do nothing: cache is already out of date. Just return the value
1760                             // we already have: there's no guarantee that the contents of mCache
1761                             // won't become invalid as soon as we return.
1762                         } else if (refreshedResult == null) {
1763                             mCache.remove(query);
1764                         } else {
1765                             mCache.put(query, refreshedResult);
1766                         }
1767                     }
1768                     return maybeCheckConsistency(query, refreshedResult);
1769                 }
1770                 if (DEBUG) {
1771                     Log.d(TAG, "cache hit for " + cacheName() + " " + queryToString(query));
1772                 }
1773                 return maybeCheckConsistency(query, cachedResult);
1774             }
1775 
1776             // Cache miss: make the value from scratch.
1777             if (DEBUG) {
1778                 Log.d(TAG, "cache miss for " + cacheName() + " " + queryToString(query));
1779             }
1780             final Result result = recompute(query);
1781             synchronized (mLock) {
1782                 // If someone else invalidated the cache while we did the recomputation, don't
1783                 // update the cache with a potentially stale result.
1784                 if (mLastSeenNonce == currentNonce) {
1785                     if (result != null || mCacheNullResults) {
1786                         mCache.put(query, result);
1787                     } else if (result == null) {
1788                         // The result was null and it was not cached.
1789                         mNulls++;
1790                     }
1791                 }
1792                 mMisses++;
1793             }
1794             return maybeCheckConsistency(query, result);
1795         }
1796     }
1797 
1798     // Inner class avoids initialization in processes that don't do any invalidation
1799     private static final class NoPreloadHolder {
1800         private static final AtomicLong sNextNonce = new AtomicLong((new Random()).nextLong());
1801         public static long next() {
1802             return sNextNonce.getAndIncrement();
1803         }
1804     }
1805 
1806     /**
1807      * Non-static convenience version of disableSystemWide() for situations in which only a
1808      * single PropertyInvalidatedCache is keyed on a particular property value.
1809      *
1810      * When multiple caches share a single property value, using an instance method on one of
1811      * the cache objects to invalidate all of the cache objects becomes confusing and you should
1812      * just use the static version of this function.
1813      * @throws IllegalStateException if the process is not running an instrumentation test.
1814      * @hide
1815      */
1816     @VisibleForTesting
1817     public void disableSystemWide() {
1818         throwIfNotTest();
1819         disableSystemWide(mPropertyName);
1820     }
1821 
1822     /**
1823      * Disable all caches system-wide that are keyed on {@var name}. This
1824      * function is synchronous: caches are invalidated and disabled upon return.
1825      *
1826      * @param name Name of the cache-key property to invalidate
1827      */
1828     private static void disableSystemWide(@NonNull String name) {
1829         getNonceHandler(name).disable();
1830     }
1831 
1832     /**
1833      * Non-static version of invalidateCache() for situations in which a cache instance is
1834      * available.  This is slightly faster than than the static versions because it does not have
1835      * to look up the NonceHandler for a given property name.
1836      * @hide
1837      */
1838     public void invalidateCache() {
1839         mNonce.invalidate();
1840     }
1841 
1842     /**
1843      * Non-static version of corkInvalidations() for situations in which the cache instance is
1844      * available.  This is slightly faster than than the static versions because it does not have
1845      * to look up the NonceHandler for a given property name.
1846      * @hide
1847      */
1848     public void corkInvalidations() {
1849         mNonce.cork();
1850     }
1851 
1852     /**
1853      * Non-static version of uncorkInvalidations() for situations in which the cache instance is
1854      * available.  This is slightly faster than than the static versions because it does not have
1855      * to look up the NonceHandler for a given property name.
1856      * @hide
1857      */
1858     public void uncorkInvalidations() {
1859         mNonce.uncork();
1860     }
1861 
1862     /**
1863      * Invalidate caches in all processes that are keyed for the module and api.
1864      * @hide
1865      */
1866     public static void invalidateCache(@NonNull String module, @NonNull String api) {
1867         invalidateCache(createPropertyName(module, api));
1868     }
1869 
1870     /**
1871      * Invalidate caches in all processes that have the module and api specified in the args.
1872      * @hide
1873      */
1874     public static void invalidateCache(@NonNull Args args) {
1875         invalidateCache(createPropertyName(args.mModule, args.mApi));
1876     }
1877 
1878     /**
1879      * Invalidate PropertyInvalidatedCache caches in all processes that are keyed on
1880      * {@var name}. This function is synchronous: caches are invalidated upon return.
1881      *
1882      * TODO(216112648) make this method private in favor of the two-argument (module, api)
1883      * override.
1884      *
1885      * @param name Name of the cache-key property to invalidate
1886      * @hide
1887      */
1888     public static void invalidateCache(@NonNull String name) {
1889         getNonceHandler(name).invalidate();
1890     }
1891 
1892     /**
1893      * Temporarily put the cache in the uninitialized state and prevent invalidations from
1894      * moving it out of that state: useful in cases where we want to avoid the overhead of a
1895      * large number of cache invalidations in a short time.  While the cache is corked, clients
1896      * bypass the cache and talk to backing services directly.  This property makes corking
1897      * correctness-preserving even if corked outside the lock that controls access to the
1898      * cache's backing service.
1899      *
1900      * corkInvalidations() and uncorkInvalidations() must be called in pairs.
1901      *
1902      * @param name Name of the cache-key property to cork
1903      * @hide
1904      */
1905     public static void corkInvalidations(@NonNull String name) {
1906         getNonceHandler(name).cork();
1907     }
1908 
1909     /**
1910      * Undo the effect of a cork, allowing cache invalidations to proceed normally.
1911      * Removing the last cork on a cache name invalidates the cache by side effect,
1912      * transitioning it to normal operation (unless explicitly disabled system-wide).
1913      *
1914      * @param name Name of the cache-key property to uncork
1915      * @hide
1916      */
1917     public static void uncorkInvalidations(@NonNull String name) {
1918         getNonceHandler(name).uncork();
1919     }
1920 
1921     /**
1922      * Time-based automatic corking helper. This class allows providers of cached data to
1923      * amortize the cost of cache invalidations by corking the cache immediately after a
1924      * modification (instructing clients to bypass the cache temporarily) and automatically
1925      * uncork after some period of time has elapsed.
1926      *
1927      * It's better to use explicit cork and uncork pairs that tighly surround big batches of
1928      * invalidations, but it's not always practical to tell where these invalidation batches
1929      * might occur. AutoCorker's time-based corking is a decent alternative.
1930      *
1931      * The auto-cork delay is configurable but it should not be too long.  The purpose of
1932      * the delay is to minimize the number of times a server writes to the system property
1933      * when invalidating the cache.  One write every 50ms does not hurt system performance.
1934      * @hide
1935      */
1936     public static final class AutoCorker {
1937         public static final int DEFAULT_AUTO_CORK_DELAY_MS = 50;
1938 
1939         private final String mPropertyName;
1940         private final int mAutoCorkDelayMs;
1941         private final Object mLock = new Object();
1942         @GuardedBy("mLock")
1943         private long mUncorkDeadlineMs = -1;  // SystemClock.uptimeMillis()
1944         @GuardedBy("mLock")
1945         private Handler mHandler;
1946 
1947         private NonceHandler mNonce;
1948 
1949         public AutoCorker(@NonNull String propertyName) {
1950             this(propertyName, DEFAULT_AUTO_CORK_DELAY_MS);
1951         }
1952 
1953         public AutoCorker(@NonNull String propertyName, int autoCorkDelayMs) {
1954             if (separatePermissionNotificationsEnabled()) {
1955                 throw new IllegalStateException("AutoCorking is unavailable");
1956             }
1957 
1958             mPropertyName = propertyName;
1959             mAutoCorkDelayMs = autoCorkDelayMs;
1960             // We can't initialize mHandler here: when we're created, the main loop might not
1961             // be set up yet! Wait until we have a main loop to initialize our
1962             // corking callback.
1963         }
1964 
1965         public void autoCork() {
1966             synchronized (mLock) {
1967                 if (mNonce == null) {
1968                     mNonce = getNonceHandler(mPropertyName);
1969                 }
1970             }
1971 
1972             if (getLooper() == null) {
1973                 // We're not ready to auto-cork yet, so just invalidate the cache immediately.
1974                 if (DEBUG) {
1975                     Log.w(TAG, "invalidating instead of autocorking early in init: "
1976                             + mPropertyName);
1977                 }
1978                 mNonce.invalidate();
1979                 return;
1980             }
1981             synchronized (mLock) {
1982                 boolean alreadyQueued = mUncorkDeadlineMs >= 0;
1983                 if (DEBUG) {
1984                     Log.d(TAG, formatSimple(
1985                             "autoCork %s mUncorkDeadlineMs=%s", mPropertyName,
1986                             mUncorkDeadlineMs));
1987                 }
1988                 mUncorkDeadlineMs = SystemClock.uptimeMillis() + mAutoCorkDelayMs;
1989                 if (!alreadyQueued) {
1990                     getHandlerLocked().sendEmptyMessageAtTime(0, mUncorkDeadlineMs);
1991                     mNonce.cork();
1992                 } else {
1993                     // Count this as a corked invalidation.
1994                     mNonce.invalidate();
1995                 }
1996             }
1997         }
1998 
1999         private void handleMessage(Message msg) {
2000             synchronized (mLock) {
2001                 if (DEBUG) {
2002                     Log.d(TAG, formatSimple(
2003                             "handleMsesage %s mUncorkDeadlineMs=%s",
2004                             mPropertyName, mUncorkDeadlineMs));
2005                 }
2006 
2007                 if (mUncorkDeadlineMs < 0) {
2008                     return;  // ???
2009                 }
2010                 long nowMs = SystemClock.uptimeMillis();
2011                 if (mUncorkDeadlineMs > nowMs) {
2012                     mUncorkDeadlineMs = nowMs + mAutoCorkDelayMs;
2013                     if (DEBUG) {
2014                         Log.d(TAG, formatSimple(
2015                                         "scheduling uncork at %s",
2016                                         mUncorkDeadlineMs));
2017                     }
2018                     getHandlerLocked().sendEmptyMessageAtTime(0, mUncorkDeadlineMs);
2019                     return;
2020                 }
2021                 if (DEBUG) {
2022                     Log.d(TAG, "automatic uncorking " + mPropertyName);
2023                 }
2024                 mUncorkDeadlineMs = -1;
2025                 mNonce.uncork();
2026             }
2027         }
2028 
2029         @GuardedBy("mLock")
2030         private Handler getHandlerLocked() {
2031             if (mHandler == null) {
2032                 mHandler = new Handler(getLooper()) {
2033                         @Override
2034                         public void handleMessage(Message msg) {
2035                             AutoCorker.this.handleMessage(msg);
2036                         }
2037                     };
2038             }
2039             return mHandler;
2040         }
2041 
2042         /**
2043          * Return a looper for auto-uncork messages.  Messages should be processed on the
2044          * background thread, not on the main thread.
2045          */
2046         private static Looper getLooper() {
2047             return BackgroundThread.getHandler().getLooper();
2048         }
2049     }
2050 
2051     /**
2052      * Return the result generated by a given query to the cache, performing debugging checks when
2053      * enabled.
2054      */
2055     private Result maybeCheckConsistency(Query query, Result proposedResult) {
2056         if (VERIFY) {
2057             Result resultToCompare = recompute(query);
2058             boolean nonceChanged = (getCurrentNonce() != mLastSeenNonce);
2059             if (!nonceChanged && !resultEquals(proposedResult, resultToCompare)) {
2060                 Log.e(TAG, formatSimple(
2061                         "cache %s inconsistent for %s is %s should be %s",
2062                         cacheName(), queryToString(query),
2063                         proposedResult, resultToCompare));
2064             }
2065             // Always return the "true" result in verification mode.
2066             return resultToCompare;
2067         }
2068         return proposedResult;
2069     }
2070 
2071     /**
2072      * Return the name of the cache, to be used in debug messages.  This is exposed
2073      * primarily for testing.
2074      * @hide
2075      */
2076     public final @NonNull String cacheName() {
2077         return mCacheName;
2078     }
2079 
2080     /**
2081      * Return the property used by the cache.  This is primarily for test purposes.
2082      * @hide
2083      */
2084     public final @NonNull String propertyName() {
2085         return mPropertyName;
2086     }
2087 
2088     /**
2089      * Return the query as a string, to be used in debug messages.  New clients should not
2090      * override this, but should instead add the necessary toString() method to the Query
2091      * class.
2092      * TODO(216112648) add a method in the QueryHandler and deprecate this API.
2093      * @hide
2094      */
2095     protected @NonNull String queryToString(@NonNull Query query) {
2096         return Objects.toString(query);
2097     }
2098 
2099     /**
2100      * Disable all caches in the local process.  This is primarily useful for testing when the
2101      * test needs to bypass the cache or when the test is for a server, and the test process does
2102      * not have privileges to write the nonce. Once disabled it is not possible to re-enable
2103      * caching in the current process.  See {@link #testPropertyName} for a more focused way to
2104      * bypass caches when the test is for a server.
2105      * @hide
2106      */
2107     public static void disableForTestMode() {
2108         Log.d(TAG, "disabling all caches in the process");
2109         sEnabled = false;
2110     }
2111 
2112     /**
2113      * Report the disabled status of this cache instance.  The return value does not
2114      * reflect status of the property key.
2115      */
2116     private boolean getDisabledState() {
2117         return isDisabled();
2118     }
2119 
2120     /**
2121      * Return the number of entries in the cache.  This is used for testing and has package-only
2122      * visibility.
2123      * @hide
2124      */
2125     public int size() {
2126         synchronized (mLock) {
2127             return mCache.size();
2128         }
2129     }
2130 
2131     /**
2132      * Returns a list of caches alive at the current time.
2133      */
2134     private static @NonNull ArrayList<PropertyInvalidatedCache> getActiveCaches() {
2135         synchronized (sGlobalLock) {
2136             return new ArrayList<PropertyInvalidatedCache>(sCaches.keySet());
2137         }
2138     }
2139 
2140     /**
2141      * Switches that can be used to control the detail emitted by a cache dump.  The
2142      * "CONTAINS" switches match if the cache (property) name contains the switch
2143      * argument.  The "LIKE" switches match if the cache (property) name matches the
2144      * switch argument as a regex.  The regular expression must match the entire name,
2145      * which generally means it may need leading/trailing "." expressions.
2146      */
2147     final static String NAME_CONTAINS = "-name-has=";
2148     final static String NAME_LIKE = "-name-like=";
2149     final static String PROPERTY_CONTAINS = "-property-has=";
2150     final static String PROPERTY_LIKE = "-property-like=";
2151     final static String BRIEF = "-brief";
2152 
2153     /**
2154      * Return true if any argument is a detailed specification switch.
2155      */
2156     private static boolean anyDetailed(String[] args) {
2157         for (String a : args) {
2158             if (a.startsWith(NAME_CONTAINS) || a.startsWith(NAME_LIKE)
2159                 || a.startsWith(PROPERTY_CONTAINS) || a.startsWith(PROPERTY_LIKE)) {
2160                 return true;
2161             }
2162         }
2163         return false;
2164     }
2165 
2166     /**
2167      * A helper method to determine if a string matches a switch.
2168      */
2169     private static boolean chooses(String arg, String key, String reference, boolean contains) {
2170         if (arg.startsWith(key)) {
2171             final String value = arg.substring(key.length());
2172             if (contains) {
2173                 return reference.contains(value);
2174             } else {
2175                 return reference.matches(value);
2176             }
2177         }
2178         return false;
2179     }
2180 
2181     /**
2182      * Return true if this cache should be dumped in detail.  This method is not called
2183      * unless it has already been determined that there is at least one match requested.
2184      */
2185     private boolean showDetailed(String[] args) {
2186         for (String a : args) {
2187             if (chooses(a, NAME_CONTAINS, cacheName(), true)
2188                 || chooses(a, NAME_LIKE, cacheName(), false)
2189                 || chooses(a, PROPERTY_CONTAINS, mPropertyName, true)
2190                 || chooses(a, PROPERTY_LIKE, mPropertyName, false)) {
2191                 return true;
2192             }
2193         }
2194         return false;
2195     }
2196 
2197     @GuardedBy("mLock")
2198     private long getSkipsLocked() {
2199         int sum = 0;
2200         for (int i = 0; i < mSkips.length; i++) {
2201             sum += mSkips[i];
2202         }
2203         return sum;
2204     }
2205 
2206     // Return true if this cache has had any activity.  If the hits, misses, and skips are all
2207     // zero then the client never tried to use the cache.  If invalidations and corks are also
2208     // zero then the server never tried to use the cache.
2209     private boolean isActive(NonceHandler.Stats stats) {
2210         synchronized (mLock) {
2211             return mHits + mMisses + getSkipsLocked()
2212                     + stats.invalidated + stats.corkedInvalidates > 0;
2213         }
2214     }
2215 
2216     @NeverCompile
2217     private void dumpContents(PrintWriter pw, boolean detailed, String[] args) {
2218         // If the user has requested specific caches and this is not one of them, return
2219         // immediately.
2220         if (detailed && !showDetailed(args)) {
2221             return;
2222         }
2223         // Does the user want brief output?
2224         boolean brief = false;
2225         for (String a : args) brief |= a.equals(BRIEF);
2226 
2227         NonceHandler.Stats stats = mNonce.getStats();
2228 
2229         synchronized (mLock) {
2230             if (brief && !isActive(stats)) {
2231                 return;
2232             }
2233 
2234             pw.println(formatSimple("  Cache Name: %s", cacheName()));
2235             pw.println(formatSimple("    Property: %s", mPropertyName));
2236             pw.println(formatSimple(
2237                 "    Hits: %d, Misses: %d, Skips: %d, Clears: %d, Nulls: %d",
2238                 mHits, mMisses, getSkipsLocked(), mClears, mNulls));
2239 
2240             // Print all the skip reasons.
2241             pw.format("    Skip-%s: %d", sNonceName[0], mSkips[0]);
2242             for (int i = 1; i < mSkips.length; i++) {
2243                 pw.format(", Skip-%s: %d", sNonceName[i], mSkips[i]);
2244             }
2245             pw.println();
2246 
2247             pw.println(formatSimple(
2248                 "    Nonce: 0x%016x, Invalidates: %d, Corked: %d",
2249                 mLastSeenNonce, stats.invalidated, stats.corkedInvalidates));
2250             pw.println(formatSimple(
2251                 "    Current Size: %d, Max Size: %d, HW Mark: %d, Overflows: %d",
2252                 mCache.size(), mMaxEntries, mHighWaterMark, mMissOverflow));
2253             mCache.dump(pw);
2254             pw.println(formatSimple("    Enabled: %s", mDisabled ? "false" : "true"));
2255 
2256             // Dump the contents of the cache.
2257             if (detailed) {
2258                 mCache.dumpDetailed(pw);
2259             }
2260 
2261             // Separator between caches.
2262             pw.println("");
2263         }
2264     }
2265 
2266     /**
2267      * Without arguments, this dumps statistics from every cache in the process to the
2268      * provided ParcelFileDescriptor.  Optional switches allow the caller to choose
2269      * specific caches (selection is by cache name or property name); if these switches
2270      * are used then the output includes both cache statistics and cache entries.
2271      */
2272     @NeverCompile
2273     private static void dumpCacheInfo(@NonNull PrintWriter pw, @NonNull String[] args) {
2274         if (!sEnabled) {
2275             pw.println("  Caching is disabled in this process.");
2276             return;
2277         }
2278 
2279         // See if detailed is requested for any cache.  If there is a specific detailed request,
2280         // then only that cache is reported.
2281         boolean detail = anyDetailed(args);
2282 
2283         if (sSharedMemoryAvailable) {
2284             pw.println("  SharedMemory: enabled");
2285             NonceStore.getInstance().dump(pw, "    ", detail);
2286         } else {
2287             pw.println("  SharedMemory: disabled");
2288          }
2289         pw.println();
2290 
2291         ArrayList<PropertyInvalidatedCache> activeCaches = getActiveCaches();
2292         for (int i = 0; i < activeCaches.size(); i++) {
2293             PropertyInvalidatedCache currentCache = activeCaches.get(i);
2294             currentCache.dumpContents(pw, detail, args);
2295         }
2296     }
2297 
2298     /**
2299      * Without arguments, this dumps statistics from every cache in the process to the
2300      * provided ParcelFileDescriptor.  Optional switches allow the caller to choose
2301      * specific caches (selection is by cache name or property name); if these switches
2302      * are used then the output includes both cache statistics and cache entries.
2303      * @hide
2304      */
2305     @NeverCompile
2306     public static void dumpCacheInfo(@NonNull ParcelFileDescriptor pfd, @NonNull String[] args) {
2307         // Create a PrintWriter that uses a byte array.  The code can safely write to
2308         // this array without fear of blocking.  The completed byte array will be sent
2309         // to the caller after all the data has been collected and all locks have been
2310         // released.
2311         ByteArrayOutputStream barray = new ByteArrayOutputStream();
2312         PrintWriter bout = new PrintWriter(barray);
2313         dumpCacheInfo(bout, args);
2314         bout.close();
2315 
2316         try {
2317             // Send the final byte array to the output.  This happens outside of all locks.
2318             var out = new FileOutputStream(pfd.getFileDescriptor());
2319             barray.writeTo(out);
2320             out.close();
2321             barray.close();
2322         } catch (IOException e) {
2323             Log.e(TAG, "Failed to dump PropertyInvalidatedCache instances");
2324         }
2325     }
2326 
2327     /**
2328      * This dumps the detailed entries (Query and Result) inside the current instance of the
2329      * {@link PropertyInvalidatedCache}.
2330      *
2331      * @param pw The PrintWriter object for the output stream.
2332      * @hide
2333      */
2334     public void dumpCacheEntries(@NonNull PrintWriter pw) {
2335         synchronized (mLock) {
2336             mCache.dumpDetailed(pw);
2337         }
2338     }
2339 
2340     /**
2341      * Nonces in shared memory are supported by a string block that acts as a table of contents
2342      * for nonce names, and an array of nonce values.  There are two key design principles with
2343      * respect to nonce maps:
2344      *
2345      * 1. It is always okay if a nonce value cannot be determined.  If the nonce is UNSET, the
2346      * cache is bypassed, which is always functionally correct.  Clients do not take extraordinary
2347      * measures to be current with the nonce map.  Clients must be current with the nonce itself;
2348      * this is achieved through the shared memory.
2349      *
2350      * 2. Once a name is mapped to a nonce index, the mapping is fixed for the lifetime of the
2351      * system.  It is only necessary to distinguish between the unmapped and mapped states.  Once
2352      * a client has mapped a nonce, that mapping is known to be good for the lifetime of the
2353      * system.
2354      * @hide
2355      */
2356     @VisibleForTesting
2357     public static class NonceStore {
2358 
2359         // A lock for the store.
2360         private final Object mLock = new Object();
2361 
2362         // The native pointer.  This is not owned by this class.  It is owned by
2363         // ApplicationSharedMemory, and it disappears when the owning instance is closed.
2364         private final long mPtr;
2365 
2366         // True if the memory is immutable.
2367         private final boolean mMutable;
2368 
2369         // The maximum length of a string in the string block.  The maximum length must fit in a
2370         // byte, but a smaller value has been chosen to limit memory use.  Because strings are
2371         // run-length encoded, a string consumes at most MAX_STRING_LENGTH+1 bytes in the string
2372         // block.
2373         private static final int MAX_STRING_LENGTH = 63;
2374 
2375         // The expected hash code of the string block.  If the hash over the string block equals
2376         // this value, then the string block is valid.  Otherwise, the block is not valid and
2377         // should be re-read.  An invalid block generally means that a client has read the shared
2378         // memory while the server was still writing it.
2379         @GuardedBy("mLock")
2380         private int mBlockHash = 0;
2381 
2382         // The number of nonces that the native layer can hold.  This is maintained for debug,
2383         // logging, and testing.
2384         @VisibleForTesting
2385         public final int mMaxNonce;
2386 
2387         // The size of the native byte block.
2388         @VisibleForTesting
2389         public final int mMaxByte;
2390 
2391         /** @hide */
2392         @VisibleForTesting
2393         public NonceStore(long ptr, boolean mutable) {
2394             mPtr = ptr;
2395             mMutable = mutable;
2396             mMaxByte = nativeGetMaxByte(ptr);
2397             mMaxNonce = nativeGetMaxNonce(ptr);
2398             refreshStringBlockLocked();
2399         }
2400 
2401         // The static lock for singleton acquisition.
2402         private static Object sLock = new Object();
2403 
2404         // NonceStore is supposed to be a singleton.
2405         private static NonceStore sInstance;
2406 
2407         // Return the singleton instance.
2408         static NonceStore getInstance() {
2409             synchronized (sLock) {
2410                 if (sInstance == null) {
2411                     try {
2412                         ApplicationSharedMemory shmem = ApplicationSharedMemory.getInstance();
2413                         sInstance = (shmem == null)
2414                                     ? null
2415                                     : new NonceStore(shmem.getSystemNonceBlock(),
2416                                             shmem.isMutable());
2417                     } catch (IllegalStateException e) {
2418                         // ApplicationSharedMemory.getInstance() throws if the shared memory is
2419                         // not yet mapped.  Swallow the exception and leave sInstance null.
2420                     }
2421                 }
2422                 return sInstance;
2423             }
2424         }
2425 
2426         // The index value of an unmapped name.
2427         public static final int INVALID_NONCE_INDEX = -1;
2428 
2429         // The highest string index extracted from the string block.  -1 means no strings have
2430         // been seen.  This is used to skip strings that have already been processed, when the
2431         // string block is updated.
2432         @GuardedBy("mLock")
2433         private int mHighestIndex = -1;
2434 
2435         // The number bytes of the string block that has been used.  This is a statistics.
2436         @GuardedBy("mLock")
2437         private int mStringBytes = 0;
2438 
2439         // The number of partial reads on the string block.  This is a statistic.
2440         @GuardedBy("mLock")
2441         private int mPartialReads = 0;
2442 
2443         // The number of times the string block was updated.  This is a statistic.
2444         @GuardedBy("mLock")
2445         private int mStringUpdated = 0;
2446 
2447         // Map a string to a native index.
2448         @GuardedBy("mLock")
2449         private final ArrayMap<String, Integer> mStringHandle = new ArrayMap<>();
2450 
2451         // Update the string map from the current string block.  The string block is not modified
2452         // and the block hash is not checked.  The function skips past strings that have already
2453         // been read, and then processes any new strings.
2454         @GuardedBy("mLock")
2455         private void updateStringMapLocked(byte[] block) {
2456             int index = 0;
2457             int offset = 0;
2458             while (offset < block.length && block[offset] != 0) {
2459                 if (index > mHighestIndex) {
2460                     // Only record the string if it has not been seen yet.
2461                     final String s = new String(block, offset+1, block[offset]);
2462                     mStringHandle.put(s, index);
2463                     mHighestIndex = index;
2464                 }
2465                 offset += block[offset] + 1;
2466                 index++;
2467             }
2468             mStringBytes = offset;
2469         }
2470 
2471         // Append a string to the string block and update the hash.  This does not write the block
2472         // to shared memory.
2473         @GuardedBy("mLock")
2474         private void appendStringToMapLocked(@NonNull String str, @NonNull byte[] block) {
2475             int offset = 0;
2476             while (offset < block.length && block[offset] != 0) {
2477                 offset += block[offset] + 1;
2478             }
2479             final byte[] strBytes = str.getBytes();
2480 
2481             if (offset + strBytes.length >= block.length) {
2482                 // Overflow.  Do not add the string to the block; the string will remain undefined.
2483                 return;
2484             }
2485 
2486             block[offset] = (byte) strBytes.length;
2487             System.arraycopy(strBytes, 0, block, offset+1, strBytes.length);
2488             mBlockHash = Arrays.hashCode(block);
2489         }
2490 
2491         // Possibly update the string block.  If the native shared memory has a new block hash,
2492         // then read the new string block values from shared memory, as well as the new hash.
2493         @GuardedBy("mLock")
2494         private void refreshStringBlockLocked() {
2495             if (mBlockHash == nativeGetByteBlockHash(mPtr)) {
2496                 // The fastest way to know that the shared memory string block has not changed.
2497                 return;
2498             }
2499             byte[] block = new byte[mMaxByte];
2500             final int hash = nativeGetByteBlock(mPtr, mBlockHash, block);
2501             if (hash != Arrays.hashCode(block)) {
2502                 // This is a partial read: ignore it.  The next time someone needs this string
2503                 // the memory will be read again and should succeed.  Set the local hash to
2504                 // zero to ensure that the next read attempt will actually read from shared
2505                 // memory.
2506                 mBlockHash = 0;
2507                 mPartialReads++;
2508                 return;
2509             }
2510             // The hash has changed.  Update the strings from the byte block.
2511             mStringUpdated++;
2512             mBlockHash = hash;
2513             updateStringMapLocked(block);
2514         }
2515 
2516         // Throw an exception if the string cannot be stored in the string block.
2517         private static void throwIfBadString(@NonNull String s) {
2518             if (s.length() == 0) {
2519                 throw new IllegalArgumentException("cannot store an empty string");
2520             }
2521             if (s.length() > MAX_STRING_LENGTH) {
2522                 throw new IllegalArgumentException("cannot store a string longer than "
2523                         + MAX_STRING_LENGTH);
2524             }
2525         }
2526 
2527         // Throw an exception if the nonce handle is invalid.  The handle is bad if it is out of
2528         // range of allocated handles.  Note that NONCE_HANDLE_INVALID will throw: this is
2529         // important for setNonce().
2530         @GuardedBy("mLock")
2531         private void throwIfBadHandle(int handle) {
2532             if (handle < 0 || handle > mHighestIndex) {
2533                 throw new IllegalArgumentException("invalid nonce handle: " + handle);
2534             }
2535         }
2536 
2537         // Throw if the memory is immutable (the process does not have write permission).  The
2538         // exception mimics the permission-denied exception thrown when a process writes to an
2539         // unauthorized system property.
2540         private void throwIfImmutable() {
2541             if (!mMutable) {
2542                 throw new RuntimeException("write permission denied");
2543             }
2544         }
2545 
2546         // Add a string to the local copy of the block and write the block to shared memory.
2547         // Return the index of the new string.  If the string has already been recorded, the
2548         // shared memory is not updated but the index of the existing string is returned.  Only
2549         // mMaxNonce strings can be stored; if mMaxNonce strings have already been allocated,
2550         // the method throws.
2551         public int storeName(@NonNull String str) {
2552             synchronized (mLock) {
2553                 Integer handle = mStringHandle.get(str);
2554                 if (handle == null) {
2555                     throwIfImmutable();
2556                     throwIfBadString(str);
2557                     if (mHighestIndex + 1 >= mMaxNonce) {
2558                         throw new RuntimeException("nonce limit exceeded");
2559                     }
2560                     byte[] block = new byte[mMaxByte];
2561                     nativeGetByteBlock(mPtr, 0, block);
2562                     appendStringToMapLocked(str, block);
2563                     nativeSetByteBlock(mPtr, mBlockHash, block);
2564                     updateStringMapLocked(block);
2565                     handle = mStringHandle.get(str);
2566                 }
2567                 return handle;
2568             }
2569         }
2570 
2571         // Retrieve the handle for a string.  -1 is returned if the string is not found.
2572         public int getHandleForName(@NonNull String str) {
2573             synchronized (mLock) {
2574                 Integer handle = mStringHandle.get(str);
2575                 if (handle == null) {
2576                     refreshStringBlockLocked();
2577                     handle  = mStringHandle.get(str);
2578                 }
2579                 return (handle != null) ? handle : INVALID_NONCE_INDEX;
2580             }
2581         }
2582 
2583         // Thin wrapper around the native method.
2584         public boolean setNonce(int handle, long value) {
2585             synchronized (mLock) {
2586                 throwIfBadHandle(handle);
2587                 throwIfImmutable();
2588                 return nativeSetNonce(mPtr, handle, value);
2589             }
2590         }
2591 
2592         public long getNonce(int handle) {
2593             synchronized (mLock) {
2594                 throwIfBadHandle(handle);
2595                 return nativeGetNonce(mPtr, handle);
2596             }
2597         }
2598 
2599         /**
2600          * Dump the nonce statistics
2601          */
2602         public void dump(@NonNull PrintWriter pw, @NonNull String prefix, boolean detailed) {
2603             synchronized (mLock) {
2604                 pw.println(formatSimple(
2605                     "%sStringsMapped: %d, BytesUsed: %d",
2606                     prefix, mHighestIndex, mStringBytes));
2607                 pw.println(formatSimple(
2608                     "%sPartialReads: %d, StringUpdates: %d",
2609                     prefix, mPartialReads, mStringUpdated));
2610 
2611                 if (detailed) {
2612                     for (String s: mStringHandle.keySet()) {
2613                         int h = mStringHandle.get(s);
2614                         pw.println(formatSimple(
2615                             "%sHandle:%d Name:%s", prefix, h, s));
2616                     }
2617                 }
2618             }
2619         }
2620     }
2621 
2622     /**
2623      * Return the maximum number of nonces supported in the native layer.
2624      *
2625      * @param mPtr the pointer to the native shared memory.
2626      * @return the number of nonces supported by the shared memory.
2627      */
2628     @FastNative
2629     private static native int nativeGetMaxNonce(long mPtr);
2630 
2631     /**
2632      * Return the maximum number of string bytes supported in the native layer.
2633      *
2634      * @param mPtr the pointer to the native shared memory.
2635      * @return the number of string bytes supported by the shared memory.
2636      */
2637     @FastNative
2638     private static native int nativeGetMaxByte(long mPtr);
2639 
2640     /**
2641      * Write the byte block and set the hash into shared memory.  The method is relatively
2642      * forgiving, in that any non-null byte array will be stored without error.  The number of
2643      * bytes will the lesser of the length of the block parameter and the size of the native
2644      * array.  The native layer performs no checks on either byte block or the hash.
2645      *
2646      * @param mPtr the pointer to the native shared memory.
2647      * @param hash a value to be stored in the native block hash.
2648      * @param block the byte array to be store.
2649      */
2650     @FastNative
2651     private static native void nativeSetByteBlock(long mPtr, int hash, @NonNull byte[] block);
2652 
2653     /**
2654      * Retrieve the string block into the array and return the hash value.  If the incoming hash
2655      * value is the same as the hash in shared memory, the native function returns immediately
2656      * without touching the block parameter.  Note that a zero hash value will always cause shared
2657      * memory to be read.  The number of bytes read is the lesser of the length of the block
2658      * parameter and the size of the native array.
2659      *
2660      * @param mPtr the pointer to the native shared memory.
2661      * @param hash a value to be compared against the hash in the native layer.
2662      * @param block an array to receive the bytes from the native layer.
2663      * @return the hash from the native layer.
2664      */
2665     @FastNative
2666     private static native int nativeGetByteBlock(long mPtr, int hash, @NonNull byte[] block);
2667 
2668     /**
2669      * Retrieve just the byte block hash from the native layer.  The function is CriticalNative
2670      * and thus very fast.
2671      *
2672      * @param mPtr the pointer to the native shared memory.
2673      * @return the current native hash value.
2674      */
2675     @CriticalNative
2676     private static native int nativeGetByteBlockHash(long mPtr);
2677 
2678     /**
2679      * Set a nonce at the specified index.  The index is checked against the size of the native
2680      * nonce array and the function returns true if the index is valid, and false.  The function
2681      * is CriticalNative and thus very fast.
2682      *
2683      * @param mPtr the pointer to the native shared memory.
2684      * @param index the index of the nonce to set.
2685      * @param value the value to set for the nonce.
2686      * @return true if the index is inside the nonce array and false otherwise.
2687      */
2688     @CriticalNative
2689     private static native boolean nativeSetNonce(long mPtr, int index, long value);
2690 
2691     /**
2692      * Get the nonce from the specified index.  The index is checked against the size of the
2693      * native nonce array; the function returns the nonce value if the index is valid, and 0
2694      * otherwise.  The function is CriticalNative and thus very fast.
2695      *
2696      * @param mPtr the pointer to the native shared memory.
2697      * @param index the index of the nonce to retrieve.
2698      * @return the value of the specified nonce, of 0 if the index is out of bounds.
2699      */
2700     @CriticalNative
2701     private static native long nativeGetNonce(long mPtr, int index);
2702 }
2703