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)62 IRadioServiceHidlImpl(BroadcastRadioService service) { 63 mService = Objects.requireNonNull(service, "broadcast radio service cannot be null"); 64 mHal1Client = new com.android.server.broadcastradio.hal1.BroadcastRadioService(); 65 mV1Modules = mHal1Client.loadModules(); 66 OptionalInt max = mV1Modules.stream().mapToInt(RadioManager.ModuleProperties::getId).max(); 67 mHal2Client = new com.android.server.broadcastradio.hal2.BroadcastRadioService( 68 max.isPresent() ? max.getAsInt() + 1 : 0); 69 } 70 71 @VisibleForTesting IRadioServiceHidlImpl(BroadcastRadioService service, com.android.server.broadcastradio.hal1.BroadcastRadioService hal1, com.android.server.broadcastradio.hal2.BroadcastRadioService hal2)72 IRadioServiceHidlImpl(BroadcastRadioService service, 73 com.android.server.broadcastradio.hal1.BroadcastRadioService hal1, 74 com.android.server.broadcastradio.hal2.BroadcastRadioService hal2) { 75 mService = Objects.requireNonNull(service, "Broadcast radio service cannot be null"); 76 mHal1Client = Objects.requireNonNull(hal1, 77 "Broadcast radio service implementation for HIDL 1 HAL cannot be null"); 78 mV1Modules = mHal1Client.loadModules(); 79 mHal2Client = Objects.requireNonNull(hal2, 80 "Broadcast radio service implementation for HIDL 2 HAL cannot be null"); 81 } 82 83 @Override listModules()84 public List<RadioManager.ModuleProperties> listModules() { 85 mService.enforcePolicyAccess(); 86 Collection<RadioManager.ModuleProperties> v2Modules = mHal2Client.listModules(); 87 List<RadioManager.ModuleProperties> modules; 88 synchronized (mLock) { 89 modules = new ArrayList<>(mV1Modules.size() + v2Modules.size()); 90 modules.addAll(mV1Modules); 91 } 92 modules.addAll(v2Modules); 93 return modules; 94 } 95 96 @Override openTuner(int moduleId, RadioManager.BandConfig bandConfig, boolean withAudio, ITunerCallback callback)97 public ITuner openTuner(int moduleId, RadioManager.BandConfig bandConfig, 98 boolean withAudio, ITunerCallback callback) throws RemoteException { 99 if (isDebugEnabled()) { 100 Slog.d(TAG, "Opening module " + moduleId); 101 } 102 mService.enforcePolicyAccess(); 103 Objects.requireNonNull(callback, "Callback must not be null"); 104 synchronized (mLock) { 105 if (mHal2Client.hasModule(moduleId)) { 106 return mHal2Client.openSession(moduleId, bandConfig, withAudio, callback); 107 } else { 108 return mHal1Client.openTuner(moduleId, bandConfig, withAudio, callback); 109 } 110 } 111 } 112 113 @Override addAnnouncementListener(int[] enabledTypes, IAnnouncementListener listener)114 public ICloseHandle addAnnouncementListener(int[] enabledTypes, 115 IAnnouncementListener listener) { 116 if (isDebugEnabled()) { 117 Slog.d(TAG, "Adding announcement listener for " + Arrays.toString(enabledTypes)); 118 } 119 Objects.requireNonNull(enabledTypes, "Enabled announcement types cannot be null"); 120 Objects.requireNonNull(listener, "Announcement listener cannot be null"); 121 mService.enforcePolicyAccess(); 122 123 synchronized (mLock) { 124 if (!mHal2Client.hasAnyModules()) { 125 Slog.w(TAG, "There are no HAL 2.0 modules registered"); 126 return new AnnouncementAggregator(listener, mLock); 127 } 128 129 return mHal2Client.addAnnouncementListener(enabledTypes, listener); 130 } 131 } 132 133 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)134 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 135 if (mService.getContext().checkCallingOrSelfPermission(Manifest.permission.DUMP) 136 != PackageManager.PERMISSION_GRANTED) { 137 pw.println("Permission Denial: can't dump HIDL BroadcastRadioService from " 138 + "from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() 139 + " without permission " + Manifest.permission.DUMP); 140 return; 141 } 142 IndentingPrintWriter radioPw = new IndentingPrintWriter(pw); 143 radioPw.printf("BroadcastRadioService\n"); 144 145 radioPw.increaseIndent(); 146 radioPw.printf("HAL1 client: %s\n", mHal1Client); 147 148 radioPw.increaseIndent(); 149 synchronized (mLock) { 150 radioPw.printf("Modules of HAL1 client: %s\n", mV1Modules); 151 } 152 radioPw.decreaseIndent(); 153 154 radioPw.printf("HAL2 client:\n"); 155 156 radioPw.increaseIndent(); 157 mHal2Client.dumpInfo(radioPw); 158 radioPw.decreaseIndent(); 159 160 radioPw.decreaseIndent(); 161 } 162 163 isDebugEnabled()164 private static boolean isDebugEnabled() { 165 return Log.isLoggable(TAG, Log.DEBUG); 166 } 167 } 168