Merge "Update IpcDataCache documentation" into main
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 0e761fc..c17da24 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -54,198 +54,8 @@
* LRU cache that's invalidated when an opaque value in a property changes. Self-synchronizing,
* but doesn't hold a lock across data fetches on query misses.
*
- * The intended use case is caching frequently-read, seldom-changed information normally
- * retrieved across interprocess communication. Imagine that you've written a user birthday
- * information daemon called "birthdayd" that exposes an {@code IUserBirthdayService} interface
- * over binder. That binder interface looks something like this:
- *
- * <pre>
- * parcelable Birthday {
- * int month;
- * int day;
- * }
- * interface IUserBirthdayService {
- * Birthday getUserBirthday(int userId);
- * }
- * </pre>
- *
- * Suppose the service implementation itself looks like this...
- *
- * <pre>
- * public class UserBirthdayServiceImpl implements IUserBirthdayService {
- * private final HashMap<Integer, Birthday%> mUidToBirthday;
- * {@literal @}Override
- * public synchronized Birthday getUserBirthday(int userId) {
- * return mUidToBirthday.get(userId);
- * }
- * private synchronized void updateBirthdays(Map<Integer, Birthday%> uidToBirthday) {
- * mUidToBirthday.clear();
- * mUidToBirthday.putAll(uidToBirthday);
- * }
- * }
- * </pre>
- *
- * ... and we have a client in frameworks (loaded into every app process) that looks
- * like this:
- *
- * <pre>
- * public class ActivityThread {
- * ...
- * public Birthday getUserBirthday(int userId) {
- * return GetService("birthdayd").getUserBirthday(userId);
- * }
- * ...
- * }
- * </pre>
- *
- * With this code, every time an app calls {@code getUserBirthday(uid)}, we make a binder call
- * to the birthdayd process and consult its database of birthdays. If we query user birthdays
- * frequently, we do a lot of work that we don't have to do, since user birthdays
- * change infrequently.
- *
- * PropertyInvalidatedCache is part of a pattern for optimizing this kind of
- * information-querying code. Using {@code PropertyInvalidatedCache}, you'd write the client
- * this way:
- *
- * <pre>
- * public class ActivityThread {
- * ...
- * private final PropertyInvalidatedCache.QueryHandler<Integer, Birthday> mBirthdayQuery =
- * new PropertyInvalidatedCache.QueryHandler<Integer, Birthday>() {
- * {@literal @}Override
- * public Birthday apply(Integer) {
- * return GetService("birthdayd").getUserBirthday(userId);
- * }
- * };
- * private static final int BDAY_CACHE_MAX = 8; // Maximum birthdays to cache
- * private static final String BDAY_CACHE_KEY = "cache_key.birthdayd";
- * private final PropertyInvalidatedCache<Integer, Birthday%> mBirthdayCache = new
- * PropertyInvalidatedCache<Integer, Birthday%>(
- * BDAY_CACHE_MAX, MODULE_SYSTEM, "getUserBirthday", mBirthdayQuery);
- *
- * public void disableUserBirthdayCache() {
- * mBirthdayCache.disableForCurrentProcess();
- * }
- * public void invalidateUserBirthdayCache() {
- * mBirthdayCache.invalidateCache();
- * }
- * public Birthday getUserBirthday(int userId) {
- * return mBirthdayCache.query(userId);
- * }
- * ...
- * }
- * </pre>
- *
- * With this cache, clients perform a binder call to birthdayd if asking for a user's birthday
- * for the first time; on subsequent queries, we return the already-known Birthday object.
- *
- * The second parameter to the IpcDataCache constructor is a string that identifies the "module"
- * that owns the cache. There are some well-known modules (such as {@code MODULE_SYSTEM} but any
- * string is permitted. The third parameters is the name of the API being cached; this, too, can
- * any value. The fourth is the name of the cache. The cache is usually named after th API.
- * Some things you must know about the three strings:
- * <list>
- * <ul> The system property that controls the cache is named {@code cache_key.<module>.<api>}.
- * Usually, the SELinux rules permit a process to write a system property (and therefore
- * invalidate a cache) based on the wildcard {@code cache_key.<module>.*}. This means that
- * although the cache can be constructed with any module string, whatever string is chosen must be
- * consistent with the SELinux configuration.
- * <ul> The API name can be any string of alphanumeric characters. All caches with the same API
- * are invalidated at the same time. If a server supports several caches and all are invalidated
- * in common, then it is most efficient to assign the same API string to every cache.
- * <ul> The cache name can be any string. In debug output, the name is used to distiguish between
- * caches with the same API name. The cache name is also used when disabling caches in the
- * current process. So, invalidation is based on the module+api but disabling (which is generally
- * a once-per-process operation) is based on the cache name.
- * </list>
- *
- * User birthdays do occasionally change, so we have to modify the server to invalidate this
- * cache when necessary. That invalidation code looks like this:
- *
- * <pre>
- * public class UserBirthdayServiceImpl {
- * ...
- * public UserBirthdayServiceImpl() {
- * ...
- * ActivityThread.currentActivityThread().disableUserBirthdayCache();
- * ActivityThread.currentActivityThread().invalidateUserBirthdayCache();
- * }
- *
- * private synchronized void updateBirthdays(Map<Integer, Birthday%> uidToBirthday) {
- * mUidToBirthday.clear();
- * mUidToBirthday.putAll(uidToBirthday);
- * ActivityThread.currentActivityThread().invalidateUserBirthdayCache();
- * }
- * ...
- * }
- * </pre>
- *
- * The call to {@code PropertyInvalidatedCache.invalidateCache()} guarantees that all clients
- * will re-fetch birthdays from binder during consequent calls to
- * {@code ActivityThread.getUserBirthday()}. Because the invalidate call happens with the lock
- * held, we maintain consistency between different client views of the birthday state. The use
- * of PropertyInvalidatedCache in this idiomatic way introduces no new race conditions.
- *
- * PropertyInvalidatedCache has a few other features for doing things like incremental
- * enhancement of cached values and invalidation of multiple caches (that all share the same
- * property key) at once.
- *
- * {@code BDAY_CACHE_KEY} is the name of a property that we set to an opaque unique value each
- * time we update the cache. SELinux configuration must allow everyone to read this property
- * and it must allow any process that needs to invalidate the cache (here, birthdayd) to write
- * the property. (These properties conventionally begin with the "cache_key." prefix.)
- *
- * The {@code UserBirthdayServiceImpl} constructor calls {@code disableUserBirthdayCache()} so
- * that calls to {@code getUserBirthday} from inside birthdayd don't go through the cache. In
- * this local case, there's no IPC, so use of the cache is (depending on exact
- * circumstance) unnecessary.
- *
- * There may be queries for which it is more efficient to bypass the cache than to cache
- * the result. This would be true, for example, if some queries would require frequent
- * cache invalidation while other queries require infrequent invalidation. To expand on
- * the birthday example, suppose that there is a userId that signifies "the next
- * birthday". When passed this userId, the server returns the next birthday among all
- * users - this value changes as time advances. The userId value can be cached, but the
- * cache must be invalidated whenever a birthday occurs, and this invalidates all
- * birthdays. If there is a large number of users, invalidation will happen so often that
- * the cache provides no value.
- *
- * The class provides a bypass mechanism to handle this situation.
- * <pre>
- * public class ActivityThread {
- * ...
- * private final IpcDataCache.QueryHandler<Integer, Birthday> mBirthdayQuery =
- * new IpcDataCache.QueryHandler<Integer, Birthday>() {
- * {@literal @}Override
- * public Birthday apply(Integer) {
- * return GetService("birthdayd").getUserBirthday(userId);
- * }
- * {@literal @}Override
- * public boolean shouldBypassQuery(Integer userId) {
- * return userId == NEXT_BIRTHDAY;
- * }
- * };
- * ...
- * }
- * </pre>
- *
- * If the {@code shouldBypassQuery()} method returns true then the cache is not used for that
- * particular query. The {@code shouldBypassQuery()} method is not abstract and the default
- * implementation returns false.
- *
- * For security, there is a allowlist of processes that are allowed to invalidate a cache.
- * The allowlist includes normal runtime processes but does not include test processes.
- * Test processes must call {@code PropertyInvalidatedCache.disableForTestMode()} to disable
- * all cache activity in that process.
- *
- * Caching can be disabled completely by initializing {@code sEnabled} to false and rebuilding.
- *
- * To test a binder cache, create one or more tests that exercise the binder method. This
- * should be done twice: once with production code and once with a special image that sets
- * {@code DEBUG} and {@code VERIFY} true. In the latter case, verify that no cache
- * inconsistencies are reported. If a cache inconsistency is reported, however, it might be a
- * false positive. This happens if the server side data can be read and written non-atomically
- * with respect to cache invalidation.
+ * This interface is deprecated. New clients should use {@link IpcDataCache} instead. Internally,
+ * that class uses {@link PropertyInvalidatedCache} , but that design may change in the future.
*
* @param <Query> The class used to index cache entries: must be hashable and comparable
* @param <Result> The class holding cache entries; use a boxed primitive if possible
diff --git a/core/java/android/os/IpcDataCache.java b/core/java/android/os/IpcDataCache.java
index 0776cf4..e2a72dd 100644
--- a/core/java/android/os/IpcDataCache.java
+++ b/core/java/android/os/IpcDataCache.java
@@ -48,6 +48,20 @@
* LRU cache that's invalidated when an opaque value in a property changes. Self-synchronizing,
* but doesn't hold a lock across data fetches on query misses.
*
+ * Clients should be aware of the following commonly-seen issues:
+ * <ul>
+ *
+ * <li>Client calls will not go through the cache before the first invalidation signal is
+ * received. Therefore, servers should signal an invalidation as soon as they have data to offer to
+ * clients.
+ *
+ * <li>Cache invalidation is restricted to well-known processes, which means that test code cannot
+ * invalidate a cache. {@link #disableForTestMode()} and {@link #testPropertyName} must be used in
+ * test processes that attempt cache invalidation. See
+ * {@link PropertyInvalidatedCacheTest#testBasicCache()} for an example.
+ *
+ * </ul>
+ *
* The intended use case is caching frequently-read, seldom-changed information normally retrieved
* across interprocess communication. Imagine that you've written a user birthday information
* daemon called "birthdayd" that exposes an {@code IUserBirthdayService} interface over
@@ -136,20 +150,20 @@
* string is permitted. The third parameters is the name of the API being cached; this, too, can
* any value. The fourth is the name of the cache. The cache is usually named after th API.
* Some things you must know about the three strings:
- * <list>
- * <ul> The system property that controls the cache is named {@code cache_key.<module>.<api>}.
+ * <ul>
+ * <li> The system property that controls the cache is named {@code cache_key.<module>.<api>}.
* Usually, the SELinux rules permit a process to write a system property (and therefore
* invalidate a cache) based on the wildcard {@code cache_key.<module>.*}. This means that
* although the cache can be constructed with any module string, whatever string is chosen must be
* consistent with the SELinux configuration.
- * <ul> The API name can be any string of alphanumeric characters. All caches with the same API
+ * <li> The API name can be any string of alphanumeric characters. All caches with the same API
* are invalidated at the same time. If a server supports several caches and all are invalidated
* in common, then it is most efficient to assign the same API string to every cache.
- * <ul> The cache name can be any string. In debug output, the name is used to distiguish between
+ * <li> The cache name can be any string. In debug output, the name is used to distiguish between
* caches with the same API name. The cache name is also used when disabling caches in the
* current process. So, invalidation is based on the module+api but disabling (which is generally
* a once-per-process operation) is based on the cache name.
- * </list>
+ * </ul>
*
* User birthdays do occasionally change, so we have to modify the server to invalidate this
* cache when necessary. That invalidation code looks like this: