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