/* * 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.net.KeepalivePacketData; import android.net.LinkProperties; import android.os.AsyncResult; import android.os.Message; import android.os.RemoteException; import android.telephony.Rlog; import android.telephony.data.DataProfile; import android.telephony.data.NetworkSliceInfo; import android.telephony.data.TrafficDescriptor; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.util.ArrayList; /** * A holder for IRadioData. * Use getAidl to get IRadioData and call the AIDL implementations of the HAL APIs. */ public class RadioDataProxy extends RadioServiceProxy { private static final String TAG = "RadioDataProxy"; private volatile android.hardware.radio.data.IRadioData mDataProxy = null; /** * Set IRadioData as the AIDL implementation for RadioServiceProxy * @param halVersion Radio HAL version * @param data IRadioData implementation * * @return updated HAL version */ public HalVersion setAidl(HalVersion halVersion, android.hardware.radio.data.IRadioData data) { HalVersion version = halVersion; try { version = RIL.getServiceHalVersion(data.getInterfaceVersion()); } catch (RemoteException e) { Rlog.e(TAG, "setAidl: " + e); } mHalVersion = version; mDataProxy = data; mIsAidl = true; Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion); return mHalVersion; } /** * Get the AIDL implementation of RadioDataProxy * @return IRadioData implementation */ public android.hardware.radio.data.IRadioData getAidl() { return mDataProxy; } /** * Reset RadioDataProxy */ @Override public void clear() { super.clear(); mDataProxy = null; } /** * Check whether a RadioData implementation exists * @return true if there is neither a HIDL nor AIDL implementation */ @Override public boolean isEmpty() { return mRadioProxy == null && mDataProxy == null; } /** * Call IRadioData#allocatePduSessionId * @param serial Serial number of request * @throws RemoteException */ public void allocatePduSessionId(int serial) throws RemoteException { if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_6)) return; if (isAidl()) { mDataProxy.allocatePduSessionId(serial); } else { ((android.hardware.radio.V1_6.IRadio) mRadioProxy).allocatePduSessionId(serial); } } /** * Call IRadioData#cancelHandover * @param serial Serial number of request * @param callId Identifier associated with the data call * @throws RemoteException */ public void cancelHandover(int serial, int callId) throws RemoteException { if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_6)) return; if (isAidl()) { mDataProxy.cancelHandover(serial, callId); } else { ((android.hardware.radio.V1_6.IRadio) mRadioProxy).cancelHandover(serial, callId); } } /** * Call IRadioData#deactivateDataCall * @param serial Serial number of request * @param cid The connection ID * @param reason Data disconnect reason * @throws RemoteException */ public void deactivateDataCall(int serial, int cid, int reason) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mDataProxy.deactivateDataCall(serial, cid, reason); } else { mRadioProxy.deactivateDataCall_1_2(serial, cid, reason); } } /** * Call IRadioData#getDataCallList * @param serial Serial number of request * @throws RemoteException */ public void getDataCallList(int serial) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mDataProxy.getDataCallList(serial); } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_6)) { ((android.hardware.radio.V1_6.IRadio) mRadioProxy).getDataCallList_1_6(serial); } else { mRadioProxy.getDataCallList(serial); } } /** * Call IRadioData#getSlicingConfig * @param serial Serial number of request * @throws RemoteException */ public void getSlicingConfig(int serial) throws RemoteException { if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_6)) return; if (isAidl()) { mDataProxy.getSlicingConfig(serial); } else { ((android.hardware.radio.V1_6.IRadio) mRadioProxy).getSlicingConfig(serial); } } /** * Call IRadioData#releasePduSessionId * @param serial Serial number of request * @param id PDU session ID to release * @throws RemoteException */ public void releasePduSessionId(int serial, int id) throws RemoteException { if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_6)) return; if (isAidl()) { mDataProxy.releasePduSessionId(serial, id); } else { ((android.hardware.radio.V1_6.IRadio) mRadioProxy).releasePduSessionId(serial, id); } } /** * Call IRadioData#responseAcknowledgement * @throws RemoteException */ @Override public void responseAcknowledgement() throws RemoteException { if (isEmpty()) return; if (isAidl()) { mDataProxy.responseAcknowledgement(); } else { mRadioProxy.responseAcknowledgement(); } } /** * Call IRadioData#setDataAllowed * @param serial Serial number of request * @param allow Whether to allow or disallow data calls * @throws RemoteException */ public void setDataAllowed(int serial, boolean allow) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mDataProxy.setDataAllowed(serial, allow); } else { mRadioProxy.setDataAllowed(serial, allow); } } /** * Call IRadioData#setDataProfile * @param serial Serial number of request * @param profiles Array of DataProfiles to set * @throws RemoteException */ public void setDataProfile(int serial, DataProfile[] profiles) throws RemoteException { if (isEmpty()) return; if (isAidl()) { android.hardware.radio.data.DataProfileInfo[] dpis = new android.hardware.radio.data.DataProfileInfo[profiles.length]; for (int i = 0; i < profiles.length; i++) { dpis[i] = RILUtils.convertToHalDataProfile(profiles[i]); } mDataProxy.setDataProfile(serial, dpis); } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) { ArrayList dpis = new ArrayList<>(); for (DataProfile dp : profiles) { dpis.add(RILUtils.convertToHalDataProfile15(dp)); } ((android.hardware.radio.V1_5.IRadio) mRadioProxy).setDataProfile_1_5(serial, dpis); } else { ArrayList dpis = new ArrayList<>(); for (DataProfile dp : profiles) { dpis.add(RILUtils.convertToHalDataProfile14(dp)); } mRadioProxy.setDataProfile_1_4(serial, dpis); } } /** * Call IRadioData#setDataThrottling * @param serial Serial number of request * @param dataThrottlingAction DataThrottlingAction as defined in DataThrottlingAction.aidl * @param completionDurationMillis Window in ms in which the requested throttling action has to * be achieved. * @throws RemoteException */ public void setDataThrottling(int serial, byte dataThrottlingAction, long completionDurationMillis) throws RemoteException { if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_6)) return; if (isAidl()) { mDataProxy.setDataThrottling(serial, dataThrottlingAction, completionDurationMillis); } else { ((android.hardware.radio.V1_6.IRadio) mRadioProxy).setDataThrottling(serial, dataThrottlingAction, completionDurationMillis); } } /** * Call IRadioData#setInitialAttachApn * @param serial Serial number of request * @param dataProfile Data profile containing APN settings * @throws RemoteException */ public void setInitialAttachApn(int serial, DataProfile dataProfile) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mDataProxy.setInitialAttachApn(serial, RILUtils.convertToHalDataProfile(dataProfile)); } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) { ((android.hardware.radio.V1_5.IRadio) mRadioProxy).setInitialAttachApn_1_5(serial, RILUtils.convertToHalDataProfile15(dataProfile)); } else { mRadioProxy.setInitialAttachApn_1_4(serial, RILUtils.convertToHalDataProfile14(dataProfile)); } } /** * Call IRadioData#setupDataCall * @param serial Serial number of request * @param accessNetwork Access network to setup the data call * @param dataProfileInfo Data profile info * @param roamingAllowed Whether or not data roaming is allowed by the user * @param reason Request reason * @param linkProperties LinkProperties containing address and DNS info * @param pduSessionId The PDU session ID to be used for this data call * @param sliceInfo SliceInfo to be used for the data connection when a handover occurs from * EPDG to 5G * @param trafficDescriptor TrafficDescriptor for which the data connection needs to be * established * @param matchAllRuleAllowed Whether or not the default match-all URSP rule for this request * is allowed * @throws RemoteException */ public void setupDataCall(int serial, int accessNetwork, DataProfile dataProfileInfo, boolean roamingAllowed, int reason, LinkProperties linkProperties, int pduSessionId, NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed) throws RemoteException { if (isEmpty()) return; ArrayList addresses = new ArrayList<>(); ArrayList dnses = new ArrayList<>(); String[] dnsesArr; if (linkProperties != null) { for (InetAddress address : linkProperties.getAddresses()) { addresses.add(address.getHostAddress()); } dnsesArr = new String[linkProperties.getDnsServers().size()]; for (int i = 0; i < linkProperties.getDnsServers().size(); i++) { dnses.add(linkProperties.getDnsServers().get(i).getHostAddress()); dnsesArr[i] = linkProperties.getDnsServers().get(i).getHostAddress(); } } else { dnsesArr = new String[0]; } if (isAidl()) { // Create a new DataProfile to set the TrafficDescriptor DataProfile dp = new DataProfile.Builder() .setType(dataProfileInfo.getType()) .setPreferred(dataProfileInfo.isPreferred()) .setTrafficDescriptor(trafficDescriptor) .setApnSetting(dataProfileInfo.getApnSetting()) .build(); mDataProxy.setupDataCall(serial, accessNetwork, RILUtils.convertToHalDataProfile(dp), roamingAllowed, reason, RILUtils.convertToHalLinkProperties(linkProperties), dnsesArr, pduSessionId, RILUtils.convertToHalSliceInfoAidl(sliceInfo), matchAllRuleAllowed); } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_6)) { ((android.hardware.radio.V1_6.IRadio) mRadioProxy).setupDataCall_1_6(serial, accessNetwork, RILUtils.convertToHalDataProfile15(dataProfileInfo), roamingAllowed, reason, RILUtils.convertToHalLinkProperties15(linkProperties), dnses, pduSessionId, RILUtils.convertToHalSliceInfo(sliceInfo), RILUtils.convertToHalTrafficDescriptor(trafficDescriptor), matchAllRuleAllowed); } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) { ((android.hardware.radio.V1_5.IRadio) mRadioProxy).setupDataCall_1_5(serial, accessNetwork, RILUtils.convertToHalDataProfile15(dataProfileInfo), roamingAllowed, reason, RILUtils.convertToHalLinkProperties15(linkProperties), dnses); } else { mRadioProxy.setupDataCall_1_4(serial, accessNetwork, RILUtils.convertToHalDataProfile14(dataProfileInfo), roamingAllowed, reason, addresses, dnses); } } /** * Call IRadioData#startHandover * @param serial Serial number of request * @param callId Identifier of the data call * @throws RemoteException */ public void startHandover(int serial, int callId) throws RemoteException { if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_6)) return; if (isAidl()) { mDataProxy.startHandover(serial, callId); } else { ((android.hardware.radio.V1_6.IRadio) mRadioProxy).startHandover(serial, callId); } } /** * Call IRadioData#startKeepalive * @param serial Serial number of request * @param contextId Context ID for the data call * @param packetData Keepalive packet data * @param intervalMillis Max keepalive interval in ms * @param result Result to return in case of invalid arguments * @throws RemoteException */ public void startKeepalive(int serial, int contextId, KeepalivePacketData packetData, int intervalMillis, Message result) throws RemoteException { if (isEmpty()) return; if (isAidl()) { android.hardware.radio.data.KeepaliveRequest req = new android.hardware.radio.data.KeepaliveRequest(); req.cid = contextId; if (packetData.getDstAddress() instanceof Inet4Address) { req.type = android.hardware.radio.data.KeepaliveRequest.TYPE_NATT_IPV4; } else if (packetData.getDstAddress() instanceof Inet6Address) { req.type = android.hardware.radio.data.KeepaliveRequest.TYPE_NATT_IPV6; } else { AsyncResult.forMessage(result, null, CommandException.fromRilErrno(RILConstants.INVALID_ARGUMENTS)); result.sendToTarget(); return; } final InetAddress srcAddress = packetData.getSrcAddress(); final InetAddress dstAddress = packetData.getDstAddress(); byte[] sourceAddress = new byte[srcAddress.getAddress().length]; for (int i = 0; i < sourceAddress.length; i++) { sourceAddress[i] = srcAddress.getAddress()[i]; } req.sourceAddress = sourceAddress; req.sourcePort = packetData.getSrcPort(); byte[] destinationAddress = new byte[dstAddress.getAddress().length]; for (int i = 0; i < destinationAddress.length; i++) { destinationAddress[i] = dstAddress.getAddress()[i]; } req.destinationAddress = destinationAddress; req.destinationPort = packetData.getDstPort(); req.maxKeepaliveIntervalMillis = intervalMillis; mDataProxy.startKeepalive(serial, req); } else { android.hardware.radio.V1_1.KeepaliveRequest req = new android.hardware.radio.V1_1.KeepaliveRequest(); req.cid = contextId; if (packetData.getDstAddress() instanceof Inet4Address) { req.type = android.hardware.radio.V1_1.KeepaliveType.NATT_IPV4; } else if (packetData.getDstAddress() instanceof Inet6Address) { req.type = android.hardware.radio.V1_1.KeepaliveType.NATT_IPV6; } else { AsyncResult.forMessage(result, null, CommandException.fromRilErrno(RILConstants.INVALID_ARGUMENTS)); result.sendToTarget(); return; } final InetAddress srcAddress = packetData.getSrcAddress(); final InetAddress dstAddress = packetData.getDstAddress(); RILUtils.appendPrimitiveArrayToArrayList( srcAddress.getAddress(), req.sourceAddress); req.sourcePort = packetData.getSrcPort(); RILUtils.appendPrimitiveArrayToArrayList( dstAddress.getAddress(), req.destinationAddress); req.destinationPort = packetData.getDstPort(); req.maxKeepaliveIntervalMillis = intervalMillis; mRadioProxy.startKeepalive(serial, req); } } /** * Call IRadioData#stopKeepalive * @param serial Serial number of request * @param sessionHandle The handle that was provided by startKeepaliveResponse * @throws RemoteException */ public void stopKeepalive(int serial, int sessionHandle) throws RemoteException { if (isEmpty()) return; if (isAidl()) { mDataProxy.stopKeepalive(serial, sessionHandle); } else { mRadioProxy.stopKeepalive(serial, sessionHandle); } } }