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
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<String> 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) {
|
||||
|
||||
@@ -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<Integer> idTypes = null;
|
||||
Set<android.hardware.radio.ProgramSelector.Identifier> 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");
|
||||
|
||||
@@ -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<String, String> setParameters(Map<String, String> 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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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<Integer> idTypes = null;
|
||||
Set<android.hardware.radio.ProgramSelector.Identifier> 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<Byte> enabledList = new ArrayList<>();
|
||||
for (int type : enabledTypes) {
|
||||
|
||||
@@ -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<String, String> setParameters(Map<String, String> 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(
|
||||
|
||||
Reference in New Issue
Block a user