Loading services/core/java/com/android/server/am/ActivityManagerService.java +5 −0 Original line number Diff line number Diff line Loading @@ -13865,6 +13865,9 @@ public class ActivityManagerService extends IActivityManager.Stub @Nullable IBinder backgroundActivityStartsToken, @Nullable int[] broadcastAllowList, @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) { // Ensure all internal loopers are registered for idle checks BroadcastLoopers.addMyLooper(); if ((resultTo != null) && (resultToApp == null)) { if (resultTo.asBinder() instanceof BinderProxy) { // Warn when requesting results without a way to deliver them Loading Loading @@ -18115,6 +18118,7 @@ public class ActivityManagerService extends IActivityManager.Stub public void waitForBroadcastIdle(@Nullable PrintWriter pw) { enforceCallingPermission(permission.DUMP, "waitForBroadcastIdle()"); BroadcastLoopers.waitForIdle(pw); for (BroadcastQueue queue : mBroadcastQueues) { queue.waitForIdle(pw); } Loading @@ -18126,6 +18130,7 @@ public class ActivityManagerService extends IActivityManager.Stub public void waitForBroadcastBarrier(@Nullable PrintWriter pw) { enforceCallingPermission(permission.DUMP, "waitForBroadcastBarrier()"); BroadcastLoopers.waitForIdle(pw); for (BroadcastQueue queue : mBroadcastQueues) { queue.waitForBarrier(pw); } services/core/java/com/android/server/am/BroadcastLoopers.java 0 → 100644 +109 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.am; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Looper; import android.os.Message; import android.os.MessageQueue; import android.os.SystemClock; import android.util.ArraySet; import android.util.Slog; import java.io.PrintWriter; import java.util.Objects; import java.util.concurrent.CountDownLatch; /** * Collection of {@link Looper} that are known to be used for broadcast dispatch * within the system. This collection can be useful for callers interested in * confirming that all pending broadcasts have been successfully enqueued. */ public class BroadcastLoopers { private static final String TAG = "BroadcastLoopers"; private static final ArraySet<Looper> sLoopers = new ArraySet<>(); /** * Register the given {@link Looper} as possibly having messages that will * dispatch broadcasts. */ public static void addLooper(@NonNull Looper looper) { synchronized (sLoopers) { sLoopers.add(Objects.requireNonNull(looper)); } } /** * If the current thread is hosting a {@link Looper}, then register it as * possibly having messages that will dispatch broadcasts. */ public static void addMyLooper() { final Looper looper = Looper.myLooper(); if (looper != null) { synchronized (sLoopers) { if (sLoopers.add(looper)) { Slog.w(TAG, "Found previously unknown looper " + looper.getThread()); } } } } /** * Wait for all registered {@link Looper} instances to become idle, as * defined by {@link MessageQueue#isIdle()}. Note that {@link Message#when} * still in the future are ignored for the purposes of the idle test. */ public static void waitForIdle(@Nullable PrintWriter pw) { final CountDownLatch latch; synchronized (sLoopers) { final int N = sLoopers.size(); latch = new CountDownLatch(N); for (int i = 0; i < N; i++) { final MessageQueue queue = sLoopers.valueAt(i).getQueue(); if (queue.isIdle()) { latch.countDown(); } else { queue.addIdleHandler(() -> { latch.countDown(); return false; }); } } } long lastPrint = 0; while (latch.getCount() > 0) { final long now = SystemClock.uptimeMillis(); if (now >= lastPrint + 1000) { lastPrint = now; logv("Waiting for " + latch.getCount() + " loopers to drain...", pw); } SystemClock.sleep(100); } logv("Loopers drained!", pw); } private static void logv(@NonNull String msg, @Nullable PrintWriter pw) { Slog.v(TAG, msg); if (pw != null) { pw.println(msg); pw.flush(); } } } services/core/java/com/android/server/audio/AudioService.java +12 −4 Original line number Diff line number Diff line Loading @@ -8768,13 +8768,21 @@ public class AudioService extends IAudioService.Stub UserInfo userInfo = UserManagerService.getInstance().getUserInfo(userId); killBackgroundUserProcessesWithRecordAudioPermission(userInfo); } try { UserManagerService.getInstance().setUserRestriction( UserManager.DISALLOW_RECORD_AUDIO, true, userId); } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed to apply DISALLOW_RECORD_AUDIO restriction: " + e); } } else if (action.equals(Intent.ACTION_USER_FOREGROUND)) { // Enable audio recording for foreground user/profile int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); try { UserManagerService.getInstance().setUserRestriction( UserManager.DISALLOW_RECORD_AUDIO, false, userId); } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed to apply DISALLOW_RECORD_AUDIO restriction: " + e); } } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1); if (state == BluetoothAdapter.STATE_OFF || Loading Loading
services/core/java/com/android/server/am/ActivityManagerService.java +5 −0 Original line number Diff line number Diff line Loading @@ -13865,6 +13865,9 @@ public class ActivityManagerService extends IActivityManager.Stub @Nullable IBinder backgroundActivityStartsToken, @Nullable int[] broadcastAllowList, @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) { // Ensure all internal loopers are registered for idle checks BroadcastLoopers.addMyLooper(); if ((resultTo != null) && (resultToApp == null)) { if (resultTo.asBinder() instanceof BinderProxy) { // Warn when requesting results without a way to deliver them Loading Loading @@ -18115,6 +18118,7 @@ public class ActivityManagerService extends IActivityManager.Stub public void waitForBroadcastIdle(@Nullable PrintWriter pw) { enforceCallingPermission(permission.DUMP, "waitForBroadcastIdle()"); BroadcastLoopers.waitForIdle(pw); for (BroadcastQueue queue : mBroadcastQueues) { queue.waitForIdle(pw); } Loading @@ -18126,6 +18130,7 @@ public class ActivityManagerService extends IActivityManager.Stub public void waitForBroadcastBarrier(@Nullable PrintWriter pw) { enforceCallingPermission(permission.DUMP, "waitForBroadcastBarrier()"); BroadcastLoopers.waitForIdle(pw); for (BroadcastQueue queue : mBroadcastQueues) { queue.waitForBarrier(pw); }
services/core/java/com/android/server/am/BroadcastLoopers.java 0 → 100644 +109 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.am; import android.annotation.NonNull; import android.annotation.Nullable; import android.os.Looper; import android.os.Message; import android.os.MessageQueue; import android.os.SystemClock; import android.util.ArraySet; import android.util.Slog; import java.io.PrintWriter; import java.util.Objects; import java.util.concurrent.CountDownLatch; /** * Collection of {@link Looper} that are known to be used for broadcast dispatch * within the system. This collection can be useful for callers interested in * confirming that all pending broadcasts have been successfully enqueued. */ public class BroadcastLoopers { private static final String TAG = "BroadcastLoopers"; private static final ArraySet<Looper> sLoopers = new ArraySet<>(); /** * Register the given {@link Looper} as possibly having messages that will * dispatch broadcasts. */ public static void addLooper(@NonNull Looper looper) { synchronized (sLoopers) { sLoopers.add(Objects.requireNonNull(looper)); } } /** * If the current thread is hosting a {@link Looper}, then register it as * possibly having messages that will dispatch broadcasts. */ public static void addMyLooper() { final Looper looper = Looper.myLooper(); if (looper != null) { synchronized (sLoopers) { if (sLoopers.add(looper)) { Slog.w(TAG, "Found previously unknown looper " + looper.getThread()); } } } } /** * Wait for all registered {@link Looper} instances to become idle, as * defined by {@link MessageQueue#isIdle()}. Note that {@link Message#when} * still in the future are ignored for the purposes of the idle test. */ public static void waitForIdle(@Nullable PrintWriter pw) { final CountDownLatch latch; synchronized (sLoopers) { final int N = sLoopers.size(); latch = new CountDownLatch(N); for (int i = 0; i < N; i++) { final MessageQueue queue = sLoopers.valueAt(i).getQueue(); if (queue.isIdle()) { latch.countDown(); } else { queue.addIdleHandler(() -> { latch.countDown(); return false; }); } } } long lastPrint = 0; while (latch.getCount() > 0) { final long now = SystemClock.uptimeMillis(); if (now >= lastPrint + 1000) { lastPrint = now; logv("Waiting for " + latch.getCount() + " loopers to drain...", pw); } SystemClock.sleep(100); } logv("Loopers drained!", pw); } private static void logv(@NonNull String msg, @Nullable PrintWriter pw) { Slog.v(TAG, msg); if (pw != null) { pw.println(msg); pw.flush(); } } }
services/core/java/com/android/server/audio/AudioService.java +12 −4 Original line number Diff line number Diff line Loading @@ -8768,13 +8768,21 @@ public class AudioService extends IAudioService.Stub UserInfo userInfo = UserManagerService.getInstance().getUserInfo(userId); killBackgroundUserProcessesWithRecordAudioPermission(userInfo); } try { UserManagerService.getInstance().setUserRestriction( UserManager.DISALLOW_RECORD_AUDIO, true, userId); } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed to apply DISALLOW_RECORD_AUDIO restriction: " + e); } } else if (action.equals(Intent.ACTION_USER_FOREGROUND)) { // Enable audio recording for foreground user/profile int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); try { UserManagerService.getInstance().setUserRestriction( UserManager.DISALLOW_RECORD_AUDIO, false, userId); } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed to apply DISALLOW_RECORD_AUDIO restriction: " + e); } } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1); if (state == BluetoothAdapter.STATE_OFF || Loading