diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/RadioServiceUserControllerTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/RadioServiceUserControllerTest.java index 3e9e9922431bb..516253b0ebfff 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/RadioServiceUserControllerTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/RadioServiceUserControllerTest.java @@ -58,7 +58,7 @@ public final class RadioServiceUserControllerTest extends ExtendedRadioMockitoTe } @Test - public void isCurrentUser_forCurrentUser_returnsFalse() { + public void isCurrentOrSystemUser_forCurrentUser_returnsFalse() { when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1); assertWithMessage("Current user") @@ -66,7 +66,7 @@ public final class RadioServiceUserControllerTest extends ExtendedRadioMockitoTe } @Test - public void isCurrentUser_forNonCurrentUser_returnsFalse() { + public void isCurrentOrSystemUser_forNonCurrentUser_returnsFalse() { when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_2); assertWithMessage("Non-current user") @@ -74,7 +74,8 @@ public final class RadioServiceUserControllerTest extends ExtendedRadioMockitoTe } @Test - public void isCurrentUser_forSystemUser_returnsTrue() { + public void isCurrentOrSystemUser_forSystemUser_returnsTrue() { + when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1); when(mUserHandleMock.getIdentifier()).thenReturn(UserHandle.USER_SYSTEM); assertWithMessage("System user") @@ -82,10 +83,26 @@ public final class RadioServiceUserControllerTest extends ExtendedRadioMockitoTe } @Test - public void isCurrentUser_withActivityManagerFails_returnsFalse() { - doThrow(new RuntimeException()).when(() -> ActivityManager.getCurrentUser()); + public void isCurrentOrSystemUser_withActivityManagerFailure_returnsFalse() { + when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1); + doThrow(new RuntimeException()).when(ActivityManager::getCurrentUser); assertWithMessage("User when activity manager fails") .that(RadioServiceUserController.isCurrentOrSystemUser()).isFalse(); } + + @Test + public void getCurrentUser() { + assertWithMessage("Current user") + .that(RadioServiceUserController.getCurrentUser()).isEqualTo(USER_ID_1); + } + + @Test + public void getCurrentUser_withActivityManagerFailure_returnsUserNull() { + when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1); + doThrow(new RuntimeException()).when(ActivityManager::getCurrentUser); + + assertWithMessage("Current user when activity manager fails") + .that(RadioServiceUserController.getCurrentUser()).isEqualTo(UserHandle.USER_NULL); + } } diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java index 78b5a4ad71de8..f85748c93c57c 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java @@ -47,9 +47,11 @@ import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioTuner; +import android.os.Binder; import android.os.ParcelableException; import android.os.RemoteException; import android.os.ServiceSpecificException; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; @@ -73,6 +75,8 @@ import java.util.Set; */ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { + private static final int USER_ID_1 = 11; + private static final int USER_ID_2 = 12; private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(/* millis= */ 200); private static final int SIGNAL_QUALITY = 90; @@ -109,7 +113,10 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { SIGNAL_QUALITY); // Mocks - @Mock private IBroadcastRadio mBroadcastRadioMock; + @Mock + private UserHandle mUserHandleMock; + @Mock + private IBroadcastRadio mBroadcastRadioMock; private android.hardware.radio.ITunerCallback[] mAidlTunerCallbackMocks; // RadioModule under test @@ -124,14 +131,18 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { @Override protected void initializeSession(StaticMockitoSessionBuilder builder) { - builder.spyStatic(RadioServiceUserController.class).spyStatic(CompatChanges.class); + builder.spyStatic(RadioServiceUserController.class).spyStatic(CompatChanges.class) + .spyStatic(Binder.class); } @Before public void setup() throws Exception { + when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1); doReturn(true).when(() -> CompatChanges.isChangeEnabled( eq(ConversionUtils.RADIO_U_VERSION_REQUIRED), anyInt())); doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + doReturn(USER_ID_1).when(() -> RadioServiceUserController.getCurrentUser()); + doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle()); mRadioModule = new RadioModule(mBroadcastRadioMock, AidlTestUtils.makeDefaultModuleProperties()); @@ -420,6 +431,21 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { .onCurrentProgramInfoChanged(tuneInfo); } + @Test + public void tune_forSystemUser() throws Exception { + when(mUserHandleMock.getIdentifier()).thenReturn(UserHandle.USER_SYSTEM); + doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle()); + doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + ProgramSelector initialSel = AidlTestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); + RadioManager.ProgramInfo tuneInfo = + AidlTestUtils.makeProgramInfo(initialSel, SIGNAL_QUALITY); + openAidlClients(/* numClients= */ 1); + + mTunerSessions[0].tune(initialSel); + + verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo); + } + @Test public void tune_withUnknownErrorFromHal_fails() throws Exception { openAidlClients(/* numClients= */ 1); @@ -1135,6 +1161,19 @@ public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { .that(thrown).hasMessageThat().contains(exceptionMessage); } + @Test + public void onCurrentProgramInfoChanged_withNoncurrentUser_doesNotInvokeCallback() + throws Exception { + openAidlClients(1); + doReturn(USER_ID_2).when(() -> RadioServiceUserController.getCurrentUser()); + + mHalTunerCallback.onCurrentProgramInfoChanged(AidlTestUtils.makeHalProgramInfo( + AidlTestUtils.makeHalFmSelector(/* freq= */ 97300), SIGNAL_QUALITY)); + + verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) + .onCurrentProgramInfoChanged(any()); + } + @Test public void onAntennaStateChange_forTunerCallback() throws Exception { int numSessions = 3; diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java index 3815008bd4fb3..fac9eaafe94c5 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java @@ -46,8 +46,10 @@ import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.hardware.radio.RadioTuner; +import android.os.Binder; import android.os.ParcelableException; import android.os.RemoteException; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.ArraySet; @@ -74,6 +76,8 @@ import java.util.Map; @RunWith(MockitoJUnitRunner.class) public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { + private static final int USER_ID_1 = 11; + private static final int USER_ID_2 = 12; private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(/* millis= */ 200); private static final int SIGNAL_QUALITY = 1; @@ -94,18 +98,25 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { private ProgramInfo mHalCurrentInfo; private TunerSession[] mTunerSessions; - @Mock private IBroadcastRadio mBroadcastRadioMock; - @Mock ITunerSession mHalTunerSessionMock; + @Mock + private UserHandle mUserHandleMock; + @Mock + private IBroadcastRadio mBroadcastRadioMock; + @Mock + ITunerSession mHalTunerSessionMock; private android.hardware.radio.ITunerCallback[] mAidlTunerCallbackMocks; @Override protected void initializeSession(StaticMockitoSessionBuilder builder) { - builder.spyStatic(RadioServiceUserController.class); + builder.spyStatic(RadioServiceUserController.class).spyStatic(Binder.class); } @Before public void setup() throws Exception { + when(mUserHandleMock.getIdentifier()).thenReturn(USER_ID_1); + doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle()); doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + doReturn(USER_ID_1).when(() -> RadioServiceUserController.getCurrentUser()); mRadioModule = new RadioModule(mBroadcastRadioMock, TestUtils.makeDefaultModuleProperties()); @@ -386,6 +397,20 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { .that(thrown).hasMessageThat().contains(Result.toString(Result.UNKNOWN_ERROR)); } + @Test + public void tune_forSystemUser() throws Exception { + when(mUserHandleMock.getIdentifier()).thenReturn(UserHandle.USER_SYSTEM); + doReturn(mUserHandleMock).when(() -> Binder.getCallingUserHandle()); + doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + ProgramSelector initialSel = TestUtils.makeFmSelector(AM_FM_FREQUENCY_LIST[1]); + RadioManager.ProgramInfo tuneInfo = TestUtils.makeProgramInfo(initialSel, SIGNAL_QUALITY); + openAidlClients(/* numClients= */ 1); + + mTunerSessions[0].tune(initialSel); + + verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT).onCurrentProgramInfoChanged(tuneInfo); + } + @Test public void step_withDirectionUp() throws Exception { long initFreq = AM_FM_FREQUENCY_LIST[1]; @@ -857,6 +882,19 @@ public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { .that(thrown).hasMessageThat().contains(exceptionMessage); } + @Test + public void onCurrentProgramInfoChanged_withNoncurrentUser_doesNotInvokeCallback() + throws Exception { + openAidlClients(1); + doReturn(USER_ID_2).when(() -> RadioServiceUserController.getCurrentUser()); + + mHalTunerCallback.onCurrentProgramInfoChanged(TestUtils.makeHalProgramInfo( + TestUtils.makeHalFmSelector(/* freq= */ 97300), SIGNAL_QUALITY)); + + verify(mAidlTunerCallbackMocks[0], CALLBACK_TIMEOUT.times(0)) + .onCurrentProgramInfoChanged(any()); + } + @Test public void onConfigFlagUpdated_forTunerCallback() throws Exception { int numSessions = 3; diff --git a/services/core/java/com/android/server/broadcastradio/RadioServiceUserController.java b/services/core/java/com/android/server/broadcastradio/RadioServiceUserController.java index 38b3233953293..4b847a27c4dee 100644 --- a/services/core/java/com/android/server/broadcastradio/RadioServiceUserController.java +++ b/services/core/java/com/android/server/broadcastradio/RadioServiceUserController.java @@ -39,18 +39,24 @@ public final class RadioServiceUserController { */ public static boolean isCurrentOrSystemUser() { int callingUser = Binder.getCallingUserHandle().getIdentifier(); + return callingUser == getCurrentUser() || callingUser == UserHandle.USER_SYSTEM; + } + + /** + * Get current foreground user for Broadcast Radio Service + * + * @return foreground user id. + */ + public static int getCurrentUser() { final long identity = Binder.clearCallingIdentity(); + int userId = UserHandle.USER_NULL; try { - int currentUser = ActivityManager.getCurrentUser(); - if (callingUser != currentUser && callingUser != UserHandle.USER_SYSTEM) { - return false; - } - return true; + userId = ActivityManager.getCurrentUser(); } catch (RuntimeException e) { // Activity manager not running, nothing we can do assume user 0. } finally { Binder.restoreCallingIdentity(identity); } - return false; + return userId; } } diff --git a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java index 132fb8ef8a952..7c87c6c552899 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java @@ -36,11 +36,13 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; +import android.os.UserHandle; import android.util.ArraySet; import android.util.IndentingPrintWriter; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.broadcastradio.RadioServiceUserController; import com.android.server.utils.Slogf; import java.util.ArrayList; @@ -419,8 +421,13 @@ final class RadioModule { @GuardedBy("mLock") private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) { + int currentUserId = RadioServiceUserController.getCurrentUser(); List deadSessions = null; for (int i = 0; i < mAidlTunerSessions.size(); i++) { + if (mAidlTunerSessions.valueAt(i).mUserId != currentUserId + && mAidlTunerSessions.valueAt(i).mUserId != UserHandle.USER_SYSTEM) { + continue; + } try { runnable.run(mAidlTunerSessions.valueAt(i).mCallback, mAidlTunerSessions.valueAt(i).getUid()); diff --git a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java index 0a3823f038fa9..beff7bd3cffd3 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java @@ -46,6 +46,7 @@ final class TunerSession extends ITuner.Stub { private final RadioLogger mLogger; private final RadioModule mModule; + final int mUserId; final android.hardware.radio.ITunerCallback mCallback; private final int mUid; private final IBroadcastRadio mService; @@ -65,6 +66,7 @@ final class TunerSession extends ITuner.Stub { android.hardware.radio.ITunerCallback callback) { mModule = Objects.requireNonNull(radioModule, "radioModule cannot be null"); mService = Objects.requireNonNull(service, "service cannot be null"); + mUserId = Binder.getCallingUserHandle().getIdentifier(); mCallback = Objects.requireNonNull(callback, "callback cannot be null"); mUid = Binder.getCallingUid(); mLogger = new RadioLogger(TAG, TUNER_EVENT_LOGGER_QUEUE_SIZE); diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java index 59a81544d8ef5..7b5cb898b6b52 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java @@ -38,12 +38,14 @@ import android.os.DeadObjectException; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; +import android.os.UserHandle; import android.util.IndentingPrintWriter; import android.util.MutableInt; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.broadcastradio.RadioServiceUserController; import java.util.ArrayList; import java.util.HashSet; @@ -374,8 +376,13 @@ final class RadioModule { @GuardedBy("mLock") private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) { + int currentUserId = RadioServiceUserController.getCurrentUser(); List deadSessions = null; for (TunerSession tunerSession : mAidlTunerSessions) { + if (tunerSession.mUserId != currentUserId && tunerSession.mUserId + != UserHandle.USER_SYSTEM) { + continue; + } try { runnable.run(tunerSession.mCallback); } catch (DeadObjectException ex) { diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java index 204b9649135e4..1efc4a50aa08f 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java @@ -26,6 +26,7 @@ import android.hardware.radio.ITuner; import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; +import android.os.Binder; import android.os.RemoteException; import android.util.ArrayMap; import android.util.IndentingPrintWriter; @@ -52,6 +53,7 @@ class TunerSession extends ITuner.Stub { private final RadioModule mModule; private final ITunerSession mHwSession; + final int mUserId; final android.hardware.radio.ITunerCallback mCallback; @GuardedBy("mLock") @@ -68,6 +70,7 @@ class TunerSession extends ITuner.Stub { @NonNull android.hardware.radio.ITunerCallback callback) { mModule = Objects.requireNonNull(module); mHwSession = Objects.requireNonNull(hwSession); + mUserId = Binder.getCallingUserHandle().getIdentifier(); mCallback = Objects.requireNonNull(callback); mEventLogger = new RadioEventLogger(TAG, TUNER_EVENT_LOGGER_QUEUE_SIZE); }