From 20cfd6b14f0d571ab3e6b8308b8a792aa88a3430 Mon Sep 17 00:00:00 2001 From: Weilin Xu Date: Mon, 24 Apr 2023 17:34:39 +0000 Subject: [PATCH] Disable sending tuner callback to non current user After current user is switched, tuner callback should not be sent to tuner sessions created by previous user even before these sessions are closed. Bug: 277380847 Test: atest com.android.server.broadcastradio Change-Id: Ib56ff9dcb1690ff5aad39963d536b973f3991036 --- .../RadioServiceUserControllerTest.java | 27 +++++++++--- .../broadcastradio/aidl/TunerSessionTest.java | 43 +++++++++++++++++- .../hal2/TunerSessionHidlTest.java | 44 +++++++++++++++++-- .../RadioServiceUserController.java | 18 +++++--- .../broadcastradio/aidl/RadioModule.java | 7 +++ .../broadcastradio/aidl/TunerSession.java | 2 + .../broadcastradio/hal2/RadioModule.java | 7 +++ .../broadcastradio/hal2/TunerSession.java | 3 ++ 8 files changed, 135 insertions(+), 16 deletions(-) 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); }