Loading core/java/android/app/PropertyInvalidatedCache.java +15 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,17 @@ import java.util.concurrent.atomic.AtomicLong; @TestApi @android.ravenwood.annotation.RavenwoodKeepWholeClass public class PropertyInvalidatedCache<Query, Result> { /** * A method to report if the PermissionManager notifications can be separated from cache * invalidation. The feature relies on a series of flags; the dependency is captured in this * method. * @hide */ public static boolean separatePermissionNotificationsEnabled() { return isSharedMemoryAvailable() && Flags.picSeparatePermissionNotifications(); } /** * This is a configuration class that customizes a cache instance. * @hide Loading Loading @@ -1921,6 +1932,10 @@ public class PropertyInvalidatedCache<Query, Result> { } public AutoCorker(@NonNull String propertyName, int autoCorkDelayMs) { if (separatePermissionNotificationsEnabled()) { throw new IllegalStateException("AutoCorking is unavailable"); } mPropertyName = propertyName; mAutoCorkDelayMs = autoCorkDelayMs; // We can't initialize mHandler here: when we're created, the main loop might not Loading core/java/android/app/performance.aconfig +8 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,14 @@ flag { bug: "373752556" } flag { namespace: "system_performance" name: "pic_separate_permission_notifications" is_fixed_read_only: true description: "Seperate PermissionManager notifications from cache udpates" bug: "373752556" } flag { namespace: "system_performance" name: "pic_cache_nulls" Loading core/java/android/content/pm/PackageManager.java +29 −18 Original line number Diff line number Diff line Loading @@ -11651,7 +11651,7 @@ public abstract class PackageManager { private static final PropertyInvalidatedCache<ApplicationInfoQuery, ApplicationInfo> sApplicationInfoCache = new PropertyInvalidatedCache<ApplicationInfoQuery, ApplicationInfo>( 2048, PermissionManager.CACHE_KEY_PACKAGE_INFO, 2048, PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE, "getApplicationInfo") { @Override public ApplicationInfo recompute(ApplicationInfoQuery query) { Loading Loading @@ -11682,18 +11682,6 @@ public abstract class PackageManager { sApplicationInfoCache.disableLocal(); } private static final PropertyInvalidatedCache.AutoCorker sCacheAutoCorker = new PropertyInvalidatedCache.AutoCorker(PermissionManager.CACHE_KEY_PACKAGE_INFO); /** * Invalidate caches of package and permission information system-wide. * * @hide */ public static void invalidatePackageInfoCache() { sCacheAutoCorker.autoCork(); } // Some of the flags don't affect the query result, but let's be conservative and cache // each combination of flags separately. Loading Loading @@ -11752,7 +11740,7 @@ public abstract class PackageManager { private static final PropertyInvalidatedCache<PackageInfoQuery, PackageInfo> sPackageInfoCache = new PropertyInvalidatedCache<PackageInfoQuery, PackageInfo>( 2048, PermissionManager.CACHE_KEY_PACKAGE_INFO, 2048, PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE, "getPackageInfo") { @Override public PackageInfo recompute(PackageInfoQuery query) { Loading Loading @@ -11784,17 +11772,40 @@ public abstract class PackageManager { /** * Inhibit package info cache invalidations when correct. * * @hide */ * @hide */ public static void corkPackageInfoCache() { PropertyInvalidatedCache.corkInvalidations(PermissionManager.CACHE_KEY_PACKAGE_INFO); sPackageInfoCache.corkInvalidations(); } /** * Enable package info cache invalidations. * * @hide */ * @hide */ public static void uncorkPackageInfoCache() { PropertyInvalidatedCache.uncorkInvalidations(PermissionManager.CACHE_KEY_PACKAGE_INFO); sPackageInfoCache.uncorkInvalidations(); } // This auto-corker is obsolete once the separate permission notifications feature is // committed. private static final PropertyInvalidatedCache.AutoCorker sCacheAutoCorker = PropertyInvalidatedCache.separatePermissionNotificationsEnabled() ? null : new PropertyInvalidatedCache .AutoCorker(PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE); /** * Invalidate caches of package and permission information system-wide. * * @hide */ public static void invalidatePackageInfoCache() { if (PropertyInvalidatedCache.separatePermissionNotificationsEnabled()) { sPackageInfoCache.invalidateCache(); } else { sCacheAutoCorker.autoCork(); } } /** Loading core/java/android/permission/PermissionManager.java +35 −4 Original line number Diff line number Diff line Loading @@ -1795,14 +1795,45 @@ public final class PermissionManager { } } /** @hide */ public static final String CACHE_KEY_PACKAGE_INFO = // The legacy system property "package_info" had two purposes: to invalidate PIC caches and to // signal that package information, and therefore permissions, might have changed. // AudioSystem is the only client of the signaling behavior. The "separate permissions // notification" feature splits the two behaviors into two system property names. // // If the feature is disabled (legacy behavior) then the two system property names have the // same value. This means there is only one system property in use. // // If the feature is enabled, then the two system property names have different values, which // means there is a system property used by PIC and a system property used for signaling. The // legacy value is hard-coded in native code that relies on the signaling behavior, so the // system property name for signaling is the legacy property name, and the system property // name for PIC is new. private static String getPackageInfoCacheKey() { if (PropertyInvalidatedCache.separatePermissionNotificationsEnabled()) { return PropertyInvalidatedCache.createSystemCacheKey("package_info_cache"); } else { return CACHE_KEY_PACKAGE_INFO_NOTIFY; } } /** * The system property that is used to notify clients that package information, and therefore * permissions, may have changed. * @hide */ public static final String CACHE_KEY_PACKAGE_INFO_NOTIFY = PropertyInvalidatedCache.createSystemCacheKey("package_info"); /** * The system property that is used to invalidate PIC caches. * @hide */ public static final String CACHE_KEY_PACKAGE_INFO_CACHE = getPackageInfoCacheKey(); /** @hide */ private static final PropertyInvalidatedCache<PermissionQuery, Integer> sPermissionCache = new PropertyInvalidatedCache<PermissionQuery, Integer>( 2048, CACHE_KEY_PACKAGE_INFO, "checkPermission") { 2048, CACHE_KEY_PACKAGE_INFO_CACHE, "checkPermission") { @Override public Integer recompute(PermissionQuery query) { return checkPermissionUncached(query.permission, query.pid, query.uid, Loading Loading @@ -1920,7 +1951,7 @@ public final class PermissionManager { private static PropertyInvalidatedCache<PackageNamePermissionQuery, Integer> sPackageNamePermissionCache = new PropertyInvalidatedCache<PackageNamePermissionQuery, Integer>( 16, CACHE_KEY_PACKAGE_INFO, "checkPackageNamePermission") { 16, CACHE_KEY_PACKAGE_INFO_CACHE, "checkPackageNamePermission") { @Override public Integer recompute(PackageNamePermissionQuery query) { return checkPackageNamePermissionUncached( Loading services/core/java/com/android/server/audio/AudioService.java +112 −2 Original line number Diff line number Diff line Loading @@ -95,6 +95,7 @@ import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.app.IUidObserver; import android.app.NotificationManager; import android.app.PropertyInvalidatedCache; import android.app.UidObserver; import android.app.role.OnRoleHoldersChangedListener; import android.app.role.RoleManager; Loading Loading @@ -248,6 +249,7 @@ import android.widget.Toast; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; import com.android.internal.os.SomeArgs; import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; Loading Loading @@ -10941,14 +10943,122 @@ public class AudioService extends IAudioService.Stub } }; mSysPropListenerNativeHandle = mAudioSystem.listenForSystemPropertyChange( PermissionManager.CACHE_KEY_PACKAGE_INFO, PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, task); } else { mAudioSystem.listenForSystemPropertyChange( PermissionManager.CACHE_KEY_PACKAGE_INFO, PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, () -> mAudioServerLifecycleExecutor.execute( mPermissionProvider::onPermissionStateChanged)); } if (PropertyInvalidatedCache.separatePermissionNotificationsEnabled()) { new PackageInfoTransducer().start(); } } /** * A transducer that converts high-speed changes in the CACHE_KEY_PACKAGE_INFO_CACHE * PropertyInvalidatedCache into low-speed changes in the CACHE_KEY_PACKAGE_INFO_NOTIFY system * property. This operates on the popcorn principle: changes in the source are done when the * source has been quiet for the soak interval. * * TODO(b/381097912) This is a temporary measure to support migration away from sysprop * sniffing. It should be cleaned up. */ private static class PackageInfoTransducer extends Thread { // The run/stop signal. private final AtomicBoolean mRunning = new AtomicBoolean(false); // The source of change information. private final PropertyInvalidatedCache.NonceWatcher mWatcher; // The handler for scheduling delayed reactions to changes. private final Handler mHandler; // How long to soak changes: 50ms is the legacy choice. private final static long SOAK_TIME_MS = 50; // The ubiquitous lock. private final Object mLock = new Object(); // If positive, this is the soak expiration time. @GuardedBy("mLock") private long mSoakDeadlineMs = -1; // A source of unique long values. @GuardedBy("mLock") private long mToken = 0; PackageInfoTransducer() { mWatcher = PropertyInvalidatedCache .getNonceWatcher(PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE); mHandler = new Handler(BackgroundThread.getHandler().getLooper()) { @Override public void handleMessage(Message msg) { PackageInfoTransducer.this.handleMessage(msg); }}; } public void run() { mRunning.set(true); while (mRunning.get()) { try { final int changes = mWatcher.waitForChange(); if (changes == 0 || !mRunning.get()) { continue; } } catch (InterruptedException e) { // We don't know why the exception occurred but keep running until told to // stop. continue; } trigger(); } } @GuardedBy("mLock") private void updateLocked() { String n = Long.toString(mToken++); SystemProperties.set(PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, n); } private void trigger() { synchronized (mLock) { boolean alreadyQueued = mSoakDeadlineMs >= 0; final long nowMs = SystemClock.uptimeMillis(); mSoakDeadlineMs = nowMs + SOAK_TIME_MS; if (!alreadyQueued) { mHandler.sendEmptyMessageAtTime(0, mSoakDeadlineMs); updateLocked(); } } } private void handleMessage(Message msg) { synchronized (mLock) { if (mSoakDeadlineMs < 0) { return; // ??? } final long nowMs = SystemClock.uptimeMillis(); if (mSoakDeadlineMs > nowMs) { mSoakDeadlineMs = nowMs + SOAK_TIME_MS; mHandler.sendEmptyMessageAtTime(0, mSoakDeadlineMs); return; } mSoakDeadlineMs = -1; updateLocked(); } } /** * Cause the thread to exit. Running is set to false and the watcher is awakened. */ public void done() { mRunning.set(false); mWatcher.wakeUp(); } } //========================================================================================== Loading Loading
core/java/android/app/PropertyInvalidatedCache.java +15 −0 Original line number Diff line number Diff line Loading @@ -79,6 +79,17 @@ import java.util.concurrent.atomic.AtomicLong; @TestApi @android.ravenwood.annotation.RavenwoodKeepWholeClass public class PropertyInvalidatedCache<Query, Result> { /** * A method to report if the PermissionManager notifications can be separated from cache * invalidation. The feature relies on a series of flags; the dependency is captured in this * method. * @hide */ public static boolean separatePermissionNotificationsEnabled() { return isSharedMemoryAvailable() && Flags.picSeparatePermissionNotifications(); } /** * This is a configuration class that customizes a cache instance. * @hide Loading Loading @@ -1921,6 +1932,10 @@ public class PropertyInvalidatedCache<Query, Result> { } public AutoCorker(@NonNull String propertyName, int autoCorkDelayMs) { if (separatePermissionNotificationsEnabled()) { throw new IllegalStateException("AutoCorking is unavailable"); } mPropertyName = propertyName; mAutoCorkDelayMs = autoCorkDelayMs; // We can't initialize mHandler here: when we're created, the main loop might not Loading
core/java/android/app/performance.aconfig +8 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,14 @@ flag { bug: "373752556" } flag { namespace: "system_performance" name: "pic_separate_permission_notifications" is_fixed_read_only: true description: "Seperate PermissionManager notifications from cache udpates" bug: "373752556" } flag { namespace: "system_performance" name: "pic_cache_nulls" Loading
core/java/android/content/pm/PackageManager.java +29 −18 Original line number Diff line number Diff line Loading @@ -11651,7 +11651,7 @@ public abstract class PackageManager { private static final PropertyInvalidatedCache<ApplicationInfoQuery, ApplicationInfo> sApplicationInfoCache = new PropertyInvalidatedCache<ApplicationInfoQuery, ApplicationInfo>( 2048, PermissionManager.CACHE_KEY_PACKAGE_INFO, 2048, PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE, "getApplicationInfo") { @Override public ApplicationInfo recompute(ApplicationInfoQuery query) { Loading Loading @@ -11682,18 +11682,6 @@ public abstract class PackageManager { sApplicationInfoCache.disableLocal(); } private static final PropertyInvalidatedCache.AutoCorker sCacheAutoCorker = new PropertyInvalidatedCache.AutoCorker(PermissionManager.CACHE_KEY_PACKAGE_INFO); /** * Invalidate caches of package and permission information system-wide. * * @hide */ public static void invalidatePackageInfoCache() { sCacheAutoCorker.autoCork(); } // Some of the flags don't affect the query result, but let's be conservative and cache // each combination of flags separately. Loading Loading @@ -11752,7 +11740,7 @@ public abstract class PackageManager { private static final PropertyInvalidatedCache<PackageInfoQuery, PackageInfo> sPackageInfoCache = new PropertyInvalidatedCache<PackageInfoQuery, PackageInfo>( 2048, PermissionManager.CACHE_KEY_PACKAGE_INFO, 2048, PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE, "getPackageInfo") { @Override public PackageInfo recompute(PackageInfoQuery query) { Loading Loading @@ -11784,17 +11772,40 @@ public abstract class PackageManager { /** * Inhibit package info cache invalidations when correct. * * @hide */ * @hide */ public static void corkPackageInfoCache() { PropertyInvalidatedCache.corkInvalidations(PermissionManager.CACHE_KEY_PACKAGE_INFO); sPackageInfoCache.corkInvalidations(); } /** * Enable package info cache invalidations. * * @hide */ * @hide */ public static void uncorkPackageInfoCache() { PropertyInvalidatedCache.uncorkInvalidations(PermissionManager.CACHE_KEY_PACKAGE_INFO); sPackageInfoCache.uncorkInvalidations(); } // This auto-corker is obsolete once the separate permission notifications feature is // committed. private static final PropertyInvalidatedCache.AutoCorker sCacheAutoCorker = PropertyInvalidatedCache.separatePermissionNotificationsEnabled() ? null : new PropertyInvalidatedCache .AutoCorker(PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE); /** * Invalidate caches of package and permission information system-wide. * * @hide */ public static void invalidatePackageInfoCache() { if (PropertyInvalidatedCache.separatePermissionNotificationsEnabled()) { sPackageInfoCache.invalidateCache(); } else { sCacheAutoCorker.autoCork(); } } /** Loading
core/java/android/permission/PermissionManager.java +35 −4 Original line number Diff line number Diff line Loading @@ -1795,14 +1795,45 @@ public final class PermissionManager { } } /** @hide */ public static final String CACHE_KEY_PACKAGE_INFO = // The legacy system property "package_info" had two purposes: to invalidate PIC caches and to // signal that package information, and therefore permissions, might have changed. // AudioSystem is the only client of the signaling behavior. The "separate permissions // notification" feature splits the two behaviors into two system property names. // // If the feature is disabled (legacy behavior) then the two system property names have the // same value. This means there is only one system property in use. // // If the feature is enabled, then the two system property names have different values, which // means there is a system property used by PIC and a system property used for signaling. The // legacy value is hard-coded in native code that relies on the signaling behavior, so the // system property name for signaling is the legacy property name, and the system property // name for PIC is new. private static String getPackageInfoCacheKey() { if (PropertyInvalidatedCache.separatePermissionNotificationsEnabled()) { return PropertyInvalidatedCache.createSystemCacheKey("package_info_cache"); } else { return CACHE_KEY_PACKAGE_INFO_NOTIFY; } } /** * The system property that is used to notify clients that package information, and therefore * permissions, may have changed. * @hide */ public static final String CACHE_KEY_PACKAGE_INFO_NOTIFY = PropertyInvalidatedCache.createSystemCacheKey("package_info"); /** * The system property that is used to invalidate PIC caches. * @hide */ public static final String CACHE_KEY_PACKAGE_INFO_CACHE = getPackageInfoCacheKey(); /** @hide */ private static final PropertyInvalidatedCache<PermissionQuery, Integer> sPermissionCache = new PropertyInvalidatedCache<PermissionQuery, Integer>( 2048, CACHE_KEY_PACKAGE_INFO, "checkPermission") { 2048, CACHE_KEY_PACKAGE_INFO_CACHE, "checkPermission") { @Override public Integer recompute(PermissionQuery query) { return checkPermissionUncached(query.permission, query.pid, query.uid, Loading Loading @@ -1920,7 +1951,7 @@ public final class PermissionManager { private static PropertyInvalidatedCache<PackageNamePermissionQuery, Integer> sPackageNamePermissionCache = new PropertyInvalidatedCache<PackageNamePermissionQuery, Integer>( 16, CACHE_KEY_PACKAGE_INFO, "checkPackageNamePermission") { 16, CACHE_KEY_PACKAGE_INFO_CACHE, "checkPackageNamePermission") { @Override public Integer recompute(PackageNamePermissionQuery query) { return checkPackageNamePermissionUncached( Loading
services/core/java/com/android/server/audio/AudioService.java +112 −2 Original line number Diff line number Diff line Loading @@ -95,6 +95,7 @@ import android.app.AppOpsManager; import android.app.BroadcastOptions; import android.app.IUidObserver; import android.app.NotificationManager; import android.app.PropertyInvalidatedCache; import android.app.UidObserver; import android.app.role.OnRoleHoldersChangedListener; import android.app.role.RoleManager; Loading Loading @@ -248,6 +249,7 @@ import android.widget.Toast; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; import com.android.internal.os.SomeArgs; import com.android.internal.util.DumpUtils; import com.android.internal.util.Preconditions; Loading Loading @@ -10941,14 +10943,122 @@ public class AudioService extends IAudioService.Stub } }; mSysPropListenerNativeHandle = mAudioSystem.listenForSystemPropertyChange( PermissionManager.CACHE_KEY_PACKAGE_INFO, PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, task); } else { mAudioSystem.listenForSystemPropertyChange( PermissionManager.CACHE_KEY_PACKAGE_INFO, PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, () -> mAudioServerLifecycleExecutor.execute( mPermissionProvider::onPermissionStateChanged)); } if (PropertyInvalidatedCache.separatePermissionNotificationsEnabled()) { new PackageInfoTransducer().start(); } } /** * A transducer that converts high-speed changes in the CACHE_KEY_PACKAGE_INFO_CACHE * PropertyInvalidatedCache into low-speed changes in the CACHE_KEY_PACKAGE_INFO_NOTIFY system * property. This operates on the popcorn principle: changes in the source are done when the * source has been quiet for the soak interval. * * TODO(b/381097912) This is a temporary measure to support migration away from sysprop * sniffing. It should be cleaned up. */ private static class PackageInfoTransducer extends Thread { // The run/stop signal. private final AtomicBoolean mRunning = new AtomicBoolean(false); // The source of change information. private final PropertyInvalidatedCache.NonceWatcher mWatcher; // The handler for scheduling delayed reactions to changes. private final Handler mHandler; // How long to soak changes: 50ms is the legacy choice. private final static long SOAK_TIME_MS = 50; // The ubiquitous lock. private final Object mLock = new Object(); // If positive, this is the soak expiration time. @GuardedBy("mLock") private long mSoakDeadlineMs = -1; // A source of unique long values. @GuardedBy("mLock") private long mToken = 0; PackageInfoTransducer() { mWatcher = PropertyInvalidatedCache .getNonceWatcher(PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE); mHandler = new Handler(BackgroundThread.getHandler().getLooper()) { @Override public void handleMessage(Message msg) { PackageInfoTransducer.this.handleMessage(msg); }}; } public void run() { mRunning.set(true); while (mRunning.get()) { try { final int changes = mWatcher.waitForChange(); if (changes == 0 || !mRunning.get()) { continue; } } catch (InterruptedException e) { // We don't know why the exception occurred but keep running until told to // stop. continue; } trigger(); } } @GuardedBy("mLock") private void updateLocked() { String n = Long.toString(mToken++); SystemProperties.set(PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, n); } private void trigger() { synchronized (mLock) { boolean alreadyQueued = mSoakDeadlineMs >= 0; final long nowMs = SystemClock.uptimeMillis(); mSoakDeadlineMs = nowMs + SOAK_TIME_MS; if (!alreadyQueued) { mHandler.sendEmptyMessageAtTime(0, mSoakDeadlineMs); updateLocked(); } } } private void handleMessage(Message msg) { synchronized (mLock) { if (mSoakDeadlineMs < 0) { return; // ??? } final long nowMs = SystemClock.uptimeMillis(); if (mSoakDeadlineMs > nowMs) { mSoakDeadlineMs = nowMs + SOAK_TIME_MS; mHandler.sendEmptyMessageAtTime(0, mSoakDeadlineMs); return; } mSoakDeadlineMs = -1; updateLocked(); } } /** * Cause the thread to exit. Running is set to false and the watcher is awakened. */ public void done() { mRunning.set(false); mWatcher.wakeUp(); } } //========================================================================================== Loading