• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.os;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.annotation.StringDef;
23 import android.annotation.SystemApi;
24 import android.annotation.TestApi;
25 import android.app.PropertyInvalidatedCache;
26 import android.app.PropertyInvalidatedCache.Args;
27 import android.text.TextUtils;
28 import android.util.ArraySet;
29 
30 import com.android.internal.annotations.GuardedBy;
31 import com.android.internal.util.FastPrintWriter;
32 
33 import java.lang.annotation.Retention;
34 import java.lang.annotation.RetentionPolicy;
35 import java.io.FileOutputStream;
36 import java.io.IOException;
37 import java.io.PrintWriter;
38 import java.util.ArrayList;
39 import java.util.HashMap;
40 import java.util.LinkedHashMap;
41 import java.util.Map;
42 import java.util.Objects;
43 import java.util.Random;
44 import java.util.Set;
45 import java.util.WeakHashMap;
46 import java.util.concurrent.atomic.AtomicLong;
47 
48 /**
49  * LRU cache that's invalidated when an opaque value in a property changes. Self-synchronizing,
50  * but doesn't hold a lock across data fetches on query misses.
51  *
52  * Clients should be aware of the following commonly-seen issues:
53  * <ul>
54  *
55  * <li>Client calls will not go through the cache before the first invalidation signal is
56  * received. Therefore, servers should signal an invalidation as soon as they have data to offer to
57  * clients.
58  *
59  * <li>Cache invalidation is restricted to well-known processes, which means that test code cannot
60  * invalidate a cache.  {@link #disableForTestMode()} and {@link #testPropertyName} must be used in
61  * test processes that attempt cache invalidation.  See
62  * {@link PropertyInvalidatedCacheTest#testBasicCache()} for an example.
63  *
64  * </ul>
65  *
66  * The intended use case is caching frequently-read, seldom-changed information normally retrieved
67  * across interprocess communication. Imagine that you've written a user birthday information
68  * daemon called "birthdayd" that exposes an {@code IUserBirthdayService} interface over
69  * binder. That binder interface looks something like this:
70  *
71  * <pre>
72  * parcelable Birthday {
73  *   int month;
74  *   int day;
75  * }
76  * interface IUserBirthdayService {
77  *   Birthday getUserBirthday(int userId);
78  * }
79  * </pre>
80  *
81  * Suppose the service implementation itself looks like this...
82  *
83  * <pre>
84  * public class UserBirthdayServiceImpl implements IUserBirthdayService {
85  *   private final HashMap&lt;Integer, Birthday%&gt; mUidToBirthday;
86  *   {@literal @}Override
87  *   public synchronized Birthday getUserBirthday(int userId) {
88  *     return mUidToBirthday.get(userId);
89  *   }
90  *   private synchronized void updateBirthdays(Map&lt;Integer, Birthday%&gt; uidToBirthday) {
91  *     mUidToBirthday.clear();
92  *     mUidToBirthday.putAll(uidToBirthday);
93  *   }
94  * }
95  * </pre>
96  *
97  * ... and we have a client in frameworks (loaded into every app process) that looks like this:
98  *
99  * <pre>
100  * public class ActivityThread {
101  *   ...
102  *   public Birthday getUserBirthday(int userId) {
103  *     return GetService("birthdayd").getUserBirthday(userId);
104  *   }
105  *   ...
106  * }
107  * </pre>
108  *
109  * With this code, every time an app calls {@code getUserBirthday(uid)}, we make a binder call to
110  * the birthdayd process and consult its database of birthdays. If we query user birthdays
111  * frequently, we do a lot of work that we don't have to do, since user birthdays change
112  * infrequently.
113  *
114  * IpcDataCache is part of a pattern for optimizing this kind of information-querying code. Using
115  * {@code IpcDataCache}, you'd write the client this way:
116  *
117  * <pre>
118  * public class ActivityThread {
119  *   ...
120  *   private final IpcDataCache.QueryHandler&lt;Integer, Birthday&gt; mBirthdayQuery =
121  *       new IpcDataCache.QueryHandler&lt;Integer, Birthday&gt;() {
122  *           {@literal @}Override
123  *           public Birthday apply(Integer) {
124  *              return GetService("birthdayd").getUserBirthday(userId);
125  *           }
126  *       };
127  *   private static final int BDAY_CACHE_MAX = 8;  // Maximum birthdays to cache
128  *   private static final String BDAY_API = "getUserBirthday";
129  *   private final IpcDataCache&lt;Integer, Birthday%&gt; mBirthdayCache = new
130  *     IpcDataCache&lt;Integer, Birthday%&gt;(
131  *             BDAY_CACHE_MAX, MODULE_SYSTEM, BDAY_API,  BDAY_API, mBirthdayQuery);
132  *
133  *   public void disableUserBirthdayCache() {
134  *     mBirthdayCache.disableForCurrentProcess();
135  *   }
136  *   public void invalidateUserBirthdayCache() {
137  *     mBirthdayCache.invalidateCache();
138  *   }
139  *   public Birthday getUserBirthday(int userId) {
140  *     return mBirthdayCache.query(userId);
141  *   }
142  *   ...
143  * }
144  * </pre>
145  *
146  * With this cache, clients perform a binder call to birthdayd if asking for a user's birthday
147  * for the first time; on subsequent queries, we return the already-known Birthday object.
148  *
149  * The second parameter to the IpcDataCache constructor is a string that identifies the "module"
150  * that owns the cache. There are some well-known modules (such as {@code MODULE_SYSTEM} but any
151  * string is permitted.  The third parameters is the name of the API being cached; this, too, can
152  * any value.  The fourth is the name of the cache.  The cache is usually named after th API.
153  * Some things you must know about the three strings:
154  * <ul>
155  * <li> The system property that controls the cache is named {@code cache_key.<module>.<api>}.
156  * Usually, the SELinux rules permit a process to write a system property (and therefore
157  * invalidate a cache) based on the wildcard {@code cache_key.<module>.*}.  This means that
158  * although the cache can be constructed with any module string, whatever string is chosen must be
159  * consistent with the SELinux configuration.
160  * <li> The API name can be any string of alphanumeric characters.  All caches with the same API
161  * are invalidated at the same time.  If a server supports several caches and all are invalidated
162  * in common, then it is most efficient to assign the same API string to every cache.
163  * <li> The cache name can be any string.  In debug output, the name is used to distiguish between
164  * caches with the same API name.  The cache name is also used when disabling caches in the
165  * current process.  So, invalidation is based on the module+api but disabling (which is generally
166  * a once-per-process operation) is based on the cache name.
167  * </ul>
168  *
169  * User birthdays do occasionally change, so we have to modify the server to invalidate this
170  * cache when necessary. That invalidation code looks like this:
171  *
172  * <pre>
173  * public class UserBirthdayServiceImpl {
174  *   ...
175  *   public UserBirthdayServiceImpl() {
176  *     ...
177  *     ActivityThread.currentActivityThread().disableUserBirthdayCache();
178  *     ActivityThread.currentActivityThread().invalidateUserBirthdayCache();
179  *   }
180  *
181  *   private synchronized void updateBirthdays(Map&lt;Integer, Birthday%&gt; uidToBirthday) {
182  *     mUidToBirthday.clear();
183  *     mUidToBirthday.putAll(uidToBirthday);
184  *     ActivityThread.currentActivityThread().invalidateUserBirthdayCache();
185  *   }
186  *   ...
187  * }
188  * </pre>
189  *
190  * The call to {@code IpcDataCache.invalidateCache()} guarantees that all clients will re-fetch
191  * birthdays from binder during consequent calls to
192  * {@code ActivityThread.getUserBirthday()}. Because the invalidate call happens with the lock
193  * held, we maintain consistency between different client views of the birthday state. The use of
194  * IpcDataCache in this idiomatic way introduces no new race conditions.
195  *
196  * IpcDataCache has a few other features for doing things like incremental enhancement of cached
197  * values and invalidation of multiple caches (that all share the same property key) at once.
198  *
199  * {@code BDAY_CACHE_KEY} is the name of a property that we set to an opaque unique value each
200  * time we update the cache. SELinux configuration must allow everyone to read this property
201  * and it must allow any process that needs to invalidate the cache (here, birthdayd) to write
202  * the property. (These properties conventionally begin with the "cache_key." prefix.)
203  *
204  * The {@code UserBirthdayServiceImpl} constructor calls {@code disableUserBirthdayCache()} so
205  * that calls to {@code getUserBirthday} from inside birthdayd don't go through the cache. In this
206  * local case, there's no IPC, so use of the cache is (depending on exact circumstance)
207  * unnecessary.
208  *
209  * There may be queries for which it is more efficient to bypass the cache than to cache the
210  * result.  This would be true, for example, if some queries would require frequent cache
211  * invalidation while other queries require infrequent invalidation.  To expand on the birthday
212  * example, suppose that there is a userId that signifies "the next birthday".  When passed this
213  * userId, the server returns the next birthday among all users - this value changes as time
214  * advances.  The userId value can be cached, but the cache must be invalidated whenever a
215  * birthday occurs, and this invalidates all birthdays.  If there is a large number of users,
216  * invalidation will happen so often that the cache provides no value.
217  *
218  * The class provides a bypass mechanism to handle this situation.
219  * <pre>
220  * public class ActivityThread {
221  *   ...
222  *   private final IpcDataCache.QueryHandler&lt;Integer, Birthday&gt; mBirthdayQuery =
223  *       new IpcDataCache.QueryHandler&lt;Integer, Birthday&gt;() {
224  *           {@literal @}Override
225  *           public Birthday apply(Integer) {
226  *              return GetService("birthdayd").getUserBirthday(userId);
227  *           }
228  *           {@literal @}Override
229  *           public boolean shouldBypassQuery(Integer userId) {
230  *               return userId == NEXT_BIRTHDAY;
231  *           }
232  *       };
233  *   ...
234  * }
235  * </pre>
236  *
237  * If the {@code shouldBypassQuery()} method returns true then the cache is not used for that
238  * particular query.  The {@code shouldBypassQuery()} method is not abstract and the default
239  * implementation returns false.
240  *
241  * For security, there is a allowlist of processes that are allowed to invalidate a cache.  The
242  * allowlist includes normal runtime processes but does not include test processes.  Test
243  * processes must call {@code IpcDataCache.disableForTestMode()} to disable all cache activity in
244  * that process.
245  *
246  * Caching can be disabled completely by initializing {@code sEnabled} to false and rebuilding.
247  *
248  * To test a binder cache, create one or more tests that exercise the binder method.  This should
249  * be done twice: once with production code and once with a special image that sets {@code DEBUG}
250  * and {@code VERIFY} true.  In the latter case, verify that no cache inconsistencies are
251  * reported.  If a cache inconsistency is reported, however, it might be a false positive.  This
252  * happens if the server side data can be read and written non-atomically with respect to cache
253  * invalidation.
254  *
255  * @param <Query> The class used to index cache entries: must be hashable and comparable
256  * @param <Result> The class holding cache entries; use a boxed primitive if possible
257  * @hide
258  */
259 @TestApi
260 @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
261 @android.ravenwood.annotation.RavenwoodKeepWholeClass
262 public class IpcDataCache<Query, Result> extends PropertyInvalidatedCache<Query, Result> {
263     /**
264      * {@inheritDoc}
265      * @hide
266      */
267     @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
268     @TestApi
269     public static abstract class QueryHandler<Q,R>
270             extends PropertyInvalidatedCache.QueryHandler<Q,R> {
271         /**
272          * Compute a result given a query.  The semantics are those of Functor.
273          */
apply(@onNull Q query)274         public abstract @Nullable R apply(@NonNull Q query);
275 
276         /**
277          * Return true if a query should not use the cache.  The default implementation
278          * always uses the cache.
279          */
shouldBypassCache(@onNull Q query)280         public boolean shouldBypassCache(@NonNull Q query) {
281             return false;
282         }
283     };
284 
285     /**
286      * The list of cache namespaces.  Each namespace corresponds to an sepolicy domain.  A
287      * namespace is owned by a single process, although a single process can have more
288      * than one namespace (system_server, as an example).
289      * @hide
290      */
291     @StringDef(
292         prefix = { "MODULE_"
293         },
294         value = {
295             MODULE_TEST,
296             MODULE_SYSTEM,
297             MODULE_BLUETOOTH,
298             MODULE_TELEPHONY
299         }
300     )
301     @Retention(RetentionPolicy.SOURCE)
302     public @interface IpcDataCacheModule { }
303 
304     /**
305      * The module used for unit tests and cts tests.  It is expected that no process in
306      * the system has permissions to write properties with this module.
307      * @hide
308      */
309     @TestApi
310     public static final String MODULE_TEST = PropertyInvalidatedCache.MODULE_TEST;
311 
312     /**
313      * The module used for system server/framework caches.  This is not visible outside
314      * the system processes.
315      * @hide
316      */
317     @TestApi
318     public static final String MODULE_SYSTEM = PropertyInvalidatedCache.MODULE_SYSTEM;
319 
320     /**
321      * The module used for bluetooth caches.
322      * @hide
323      */
324     @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
325     @TestApi
326     public static final String MODULE_BLUETOOTH = PropertyInvalidatedCache.MODULE_BLUETOOTH;
327 
328     /**
329      * Make a new property invalidated cache.  The key is computed from the module and api
330      * parameters.
331      *
332      * @param maxEntries Maximum number of entries to cache; LRU discard
333      * @param module The module under which the cache key should be placed.
334      * @param api The api this cache front-ends.  The api must be a Java identifier but
335      * need not be an actual api.
336      * @param cacheName Name of this cache in debug and dumpsys
337      * @param computer The code to compute values that are not in the cache.
338      * @hide
339      */
340     @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
341     @TestApi
IpcDataCache(int maxEntries, @NonNull @IpcDataCacheModule String module, @NonNull String api, @NonNull String cacheName, @NonNull QueryHandler<Query, Result> computer)342     public IpcDataCache(int maxEntries, @NonNull @IpcDataCacheModule String module,
343             @NonNull String api, @NonNull String cacheName,
344             @NonNull QueryHandler<Query, Result> computer) {
345         super(new Args(module).maxEntries(maxEntries).api(api), cacheName, computer);
346     }
347 
348     /**
349      * {@inheritDoc}
350      * @hide
351      */
352     @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
353     @TestApi
354     @Override
disableForCurrentProcess()355     public void disableForCurrentProcess() {
356         super.disableForCurrentProcess();
357     }
358 
359     /**
360      * {@inheritDoc}
361      * @hide
362      */
363     @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
364     @TestApi
disableForCurrentProcess(@onNull String cacheName)365     public static void disableForCurrentProcess(@NonNull String cacheName) {
366         PropertyInvalidatedCache.disableForCurrentProcess(cacheName);
367     }
368 
369     /**
370      * {@inheritDoc}
371      * @hide
372      */
373     @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
374     @TestApi
375     @Override
query(@onNull Query query)376     public @Nullable Result query(@NonNull Query query) {
377         return super.query(query);
378     }
379 
380     /**
381      * {@inheritDoc}
382      * @hide
383      */
384     @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
385     @TestApi
386     @Override
invalidateCache()387     public void invalidateCache() {
388         super.invalidateCache();
389     }
390 
391     /**
392      * Invalidate caches in all processes that are keyed for the module and api.
393      * @hide
394      */
395     @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
396     @TestApi
invalidateCache(@onNull @pcDataCacheModule String module, @NonNull String api)397     public static void invalidateCache(@NonNull @IpcDataCacheModule String module,
398             @NonNull String api) {
399         PropertyInvalidatedCache.invalidateCache(module, api);
400     }
401 
402     /**
403      * This is a convenience class that encapsulates configuration information for a cache.  It
404      * may be supplied to the cache constructors in lieu of the other parameters.  The class
405      * captures maximum entry count, the module, the key, and the api.  The key is used to
406      * invalidate the cache and may be shared by different caches.  The api is a user-visible (in
407      * debug) name for the cache.
408      *
409      * There are three specific use cases supported by this class.
410      *
411      * 1. Instance-per-cache: create a static instance of this class using the same
412      *    parameters as would have been given to IpcDataCache (or
413      *    PropertyInvalidatedCache).  This static instance provides a hook for the
414      *    invalidateCache() and disableForLocalProcess() calls, which, generally, must
415      *    also be static.
416      *
417      * 2. Short-hand for shared configuration parameters: create an instance of this class
418      *    to capture the maximum number of entries and the module to be used by more than
419      *    one cache in the class.  Refer to this instance when creating new configs.  Only
420      *    the api and (optionally key) for the new cache must be supplied.
421      *
422      * 3. Tied caches: create a static instance of this class to capture the maximum
423      *    number of entries, the module, and the key.  Refer to this instance when
424      *    creating a new config that differs in only the api.  The new config can be
425      *    created as part of the cache constructor.  All caches that trace back to the
426      *    root config share the same key and are invalidated by the invalidateCache()
427      *    method of the root config.  All caches that trace back to the root config can be
428      *    disabled in the local process by the disableAllForCurrentProcess() method of the
429      *    root config.
430      *
431      * @hide
432      */
433     public static class Config {
434         final Args mArgs;
435         final String mName;
436 
437         /**
438          * The list of cache names that were created extending this Config.  If
439          * disableForCurrentProcess() is invoked on this config then all children will be
440          * disabled.  Furthermore, any new children based off of this config will be
441          * disabled.  The construction order guarantees that new caches will be disabled
442          * before they are created (the Config must be created before the IpcDataCache is
443          * created).
444          */
445         private ArraySet<String> mChildren;
446 
447         /**
448          * True if registered children are disabled in the current process.  If this is
449          * true then all new children are disabled as they are registered.
450          */
451         private boolean mDisabled = false;
452 
453         /**
454          * Fully construct a config.
455          */
Config(@onNull Args args, @NonNull String name)456         private Config(@NonNull Args args, @NonNull String name) {
457             mArgs = args;
458             mName = name;
459         }
460 
461         /**
462          *
463          */
Config(int maxEntries, @NonNull @IpcDataCacheModule String module, @NonNull String api, @NonNull String name)464         public Config(int maxEntries, @NonNull @IpcDataCacheModule String module,
465                 @NonNull String api, @NonNull String name) {
466             this(new Args(module).api(api).maxEntries(maxEntries), name);
467         }
468 
469         /**
470          * A short-hand constructor that makes the name the same as the api.
471          */
Config(int maxEntries, @NonNull @IpcDataCacheModule String module, @NonNull String api)472         public Config(int maxEntries, @NonNull @IpcDataCacheModule String module,
473                 @NonNull String api) {
474             this(maxEntries, module, api, api);
475         }
476 
477         /**
478          * Copy the module and max entries from the Config and take the api and name from
479          * the parameter list.
480          */
Config(@onNull Config root, @NonNull String api, @NonNull String name)481         public Config(@NonNull Config root, @NonNull String api, @NonNull String name) {
482             this(root.mArgs.api(api), name);
483         }
484 
485         /**
486          * Copy the module and max entries from the Config and take the api and name from
487          * the parameter list.
488          */
Config(@onNull Config root, @NonNull String api)489         public Config(@NonNull Config root, @NonNull String api) {
490             this(root.mArgs.api(api), api);
491         }
492 
493         /**
494          * Fetch a config that is a child of <this>.  The child shares the same api as the
495          * parent and is registered with the parent for the purposes of disabling in the
496          * current process.
497          */
child(@onNull String name)498         public Config child(@NonNull String name) {
499             final Config result = new Config(mArgs, name);
500             registerChild(name);
501             return result;
502         }
503 
504         /**
505          * Set the cacheNull behavior.
506          */
cacheNulls(boolean enable)507         public Config cacheNulls(boolean enable) {
508             return new Config(mArgs.cacheNulls(enable), mName);
509         }
510 
511         /**
512          * Set the isolateUidss behavior.
513          */
isolateUids(boolean enable)514         public Config isolateUids(boolean enable) {
515             return new Config(mArgs.isolateUids(enable), mName);
516         }
517 
518         /**
519          * Register a child cache name.  If disableForCurrentProcess() has been called
520          * against this cache, disable th new child.
521          */
registerChild(String name)522         private final void registerChild(String name) {
523             synchronized (this) {
524                 if (mChildren == null) {
525                     mChildren = new ArraySet<>();
526                 }
527                 mChildren.add(name);
528                 if (mDisabled) {
529                     IpcDataCache.disableForCurrentProcess(name);
530                 }
531             }
532         }
533 
534         /**
535          * Invalidate all caches that share this Config's module and api.
536          */
invalidateCache()537         public void invalidateCache() {
538             IpcDataCache.invalidateCache(mArgs);
539         }
540 
541         /**
542          * Disable all caches that share this Config's name.
543          */
disableForCurrentProcess()544         public void disableForCurrentProcess() {
545             IpcDataCache.disableForCurrentProcess(mName);
546         }
547 
548         /**
549          * Disable this cache and all children.  Any child that is added in the future
550          * will alwo be disabled.
551          */
disableAllForCurrentProcess()552         public void disableAllForCurrentProcess() {
553             synchronized (this) {
554                 mDisabled = true;
555                 disableForCurrentProcess();
556                 if (mChildren != null) {
557                     for (String c : mChildren) {
558                         IpcDataCache.disableForCurrentProcess(c);
559                     }
560                 }
561             }
562         }
563     }
564 
565     /**
566      * Create a new cache using a config.
567      * @hide
568      */
IpcDataCache(@onNull Config config, @NonNull QueryHandler<Query, Result> computer)569     public IpcDataCache(@NonNull Config config, @NonNull QueryHandler<Query, Result> computer) {
570         super(config.mArgs, config.mName, computer);
571     }
572 
573     /**
574      * An interface suitable for a lambda expression instead of a QueryHandler applying remote call.
575      * @hide
576      */
577     public interface RemoteCall<Query, Result> {
apply(Query query)578         Result apply(Query query) throws RemoteException;
579     }
580 
581     /**
582      * An interface suitable for a lambda expression instead of a QueryHandler bypassing the cache.
583      * @hide
584      */
585     public interface BypassCall<Query> {
apply(Query query)586         Boolean apply(Query query);
587     }
588 
589     /**
590      * This is a query handler that is created with a lambda expression that is invoked
591      * every time the handler is called.  The handler is specifically meant for services
592      * hosted by system_server; the handler automatically rethrows RemoteException as a
593      * RuntimeException, which is the usual handling for failed binder calls.
594      */
595     private static class SystemServerCallHandler<Query, Result>
596             extends IpcDataCache.QueryHandler<Query, Result> {
597         private final RemoteCall<Query, Result> mHandler;
SystemServerCallHandler(RemoteCall handler)598         public SystemServerCallHandler(RemoteCall handler) {
599             mHandler = handler;
600         }
601         @Override
apply(Query query)602         public Result apply(Query query) {
603             try {
604                 return mHandler.apply(query);
605             } catch (RemoteException e) {
606                 throw e.rethrowFromSystemServer();
607             }
608         }
609     }
610 
611 
612     /**
613      * Create a cache using a config and a lambda expression.
614      * @param config The configuration for the cache.
615      * @param remoteCall The lambda expression that will be invoked to fetch the data.
616      * @hide
617      */
IpcDataCache(@onNull Config config, @NonNull RemoteCall<Query, Result> remoteCall)618     public IpcDataCache(@NonNull Config config, @NonNull RemoteCall<Query, Result> remoteCall) {
619       this(config, android.multiuser.Flags.cachingDevelopmentImprovements() ?
620         new QueryHandler<Query, Result>() {
621             @Override
622             public Result apply(Query query) {
623                 try {
624                     return remoteCall.apply(query);
625                 } catch (RemoteException e) {
626                     throw e.rethrowFromSystemServer();
627                 }
628             }
629         } : new SystemServerCallHandler<>(remoteCall));
630     }
631 
632 
633     /**
634      * Create a cache using a config and a lambda expression.
635      * @param config The configuration for the cache.
636      * @param remoteCall The lambda expression that will be invoked to fetch the data.
637      * @param bypass The lambda expression that will be invoked to determine if the cache should be
638      *     bypassed.
639      * @hide
640      */
641     @FlaggedApi(android.multiuser.Flags.FLAG_CACHING_DEVELOPMENT_IMPROVEMENTS)
IpcDataCache(@onNull Config config, @NonNull RemoteCall<Query, Result> remoteCall, @NonNull BypassCall<Query> bypass)642     public IpcDataCache(@NonNull Config config,
643             @NonNull RemoteCall<Query, Result> remoteCall,
644             @NonNull BypassCall<Query> bypass) {
645         this(config, new QueryHandler<Query, Result>() {
646             @Override
647             public Result apply(Query query) {
648                 try {
649                     return remoteCall.apply(query);
650                 } catch (RemoteException e) {
651                     throw e.rethrowFromSystemServer();
652                 }
653             }
654 
655             @Override
656             public boolean shouldBypassCache(Query query) {
657                 return bypass.apply(query);
658             }
659         });
660     }
661 
662     /**
663      * The following APIs are exposed to support testing.  They only forward the superclass but
664      * that means the superclass does not have to expose the APIs itself.
665      */
666 
667     /**
668      * Stop disabling local caches with the same name as <this>.  Any caches that are currently
669      * disabled remain disabled (the "disabled" setting is sticky).  However, new caches with this
670      * name will not be disabled.  It is not an error if the cache name is not found in the list
671      * of disabled caches.
672      * @hide
673      */
674     @TestApi
675     @Override
forgetDisableLocal()676     public final void forgetDisableLocal() {
677         super.forgetDisableLocal();
678     }
679 
680     /**
681      * Return whether a cache instance is disabled.
682      * @hide
683      */
684     @TestApi
685     @Override
isDisabled()686     public final boolean isDisabled() {
687         return super.isDisabled();
688     }
689 
690     /**
691      * This is an obsolete synonym for {@link #isDisabled()}.
692      * @hide
693      */
694     @TestApi
getDisabledState()695     public boolean getDisabledState() {
696         return isDisabled();
697     }
698 
699     /**
700      * Disable the use of this cache in this process.  This method is used internally and during
701      * testing.  To disable a cache in normal code, use disableProcessLocal().
702      * @hide
703      */
704     @TestApi
705     @Override
disableInstance()706     public final void disableInstance() {
707         super.disableInstance();
708     }
709 
710     /**
711      * Disable all caches that use the property as the current cache.
712      * @hide
713      */
714     @TestApi
715     @Override
disableSystemWide()716     public final void disableSystemWide() {
717         super.disableSystemWide();
718     }
719 
720     /**
721      * Enable or disable test mode.  The protocol requires that the mode toggle: for instance, it is
722      * illegal to clear the test mode if the test mode is already off.  Enabling test mode puts
723      * all caches in the process into test mode; all nonces are initialized to UNSET and
724      * subsequent reads and writes are to process memory.  This has the effect of disabling all
725      * caches that are not local to the process.  Disabling test mode restores caches to normal
726      * operation.
727      * @param mode The desired test mode.
728      * @throws IllegalStateException if the supplied mode is already set.
729      * @throws IllegalStateException if the process is not running an instrumentation test.
730      * @hide
731      */
732     @TestApi
setTestMode(boolean mode)733     public static void setTestMode(boolean mode) {
734         PropertyInvalidatedCache.setTestMode(mode);
735     }
736 
737     /**
738      * Enable or disable test mode.  The protocol requires that the mode toggle: for instance, it is
739      * illegal to clear the test mode if the test mode is already off.  Enabling test mode puts
740      * all caches in the process into test mode; all nonces are initialized to UNSET and
741      * subsequent reads and writes are to process memory.  This has the effect of disabling all
742      * caches that are not local to the process.  Disabling test mode restores caches to normal
743      * operation.
744      * @param mode The desired test mode.
745      * @throws IllegalStateException if the supplied mode is already set.
746      * @throws IllegalStateException if the process is not running an instrumentation test.
747      * @hide
748      */
749     @FlaggedApi(android.os.Flags.FLAG_IPC_DATA_CACHE_TEST_APIS)
750     @SystemApi(client=SystemApi.Client.MODULE_LIBRARIES)
setCacheTestMode(boolean mode)751     public static void setCacheTestMode(boolean mode) {
752         // Trunk-stable flagging requires that this API have a name different from the existing
753         // setTestMode() API.  However, the functionality is identical.
754         setTestMode(mode);
755     }
756 }
757