1 /** 2 * Copyright (C) 2022 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.Manifest; 20 import android.content.pm.PackageManager; 21 import android.hardware.radio.IAnnouncementListener; 22 import android.hardware.radio.ICloseHandle; 23 import android.hardware.radio.IRadioService; 24 import android.hardware.radio.ITuner; 25 import android.hardware.radio.ITunerCallback; 26 import android.hardware.radio.RadioManager; 27 import android.os.Binder; 28 import android.os.RemoteException; 29 import android.util.IndentingPrintWriter; 30 import android.util.Log; 31 import android.util.Slog; 32 33 import com.android.internal.annotations.GuardedBy; 34 import com.android.internal.annotations.VisibleForTesting; 35 import com.android.server.broadcastradio.hal2.AnnouncementAggregator; 36 37 import java.io.FileDescriptor; 38 import java.io.PrintWriter; 39 import java.util.ArrayList; 40 import java.util.Arrays; 41 import java.util.Collection; 42 import java.util.List; 43 import java.util.Objects; 44 import java.util.OptionalInt; 45 46 /** 47 * Wrapper for HIDL interface for BroadcastRadio HAL 48 */ 49 final class IRadioServiceHidlImpl extends IRadioService.Stub { 50 private static final String TAG = "BcRadioSrvHidl"; 51 52 private final com.android.server.broadcastradio.hal1.BroadcastRadioService mHal1Client; 53 private final com.android.server.broadcastradio.hal2.BroadcastRadioService mHal2Client; 54 55 private final Object mLock = new Object(); 56 57 private final BroadcastRadioService mService; 58 59 @GuardedBy("mLock") 60 private final List<RadioManager.ModuleProperties> mV1Modules; 61 IRadioServiceHidlImpl(BroadcastRadioService service, RadioServiceUserController userController)62 IRadioServiceHidlImpl(BroadcastRadioService service, 63 RadioServiceUserController userController) { 64 mService = Objects.requireNonNull(service, "broadcast radio service cannot be null"); 65 Objects.requireNonNull(userController, "user controller cannot be null"); 66 mHal1Client = new com.android.server.broadcastradio.hal1.BroadcastRadioService( 67 userController); 68 mV1Modules = mHal1Client.loadModules(); 69 OptionalInt max = mV1Modules.stream().mapToInt(RadioManager.ModuleProperties::getId).max(); 70 mHal2Client = new com.android.server.broadcastradio.hal2.BroadcastRadioService( 71 max.isPresent() ? max.getAsInt() + 1 : 0, userController); 72 } 73 74 @VisibleForTesting IRadioServiceHidlImpl(BroadcastRadioService service, com.android.server.broadcastradio.hal1.BroadcastRadioService hal1, com.android.server.broadcastradio.hal2.BroadcastRadioService hal2)75 IRadioServiceHidlImpl(BroadcastRadioService service, 76 com.android.server.broadcastradio.hal1.BroadcastRadioService hal1, 77 com.android.server.broadcastradio.hal2.BroadcastRadioService hal2) { 78 mService = Objects.requireNonNull(service, "Broadcast radio service cannot be null"); 79 mHal1Client = Objects.requireNonNull(hal1, 80 "Broadcast radio service implementation for HIDL 1 HAL cannot be null"); 81 mV1Modules = mHal1Client.loadModules(); 82 mHal2Client = Objects.requireNonNull(hal2, 83 "Broadcast radio service implementation for HIDL 2 HAL cannot be null"); 84 } 85 86 @Override listModules()87 public List<RadioManager.ModuleProperties> listModules() { 88 mService.enforcePolicyAccess(); 89 Collection<RadioManager.ModuleProperties> v2Modules = mHal2Client.listModules(); 90 List<RadioManager.ModuleProperties> modules; 91 synchronized (mLock) { 92 modules = new ArrayList<>(mV1Modules.size() + v2Modules.size()); 93 modules.addAll(mV1Modules); 94 } 95 modules.addAll(v2Modules); 96 return modules; 97 } 98 99 @Override openTuner(int moduleId, RadioManager.BandConfig bandConfig, boolean withAudio, ITunerCallback callback)100 public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig, 101 boolean withAudio, ITunerCallback callback) throws RemoteException { 102 if (isDebugEnabled()) { 103 Slog.d(TAG, "Opening module " + moduleId); 104 } 105 mService.enforcePolicyAccess(); 106 Objects.requireNonNull(callback, "Callback must not be null"); 107 synchronized (mLock) { 108 if (mHal2Client.hasModule(moduleId)) { 109 return mHal2Client.openSession(moduleId, bandConfig, withAudio, callback); 110 } else { 111 return mHal1Client.openTuner(moduleId, bandConfig, withAudio, callback); 112 } 113 } 114 } 115 116 @Override addAnnouncementListener(int[] enabledTypes, IAnnouncementListener listener)117 public ICloseHandle addAnnouncementListener(int[] enabledTypes, 118 IAnnouncementListener listener) { 119 if (isDebugEnabled()) { 120 Slog.d(TAG, "Adding announcement listener for " + Arrays.toString(enabledTypes)); 121 } 122 Objects.requireNonNull(enabledTypes, "Enabled announcement types cannot be null"); 123 Objects.requireNonNull(listener, "Announcement listener cannot be null"); 124 mService.enforcePolicyAccess(); 125 126 synchronized (mLock) { 127 if (!mHal2Client.hasAnyModules()) { 128 Slog.w(TAG, "There are no HAL 2.0 modules registered"); 129 return new AnnouncementAggregator(listener, mLock); 130 } 131 132 return mHal2Client.addAnnouncementListener(enabledTypes, listener); 133 } 134 } 135 136 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)137 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 138 if (mService.getContext().checkCallingOrSelfPermission(Manifest.permission.DUMP) 139 != PackageManager.PERMISSION_GRANTED) { 140 pw.println("Permission Denial: can't dump HIDL BroadcastRadioService from " 141 + "from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() 142 + " without permission " + Manifest.permission.DUMP); 143 return; 144 } 145 IndentingPrintWriter radioPw = new IndentingPrintWriter(pw); 146 radioPw.printf("BroadcastRadioService\n"); 147 148 radioPw.increaseIndent(); 149 radioPw.printf("HAL1 client: %s\n", mHal1Client); 150 151 radioPw.increaseIndent(); 152 synchronized (mLock) { 153 radioPw.printf("Modules of HAL1 client: %s\n", mV1Modules); 154 } 155 radioPw.decreaseIndent(); 156 157 radioPw.printf("HAL2 client:\n"); 158 159 radioPw.increaseIndent(); 160 mHal2Client.dumpInfo(radioPw); 161 radioPw.decreaseIndent(); 162 163 radioPw.decreaseIndent(); 164 } 165 166 isDebugEnabled()167 private static boolean isDebugEnabled() { 168 return Log.isLoggable(TAG, Log.DEBUG); 169 } 170 } 171