1 /*
2  * Copyright (C) 2022 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 android.telephony.mockmodem;
18 
19 import android.content.Context;
20 import android.hardware.radio.RadioError;
21 import android.hardware.radio.data.DataCallFailCause;
22 import android.hardware.radio.data.DataProfileInfo;
23 import android.hardware.radio.data.LinkAddress;
24 import android.hardware.radio.data.PdpProtocolType;
25 import android.hardware.radio.data.Qos;
26 import android.hardware.radio.data.QosSession;
27 import android.hardware.radio.data.SetupDataCallResult;
28 import android.hardware.radio.data.SliceInfo;
29 import android.hardware.radio.data.TrafficDescriptor;
30 import android.util.Log;
31 
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Iterator;
35 import java.util.List;
36 
37 public class MockDataService {
38     private static final String TAG = "MockDataService";
39     private String mTag;
40     private Context mContext;
41 
42     // Data Profile
43     List<DataProfileInfo> mDataProfileInfo = new ArrayList<>();
44     DataProfileInfo mInitialAttachProfile;
45     int mInitialAttachProfileId;
46 
47     // setup data call
48     public static final int APN_TYPE_IMS = 0;
49     public static final int APN_TYPE_DEFAULT = 1;
50     public static final int PHONE0 = 0;
51     public static final int PHONE1 = 1;
52 
53     SetupDataCallResult mSetupDataCallResultIms = new SetupDataCallResult();
54     SetupDataCallResult mSetupDataCallResultDefault = new SetupDataCallResult();
55 
56     // data call list
57     static List<SetupDataCallResult> sDataCallLists = new ArrayList<>();
58 
59     // Supported capability in physical layer
60     static List<String> sSupportedCapabilities = new ArrayList<>();
61 
62     /* Mock Data Config XML TAG definition */
63     private static final String MOCK_DATA_CONFIG_TAG = "MockDataConfig";
64     private static final String MOCK_CUTTLEFISH_CONFIG_TAG = "CuttlefishConfig";
65     private static final String MOCK_CUTTLEFISH_TYPE = "Cuttlefish";
66     private static final String MOCK_INTERFACE_NAME_TAG = "InterfaceName";
67     private static final String MOCK_IP_ADDRESS_TAG = "IpAddress";
68     private static final String MOCK_DNS_ADDRESS_TAG = "DnsAddress";
69     private static final String MOCK_GATEWAY_ADDRESS_TAG = "GatewayAddress";
70     private static final String MOCK_MTU_V4_TAG = "MtuV4";
71 
72     // Setup data call result parameteres
73     int mDataCallFailCause;
74     int mSuggestedRetryTime;
75     int mImsCid;
76     int mImsType;
77     String mImsIfname;
78     String mImsAddress;
79     String[] mImsGateways;
80     String[] mImsPcscf;
81     int mImsMtuV4;
82     int mImsMtuV6;
83     int mInternetCid;
84     int mInternetType;
85     String mInternetIfname;
86     String mInternetAddress;
87     String[] mInternetDnses;
88     String[] mInternetGateways;
89     int mInternetMtuV4;
90     int mInternetMtuV6;
91     int mAddressProperties;
92     long mLaDeprecationTime;
93     long mLaExpirationTime;
94     Qos mDefaultQos;
95     QosSession[] mQosSessions;
96     byte mHandoverFailureMode;
97     int mPduSessionId;
98     SliceInfo mSliceInfo;
99     TrafficDescriptor[] mTrafficDescriptors;
100     private final Object mDataCallListLock = new Object();
101     LinkAddress[] mImsLinkAddress;
102     LinkAddress[] mDefaultLinkAddress;
103     int mPhoneId;
104 
MockDataService(Context context, int instanceId)105     public MockDataService(Context context, int instanceId) {
106         mTag = TAG + "-" + instanceId;
107         mContext = context;
108         mPhoneId = instanceId;
109         initializeParameter();
110     }
111 
112     /* Default value definition */
initializeParameter()113     private void initializeParameter() {
114         this.mDataCallFailCause = DataCallFailCause.NONE;
115         this.mSuggestedRetryTime = -1;
116 
117         this.mImsType = PdpProtocolType.IP;
118         this.mImsIfname = "mock_network0";
119         this.mImsAddress = "192.168.66.2";
120         this.mImsGateways = new String[] {"0.0.0.0"};
121         this.mImsPcscf = new String[] {"192.168.66.100", "192.168.66.101"};
122         this.mImsMtuV4 = 1280;
123         this.mImsMtuV6 = 0;
124         this.mImsLinkAddress = new LinkAddress[1];
125 
126         this.mInternetType = PdpProtocolType.IP;
127         this.mInternetIfname = "mock_network1";
128         this.mInternetAddress = "192.168.66.1";
129         this.mInternetDnses = new String[] {"8.8.8.8"};
130         this.mInternetGateways = new String[] {"0.0.0.0"};
131         this.mInternetMtuV4 = 1280;
132         this.mInternetMtuV6 = 0;
133         this.mDefaultLinkAddress = new LinkAddress[1];
134 
135         this.mAddressProperties = LinkAddress.ADDRESS_PROPERTY_NONE;
136         this.mLaDeprecationTime = 0x7FFFFFFF;
137         this.mLaExpirationTime = 0x7FFFFFFF;
138 
139         this.mDefaultQos = new Qos();
140         this.mQosSessions = new QosSession[0];
141         this.mHandoverFailureMode =
142                 SetupDataCallResult.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER;
143         this.mPduSessionId = 0;
144         this.mSliceInfo = null;
145         this.mTrafficDescriptors = new TrafficDescriptor[0];
146     }
147 
setDataProfileInfo(DataProfileInfo[] dataProfilesInfo)148     public int setDataProfileInfo(DataProfileInfo[] dataProfilesInfo) {
149         int result = RadioError.NONE;
150         if (dataProfilesInfo != null) {
151             mDataProfileInfo.clear();
152             for (DataProfileInfo dp : dataProfilesInfo) {
153                 mDataProfileInfo.add(dp);
154                 Log.d(mTag, "setDataProfileInfo: profileId=" + dp.profileId + ", " + dp.apn);
155             }
156             return result;
157         }
158         return RadioError.INVALID_ARGUMENTS;
159     }
160 
setInitialAttachProfile(DataProfileInfo dataProfileInfo)161     public int setInitialAttachProfile(DataProfileInfo dataProfileInfo) {
162         int result = RadioError.NONE;
163         if (dataProfileInfo != null) {
164             Log.d(mTag, "setInitialAttachProfile: profileId=" + dataProfileInfo.profileId);
165             mInitialAttachProfile = dataProfileInfo;
166             mInitialAttachProfileId = dataProfileInfo.profileId;
167             return result;
168         }
169         return RadioError.INVALID_ARGUMENTS;
170     }
171 
setupDataCall(int apnType)172     SetupDataCallResult setupDataCall(int apnType) {
173         checkExistDataCall(apnType);
174 
175         SetupDataCallResult dc = new SetupDataCallResult();
176         dc.cause = this.mDataCallFailCause;
177         dc.suggestedRetryTime = this.mSuggestedRetryTime;
178 
179         dc.active = SetupDataCallResult.DATA_CONNECTION_STATUS_ACTIVE;
180         LinkAddress[] arrayLinkAddress = new LinkAddress[1];
181         LinkAddress linkAddress = new LinkAddress();
182 
183         switch (apnType) {
184             case APN_TYPE_IMS:
185                 dc.cid = this.mImsCid;
186                 dc.type = this.mImsType;
187                 dc.ifname = this.mImsIfname;
188                 linkAddress.address = this.mImsAddress;
189                 linkAddress.addressProperties = this.mAddressProperties;
190                 linkAddress.deprecationTime = this.mLaDeprecationTime;
191                 linkAddress.expirationTime = this.mLaExpirationTime;
192                 arrayLinkAddress[0] = linkAddress;
193                 dc.addresses = this.mImsLinkAddress;
194                 dc.gateways = this.mImsGateways;
195                 dc.pcscf = this.mImsPcscf;
196                 dc.mtuV4 = this.mImsMtuV4;
197                 dc.mtuV6 = this.mImsMtuV6;
198                 break;
199             case APN_TYPE_DEFAULT:
200                 dc.cid = this.mInternetCid;
201                 dc.type = this.mInternetType;
202                 dc.ifname = this.mInternetIfname;
203                 linkAddress.address = this.mInternetAddress;
204                 linkAddress.addressProperties = this.mAddressProperties;
205                 linkAddress.deprecationTime = this.mLaDeprecationTime;
206                 linkAddress.expirationTime = this.mLaExpirationTime;
207                 arrayLinkAddress[0] = linkAddress;
208                 dc.addresses = this.mDefaultLinkAddress;
209                 dc.dnses = this.mInternetDnses;
210                 dc.gateways = this.mInternetGateways;
211                 dc.mtuV4 = this.mInternetMtuV4;
212                 dc.mtuV6 = this.mInternetMtuV6;
213                 break;
214             default:
215                 Log.d(mTag, "Unexpected APN type: " + apnType);
216                 return new SetupDataCallResult();
217         }
218         dc.defaultQos = this.mDefaultQos;
219         dc.qosSessions = this.mQosSessions;
220         dc.handoverFailureMode = this.mHandoverFailureMode;
221         dc.pduSessionId = this.mPduSessionId;
222         dc.sliceInfo = this.mSliceInfo;
223         dc.trafficDescriptors = this.mTrafficDescriptors;
224         synchronized (mDataCallListLock) {
225             sDataCallLists.add(dc);
226         }
227         return dc;
228     }
229 
230     /**
231      * Get current data call list
232      *
233      * @return The SetupDataCallResult array list.
234      */
getDataCallList()235     List<SetupDataCallResult> getDataCallList() {
236         List<SetupDataCallResult> dataCallLists;
237         synchronized (mDataCallListLock) {
238             dataCallLists = sDataCallLists;
239         }
240         return dataCallLists;
241     }
242 
deactivateDataCall(int cid, int reason)243     void deactivateDataCall(int cid, int reason) {
244         synchronized (mDataCallListLock) {
245             Iterator<SetupDataCallResult> it = sDataCallLists.iterator();
246             while (it.hasNext()) {
247                 SetupDataCallResult dc = it.next();
248                 if (dc.cid == cid) {
249                     it.remove();
250                 }
251             }
252         }
253     }
254 
checkExistDataCall(int apnType)255     void checkExistDataCall(int apnType) {
256         synchronized (mDataCallListLock) {
257             int cid = (apnType == APN_TYPE_IMS) ? mImsCid : mInternetCid;
258             Iterator<SetupDataCallResult> it = sDataCallLists.iterator();
259             while (it.hasNext()) {
260                 SetupDataCallResult dc = it.next();
261                 if (dc.cid == cid) {
262                     it.remove();
263                 }
264             }
265         }
266     }
267 
convertToMtuV4(String mtuv4)268     private int convertToMtuV4(String mtuv4) {
269         int value = 0;
270         try {
271             value = Integer.parseInt(mtuv4);
272         } catch (NumberFormatException ex) {
273             Log.e(mTag, "Exception error: " + ex);
274         }
275         return value;
276     }
277 
getInterfaceName(String string)278     private String getInterfaceName(String string) {
279         String interfaceName = "";
280         try {
281             interfaceName = string.split("InterfaceName: ")[1].split(" LinkAddresses")[0];
282             Log.d(mTag, "getInterfaceName: " + interfaceName);
283         } catch (Exception e) {
284             Log.e(mTag, "Exception error: " + e);
285         }
286         return interfaceName;
287     }
288 
getIpAddress(String string)289     private LinkAddress[] getIpAddress(String string) {
290         String[] ipaddress = new String[] {};
291         LinkAddress[] arrayLinkAddress = new LinkAddress[0];
292         try {
293             ipaddress =
294                     string.split("LinkAddresses: \\[ ")[1].split(" ] DnsAddresses")[0].split(",");
295             arrayLinkAddress = new LinkAddress[ipaddress.length];
296             for (int idx = 0; idx < ipaddress.length; idx++) {
297                 if (ipaddress[idx].equals("LinkAddresses: [ ]")) {
298                     throw new Exception("Not valid ip address");
299                 }
300                 LinkAddress linkAddress = new LinkAddress();
301                 linkAddress.address = ipaddress[idx];
302                 linkAddress.addressProperties = this.mAddressProperties;
303                 linkAddress.deprecationTime = this.mLaDeprecationTime;
304                 linkAddress.expirationTime = this.mLaExpirationTime;
305                 arrayLinkAddress[idx] = linkAddress;
306                 Log.d(mTag, "getIpAddress:" + linkAddress.address);
307             }
308         } catch (Exception e) {
309             Log.e(mTag, "Exception error: " + e);
310         }
311         return arrayLinkAddress;
312     }
313 
getDnses(String string)314     private String[] getDnses(String string) {
315         String[] dnses = new String[] {};
316         try {
317             dnses =
318                     string.split("DnsAddresses: \\[ ")[1]
319                             .split(" ] Domains:")[0]
320                             .replace("/", "")
321                             .split(",");
322             Log.d(mTag, "getDnses: " + Arrays.toString(dnses));
323         } catch (Exception e) {
324             Log.e(mTag, "Exception error: " + e);
325         }
326         return dnses;
327     }
328 
getGateways(String string)329     private String[] getGateways(String string) {
330         ArrayList<String> gateways = new ArrayList<String>();
331         try {
332             gateways.add(
333                     string.split("Routes: \\[ ")[1]
334                             .split("-> ")[1]
335                             .split(" ")[0]);
336             Log.d(mTag, "getGateways: " + gateways);
337         } catch (Exception e) {
338             Log.e(mTag, "Exception error: " + e);
339         }
340         return gateways.toArray(new String[gateways.size()]);
341     }
342 
getMtu(String string)343     private int getMtu(String string) {
344         String mtu = "";
345         try {
346             mtu = string.split(" MTU: ")[1].split(" TcpBufferSizes:")[0];
347             Log.d(mTag, "getMtu: " + mtu);
348         } catch (Exception e) {
349             Log.e(mTag, "Exception error: " + e);
350         }
351         return Integer.valueOf(mtu);
352     }
353 
getPcscf(String string)354     private String[] getPcscf(String string) {
355         String[] pcscf = new String[] {};
356         try {
357             pcscf =
358                     string.split(" PcscfAddresses: \\[ ")[1]
359                             .split(" ] Domains:")[0]
360                             .replace("/", "")
361                             .split(",");
362             Log.d(mTag, "getPcscf: " + Arrays.toString(pcscf));
363         } catch (Exception e) {
364             Log.e(mTag, "Exception error: " + e);
365         }
366         return pcscf;
367     }
368 
getCapabilities(String string)369     private String getCapabilities(String string) {
370         String capabilities = "";
371         try {
372             capabilities = string.trim().split("Capabilities:")[1].split("LinkUpBandwidth")[0];
373             Log.d(mTag, "getCapabilities: " + capabilities);
374         } catch (Exception e) {
375             Log.e(mTag, "getCapabilities(): Exception error: " + e);
376         }
377         return capabilities;
378     }
379 
getCid(String string)380     private int getCid(String string) {
381         int cid = 0;
382         try {
383             String strCid = string.split("WWAN cid=")[1].split("WLAN cid")[0].trim();
384             cid = Integer.parseInt(strCid);
385             Log.d(mTag, "getCid: " + strCid);
386         } catch (Exception e) {
387             Log.e(mTag, "getCid(): Exception error: " + e);
388         }
389         return cid;
390     }
391 
setBridgeTheDataConnection(String string)392     public synchronized void setBridgeTheDataConnection(String string) {
393         try {
394             String[] lines = new String[] {};
395             String line =
396                     string.split("DataNetworkController-" + mPhoneId)[1]
397                             .split("All telephony network requests:")[0];
398             if (line.contains("curState=ConnectedState")) {
399                 lines = line.split(("curState=ConnectedState"));
400             }
401             for (String str : lines) {
402                 String capabilities = getCapabilities(str);
403                 if (capabilities.contains("INTERNET")) {
404                     Log.d(mTag, "[internet]:" + str);
405                     sSupportedCapabilities.add("internet");
406                     this.mInternetCid = getCid(str);
407                     this.mInternetIfname = getInterfaceName(str);
408                     this.mDefaultLinkAddress = getIpAddress(str);
409                     this.mInternetDnses = getDnses(str);
410                     this.mInternetGateways = getGateways(str);
411                     this.mInternetMtuV4 = getMtu(str);
412                     this.mInternetMtuV6 = getMtu(str);
413                 } else if (capabilities.contains("IMS")) {
414                     Log.d(mTag, "[ims]:" + str);
415                     sSupportedCapabilities.add("ims");
416                     this.mImsCid = getCid(str);
417                     this.mImsIfname = getInterfaceName(str);
418                     this.mImsLinkAddress = getIpAddress(str);
419                     this.mImsGateways = getGateways(str);
420                     this.mImsPcscf = getPcscf(str);
421                     this.mImsMtuV4 = getMtu(str);
422                     this.mImsMtuV6 = getMtu(str);
423                 }
424             }
425         } catch (Exception e) {
426             Log.e(mTag, "Exception error: [No NetworkAgentInfo]" + e);
427         }
428     }
429 
resetCapability()430     public synchronized void resetCapability() {
431         sSupportedCapabilities = new ArrayList<>();
432     }
433 
isSupportedCapability(String capability)434     public synchronized boolean isSupportedCapability(String capability) {
435         for (String cap : sSupportedCapabilities) {
436             Log.d(mTag, "Supported Capability:" + cap + ", Requested Capability:" + capability);
437             if (cap.contains(capability)) {
438                 return true;
439             }
440         }
441         return false;
442     }
443 
setDataCallFailCause(int failcause)444     public synchronized void setDataCallFailCause(int failcause) {
445         this.mDataCallFailCause = failcause;
446     }
447 
setSuggestedRetryTime(int retrytime)448     public synchronized void setSuggestedRetryTime(int retrytime) {
449         this.mSuggestedRetryTime = retrytime;
450     }
451 
setImsMtuV4(int mtusize)452     public synchronized void setImsMtuV4(int mtusize) {
453         this.mImsMtuV4 = mtusize;
454     }
455 
setImsMtuV6(int mtusize)456     public synchronized void setImsMtuV6(int mtusize) {
457         this.mImsMtuV6 = mtusize;
458     }
459 
setInternetMtuV4(int mtusize)460     public synchronized void setInternetMtuV4(int mtusize) {
461         this.mInternetMtuV4 = mtusize;
462     }
463 
setInternetMtuV6(int mtusize)464     public synchronized void setInternetMtuV6(int mtusize) {
465         this.mInternetMtuV6 = mtusize;
466     }
467 }
468