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