1 /** 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.broadcastradio; 18 19 import android.annotation.NonNull; 20 import android.Manifest; 21 import android.content.Context; 22 import android.content.pm.PackageManager; 23 import android.hardware.radio.IAnnouncementListener; 24 import android.hardware.radio.ICloseHandle; 25 import android.hardware.radio.IRadioService; 26 import android.hardware.radio.ITuner; 27 import android.hardware.radio.ITunerCallback; 28 import android.hardware.radio.RadioManager; 29 import android.os.ParcelableException; 30 import android.os.RemoteException; 31 import android.util.Slog; 32 33 import com.android.internal.util.Preconditions; 34 import com.android.server.SystemService; 35 import com.android.server.broadcastradio.hal2.AnnouncementAggregator; 36 37 import java.util.Arrays; 38 import java.util.List; 39 import java.util.Objects; 40 import java.util.OptionalInt; 41 42 public class BroadcastRadioService extends SystemService { 43 private static final String TAG = "BcRadioSrv"; 44 private static final boolean DEBUG = false; 45 46 private final ServiceImpl mServiceImpl = new ServiceImpl(); 47 48 private final com.android.server.broadcastradio.hal1.BroadcastRadioService mHal1 = 49 new com.android.server.broadcastradio.hal1.BroadcastRadioService(); 50 private final com.android.server.broadcastradio.hal2.BroadcastRadioService mHal2 = 51 new com.android.server.broadcastradio.hal2.BroadcastRadioService(); 52 53 private final Object mLock = new Object(); 54 private List<RadioManager.ModuleProperties> mModules = null; 55 56 public BroadcastRadioService(Context context) { 57 super(context); 58 } 59 60 @Override 61 public void onStart() { 62 publishBinderService(Context.RADIO_SERVICE, mServiceImpl); 63 } 64 65 /** 66 * Finds next available index for newly loaded modules. 67 */ 68 private static int getNextId(@NonNull List<RadioManager.ModuleProperties> modules) { 69 OptionalInt max = modules.stream().mapToInt(RadioManager.ModuleProperties::getId).max(); 70 return max.isPresent() ? max.getAsInt() + 1 : 0; 71 } 72 73 private class ServiceImpl extends IRadioService.Stub { 74 private void enforcePolicyAccess() { 75 if (PackageManager.PERMISSION_GRANTED != getContext().checkCallingPermission( 76 Manifest.permission.ACCESS_BROADCAST_RADIO)) { 77 throw new SecurityException("ACCESS_BROADCAST_RADIO permission not granted"); 78 } 79 } 80 81 @Override 82 public List<RadioManager.ModuleProperties> listModules() { 83 enforcePolicyAccess(); 84 synchronized (mLock) { 85 if (mModules != null) return mModules; 86 87 mModules = mHal1.loadModules(); 88 mModules.addAll(mHal2.loadModules(getNextId(mModules))); 89 90 return mModules; 91 } 92 } 93 94 @Override 95 public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig, 96 boolean withAudio, ITunerCallback callback) throws RemoteException { 97 if (DEBUG) Slog.i(TAG, "Opening module " + moduleId); 98 enforcePolicyAccess(); 99 if (callback == null) { 100 throw new IllegalArgumentException("Callback must not be empty"); 101 } 102 synchronized (mLock) { 103 if (mHal2.hasModule(moduleId)) { 104 return mHal2.openSession(moduleId, bandConfig, withAudio, callback); 105 } else { 106 return mHal1.openTuner(moduleId, bandConfig, withAudio, callback); 107 } 108 } 109 } 110 111 @Override 112 public ICloseHandle addAnnouncementListener(int[] enabledTypes, 113 IAnnouncementListener listener) { 114 if (DEBUG) { 115 Slog.i(TAG, "Adding announcement listener for " + Arrays.toString(enabledTypes)); 116 } 117 Objects.requireNonNull(enabledTypes); 118 Objects.requireNonNull(listener); 119 enforcePolicyAccess(); 120 121 synchronized (mLock) { 122 if (!mHal2.hasAnyModules()) { 123 Slog.i(TAG, "There are no HAL 2.x modules registered"); 124 return new AnnouncementAggregator(listener); 125 } 126 127 return mHal2.addAnnouncementListener(enabledTypes, listener); 128 } 129 } 130 } 131 } 132