1 /*
2  * Copyright (C) 2021 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.internal.telephony;
18 
19 import android.net.KeepalivePacketData;
20 import android.net.LinkProperties;
21 import android.os.AsyncResult;
22 import android.os.Message;
23 import android.os.RemoteException;
24 import android.telephony.Rlog;
25 import android.telephony.data.DataProfile;
26 import android.telephony.data.NetworkSliceInfo;
27 import android.telephony.data.TrafficDescriptor;
28 
29 import java.net.Inet4Address;
30 import java.net.Inet6Address;
31 import java.net.InetAddress;
32 import java.util.ArrayList;
33 
34 /**
35  * A holder for IRadioData.
36  * Use getAidl to get IRadioData and call the AIDL implementations of the HAL APIs.
37  */
38 public class RadioDataProxy extends RadioServiceProxy {
39     private static final String TAG = "RadioDataProxy";
40     private volatile android.hardware.radio.data.IRadioData mDataProxy = null;
41 
42     /**
43      * Set IRadioData as the AIDL implementation for RadioServiceProxy
44      * @param halVersion Radio HAL version
45      * @param data IRadioData implementation
46      *
47      * @return updated HAL version
48      */
setAidl(HalVersion halVersion, android.hardware.radio.data.IRadioData data)49     public HalVersion setAidl(HalVersion halVersion, android.hardware.radio.data.IRadioData data) {
50         HalVersion version = halVersion;
51         try {
52             version = RIL.getServiceHalVersion(data.getInterfaceVersion());
53         } catch (RemoteException e) {
54             Rlog.e(TAG, "setAidl: " + e);
55         }
56         mHalVersion = version;
57         mDataProxy = data;
58         mIsAidl = true;
59 
60         Rlog.d(TAG, "AIDL initialized mHalVersion=" + mHalVersion);
61         return mHalVersion;
62     }
63 
64     /**
65      * Get the AIDL implementation of RadioDataProxy
66      * @return IRadioData implementation
67      */
getAidl()68     public android.hardware.radio.data.IRadioData getAidl() {
69         return mDataProxy;
70     }
71 
72     /**
73      * Reset RadioDataProxy
74      */
75     @Override
clear()76     public void clear() {
77         super.clear();
78         mDataProxy = null;
79     }
80 
81     /**
82      * Check whether a RadioData implementation exists
83      * @return true if there is neither a HIDL nor AIDL implementation
84      */
85     @Override
isEmpty()86     public boolean isEmpty() {
87         return mRadioProxy == null && mDataProxy == null;
88     }
89 
90     /**
91      * Call IRadioData#allocatePduSessionId
92      * @param serial Serial number of request
93      * @throws RemoteException
94      */
allocatePduSessionId(int serial)95     public void allocatePduSessionId(int serial) throws RemoteException {
96         if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_6)) return;
97         if (isAidl()) {
98             mDataProxy.allocatePduSessionId(serial);
99         } else {
100             ((android.hardware.radio.V1_6.IRadio) mRadioProxy).allocatePduSessionId(serial);
101         }
102     }
103 
104     /**
105      * Call IRadioData#cancelHandover
106      * @param serial Serial number of request
107      * @param callId Identifier associated with the data call
108      * @throws RemoteException
109      */
cancelHandover(int serial, int callId)110     public void cancelHandover(int serial, int callId) throws RemoteException {
111         if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_6)) return;
112         if (isAidl()) {
113             mDataProxy.cancelHandover(serial, callId);
114         } else {
115             ((android.hardware.radio.V1_6.IRadio) mRadioProxy).cancelHandover(serial, callId);
116         }
117     }
118 
119     /**
120      * Call IRadioData#deactivateDataCall
121      * @param serial Serial number of request
122      * @param cid The connection ID
123      * @param reason Data disconnect reason
124      * @throws RemoteException
125      */
deactivateDataCall(int serial, int cid, int reason)126     public void deactivateDataCall(int serial, int cid, int reason) throws RemoteException {
127         if (isEmpty()) return;
128         if (isAidl()) {
129             mDataProxy.deactivateDataCall(serial, cid, reason);
130         } else {
131             mRadioProxy.deactivateDataCall_1_2(serial, cid, reason);
132         }
133     }
134 
135     /**
136      * Call IRadioData#getDataCallList
137      * @param serial Serial number of request
138      * @throws RemoteException
139      */
getDataCallList(int serial)140     public void getDataCallList(int serial) throws RemoteException {
141         if (isEmpty()) return;
142         if (isAidl()) {
143             mDataProxy.getDataCallList(serial);
144         } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_6)) {
145             ((android.hardware.radio.V1_6.IRadio) mRadioProxy).getDataCallList_1_6(serial);
146         } else {
147             mRadioProxy.getDataCallList(serial);
148         }
149     }
150 
151     /**
152      * Call IRadioData#getSlicingConfig
153      * @param serial Serial number of request
154      * @throws RemoteException
155      */
getSlicingConfig(int serial)156     public void getSlicingConfig(int serial) throws RemoteException {
157         if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_6)) return;
158         if (isAidl()) {
159             mDataProxy.getSlicingConfig(serial);
160         } else {
161             ((android.hardware.radio.V1_6.IRadio) mRadioProxy).getSlicingConfig(serial);
162         }
163     }
164 
165     /**
166      * Call IRadioData#releasePduSessionId
167      * @param serial Serial number of request
168      * @param id PDU session ID to release
169      * @throws RemoteException
170      */
releasePduSessionId(int serial, int id)171     public void releasePduSessionId(int serial, int id) throws RemoteException {
172         if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_6)) return;
173         if (isAidl()) {
174             mDataProxy.releasePduSessionId(serial, id);
175         } else {
176             ((android.hardware.radio.V1_6.IRadio) mRadioProxy).releasePduSessionId(serial, id);
177         }
178     }
179 
180     /**
181      * Call IRadioData#responseAcknowledgement
182      * @throws RemoteException
183      */
184     @Override
responseAcknowledgement()185     public void responseAcknowledgement() throws RemoteException {
186         if (isEmpty()) return;
187         if (isAidl()) {
188             mDataProxy.responseAcknowledgement();
189         } else {
190             mRadioProxy.responseAcknowledgement();
191         }
192     }
193 
194     /**
195      * Call IRadioData#setDataAllowed
196      * @param serial Serial number of request
197      * @param allow Whether to allow or disallow data calls
198      * @throws RemoteException
199      */
setDataAllowed(int serial, boolean allow)200     public void setDataAllowed(int serial, boolean allow) throws RemoteException {
201         if (isEmpty()) return;
202         if (isAidl()) {
203             mDataProxy.setDataAllowed(serial, allow);
204         } else {
205             mRadioProxy.setDataAllowed(serial, allow);
206         }
207     }
208 
209     /**
210      * Call IRadioData#setDataProfile
211      * @param serial Serial number of request
212      * @param profiles Array of DataProfiles to set
213      * @throws RemoteException
214      */
setDataProfile(int serial, DataProfile[] profiles)215     public void setDataProfile(int serial, DataProfile[] profiles) throws RemoteException {
216         if (isEmpty()) return;
217         if (isAidl()) {
218             android.hardware.radio.data.DataProfileInfo[] dpis =
219                     new android.hardware.radio.data.DataProfileInfo[profiles.length];
220             for (int i = 0; i < profiles.length; i++) {
221                 dpis[i] = RILUtils.convertToHalDataProfile(profiles[i]);
222             }
223             mDataProxy.setDataProfile(serial, dpis);
224         } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) {
225             ArrayList<android.hardware.radio.V1_5.DataProfileInfo> dpis = new ArrayList<>();
226             for (DataProfile dp : profiles) {
227                 dpis.add(RILUtils.convertToHalDataProfile15(dp));
228             }
229             ((android.hardware.radio.V1_5.IRadio) mRadioProxy).setDataProfile_1_5(serial, dpis);
230         } else {
231             ArrayList<android.hardware.radio.V1_4.DataProfileInfo> dpis = new ArrayList<>();
232             for (DataProfile dp : profiles) {
233                 dpis.add(RILUtils.convertToHalDataProfile14(dp));
234             }
235             mRadioProxy.setDataProfile_1_4(serial, dpis);
236         }
237     }
238 
239     /**
240      * Call IRadioData#setDataThrottling
241      * @param serial Serial number of request
242      * @param dataThrottlingAction DataThrottlingAction as defined in DataThrottlingAction.aidl
243      * @param completionDurationMillis Window in ms in which the requested throttling action has to
244      *                                 be achieved.
245      * @throws RemoteException
246      */
setDataThrottling(int serial, byte dataThrottlingAction, long completionDurationMillis)247     public void setDataThrottling(int serial, byte dataThrottlingAction,
248             long completionDurationMillis) throws RemoteException {
249         if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_6)) return;
250         if (isAidl()) {
251             mDataProxy.setDataThrottling(serial, dataThrottlingAction, completionDurationMillis);
252         } else {
253             ((android.hardware.radio.V1_6.IRadio) mRadioProxy).setDataThrottling(serial,
254                     dataThrottlingAction, completionDurationMillis);
255         }
256     }
257 
258     /**
259      * Call IRadioData#setInitialAttachApn
260      * @param serial Serial number of request
261      * @param dataProfile Data profile containing APN settings
262      * @throws RemoteException
263      */
setInitialAttachApn(int serial, DataProfile dataProfile)264     public void setInitialAttachApn(int serial, DataProfile dataProfile)
265             throws RemoteException {
266         if (isEmpty()) return;
267         if (isAidl()) {
268             mDataProxy.setInitialAttachApn(serial, RILUtils.convertToHalDataProfile(dataProfile));
269         } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) {
270             ((android.hardware.radio.V1_5.IRadio) mRadioProxy).setInitialAttachApn_1_5(serial,
271                     RILUtils.convertToHalDataProfile15(dataProfile));
272         } else {
273             mRadioProxy.setInitialAttachApn_1_4(serial,
274                     RILUtils.convertToHalDataProfile14(dataProfile));
275         }
276     }
277 
278     /**
279      * Call IRadioData#setupDataCall
280      * @param serial Serial number of request
281      * @param accessNetwork Access network to setup the data call
282      * @param dataProfileInfo Data profile info
283      * @param roamingAllowed Whether or not data roaming is allowed by the user
284      * @param reason Request reason
285      * @param linkProperties LinkProperties containing address and DNS info
286      * @param pduSessionId The PDU session ID to be used for this data call
287      * @param sliceInfo SliceInfo to be used for the data connection when a handover occurs from
288      *                  EPDG to 5G
289      * @param trafficDescriptor TrafficDescriptor for which the data connection needs to be
290      *                          established
291      * @param matchAllRuleAllowed Whether or not the default match-all URSP rule for this request
292      *                            is allowed
293      * @throws RemoteException
294      */
setupDataCall(int serial, int accessNetwork, DataProfile dataProfileInfo, boolean roamingAllowed, int reason, LinkProperties linkProperties, int pduSessionId, NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed)295     public void setupDataCall(int serial, int accessNetwork, DataProfile dataProfileInfo,
296             boolean roamingAllowed, int reason, LinkProperties linkProperties, int pduSessionId,
297             NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor,
298             boolean matchAllRuleAllowed) throws RemoteException {
299         if (isEmpty()) return;
300         ArrayList<String> addresses = new ArrayList<>();
301         ArrayList<String> dnses = new ArrayList<>();
302         String[] dnsesArr;
303         if (linkProperties != null) {
304             for (InetAddress address : linkProperties.getAddresses()) {
305                 addresses.add(address.getHostAddress());
306             }
307             dnsesArr = new String[linkProperties.getDnsServers().size()];
308             for (int i = 0; i < linkProperties.getDnsServers().size(); i++) {
309                 dnses.add(linkProperties.getDnsServers().get(i).getHostAddress());
310                 dnsesArr[i] = linkProperties.getDnsServers().get(i).getHostAddress();
311             }
312         } else {
313             dnsesArr = new String[0];
314         }
315         if (isAidl()) {
316             // Create a new DataProfile to set the TrafficDescriptor
317             DataProfile dp = new DataProfile.Builder()
318                     .setType(dataProfileInfo.getType())
319                     .setPreferred(dataProfileInfo.isPreferred())
320                     .setTrafficDescriptor(trafficDescriptor)
321                     .setApnSetting(dataProfileInfo.getApnSetting())
322                     .build();
323             mDataProxy.setupDataCall(serial, accessNetwork, RILUtils.convertToHalDataProfile(dp),
324                     roamingAllowed, reason, RILUtils.convertToHalLinkProperties(linkProperties),
325                     dnsesArr, pduSessionId, RILUtils.convertToHalSliceInfoAidl(sliceInfo),
326                     matchAllRuleAllowed);
327         } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_6)) {
328             ((android.hardware.radio.V1_6.IRadio) mRadioProxy).setupDataCall_1_6(serial,
329                     accessNetwork, RILUtils.convertToHalDataProfile15(dataProfileInfo),
330                     roamingAllowed, reason, RILUtils.convertToHalLinkProperties15(linkProperties),
331                     dnses, pduSessionId, RILUtils.convertToHalSliceInfo(sliceInfo),
332                     RILUtils.convertToHalTrafficDescriptor(trafficDescriptor),
333                     matchAllRuleAllowed);
334         } else if (mHalVersion.greaterOrEqual(RIL.RADIO_HAL_VERSION_1_5)) {
335             ((android.hardware.radio.V1_5.IRadio) mRadioProxy).setupDataCall_1_5(serial,
336                     accessNetwork, RILUtils.convertToHalDataProfile15(dataProfileInfo),
337                     roamingAllowed, reason, RILUtils.convertToHalLinkProperties15(linkProperties),
338                     dnses);
339         } else {
340             mRadioProxy.setupDataCall_1_4(serial, accessNetwork,
341                     RILUtils.convertToHalDataProfile14(dataProfileInfo),
342                     roamingAllowed, reason, addresses, dnses);
343         }
344     }
345 
346     /**
347      * Call IRadioData#startHandover
348      * @param serial Serial number of request
349      * @param callId Identifier of the data call
350      * @throws RemoteException
351      */
startHandover(int serial, int callId)352     public void startHandover(int serial, int callId) throws RemoteException {
353         if (isEmpty() || mHalVersion.less(RIL.RADIO_HAL_VERSION_1_6)) return;
354         if (isAidl()) {
355             mDataProxy.startHandover(serial, callId);
356         } else {
357             ((android.hardware.radio.V1_6.IRadio) mRadioProxy).startHandover(serial, callId);
358         }
359     }
360 
361     /**
362      * Call IRadioData#startKeepalive
363      * @param serial Serial number of request
364      * @param contextId Context ID for the data call
365      * @param packetData Keepalive packet data
366      * @param intervalMillis Max keepalive interval in ms
367      * @param result Result to return in case of invalid arguments
368      * @throws RemoteException
369      */
startKeepalive(int serial, int contextId, KeepalivePacketData packetData, int intervalMillis, Message result)370     public void startKeepalive(int serial, int contextId, KeepalivePacketData packetData,
371             int intervalMillis, Message result) throws RemoteException {
372         if (isEmpty()) return;
373         if (isAidl()) {
374             android.hardware.radio.data.KeepaliveRequest req =
375                     new android.hardware.radio.data.KeepaliveRequest();
376             req.cid = contextId;
377 
378             if (packetData.getDstAddress() instanceof Inet4Address) {
379                 req.type = android.hardware.radio.data.KeepaliveRequest.TYPE_NATT_IPV4;
380             } else if (packetData.getDstAddress() instanceof Inet6Address) {
381                 req.type = android.hardware.radio.data.KeepaliveRequest.TYPE_NATT_IPV6;
382             } else {
383                 AsyncResult.forMessage(result, null,
384                         CommandException.fromRilErrno(RILConstants.INVALID_ARGUMENTS));
385                 result.sendToTarget();
386                 return;
387             }
388 
389             final InetAddress srcAddress = packetData.getSrcAddress();
390             final InetAddress dstAddress = packetData.getDstAddress();
391             byte[] sourceAddress = new byte[srcAddress.getAddress().length];
392             for (int i = 0; i < sourceAddress.length; i++) {
393                 sourceAddress[i] = srcAddress.getAddress()[i];
394             }
395             req.sourceAddress = sourceAddress;
396             req.sourcePort = packetData.getSrcPort();
397             byte[] destinationAddress = new byte[dstAddress.getAddress().length];
398             for (int i = 0; i < destinationAddress.length; i++) {
399                 destinationAddress[i] = dstAddress.getAddress()[i];
400             }
401             req.destinationAddress = destinationAddress;
402             req.destinationPort = packetData.getDstPort();
403             req.maxKeepaliveIntervalMillis = intervalMillis;
404 
405             mDataProxy.startKeepalive(serial, req);
406         } else {
407             android.hardware.radio.V1_1.KeepaliveRequest req =
408                     new android.hardware.radio.V1_1.KeepaliveRequest();
409 
410             req.cid = contextId;
411 
412             if (packetData.getDstAddress() instanceof Inet4Address) {
413                 req.type = android.hardware.radio.V1_1.KeepaliveType.NATT_IPV4;
414             } else if (packetData.getDstAddress() instanceof Inet6Address) {
415                 req.type = android.hardware.radio.V1_1.KeepaliveType.NATT_IPV6;
416             } else {
417                 AsyncResult.forMessage(result, null,
418                         CommandException.fromRilErrno(RILConstants.INVALID_ARGUMENTS));
419                 result.sendToTarget();
420                 return;
421             }
422 
423             final InetAddress srcAddress = packetData.getSrcAddress();
424             final InetAddress dstAddress = packetData.getDstAddress();
425             RILUtils.appendPrimitiveArrayToArrayList(
426                     srcAddress.getAddress(), req.sourceAddress);
427             req.sourcePort = packetData.getSrcPort();
428             RILUtils.appendPrimitiveArrayToArrayList(
429                     dstAddress.getAddress(), req.destinationAddress);
430             req.destinationPort = packetData.getDstPort();
431             req.maxKeepaliveIntervalMillis = intervalMillis;
432 
433             mRadioProxy.startKeepalive(serial, req);
434         }
435     }
436 
437     /**
438      * Call IRadioData#stopKeepalive
439      * @param serial Serial number of request
440      * @param sessionHandle The handle that was provided by startKeepaliveResponse
441      * @throws RemoteException
442      */
stopKeepalive(int serial, int sessionHandle)443     public void stopKeepalive(int serial, int sessionHandle) throws RemoteException {
444         if (isEmpty()) return;
445         if (isAidl()) {
446             mDataProxy.stopKeepalive(serial, sessionHandle);
447         } else {
448             mRadioProxy.stopKeepalive(serial, sessionHandle);
449         }
450     }
451 }
452