Loading core/java/android/hardware/radio/RadioManager.java +2 −1 Original line number Diff line number Diff line Loading @@ -161,7 +161,8 @@ public class RadioManager { private final Set<Integer> mSupportedIdentifierTypes; @NonNull private final Map<String, String> mVendorInfo; ModuleProperties(int id, String serviceName, int classId, String implementor, /** @hide */ public ModuleProperties(int id, String serviceName, int classId, String implementor, String product, String version, String serial, int numTuners, int numAudioSources, boolean isCaptureSupported, BandDescriptor[] bands, boolean isBgScanSupported, @ProgramSelector.ProgramType int[] supportedProgramTypes, Loading services/core/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ java_library_static { static_libs: [ "time_zone_distro", "time_zone_distro_installer", "android.hardware.broadcastradio-V2.0-java", "android.hardware.health-V1.0-java", "android.hardware.health-V2.0-java", "android.hardware.weaver-V1.0-java", Loading services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java +17 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.broadcastradio; import android.annotation.NonNull; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; Loading @@ -28,10 +29,15 @@ import android.os.ParcelableException; import com.android.server.SystemService; import java.util.List; import java.util.Objects; import java.util.OptionalInt; public class BroadcastRadioService extends SystemService { private final ServiceImpl mServiceImpl = new ServiceImpl(); private final com.android.server.broadcastradio.hal2.BroadcastRadioService mHal2 = new com.android.server.broadcastradio.hal2.BroadcastRadioService(); /** * This field is used by native code, do not access or modify. */ Loading Loading @@ -61,6 +67,14 @@ public class BroadcastRadioService extends SystemService { publishBinderService(Context.RADIO_SERVICE, mServiceImpl); } /** * Finds next available index for newly loaded modules. */ private static int getNextId(@NonNull List<RadioManager.ModuleProperties> modules) { OptionalInt max = modules.stream().mapToInt(RadioManager.ModuleProperties::getId).max(); return max.isPresent() ? max.getAsInt() + 1 : 0; } private class ServiceImpl extends IRadioService.Stub { private void enforcePolicyAccess() { if (PackageManager.PERMISSION_GRANTED != getContext().checkCallingPermission( Loading @@ -78,9 +92,11 @@ public class BroadcastRadioService extends SystemService { mModules = nativeLoadModules(mNativeContext); if (mModules == null) { throw new ParcelableException(new NullPointerException( "couldn't load radio modules")); "couldn't load radio HAL 1.x modules")); } mModules.addAll(mHal2.loadModules(getNextId(mModules))); return mModules; } } Loading services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java 0 → 100644 +75 −0 Original line number Diff line number Diff line /** * Copyright (C) 2017 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.hal2; import android.annotation.NonNull; import android.hardware.radio.RadioManager; import android.hardware.broadcastradio.V2_0.IBroadcastRadio; import android.hidl.manager.V1_0.IServiceManager; import android.os.RemoteException; import android.util.Slog; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class BroadcastRadioService { private static final String TAG = "BcRadio2Srv"; private final Map<Integer, RadioModule> mModules = new HashMap<>(); private static @NonNull List<String> listByInterface(@NonNull String fqName) { try { IServiceManager manager = IServiceManager.getService(); if (manager == null) { Slog.e(TAG, "Failed to get HIDL Service Manager"); return Collections.emptyList(); } List<String> list = manager.listByInterface(fqName); if (list == null) { Slog.e(TAG, "Didn't get interface list from HIDL Service Manager"); return Collections.emptyList(); } return list; } catch (RemoteException ex) { Slog.e(TAG, "Failed fetching interface list", ex); return Collections.emptyList(); } } public @NonNull Collection<RadioManager.ModuleProperties> loadModules(int idx) { Slog.v(TAG, "loadModules(" + idx + ")"); for (String serviceName : listByInterface(IBroadcastRadio.kInterfaceName)) { Slog.v(TAG, "checking service: " + serviceName); RadioModule module = RadioModule.tryLoadingModule(idx, serviceName); if (module != null) { Slog.i(TAG, "loaded broadcast radio module " + idx + ": " + serviceName + " (HAL 2.0)"); mModules.put(idx++, module); } } return mModules.values().stream().map(module -> module.mProperties). collect(Collectors.toList()); } } services/core/java/com/android/server/broadcastradio/hal2/Convert.java 0 → 100644 +132 −0 Original line number Diff line number Diff line /** * Copyright (C) 2017 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.hal2; import android.annotation.NonNull; import android.annotation.Nullable; import android.hardware.broadcastradio.V2_0.Properties; import android.hardware.broadcastradio.V2_0.VendorKeyValue; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.util.Slog; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; class Convert { private static final String TAG = "BcRadio2Srv.convert"; private static @NonNull Map<String, String> vendorInfoFromHal(@Nullable List<VendorKeyValue> info) { if (info == null) return Collections.emptyMap(); Map<String, String> map = new HashMap<>(); for (VendorKeyValue kvp : info) { if (kvp.key == null || kvp.value == null) { Slog.w(TAG, "VendorKeyValue contains null pointers"); continue; } map.put(kvp.key, kvp.value); } return map; } private static @NonNull int[] identifierTypesToProgramTypes(@NonNull int[] idTypes) { Set<Integer> pTypes = new HashSet<>(); for (int idType : idTypes) { switch (idType) { case ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY: case ProgramSelector.IDENTIFIER_TYPE_RDS_PI: // TODO(b/69958423): verify AM/FM with region info pTypes.add(ProgramSelector.PROGRAM_TYPE_AM); pTypes.add(ProgramSelector.PROGRAM_TYPE_FM); break; case ProgramSelector.IDENTIFIER_TYPE_HD_STATION_ID_EXT: // TODO(b/69958423): verify AM/FM with region info pTypes.add(ProgramSelector.PROGRAM_TYPE_AM_HD); pTypes.add(ProgramSelector.PROGRAM_TYPE_FM_HD); break; case ProgramSelector.IDENTIFIER_TYPE_DAB_SIDECC: case ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE: case ProgramSelector.IDENTIFIER_TYPE_DAB_SCID: case ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY: pTypes.add(ProgramSelector.PROGRAM_TYPE_DAB); break; case ProgramSelector.IDENTIFIER_TYPE_DRMO_SERVICE_ID: case ProgramSelector.IDENTIFIER_TYPE_DRMO_FREQUENCY: pTypes.add(ProgramSelector.PROGRAM_TYPE_DRMO); break; case ProgramSelector.IDENTIFIER_TYPE_SXM_SERVICE_ID: case ProgramSelector.IDENTIFIER_TYPE_SXM_CHANNEL: pTypes.add(ProgramSelector.PROGRAM_TYPE_SXM); break; default: break; } if (idType >= ProgramSelector.IDENTIFIER_TYPE_VENDOR_PRIMARY_START && idType <= ProgramSelector.IDENTIFIER_TYPE_VENDOR_PRIMARY_END) { pTypes.add(idType); } } return pTypes.stream().mapToInt(Integer::intValue).toArray(); } static @NonNull RadioManager.ModuleProperties propertiesFromHal(int id, @NonNull String serviceName, Properties prop) { Objects.requireNonNull(prop); // TODO(b/69958423): implement region info RadioManager.BandDescriptor[] bands = new RadioManager.BandDescriptor[0]; int[] supportedIdentifierTypes = prop.supportedIdentifierTypes.stream(). mapToInt(Integer::intValue).toArray(); int[] supportedProgramTypes = identifierTypesToProgramTypes(supportedIdentifierTypes); return new RadioManager.ModuleProperties( id, serviceName, // There is no Class concept in HAL 2.0. RadioManager.CLASS_AM_FM, prop.maker, prop.product, prop.version, prop.serial, /* HAL 2.0 only supports single tuner and audio source per * HAL implementation instance. */ 1, // numTuners 1, // numAudioSources false, // isCaptureSupported bands, true, // isBgScanSupported is deprecated supportedProgramTypes, supportedIdentifierTypes, vendorInfoFromHal(prop.vendorInfo)); } } Loading
core/java/android/hardware/radio/RadioManager.java +2 −1 Original line number Diff line number Diff line Loading @@ -161,7 +161,8 @@ public class RadioManager { private final Set<Integer> mSupportedIdentifierTypes; @NonNull private final Map<String, String> mVendorInfo; ModuleProperties(int id, String serviceName, int classId, String implementor, /** @hide */ public ModuleProperties(int id, String serviceName, int classId, String implementor, String product, String version, String serial, int numTuners, int numAudioSources, boolean isCaptureSupported, BandDescriptor[] bands, boolean isBgScanSupported, @ProgramSelector.ProgramType int[] supportedProgramTypes, Loading
services/core/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ java_library_static { static_libs: [ "time_zone_distro", "time_zone_distro_installer", "android.hardware.broadcastradio-V2.0-java", "android.hardware.health-V1.0-java", "android.hardware.health-V2.0-java", "android.hardware.weaver-V1.0-java", Loading
services/core/java/com/android/server/broadcastradio/BroadcastRadioService.java +17 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.broadcastradio; import android.annotation.NonNull; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; Loading @@ -28,10 +29,15 @@ import android.os.ParcelableException; import com.android.server.SystemService; import java.util.List; import java.util.Objects; import java.util.OptionalInt; public class BroadcastRadioService extends SystemService { private final ServiceImpl mServiceImpl = new ServiceImpl(); private final com.android.server.broadcastradio.hal2.BroadcastRadioService mHal2 = new com.android.server.broadcastradio.hal2.BroadcastRadioService(); /** * This field is used by native code, do not access or modify. */ Loading Loading @@ -61,6 +67,14 @@ public class BroadcastRadioService extends SystemService { publishBinderService(Context.RADIO_SERVICE, mServiceImpl); } /** * Finds next available index for newly loaded modules. */ private static int getNextId(@NonNull List<RadioManager.ModuleProperties> modules) { OptionalInt max = modules.stream().mapToInt(RadioManager.ModuleProperties::getId).max(); return max.isPresent() ? max.getAsInt() + 1 : 0; } private class ServiceImpl extends IRadioService.Stub { private void enforcePolicyAccess() { if (PackageManager.PERMISSION_GRANTED != getContext().checkCallingPermission( Loading @@ -78,9 +92,11 @@ public class BroadcastRadioService extends SystemService { mModules = nativeLoadModules(mNativeContext); if (mModules == null) { throw new ParcelableException(new NullPointerException( "couldn't load radio modules")); "couldn't load radio HAL 1.x modules")); } mModules.addAll(mHal2.loadModules(getNextId(mModules))); return mModules; } } Loading
services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java 0 → 100644 +75 −0 Original line number Diff line number Diff line /** * Copyright (C) 2017 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.hal2; import android.annotation.NonNull; import android.hardware.radio.RadioManager; import android.hardware.broadcastradio.V2_0.IBroadcastRadio; import android.hidl.manager.V1_0.IServiceManager; import android.os.RemoteException; import android.util.Slog; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class BroadcastRadioService { private static final String TAG = "BcRadio2Srv"; private final Map<Integer, RadioModule> mModules = new HashMap<>(); private static @NonNull List<String> listByInterface(@NonNull String fqName) { try { IServiceManager manager = IServiceManager.getService(); if (manager == null) { Slog.e(TAG, "Failed to get HIDL Service Manager"); return Collections.emptyList(); } List<String> list = manager.listByInterface(fqName); if (list == null) { Slog.e(TAG, "Didn't get interface list from HIDL Service Manager"); return Collections.emptyList(); } return list; } catch (RemoteException ex) { Slog.e(TAG, "Failed fetching interface list", ex); return Collections.emptyList(); } } public @NonNull Collection<RadioManager.ModuleProperties> loadModules(int idx) { Slog.v(TAG, "loadModules(" + idx + ")"); for (String serviceName : listByInterface(IBroadcastRadio.kInterfaceName)) { Slog.v(TAG, "checking service: " + serviceName); RadioModule module = RadioModule.tryLoadingModule(idx, serviceName); if (module != null) { Slog.i(TAG, "loaded broadcast radio module " + idx + ": " + serviceName + " (HAL 2.0)"); mModules.put(idx++, module); } } return mModules.values().stream().map(module -> module.mProperties). collect(Collectors.toList()); } }
services/core/java/com/android/server/broadcastradio/hal2/Convert.java 0 → 100644 +132 −0 Original line number Diff line number Diff line /** * Copyright (C) 2017 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.hal2; import android.annotation.NonNull; import android.annotation.Nullable; import android.hardware.broadcastradio.V2_0.Properties; import android.hardware.broadcastradio.V2_0.VendorKeyValue; import android.hardware.radio.ProgramSelector; import android.hardware.radio.RadioManager; import android.util.Slog; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; class Convert { private static final String TAG = "BcRadio2Srv.convert"; private static @NonNull Map<String, String> vendorInfoFromHal(@Nullable List<VendorKeyValue> info) { if (info == null) return Collections.emptyMap(); Map<String, String> map = new HashMap<>(); for (VendorKeyValue kvp : info) { if (kvp.key == null || kvp.value == null) { Slog.w(TAG, "VendorKeyValue contains null pointers"); continue; } map.put(kvp.key, kvp.value); } return map; } private static @NonNull int[] identifierTypesToProgramTypes(@NonNull int[] idTypes) { Set<Integer> pTypes = new HashSet<>(); for (int idType : idTypes) { switch (idType) { case ProgramSelector.IDENTIFIER_TYPE_AMFM_FREQUENCY: case ProgramSelector.IDENTIFIER_TYPE_RDS_PI: // TODO(b/69958423): verify AM/FM with region info pTypes.add(ProgramSelector.PROGRAM_TYPE_AM); pTypes.add(ProgramSelector.PROGRAM_TYPE_FM); break; case ProgramSelector.IDENTIFIER_TYPE_HD_STATION_ID_EXT: // TODO(b/69958423): verify AM/FM with region info pTypes.add(ProgramSelector.PROGRAM_TYPE_AM_HD); pTypes.add(ProgramSelector.PROGRAM_TYPE_FM_HD); break; case ProgramSelector.IDENTIFIER_TYPE_DAB_SIDECC: case ProgramSelector.IDENTIFIER_TYPE_DAB_ENSEMBLE: case ProgramSelector.IDENTIFIER_TYPE_DAB_SCID: case ProgramSelector.IDENTIFIER_TYPE_DAB_FREQUENCY: pTypes.add(ProgramSelector.PROGRAM_TYPE_DAB); break; case ProgramSelector.IDENTIFIER_TYPE_DRMO_SERVICE_ID: case ProgramSelector.IDENTIFIER_TYPE_DRMO_FREQUENCY: pTypes.add(ProgramSelector.PROGRAM_TYPE_DRMO); break; case ProgramSelector.IDENTIFIER_TYPE_SXM_SERVICE_ID: case ProgramSelector.IDENTIFIER_TYPE_SXM_CHANNEL: pTypes.add(ProgramSelector.PROGRAM_TYPE_SXM); break; default: break; } if (idType >= ProgramSelector.IDENTIFIER_TYPE_VENDOR_PRIMARY_START && idType <= ProgramSelector.IDENTIFIER_TYPE_VENDOR_PRIMARY_END) { pTypes.add(idType); } } return pTypes.stream().mapToInt(Integer::intValue).toArray(); } static @NonNull RadioManager.ModuleProperties propertiesFromHal(int id, @NonNull String serviceName, Properties prop) { Objects.requireNonNull(prop); // TODO(b/69958423): implement region info RadioManager.BandDescriptor[] bands = new RadioManager.BandDescriptor[0]; int[] supportedIdentifierTypes = prop.supportedIdentifierTypes.stream(). mapToInt(Integer::intValue).toArray(); int[] supportedProgramTypes = identifierTypesToProgramTypes(supportedIdentifierTypes); return new RadioManager.ModuleProperties( id, serviceName, // There is no Class concept in HAL 2.0. RadioManager.CLASS_AM_FM, prop.maker, prop.product, prop.version, prop.serial, /* HAL 2.0 only supports single tuner and audio source per * HAL implementation instance. */ 1, // numTuners 1, // numAudioSources false, // isCaptureSupported bands, true, // isBgScanSupported is deprecated supportedProgramTypes, supportedIdentifierTypes, vendorInfoFromHal(prop.vendorInfo)); } }