Home | History | Annotate | Download | only in broadcastradio
      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