Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d65b3ca0 authored by Tomasz Wasilczyk's avatar Tomasz Wasilczyk
Browse files

Initial implementation of HAL 2.0 counterpart for radio service.

Test: KitchenSink
Bug: 69958777
Change-Id: I7c697af76114e8c5d158ca592d2711b980101d60
parent 2ff754c1
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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,
+1 −0
Original line number Diff line number Diff line
@@ -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",
+17 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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.
     */
@@ -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(
@@ -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;
            }
        }
+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());
    }
}
+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