Loading services/core/java/com/android/server/audio/AudioService.java +28 −76 Original line number Original line Diff line number Diff line Loading @@ -837,6 +837,7 @@ public class AudioService extends IAudioService.Stub private final Executor mAudioServerLifecycleExecutor; private final Executor mAudioServerLifecycleExecutor; private long mSysPropListenerNativeHandle; private long mSysPropListenerNativeHandle; private CacheWatcher mCacheWatcher; private final List<Future> mScheduledPermissionTasks = new ArrayList(); private final List<Future> mScheduledPermissionTasks = new ArrayList(); private IMediaProjectionManager mProjectionService; // to validate projection token private IMediaProjectionManager mProjectionService; // to validate projection token Loading Loading @@ -11093,31 +11094,26 @@ public class AudioService extends IAudioService.Stub }, getAudioPermissionsDelay(), TimeUnit.MILLISECONDS)); }, getAudioPermissionsDelay(), TimeUnit.MILLISECONDS)); } } }; }; if (PropertyInvalidatedCache.separatePermissionNotificationsEnabled()) { mCacheWatcher = new CacheWatcher(task); mCacheWatcher.start(); } else { mSysPropListenerNativeHandle = mAudioSystem.listenForSystemPropertyChange( mSysPropListenerNativeHandle = mAudioSystem.listenForSystemPropertyChange( PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, task); task); } } else { } else { mAudioSystem.listenForSystemPropertyChange( mAudioSystem.listenForSystemPropertyChange( PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, () -> mAudioServerLifecycleExecutor.execute( () -> mAudioServerLifecycleExecutor.execute( mPermissionProvider::onPermissionStateChanged)); mPermissionProvider::onPermissionStateChanged)); } } if (PropertyInvalidatedCache.separatePermissionNotificationsEnabled()) { new PackageInfoTransducer().start(); } } } /** /** * A transducer that converts high-speed changes in the CACHE_KEY_PACKAGE_INFO_CACHE * Listens for CACHE_KEY_PACKAGE_INFO_CACHE invalidations to trigger permission syncing * 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 { private static class CacheWatcher extends Thread { // The run/stop signal. // The run/stop signal. private final AtomicBoolean mRunning = new AtomicBoolean(false); private final AtomicBoolean mRunning = new AtomicBoolean(false); Loading @@ -11125,81 +11121,33 @@ public class AudioService extends IAudioService.Stub // The source of change information. // The source of change information. private final PropertyInvalidatedCache.NonceWatcher mWatcher; private final PropertyInvalidatedCache.NonceWatcher mWatcher; // The handler for scheduling delayed reactions to changes. // Task to trigger when cache changes private final Handler mHandler; private final Runnable mTask; // How long to soak changes: 50ms is the legacy choice. public CacheWatcher(Runnable r) { private final static long SOAK_TIME_MS = 50; mWatcher = PropertyInvalidatedCache.getNonceWatcher( PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE); // The ubiquitous lock. mTask = r; 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() { public void run() { mRunning.set(true); mRunning.set(true); while (mRunning.get()) { while (mRunning.get()) { doCheck(); try { try { final int changes = mWatcher.waitForChange(); mWatcher.waitForChange(); if (changes == 0 || !mRunning.get()) { continue; } } catch (InterruptedException e) { } catch (InterruptedException e) { Log.wtf(TAG, "Unexpected Interrupt", e); // We don't know why the exception occurred but keep running until told to // We don't know why the exception occurred but keep running until told to // stop. // stop. continue; continue; } } trigger(); } } } @GuardedBy("mLock") private void updateLocked() { String n = Long.toString(mToken++); SystemPropertySetter.setWithRetry(PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, n); } } private void trigger() { public synchronized void doCheck() { synchronized (mLock) { if (mWatcher.isChanged()) { boolean alreadyQueued = mSoakDeadlineMs >= 0; mTask.run(); 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(); } } } } Loading Loading @@ -15376,7 +15324,11 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#permissionUpdateBarrier() */ /** @see AudioManager#permissionUpdateBarrier() */ public void permissionUpdateBarrier() { public void permissionUpdateBarrier() { if (!audioserverPermissions()) return; if (!audioserverPermissions()) return; if (PropertyInvalidatedCache.separatePermissionNotificationsEnabled()) { mCacheWatcher.doCheck(); } else { mAudioSystem.triggerSystemPropertyUpdate(mSysPropListenerNativeHandle); mAudioSystem.triggerSystemPropertyUpdate(mSysPropListenerNativeHandle); } List<Future> snapshot; List<Future> snapshot; synchronized (mScheduledPermissionTasks) { synchronized (mScheduledPermissionTasks) { snapshot = List.copyOf(mScheduledPermissionTasks); snapshot = List.copyOf(mScheduledPermissionTasks); Loading
services/core/java/com/android/server/audio/AudioService.java +28 −76 Original line number Original line Diff line number Diff line Loading @@ -837,6 +837,7 @@ public class AudioService extends IAudioService.Stub private final Executor mAudioServerLifecycleExecutor; private final Executor mAudioServerLifecycleExecutor; private long mSysPropListenerNativeHandle; private long mSysPropListenerNativeHandle; private CacheWatcher mCacheWatcher; private final List<Future> mScheduledPermissionTasks = new ArrayList(); private final List<Future> mScheduledPermissionTasks = new ArrayList(); private IMediaProjectionManager mProjectionService; // to validate projection token private IMediaProjectionManager mProjectionService; // to validate projection token Loading Loading @@ -11093,31 +11094,26 @@ public class AudioService extends IAudioService.Stub }, getAudioPermissionsDelay(), TimeUnit.MILLISECONDS)); }, getAudioPermissionsDelay(), TimeUnit.MILLISECONDS)); } } }; }; if (PropertyInvalidatedCache.separatePermissionNotificationsEnabled()) { mCacheWatcher = new CacheWatcher(task); mCacheWatcher.start(); } else { mSysPropListenerNativeHandle = mAudioSystem.listenForSystemPropertyChange( mSysPropListenerNativeHandle = mAudioSystem.listenForSystemPropertyChange( PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, task); task); } } else { } else { mAudioSystem.listenForSystemPropertyChange( mAudioSystem.listenForSystemPropertyChange( PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, () -> mAudioServerLifecycleExecutor.execute( () -> mAudioServerLifecycleExecutor.execute( mPermissionProvider::onPermissionStateChanged)); mPermissionProvider::onPermissionStateChanged)); } } if (PropertyInvalidatedCache.separatePermissionNotificationsEnabled()) { new PackageInfoTransducer().start(); } } } /** /** * A transducer that converts high-speed changes in the CACHE_KEY_PACKAGE_INFO_CACHE * Listens for CACHE_KEY_PACKAGE_INFO_CACHE invalidations to trigger permission syncing * 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 { private static class CacheWatcher extends Thread { // The run/stop signal. // The run/stop signal. private final AtomicBoolean mRunning = new AtomicBoolean(false); private final AtomicBoolean mRunning = new AtomicBoolean(false); Loading @@ -11125,81 +11121,33 @@ public class AudioService extends IAudioService.Stub // The source of change information. // The source of change information. private final PropertyInvalidatedCache.NonceWatcher mWatcher; private final PropertyInvalidatedCache.NonceWatcher mWatcher; // The handler for scheduling delayed reactions to changes. // Task to trigger when cache changes private final Handler mHandler; private final Runnable mTask; // How long to soak changes: 50ms is the legacy choice. public CacheWatcher(Runnable r) { private final static long SOAK_TIME_MS = 50; mWatcher = PropertyInvalidatedCache.getNonceWatcher( PermissionManager.CACHE_KEY_PACKAGE_INFO_CACHE); // The ubiquitous lock. mTask = r; 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() { public void run() { mRunning.set(true); mRunning.set(true); while (mRunning.get()) { while (mRunning.get()) { doCheck(); try { try { final int changes = mWatcher.waitForChange(); mWatcher.waitForChange(); if (changes == 0 || !mRunning.get()) { continue; } } catch (InterruptedException e) { } catch (InterruptedException e) { Log.wtf(TAG, "Unexpected Interrupt", e); // We don't know why the exception occurred but keep running until told to // We don't know why the exception occurred but keep running until told to // stop. // stop. continue; continue; } } trigger(); } } } @GuardedBy("mLock") private void updateLocked() { String n = Long.toString(mToken++); SystemPropertySetter.setWithRetry(PermissionManager.CACHE_KEY_PACKAGE_INFO_NOTIFY, n); } } private void trigger() { public synchronized void doCheck() { synchronized (mLock) { if (mWatcher.isChanged()) { boolean alreadyQueued = mSoakDeadlineMs >= 0; mTask.run(); 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(); } } } } Loading Loading @@ -15376,7 +15324,11 @@ public class AudioService extends IAudioService.Stub /** @see AudioManager#permissionUpdateBarrier() */ /** @see AudioManager#permissionUpdateBarrier() */ public void permissionUpdateBarrier() { public void permissionUpdateBarrier() { if (!audioserverPermissions()) return; if (!audioserverPermissions()) return; if (PropertyInvalidatedCache.separatePermissionNotificationsEnabled()) { mCacheWatcher.doCheck(); } else { mAudioSystem.triggerSystemPropertyUpdate(mSysPropListenerNativeHandle); mAudioSystem.triggerSystemPropertyUpdate(mSysPropListenerNativeHandle); } List<Future> snapshot; List<Future> snapshot; synchronized (mScheduledPermissionTasks) { synchronized (mScheduledPermissionTasks) { snapshot = List.copyOf(mScheduledPermissionTasks); snapshot = List.copyOf(mScheduledPermissionTasks);