From 024ec1687e81ba8df7d9bb8800fc9d4e0fd67423 Mon Sep 17 00:00:00 2001 From: Weilin Xu Date: Thu, 27 Oct 2022 21:45:22 +0000 Subject: [PATCH] Add user control for broadcast radio HAL client For opening tuner and adding announcement listener methods in HAL clients, an illegal state exception is thrown if the user calling methods is not the current user or system user. Calls from non-current on other public methods in HAL clients which can modify HAL state are rejected silently, to avoid crash radio apps when the current user is switched. Meanwhile, public methods in radio modules are changed to non-public since there is no need to access them outside their package. HAL 2.0 client code is also refactored. Bug: 240344065 Test: atest com.android.server.broadcastradio.aidl Change-Id: I62147a5d68b1f6a0314941ab65d0faedb78bfa7d --- .../aidl/BroadcastRadioServiceImplTest.java | 5 +- .../broadcastradio/aidl/TunerSessionTest.java | 18 ++++-- .../hal2/BroadcastRadioServiceHidlTest.java | 6 +- .../hal2/ProgramInfoCacheTest.java | 4 +- .../StartProgramListUpdatesFanoutTest.java | 20 ++++--- .../hal2/TunerSessionHidlTest.java | 15 ++++- .../RadioServiceUserController.java | 56 +++++++++++++++++++ .../aidl/BroadcastRadioServiceImpl.java | 8 ++- .../broadcastradio/aidl/RadioModule.java | 15 +++-- .../broadcastradio/aidl/TunerSession.java | 46 ++++++++++++++- .../hal1/BroadcastRadioService.java | 14 ++++- .../server/broadcastradio/hal1/Convert.java | 3 +- .../server/broadcastradio/hal1/Tuner.java | 49 +++++++++++++++- .../broadcastradio/hal1/TunerCallback.java | 3 +- .../hal2/BroadcastRadioService.java | 6 ++ .../broadcastradio/hal2/ProgramInfoCache.java | 2 +- .../broadcastradio/hal2/RadioModule.java | 19 ++++--- .../broadcastradio/hal2/TunerSession.java | 47 ++++++++++++++++ 18 files changed, 295 insertions(+), 41 deletions(-) create mode 100644 services/core/java/com/android/server/broadcastradio/RadioServiceUserController.java diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java index 635d1e7927150..93214e5a69448 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java @@ -39,6 +39,7 @@ import android.os.ServiceManager; import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase; +import com.android.server.broadcastradio.RadioServiceUserController; import org.junit.Test; import org.mockito.Mock; @@ -81,7 +82,8 @@ public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTes @Override protected void initializeSession(StaticMockitoSessionBuilder builder) { builder.spyStatic(ServiceManager.class) - .spyStatic(RadioModule.class); + .spyStatic(RadioModule.class) + .spyStatic(RadioServiceUserController.class); } @Test @@ -150,6 +152,7 @@ public final class BroadcastRadioServiceImplTest extends ExtendedRadioMockitoTes } private void createBroadcastRadioService() throws RemoteException { + doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); mockServiceManager(); mBroadcastRadioService = new BroadcastRadioServiceImpl(SERVICE_LIST); } 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 3bf993c07aed6..a29e9c5c9bb13 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 @@ -16,6 +16,8 @@ package com.android.server.broadcastradio.aidl; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; + import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertThrows; @@ -44,12 +46,14 @@ import android.os.ServiceSpecificException; import android.util.ArrayMap; import android.util.ArraySet; +import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; +import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase; +import com.android.server.broadcastradio.RadioServiceUserController; + import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; import org.mockito.verification.VerificationWithTimeout; import java.util.ArrayList; @@ -59,8 +63,7 @@ import java.util.Map; /** * Tests for AIDL HAL TunerSession. */ -@RunWith(MockitoJUnitRunner.class) -public final class TunerSessionTest { +public final class TunerSessionTest extends ExtendedRadioMockitoTestCase { private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(/* millis= */ 200); @@ -91,8 +94,15 @@ public final class TunerSessionTest { private TunerSession[] mTunerSessions; + @Override + protected void initializeSession(StaticMockitoSessionBuilder builder) { + builder.spyStatic(RadioServiceUserController.class); + } + @Before public void setup() throws Exception { + doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + mRadioModule = new RadioModule(mBroadcastRadioMock, AidlTestUtils.makeDefaultModuleProperties(), mLock); diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/BroadcastRadioServiceHidlTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/BroadcastRadioServiceHidlTest.java index 4d0b753b0acc1..99e70436ac955 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/BroadcastRadioServiceHidlTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/BroadcastRadioServiceHidlTest.java @@ -43,6 +43,7 @@ import android.os.RemoteException; import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase; +import com.android.server.broadcastradio.RadioServiceUserController; import org.junit.Test; import org.mockito.Mock; @@ -92,7 +93,8 @@ public final class BroadcastRadioServiceHidlTest extends ExtendedRadioMockitoTes @Override protected void initializeSession(StaticMockitoSessionBuilder builder) { - builder.spyStatic(RadioModule.class); + builder.spyStatic(RadioModule.class) + .spyStatic(RadioServiceUserController.class); } @Test @@ -181,6 +183,8 @@ public final class BroadcastRadioServiceHidlTest extends ExtendedRadioMockitoTes } private void createBroadcastRadioService() throws RemoteException { + doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + mockServiceManager(); mBroadcastRadioService = new BroadcastRadioService(/* nextModuleId= */ FM_RADIO_MODULE_ID, mLock, mServiceManagerMock); diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java index eadf226b01ce2..ec55ddbe1a4a6 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/ProgramInfoCacheTest.java @@ -25,6 +25,8 @@ import android.test.suitebuilder.annotation.MediumTest; import androidx.test.runner.AndroidJUnit4; +import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase; + import org.junit.Test; import org.junit.runner.RunWith; @@ -37,7 +39,7 @@ import java.util.Set; */ @RunWith(AndroidJUnit4.class) @MediumTest -public class ProgramInfoCacheTest { +public class ProgramInfoCacheTest extends ExtendedRadioMockitoTestCase { private static final String TAG = "BroadcastRadioTests.ProgramInfoCache"; private final ProgramSelector.Identifier mAmFmIdentifier = diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java index d1043595535a2..e3c9faa601e79 100644 --- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java +++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java @@ -15,6 +15,8 @@ */ package com.android.server.broadcastradio.hal2; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; + import static org.junit.Assert.*; import static org.mockito.Matchers.any; import static org.mockito.Mockito.doAnswer; @@ -34,15 +36,14 @@ import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.os.RemoteException; -import android.test.suitebuilder.annotation.MediumTest; -import androidx.test.runner.AndroidJUnit4; +import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; +import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase; +import com.android.server.broadcastradio.RadioServiceUserController; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; import org.mockito.verification.VerificationWithTimeout; @@ -53,9 +54,7 @@ import java.util.List; /** * Tests for v2 HAL RadioModule. */ -@RunWith(AndroidJUnit4.class) -@MediumTest -public class StartProgramListUpdatesFanoutTest { +public class StartProgramListUpdatesFanoutTest extends ExtendedRadioMockitoTestCase { private static final String TAG = "BroadcastRadioTests.hal2.StartProgramListUpdatesFanout"; private static final VerificationWithTimeout CB_TIMEOUT = timeout(500); @@ -91,9 +90,14 @@ public class StartProgramListUpdatesFanoutTest { private final RadioManager.ProgramInfo mDabEnsembleInfo = TestUtils.makeProgramInfo( ProgramSelector.PROGRAM_TYPE_DAB, mDabEnsembleIdentifier, 0); + @Override + protected void initializeSession(StaticMockitoSessionBuilder builder) { + builder.spyStatic(RadioServiceUserController.class); + } + @Before public void setup() throws RemoteException { - MockitoAnnotations.initMocks(this); + doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); mRadioModule = new RadioModule(mBroadcastRadioMock, TestUtils.makeDefaultModuleProperties(), mLock); 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 936e606fcb76d..8884053bb58c0 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 @@ -16,6 +16,8 @@ package com.android.server.broadcastradio.hal2; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; + import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertThrows; @@ -45,6 +47,10 @@ import android.hardware.radio.RadioTuner; import android.util.ArrayMap; import android.util.ArraySet; +import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; +import com.android.server.broadcastradio.ExtendedRadioMockitoTestCase; +import com.android.server.broadcastradio.RadioServiceUserController; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -61,7 +67,7 @@ import java.util.Map; * Tests for HIDL HAL TunerSession. */ @RunWith(MockitoJUnitRunner.class) -public final class TunerSessionHidlTest { +public final class TunerSessionHidlTest extends ExtendedRadioMockitoTestCase { private static final VerificationWithTimeout CALLBACK_TIMEOUT = timeout(/* millis= */ 200); @@ -88,8 +94,15 @@ public final class TunerSessionHidlTest { @Mock ITunerSession mHalTunerSessionMock; private android.hardware.radio.ITunerCallback[] mAidlTunerCallbackMocks; + @Override + protected void initializeSession(StaticMockitoSessionBuilder builder) { + builder.spyStatic(RadioServiceUserController.class); + } + @Before public void setup() throws Exception { + doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser()); + mRadioModule = new RadioModule(mBroadcastRadioMock, TestUtils.makeDefaultModuleProperties(), mLock); diff --git a/services/core/java/com/android/server/broadcastradio/RadioServiceUserController.java b/services/core/java/com/android/server/broadcastradio/RadioServiceUserController.java new file mode 100644 index 0000000000000..38b3233953293 --- /dev/null +++ b/services/core/java/com/android/server/broadcastradio/RadioServiceUserController.java @@ -0,0 +1,56 @@ +/** + * 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.broadcastradio; + +import android.app.ActivityManager; +import android.os.Binder; +import android.os.UserHandle; + +/** + * Controller to handle users in {@link com.android.server.broadcastradio.BroadcastRadioService} + */ +public final class RadioServiceUserController { + + private RadioServiceUserController() { + throw new UnsupportedOperationException( + "RadioServiceUserController class is noninstantiable"); + } + + /** + * Check if the user calling the method in Broadcast Radio Service is the current user or the + * system user. + * + * @return {@code true} if the user calling this method is the current user of system user, + * {@code false} otherwise. + */ + public static boolean isCurrentOrSystemUser() { + int callingUser = Binder.getCallingUserHandle().getIdentifier(); + final long identity = Binder.clearCallingIdentity(); + try { + int currentUser = ActivityManager.getCurrentUser(); + if (callingUser != currentUser && callingUser != UserHandle.USER_SYSTEM) { + return false; + } + return true; + } catch (RuntimeException e) { + // Activity manager not running, nothing we can do assume user 0. + } finally { + Binder.restoreCallingIdentity(identity); + } + return false; + } +} diff --git a/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java b/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java index 4fcfea2d0e070..1d7112133b486 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java @@ -34,6 +34,7 @@ import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; +import com.android.server.broadcastradio.RadioServiceUserController; import com.android.server.utils.Slogf; import java.util.ArrayList; @@ -149,8 +150,7 @@ public final class BroadcastRadioServiceImpl { public BroadcastRadioServiceImpl(ArrayList serviceNameList) { mNextModuleId = 0; if (DEBUG) { - Slogf.d(TAG, "Initializing BroadcastRadioServiceImpl %s", - IBroadcastRadio.DESCRIPTOR); + Slogf.d(TAG, "Initializing BroadcastRadioServiceImpl %s", IBroadcastRadio.DESCRIPTOR); } for (int i = 0; i < serviceNameList.size(); i++) { try { @@ -203,6 +203,10 @@ public final class BroadcastRadioServiceImpl { if (DEBUG) { Slogf.d(TAG, "Open AIDL radio session"); } + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.e(TAG, "Cannot open tuner on AIDL HAL client for non-current user"); + throw new IllegalStateException("Cannot open session for non-current user"); + } Objects.requireNonNull(callback); if (!withAudio) { 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 d4c7242f71a92..eb9dafbe5281b 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java @@ -175,7 +175,7 @@ final class RadioModule { } @Nullable - public static RadioModule tryLoadingModule(int moduleId, String moduleName, + static RadioModule tryLoadingModule(int moduleId, String moduleName, IBinder serviceBinder, Object lock) { try { Slogf.i(TAG, "Try loading module for module id = %d, module name = %s", @@ -213,11 +213,11 @@ final class RadioModule { } } - public IBroadcastRadio getService() { + IBroadcastRadio getService() { return mService; } - public RadioManager.ModuleProperties getProperties() { + RadioManager.ModuleProperties getProperties() { return mProperties; } @@ -227,7 +227,7 @@ final class RadioModule { } } - public TunerSession openSession(android.hardware.radio.ITunerCallback userCb) + TunerSession openSession(android.hardware.radio.ITunerCallback userCb) throws RemoteException { mLogger.logRadioEvent("Open TunerSession"); TunerSession tunerSession; @@ -252,7 +252,7 @@ final class RadioModule { return tunerSession; } - public void closeSessions(int error) { + void closeSessions(int error) { mLogger.logRadioEvent("Close TunerSessions %d", error); // TunerSession.close() must be called without mAidlTunerSessions locked because // it can call onTunerSessionClosed(). Therefore, the contents of mAidlTunerSessions @@ -275,8 +275,7 @@ final class RadioModule { @GuardedBy("mLock") @Nullable - private android.hardware.radio.ProgramList.Filter - buildUnionOfTunerSessionFiltersLocked() { + private android.hardware.radio.ProgramList.Filter buildUnionOfTunerSessionFiltersLocked() { Set idTypes = null; Set ids = null; boolean includeCategories = false; @@ -423,7 +422,7 @@ final class RadioModule { } } - public android.hardware.radio.ICloseHandle addAnnouncementListener( + android.hardware.radio.ICloseHandle addAnnouncementListener( android.hardware.radio.IAnnouncementListener listener, int[] enabledTypes) throws RemoteException { mLogger.logRadioEvent("Add AnnouncementListener"); 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 7c26a8741a03a..d33633c435b10 100644 --- a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java +++ b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java @@ -26,10 +26,12 @@ import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.os.RemoteException; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.IndentingPrintWriter; import com.android.internal.annotations.GuardedBy; +import com.android.server.broadcastradio.RadioServiceUserController; import com.android.server.utils.Slogf; import java.util.List; @@ -70,7 +72,7 @@ final class TunerSession extends ITuner.Stub { @Override public void close() { - mLogger.logRadioEvent("Close tuner session"); + mLogger.logRadioEvent("Close tuner"); close(null); } @@ -118,6 +120,10 @@ final class TunerSession extends ITuner.Stub { @Override public void setConfiguration(RadioManager.BandConfig config) { + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot set configuration for AIDL HAL client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); mPlaceHolderConfig = Objects.requireNonNull(config, "config cannot be null"); @@ -157,6 +163,10 @@ final class TunerSession extends ITuner.Stub { public void step(boolean directionDown, boolean skipSubChannel) throws RemoteException { mLogger.logRadioEvent("Step with direction %s, skipSubChannel? %s", directionDown ? "down" : "up", skipSubChannel ? "yes" : "no"); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot step on AIDL HAL client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); try { @@ -171,6 +181,10 @@ final class TunerSession extends ITuner.Stub { public void scan(boolean directionDown, boolean skipSubChannel) throws RemoteException { mLogger.logRadioEvent("Scan with direction %s, skipSubChannel? %s", directionDown ? "down" : "up", skipSubChannel ? "yes" : "no"); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot scan on AIDL HAL client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); try { @@ -184,6 +198,10 @@ final class TunerSession extends ITuner.Stub { @Override public void tune(ProgramSelector selector) throws RemoteException { mLogger.logRadioEvent("Tune with selector %s", selector); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot tune on AIDL HAL client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); try { @@ -197,6 +215,10 @@ final class TunerSession extends ITuner.Stub { @Override public void cancel() { Slogf.i(TAG, "Cancel"); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot cancel on AIDL HAL client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); try { @@ -223,6 +245,10 @@ final class TunerSession extends ITuner.Stub { @Override public boolean startBackgroundScan() { Slogf.i(TAG, "Explicit background scan trigger is not supported with HAL AIDL"); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot start background scan on AIDL HAL client from non-current user"); + return false; + } mModule.fanoutAidlCallback(ITunerCallback::onBackgroundScanComplete); return true; } @@ -230,6 +256,11 @@ final class TunerSession extends ITuner.Stub { @Override public void startProgramListUpdates(ProgramList.Filter filter) throws RemoteException { mLogger.logRadioEvent("Start programList updates %s", filter); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, + "Cannot start program list updates on AIDL HAL client from non-current user"); + return; + } // If the AIDL client provides a null filter, it wants all updates, so use the most broad // filter. if (filter == null) { @@ -291,6 +322,11 @@ final class TunerSession extends ITuner.Stub { @Override public void stopProgramListUpdates() throws RemoteException { mLogger.logRadioEvent("Stop programList updates"); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, + "Cannot stop program list updates on AIDL HAL client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); mProgramInfoCache = null; @@ -331,6 +367,10 @@ final class TunerSession extends ITuner.Stub { public void setConfigFlag(int flag, boolean value) throws RemoteException { mLogger.logRadioEvent("set ConfigFlag %s to %b ", ConfigFlag.$.toString(flag), value); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot set config flag for AIDL HAL client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); try { @@ -344,6 +384,10 @@ final class TunerSession extends ITuner.Stub { @Override public Map setParameters(Map parameters) { mLogger.logRadioEvent("Set parameters "); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot set parameters for AIDL HAL client from non-current user"); + return new ArrayMap<>(); + } synchronized (mLock) { checkNotClosedLocked(); try { diff --git a/services/core/java/com/android/server/broadcastradio/hal1/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal1/BroadcastRadioService.java index 5da60328cd709..e50c6e8c21b8d 100644 --- a/services/core/java/com/android/server/broadcastradio/hal1/BroadcastRadioService.java +++ b/services/core/java/com/android/server/broadcastradio/hal1/BroadcastRadioService.java @@ -21,10 +21,16 @@ import android.hardware.radio.ITuner; import android.hardware.radio.ITunerCallback; import android.hardware.radio.RadioManager; +import com.android.server.broadcastradio.RadioServiceUserController; +import com.android.server.utils.Slogf; + import java.util.List; import java.util.Objects; public class BroadcastRadioService { + + private static final String TAG = "BcRadio1Srv"; + /** * This field is used by native code, do not access or modify. */ @@ -48,7 +54,7 @@ public class BroadcastRadioService { * Constructor. should pass * {@code com.android.server.broadcastradio.BroadcastRadioService#mLock} for lock. */ - public BroadcastRadioService(@NonNull Object lock) { + public BroadcastRadioService(Object lock) { mLock = lock; } @@ -59,7 +65,11 @@ public class BroadcastRadioService { } public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig, - boolean withAudio, @NonNull ITunerCallback callback) { + boolean withAudio, ITunerCallback callback) { + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.e(TAG, "Cannot open tuner on HAL 1.x client for non-current user"); + throw new IllegalStateException("Cannot open tuner for non-current user"); + } synchronized (mLock) { return nativeOpenTuner(mNativeContext, moduleId, bandConfig, withAudio, callback); } diff --git a/services/core/java/com/android/server/broadcastradio/hal1/Convert.java b/services/core/java/com/android/server/broadcastradio/hal1/Convert.java index 80c776254d981..219ee4c3229ae 100644 --- a/services/core/java/com/android/server/broadcastradio/hal1/Convert.java +++ b/services/core/java/com/android/server/broadcastradio/hal1/Convert.java @@ -24,7 +24,8 @@ import java.util.Map; import java.util.Set; class Convert { - private static final String TAG = "BroadcastRadioService.Convert"; + + private static final String TAG = "BcRadio1Srv.Convert"; /** * Converts string map to an array that's easily accessible by native code. diff --git a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java index e7118ad72bf42..ed8a37aab14a3 100644 --- a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java +++ b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java @@ -28,11 +28,15 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; +import com.android.server.broadcastradio.RadioServiceUserController; +import com.android.server.utils.Slogf; + import java.util.List; import java.util.Map; class Tuner extends ITuner.Stub { - private static final String TAG = "BroadcastRadioService.Tuner"; + + private static final String TAG = "BcRadio1Srv.Tuner"; /** * This field is used by native code, do not access or modify. @@ -124,6 +128,10 @@ class Tuner extends ITuner.Stub { @Override public void setConfiguration(RadioManager.BandConfig config) { + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot set configuration for HAL 1.x client from non-current user"); + return; + } if (config == null) { throw new IllegalArgumentException("The argument must not be a null pointer"); } @@ -169,6 +177,10 @@ class Tuner extends ITuner.Stub { @Override public void step(boolean directionDown, boolean skipSubChannel) { + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot step on HAL 1.x client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); if (!checkConfiguredLocked()) return; @@ -178,6 +190,10 @@ class Tuner extends ITuner.Stub { @Override public void scan(boolean directionDown, boolean skipSubChannel) { + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot scan on HAL 1.x client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); if (!checkConfiguredLocked()) return; @@ -187,6 +203,10 @@ class Tuner extends ITuner.Stub { @Override public void tune(ProgramSelector selector) { + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot tune on HAL 1.x client from non-current user"); + return; + } if (selector == null) { throw new IllegalArgumentException("The argument must not be a null pointer"); } @@ -200,6 +220,10 @@ class Tuner extends ITuner.Stub { @Override public void cancel() { + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot cancel on HAL 1.x client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); nativeCancel(mNativeContext); @@ -208,6 +232,10 @@ class Tuner extends ITuner.Stub { @Override public void cancelAnnouncement() { + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot cancel announcement on HAL 1.x client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); nativeCancelAnnouncement(mNativeContext); @@ -233,6 +261,11 @@ class Tuner extends ITuner.Stub { @Override public boolean startBackgroundScan() { + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, + "Cannot start background scan on HAL 1.x client from non-current user"); + return false; + } synchronized (mLock) { checkNotClosedLocked(); return nativeStartBackgroundScan(mNativeContext); @@ -253,11 +286,21 @@ class Tuner extends ITuner.Stub { @Override public void startProgramListUpdates(ProgramList.Filter filter) { + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, + "Cannot start program list updates on HAL 1.x client from non-current user"); + return; + } mTunerCallback.startProgramListUpdates(filter); } @Override public void stopProgramListUpdates() { + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, + "Cannot stop program list updates on HAL 1.x client from non-current user"); + return; + } mTunerCallback.stopProgramListUpdates(); } @@ -279,6 +322,10 @@ class Tuner extends ITuner.Stub { @Override public void setConfigFlag(int flag, boolean value) { + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot set config flag for HAL 1.x client from non-current user"); + return; + } if (flag == RadioManager.CONFIG_FORCE_ANALOG) { synchronized (mLock) { checkNotClosedLocked(); diff --git a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java index 867d5b4b6f49b..0cc3833896bec 100644 --- a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java +++ b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java @@ -34,7 +34,8 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; class TunerCallback implements ITunerCallback { - private static final String TAG = "BroadcastRadioService.TunerCallback"; + + private static final String TAG = "BcRadio1Srv.TunerCallback"; /** * This field is used by native code, do not access or modify. diff --git a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java index 4c3760928df32..3d6962783f4a5 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java @@ -34,6 +34,8 @@ import android.util.Slog; 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.Collection; import java.util.HashMap; @@ -168,6 +170,10 @@ public class BroadcastRadioService { public ITuner openSession(int moduleId, @Nullable RadioManager.BandConfig legacyConfig, boolean withAudio, @NonNull ITunerCallback callback) throws RemoteException { Slog.v(TAG, "Open HIDL 2.0 session with module id " + moduleId); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.e(TAG, "Cannot open tuner on HAL 2.0 client for non-current user"); + throw new IllegalStateException("Cannot open session for non-current user"); + } Objects.requireNonNull(callback); if (!withAudio) { diff --git a/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java b/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java index 6654c0c2304d2..9831af6b523ea 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java @@ -33,7 +33,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -class ProgramInfoCache { +final class ProgramInfoCache { // Maximum number of RadioManager.ProgramInfo elements that will be put into a // ProgramList.Chunk.mModified array. Used to try to ensure a single ProgramList.Chunk stays // within the AIDL data size limit. 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 5913e0685eb4f..cf1b504037bc9 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java @@ -53,7 +53,7 @@ import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; -class RadioModule { +final class RadioModule { private static final String TAG = "BcRadio2Srv.module"; private static final int RADIO_EVENT_LOGGER_QUEUE_SIZE = 25; @@ -143,7 +143,8 @@ class RadioModule { mEventLogger = new RadioEventLogger(TAG, RADIO_EVENT_LOGGER_QUEUE_SIZE); } - public static @Nullable RadioModule tryLoadingModule(int idx, @NonNull String fqName, + @Nullable + static RadioModule tryLoadingModule(int idx, @NonNull String fqName, Object lock) { try { Slog.i(TAG, "Try loading module for idx " + idx + ", fqName " + fqName); @@ -173,7 +174,8 @@ class RadioModule { } } - public @NonNull IBroadcastRadio getService() { + @NonNull + IBroadcastRadio getService() { return mService; } @@ -181,7 +183,7 @@ class RadioModule { return mProperties; } - public @NonNull TunerSession openSession(@NonNull android.hardware.radio.ITunerCallback userCb) + TunerSession openSession(@NonNull android.hardware.radio.ITunerCallback userCb) throws RemoteException { mEventLogger.logRadioEvent("Open TunerSession"); synchronized (mLock) { @@ -211,7 +213,7 @@ class RadioModule { } } - public void closeSessions(Integer error) { + void closeSessions(Integer error) { // Copy the contents of mAidlTunerSessions into a local array because TunerSession.close() // must be called without mAidlTunerSessions locked because it can call // onTunerSessionClosed(). @@ -227,7 +229,8 @@ class RadioModule { } } - private @Nullable android.hardware.radio.ProgramList.Filter + @Nullable + private android.hardware.radio.ProgramList.Filter buildUnionOfTunerSessionFiltersLocked() { Set idTypes = null; Set ids = null; @@ -378,8 +381,8 @@ class RadioModule { } } - public android.hardware.radio.ICloseHandle addAnnouncementListener(@NonNull int[] enabledTypes, - @NonNull android.hardware.radio.IAnnouncementListener listener) throws RemoteException { + android.hardware.radio.ICloseHandle addAnnouncementListener(int[] enabledTypes, + android.hardware.radio.IAnnouncementListener listener) throws RemoteException { mEventLogger.logRadioEvent("Add AnnouncementListener"); ArrayList enabledList = new ArrayList<>(); for (int type : enabledTypes) { 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 918dc98e3a9e7..12211eed47fda 100644 --- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java +++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java @@ -27,11 +27,15 @@ import android.hardware.radio.ProgramList; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.os.RemoteException; +import android.util.ArrayMap; import android.util.IndentingPrintWriter; import android.util.MutableBoolean; import android.util.MutableInt; import android.util.Slog; +import com.android.server.broadcastradio.RadioServiceUserController; +import com.android.server.utils.Slogf; + import java.util.HashSet; import java.util.List; import java.util.Map; @@ -107,6 +111,10 @@ class TunerSession extends ITuner.Stub { @Override public void setConfiguration(RadioManager.BandConfig config) { + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot set configuration for HAL 2.0 client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); mDummyConfig = Objects.requireNonNull(config); @@ -145,6 +153,10 @@ class TunerSession extends ITuner.Stub { public void step(boolean directionDown, boolean skipSubChannel) throws RemoteException { mEventLogger.logRadioEvent("Step with direction %s, skipSubChannel? %s", directionDown ? "down" : "up", skipSubChannel ? "yes" : "no"); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot step on HAL 2.0 client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); int halResult = mHwSession.step(!directionDown); @@ -156,6 +168,10 @@ class TunerSession extends ITuner.Stub { public void scan(boolean directionDown, boolean skipSubChannel) throws RemoteException { mEventLogger.logRadioEvent("Scan with direction %s, skipSubChannel? %s", directionDown ? "down" : "up", skipSubChannel ? "yes" : "no"); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot scan on HAL 2.0 client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); int halResult = mHwSession.scan(!directionDown, skipSubChannel); @@ -166,6 +182,10 @@ class TunerSession extends ITuner.Stub { @Override public void tune(ProgramSelector selector) throws RemoteException { mEventLogger.logRadioEvent("Tune with selector %s", selector); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot tune on HAL 2.0 client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); int halResult = mHwSession.tune(Convert.programSelectorToHal(selector)); @@ -176,6 +196,10 @@ class TunerSession extends ITuner.Stub { @Override public void cancel() { Slog.i(TAG, "Cancel"); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot cancel on HAL 2.0 client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); Utils.maybeRethrow(mHwSession::cancel); @@ -196,6 +220,11 @@ class TunerSession extends ITuner.Stub { @Override public boolean startBackgroundScan() { Slog.i(TAG, "Explicit background scan trigger is not supported with HAL 2.0"); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, + "Cannot start background scan on HAL 2.0 client from non-current user"); + return false; + } mModule.fanoutAidlCallback(cb -> cb.onBackgroundScanComplete()); return true; } @@ -203,6 +232,11 @@ class TunerSession extends ITuner.Stub { @Override public void startProgramListUpdates(ProgramList.Filter filter) throws RemoteException { mEventLogger.logRadioEvent("start programList updates %s", filter); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, + "Cannot start program list updates on HAL 2.0 client from non-current user"); + return; + } // If the AIDL client provides a null filter, it wants all updates, so use the most broad // filter. if (filter == null) { @@ -262,6 +296,11 @@ class TunerSession extends ITuner.Stub { @Override public void stopProgramListUpdates() throws RemoteException { mEventLogger.logRadioEvent("Stop programList updates"); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, + "Cannot stop program list updates on HAL 2.0 client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); mProgramInfoCache = null; @@ -308,6 +347,10 @@ class TunerSession extends ITuner.Stub { @Override public void setConfigFlag(int flag, boolean value) throws RemoteException { mEventLogger.logRadioEvent("Set ConfigFlag %s = %b", ConfigFlag.toString(flag), value); + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot set config flag for HAL 2.0 client from non-current user"); + return; + } synchronized (mLock) { checkNotClosedLocked(); int halResult = mHwSession.setConfigFlag(flag, value); @@ -317,6 +360,10 @@ class TunerSession extends ITuner.Stub { @Override public Map setParameters(Map parameters) { + if (!RadioServiceUserController.isCurrentOrSystemUser()) { + Slogf.w(TAG, "Cannot set parameters for HAL 2.0 client from non-current user"); + return new ArrayMap<>(); + } synchronized (mLock) { checkNotClosedLocked(); return Convert.vendorInfoFromHal(Utils.maybeRethrow(