| /* |
| * Copyright (C) 2021 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.internal.telephony; |
| |
| import android.os.HwBinder; |
| import android.os.IBinder; |
| import android.os.RemoteException; |
| import android.telephony.UiccSlotMapping; |
| |
| import com.android.telephony.Rlog; |
| |
| import java.util.List; |
| import java.util.Set; |
| |
| /** |
| * RadioConfig proxy class that abstracts the underlying RadioConfig service implementation to |
| * downstream users. |
| */ |
| public class RadioConfigProxy { |
| private static final String TAG = "RadioConfigProxy"; |
| private HalVersion mRadioHalVersion; |
| private final RadioConfigHidlServiceDeathRecipient mRadioConfigHidlServiceDeathRecipient; |
| private final RadioConfigAidlServiceDeathRecipient mRadioConfigAidlServiceDeathRecipient; |
| |
| private volatile android.hardware.radio.config.V1_1.IRadioConfig mHidlRadioConfigProxy = null; |
| private volatile android.hardware.radio.config.IRadioConfig mAidlRadioConfigProxy = null; |
| |
| private HalVersion mRadioConfigHalVersion = RIL.RADIO_HAL_VERSION_UNKNOWN; |
| private boolean mIsAidl; |
| |
| public RadioConfigProxy(RadioConfig radioConfig, HalVersion radioHalVersion) { |
| mRadioHalVersion = radioHalVersion; |
| mRadioConfigAidlServiceDeathRecipient = |
| new RadioConfigAidlServiceDeathRecipient(radioConfig); |
| mRadioConfigHidlServiceDeathRecipient = |
| new RadioConfigHidlServiceDeathRecipient(radioConfig); |
| } |
| |
| /** |
| * Set IRadioConfig as the HIDL implementation for RadioConfigProxy |
| * |
| * @param radioConfigHalVersion RadioConfig HAL version |
| * @param radioConfig IRadioConfig implementation |
| */ |
| public void setHidl( |
| HalVersion radioConfigHalVersion, |
| android.hardware.radio.config.V1_1.IRadioConfig radioConfig) { |
| mRadioConfigHalVersion = radioConfigHalVersion; |
| mHidlRadioConfigProxy = radioConfig; |
| mIsAidl = false; |
| mRadioConfigHidlServiceDeathRecipient.setService(radioConfig); |
| } |
| |
| /** |
| * Get HIDL IRadioConfig V1_1 |
| * @return IRadioConfigV1_1 |
| */ |
| public android.hardware.radio.config.V1_1.IRadioConfig getHidl11() { |
| return mHidlRadioConfigProxy; |
| } |
| |
| /** |
| * Get HIDL IRadioConfig V1_3 |
| * @return IRadioConfigV1_3 |
| */ |
| public android.hardware.radio.config.V1_3.IRadioConfig getHidl13() { |
| return (android.hardware.radio.config.V1_3.IRadioConfig) mHidlRadioConfigProxy; |
| } |
| |
| /** |
| * Set IRadioConfig as the AIDL implementation for RadioConfigProxy |
| * |
| * @param radioConfig IRadioConfig implementation |
| */ |
| public void setAidl(android.hardware.radio.config.IRadioConfig radioConfig) { |
| try { |
| mRadioConfigHalVersion = RIL.getServiceHalVersion(radioConfig.getInterfaceVersion()); |
| Rlog.d(TAG, "setAidl: setting HAL version to version = " + mRadioConfigHalVersion); |
| } catch (RemoteException e) { |
| Rlog.e(TAG, "setAidl: " + e); |
| } |
| mAidlRadioConfigProxy = radioConfig; |
| mIsAidl = true; |
| mRadioConfigAidlServiceDeathRecipient.setService(radioConfig.asBinder()); |
| } |
| |
| /** |
| * Get the AIDL implementation of RadioConfigProxy |
| * |
| * @return IRadio implementation |
| */ |
| public android.hardware.radio.config.IRadioConfig getAidl() { |
| return mAidlRadioConfigProxy; |
| } |
| |
| /** Reset RadioConfigProxy */ |
| public void clear() { |
| mRadioConfigHalVersion = RIL.RADIO_HAL_VERSION_UNKNOWN; |
| mHidlRadioConfigProxy = null; |
| mAidlRadioConfigProxy = null; |
| mRadioConfigHidlServiceDeathRecipient.clear(); |
| mRadioConfigAidlServiceDeathRecipient.clear(); |
| } |
| |
| /** |
| * Wrapper for service's linkToDeath() |
| */ |
| public void linkToDeath(long cookie) throws RemoteException { |
| if (isAidl()) { |
| mRadioConfigAidlServiceDeathRecipient.linkToDeath((int) cookie); |
| } else { |
| mRadioConfigHidlServiceDeathRecipient.linkToDeath(cookie); |
| } |
| } |
| |
| /** |
| * Check whether an implementation exists for this service |
| * |
| * @return false if there is neither a HIDL nor AIDL implementation |
| */ |
| public boolean isEmpty() { |
| return mAidlRadioConfigProxy == null && mHidlRadioConfigProxy == null; |
| } |
| |
| /** |
| * Whether RadioConfigProxy is an AIDL or HIDL implementation |
| * |
| * @return true if AIDL, false if HIDL |
| */ |
| public boolean isAidl() { |
| return mIsAidl; |
| } |
| |
| /** |
| * Return RadioConfig HAL version used by this instance |
| * @return RadioConfig HAL Version |
| */ |
| public HalVersion getVersion() { |
| return mRadioConfigHalVersion; |
| } |
| |
| /** |
| * Set the response functions for RadioConfig instance |
| * @param radioConfig main RadioConfig instance |
| * @throws RemoteException |
| */ |
| public void setResponseFunctions(RadioConfig radioConfig) throws RemoteException { |
| if (isEmpty()) return; |
| |
| if (isAidl()) { |
| mAidlRadioConfigProxy.setResponseFunctions( |
| new RadioConfigResponseAidl(radioConfig, mRadioHalVersion), |
| new RadioConfigIndicationAidl(radioConfig)); |
| } else { |
| mHidlRadioConfigProxy.setResponseFunctions( |
| new RadioConfigResponseHidl(radioConfig, mRadioHalVersion), |
| new RadioConfigIndicationHidl(radioConfig)); |
| } |
| } |
| |
| /** |
| * Get capabilities based off of the radio hal version and feature set configurations |
| * @return Set string capabilities |
| */ |
| public Set<String> getFullCapabilitySet() { |
| return RILUtils.getCaps(mRadioHalVersion, false); |
| } |
| |
| /** |
| * Wrapper function for IRadioConfig.getSimSlotsStatus(). |
| */ |
| public void getSimSlotStatus(int serial) throws RemoteException { |
| if (isAidl()) { |
| getAidl().getSimSlotsStatus(serial); |
| } else { |
| getHidl11().getSimSlotsStatus(serial); |
| } |
| } |
| |
| /** |
| * Wrapper function for IRadioConfig.setPreferredDataModem(int modemId). |
| */ |
| public void setPreferredDataModem(int serial, int modemId) throws RemoteException { |
| if (isAidl()) { |
| getAidl().setPreferredDataModem(serial, (byte) modemId); |
| } else { |
| getHidl11().setPreferredDataModem(serial, (byte) modemId); |
| } |
| } |
| |
| /** |
| * Wrapper function for IRadioConfig.getPhoneCapability(). |
| */ |
| public void getPhoneCapability(int serial) throws RemoteException { |
| if (isAidl()) { |
| getAidl().getPhoneCapability(serial); |
| } else { |
| getHidl11().getPhoneCapability(serial); |
| } |
| } |
| |
| /** |
| * Wrapper function for IRadioConfig.setSimSlotsMapping(int32_t serial, |
| * vec<SlotPortMapping> portMap). |
| */ |
| public void setSimSlotsMapping(int serial, List<UiccSlotMapping> slotMapping) |
| throws RemoteException { |
| if (isAidl()) { |
| getAidl().setSimSlotsMapping(serial, RILUtils.convertSimSlotsMapping(slotMapping)); |
| } else { |
| getHidl11().setSimSlotsMapping(serial, |
| RILUtils.convertSlotMappingToList(slotMapping)); |
| } |
| } |
| |
| /** |
| * Wrapper function for IRadioConfig.getSimultaneousCallingSupport() |
| */ |
| public void updateSimultaneousCallingSupport(int serial) throws RemoteException { |
| if (isAidl()) { |
| getAidl().getSimultaneousCallingSupport(serial); |
| } |
| // Only supported on AIDL. |
| } |
| |
| /** |
| * Wrapper function for using IRadioConfig.setNumOfLiveModems(int32_t serial, |
| * byte numOfLiveModems) to switch between single-sim and multi-sim. |
| */ |
| public void setNumOfLiveModems(int serial, int numOfLiveModems) throws RemoteException { |
| if (isAidl()) { |
| getAidl().setNumOfLiveModems(serial, (byte) numOfLiveModems); |
| } else { |
| android.hardware.radio.config.V1_1.ModemsConfig modemsConfig = |
| new android.hardware.radio.config.V1_1.ModemsConfig(); |
| modemsConfig.numOfLiveModems = (byte) numOfLiveModems; |
| getHidl11().setModemsConfig(serial, modemsConfig); |
| } |
| } |
| |
| /** |
| * Gets the hal capabilities from the device. |
| */ |
| public void getHalDeviceCapabilities(int serial) throws RemoteException { |
| if (isAidl()) { |
| getAidl().getHalDeviceCapabilities(serial); |
| } else { |
| getHidl13().getHalDeviceCapabilities(serial); |
| } |
| } |
| |
| /** |
| * Death Recipient for HIDL binder (if any) of RadioConfig. |
| */ |
| private static class RadioConfigHidlServiceDeathRecipient implements HwBinder.DeathRecipient { |
| private static final String TAG = "RadioConfigHidlSDR"; |
| |
| private final RadioConfig mRadioConfig; |
| private android.hardware.radio.config.V1_1.IRadioConfig mService; |
| |
| RadioConfigHidlServiceDeathRecipient(RadioConfig radioConfig) { |
| mRadioConfig = radioConfig; |
| } |
| |
| public void setService(android.hardware.radio.config.V1_1.IRadioConfig service) { |
| mService = service; |
| } |
| |
| public void linkToDeath(long cookie) throws RemoteException { |
| mService.linkToDeath(this, cookie); |
| } |
| |
| public void clear() { |
| mService = null; |
| } |
| |
| @Override |
| public void serviceDied(long cookie) { |
| // Deal with service going away |
| Rlog.e(TAG, "serviceDied"); |
| mRadioConfig.sendMessage( |
| mRadioConfig.obtainMessage(RadioConfig.EVENT_HIDL_SERVICE_DEAD, cookie)); |
| } |
| } |
| |
| /** |
| * DeathRecipient for AIDL binder service (if any) of RadioConfig |
| */ |
| private static class RadioConfigAidlServiceDeathRecipient implements IBinder.DeathRecipient { |
| private static final String TAG = "RadioConfigAidlSDR"; |
| |
| private final RadioConfig mRadioConfig; |
| |
| private IBinder mService; |
| |
| RadioConfigAidlServiceDeathRecipient(RadioConfig radioConfig) { |
| mRadioConfig = radioConfig; |
| } |
| |
| public void setService(IBinder service) { |
| mService = service; |
| } |
| |
| public void linkToDeath(int cookie) throws RemoteException { |
| mService.linkToDeath(this, cookie); |
| } |
| |
| public void clear() { |
| mService = null; |
| } |
| |
| /** |
| * Unlink from RadioConfig if any. |
| */ |
| public synchronized void unlinkToDeath() { |
| if (mService != null) { |
| mService.unlinkToDeath(this, 0); |
| mService = null; |
| } |
| } |
| |
| @Override |
| public void binderDied() { |
| Rlog.e(TAG, "service died."); |
| unlinkToDeath(); |
| mRadioConfig.sendMessage( |
| mRadioConfig.obtainMessage(RadioConfig.EVENT_AIDL_SERVICE_DEAD)); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return "RadioConfigProxy[" |
| + "mRadioHalVersion=" + mRadioHalVersion |
| + ", mRadioConfigHalVersion=" + mRadioConfigHalVersion + ']'; |
| } |
| } |