• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 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.google.android.iwlan;
18 
19 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
20 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
21 
22 import android.content.Context;
23 import android.content.Intent;
24 import android.net.ConnectivityManager;
25 import android.net.LinkAddress;
26 import android.net.LinkProperties;
27 import android.net.Network;
28 import android.net.NetworkCapabilities;
29 import android.os.Handler;
30 import android.os.HandlerThread;
31 import android.os.IBinder;
32 import android.os.Looper;
33 import android.os.Message;
34 import android.support.annotation.GuardedBy;
35 import android.support.annotation.IntRange;
36 import android.support.annotation.NonNull;
37 import android.support.annotation.Nullable;
38 import android.telephony.AccessNetworkConstants.AccessNetworkType;
39 import android.telephony.DataFailCause;
40 import android.telephony.TelephonyManager;
41 import android.telephony.data.ApnSetting;
42 import android.telephony.data.DataCallResponse;
43 import android.telephony.data.DataProfile;
44 import android.telephony.data.DataService;
45 import android.telephony.data.DataServiceCallback;
46 import android.telephony.data.NetworkSliceInfo;
47 import android.telephony.data.TrafficDescriptor;
48 import android.util.Log;
49 
50 import com.android.internal.annotations.VisibleForTesting;
51 
52 import com.google.android.iwlan.epdg.EpdgSelector;
53 import com.google.android.iwlan.epdg.EpdgTunnelManager;
54 import com.google.android.iwlan.epdg.TunnelLinkProperties;
55 import com.google.android.iwlan.epdg.TunnelSetupRequest;
56 
57 import java.io.FileDescriptor;
58 import java.io.PrintWriter;
59 import java.net.Inet4Address;
60 import java.net.Inet6Address;
61 import java.net.InetAddress;
62 import java.net.UnknownHostException;
63 import java.util.ArrayList;
64 import java.util.Calendar;
65 import java.util.Date;
66 import java.util.HashMap;
67 import java.util.List;
68 import java.util.LongSummaryStatistics;
69 import java.util.Map;
70 import java.util.concurrent.ConcurrentHashMap;
71 
72 public class IwlanDataService extends DataService {
73 
74     private static final String TAG = IwlanDataService.class.getSimpleName();
75     private static Context mContext;
76     private IwlanNetworkMonitorCallback mNetworkMonitorCallback;
77     private HandlerThread mNetworkCallbackHandlerThread;
78     private static boolean sNetworkConnected = false;
79     private static Network sNetwork = null;
80     // TODO: Change this to a hashmap as there is only one provider per slot
81     private static List<IwlanDataServiceProvider> sIwlanDataServiceProviderList =
82             new ArrayList<IwlanDataServiceProvider>();
83 
84     @VisibleForTesting
85     enum Transport {
86         UNSPECIFIED_NETWORK,
87         MOBILE,
88         WIFI;
89     }
90 
91     private static Transport sDefaultDataTransport = Transport.UNSPECIFIED_NETWORK;
92 
93     enum LinkProtocolType {
94         UNKNOWN,
95         IPV4,
96         IPV6,
97         IPV4V6;
98     }
99 
100     private static LinkProtocolType sLinkProtocolType = LinkProtocolType.UNKNOWN;
101 
102     // TODO: see if network monitor callback impl can be shared between dataservice and
103     // networkservice
104     static class IwlanNetworkMonitorCallback extends ConnectivityManager.NetworkCallback {
105 
106         /** Called when the framework connects and has declared a new network ready for use. */
107         @Override
onAvailable(Network network)108         public void onAvailable(Network network) {
109             Log.d(TAG, "onAvailable: " + network);
110         }
111 
112         /**
113          * Called when the network is about to be lost, typically because there are no outstanding
114          * requests left for it. This may be paired with a {@link NetworkCallback#onAvailable} call
115          * with the new replacement network for graceful handover. This method is not guaranteed to
116          * be called before {@link NetworkCallback#onLost} is called, for example in case a network
117          * is suddenly disconnected.
118          */
119         @Override
onLosing(Network network, int maxMsToLive)120         public void onLosing(Network network, int maxMsToLive) {
121             Log.d(TAG, "onLosing: maxMsToLive: " + maxMsToLive + " network: " + network);
122         }
123 
124         /**
125          * Called when a network disconnects or otherwise no longer satisfies this request or
126          * callback.
127          */
128         @Override
onLost(Network network)129         public void onLost(Network network) {
130             Log.d(TAG, "onLost: " + network);
131             IwlanDataService.setNetworkConnected(false, network, Transport.UNSPECIFIED_NETWORK);
132         }
133 
134         /** Called when the network corresponding to this request changes {@link LinkProperties}. */
135         @Override
onLinkPropertiesChanged(Network network, LinkProperties linkProperties)136         public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {
137             Log.d(TAG, "onLinkPropertiesChanged: " + linkProperties);
138             if (isLinkProtocolTypeChanged(linkProperties)) {
139                 for (IwlanDataServiceProvider dp : sIwlanDataServiceProviderList) {
140                     dp.dnsPrefetchCheck();
141                 }
142             }
143         }
144 
145         /** Called when access to the specified network is blocked or unblocked. */
146         @Override
onBlockedStatusChanged(Network network, boolean blocked)147         public void onBlockedStatusChanged(Network network, boolean blocked) {
148             // TODO: check if we need to handle this
149             Log.d(TAG, "onBlockedStatusChanged: " + network + " BLOCKED:" + blocked);
150         }
151 
152         @Override
onCapabilitiesChanged( Network network, NetworkCapabilities networkCapabilities)153         public void onCapabilitiesChanged(
154                 Network network, NetworkCapabilities networkCapabilities) {
155             // onCapabilitiesChanged is guaranteed to be called immediately after onAvailable per
156             // API
157             Log.d(TAG, "onCapabilitiesChanged: " + network + " " + networkCapabilities);
158             if (networkCapabilities != null) {
159                 if (networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) {
160                     Log.d(TAG, "Network " + network + " connected using transport MOBILE");
161                     IwlanDataService.setNetworkConnected(true, network, Transport.MOBILE);
162                 } else if (networkCapabilities.hasTransport(TRANSPORT_WIFI)) {
163                     Log.d(TAG, "Network " + network + " connected using transport WIFI");
164                     IwlanDataService.setNetworkConnected(true, network, Transport.WIFI);
165                 } else {
166                     Log.w(TAG, "Network does not have cellular or wifi capability");
167                 }
168             }
169         }
170     }
171 
172     @VisibleForTesting
173     class IwlanDataServiceProvider extends DataService.DataServiceProvider {
174 
175         private static final int CALLBACK_TYPE_SETUP_DATACALL_COMPLETE = 1;
176         private static final int CALLBACK_TYPE_DEACTIVATE_DATACALL_COMPLETE = 2;
177         private static final int CALLBACK_TYPE_GET_DATACALL_LIST_COMPLETE = 3;
178         private final String SUB_TAG;
179         private final IwlanDataService mIwlanDataService;
180         private final IwlanTunnelCallback mIwlanTunnelCallback;
181         private HandlerThread mHandlerThread;
182         @VisibleForTesting Handler mHandler;
183         private boolean mWfcEnabled = false;
184         private boolean mCarrierConfigReady = false;
185         private EpdgSelector mEpdgSelector;
186         private IwlanDataTunnelStats mTunnelStats;
187 
188         // apn to TunnelState
189         // Lock this at public entry and exit points if:
190         // 1) the function changes mTunnelStateForApn
191         // 2) Makes decisions based on contents of mTunnelStateForApn
192         @GuardedBy("mTunnelStateForApn")
193         private Map<String, TunnelState> mTunnelStateForApn = new ConcurrentHashMap<>();
194 
195         // Holds the state of a tunnel (for an APN)
196         @VisibleForTesting
197         class TunnelState {
198 
199             // this should be ideally be based on path MTU discovery. 1280 is the minimum packet
200             // size ipv6 routers have to handle so setting it to 1280 is the safest approach.
201             // ideally it should be 1280 - tunnelling overhead ?
202             private static final int LINK_MTU =
203                     1280; // TODO: need to substract tunnelling overhead?
204             static final int TUNNEL_DOWN = 1;
205             static final int TUNNEL_IN_BRINGUP = 2;
206             static final int TUNNEL_UP = 3;
207             static final int TUNNEL_IN_BRINGDOWN = 4;
208             static final int TUNNEL_IN_FORCE_CLEAN_WAS_IN_BRINGUP = 5;
209             private DataServiceCallback dataServiceCallback;
210             private int mState;
211             private int mPduSessionId;
212             private TunnelLinkProperties mTunnelLinkProperties;
213             private boolean mIsHandover;
214             private Date mBringUpStateTime = null;
215             private Date mUpStateTime = null;
216 
getPduSessionId()217             public int getPduSessionId() {
218                 return mPduSessionId;
219             }
220 
setPduSessionId(int mPduSessionId)221             public void setPduSessionId(int mPduSessionId) {
222                 this.mPduSessionId = mPduSessionId;
223             }
224 
getProtocolType()225             public int getProtocolType() {
226                 return mProtocolType;
227             }
228 
getLinkMtu()229             public int getLinkMtu() {
230                 return LINK_MTU; // TODO: need to substract tunnelling overhead
231             }
232 
setProtocolType(int protocolType)233             public void setProtocolType(int protocolType) {
234                 mProtocolType = protocolType;
235             }
236 
237             private int mProtocolType; // from DataProfile
238 
getTunnelLinkProperties()239             public TunnelLinkProperties getTunnelLinkProperties() {
240                 return mTunnelLinkProperties;
241             }
242 
setTunnelLinkProperties(TunnelLinkProperties tunnelLinkProperties)243             public void setTunnelLinkProperties(TunnelLinkProperties tunnelLinkProperties) {
244                 mTunnelLinkProperties = tunnelLinkProperties;
245             }
246 
getDataServiceCallback()247             public DataServiceCallback getDataServiceCallback() {
248                 return dataServiceCallback;
249             }
250 
setDataServiceCallback(DataServiceCallback dataServiceCallback)251             public void setDataServiceCallback(DataServiceCallback dataServiceCallback) {
252                 this.dataServiceCallback = dataServiceCallback;
253             }
254 
TunnelState(DataServiceCallback callback)255             public TunnelState(DataServiceCallback callback) {
256                 dataServiceCallback = callback;
257                 mState = TUNNEL_DOWN;
258             }
259 
getState()260             public int getState() {
261                 return mState;
262             }
263 
264             /** @param state (TunnelState.TUNNEL_DOWN|TUNNEL_UP|TUNNEL_DOWN) */
setState(int state)265             public void setState(int state) {
266                 mState = state;
267                 if (mState == TunnelState.TUNNEL_IN_BRINGUP) {
268                     mBringUpStateTime = Calendar.getInstance().getTime();
269                 }
270                 if (mState == TunnelState.TUNNEL_UP) {
271                     mUpStateTime = Calendar.getInstance().getTime();
272                 }
273             }
274 
setIsHandover(boolean isHandover)275             public void setIsHandover(boolean isHandover) {
276                 mIsHandover = isHandover;
277             }
278 
getIsHandover()279             public boolean getIsHandover() {
280                 return mIsHandover;
281             }
282 
getBringUpStateTime()283             public Date getBringUpStateTime() {
284                 return mBringUpStateTime;
285             }
286 
getUpStateTime()287             public Date getUpStateTime() {
288                 return mUpStateTime;
289             }
290 
291             @Override
toString()292             public String toString() {
293                 StringBuilder sb = new StringBuilder();
294                 String tunnelState = "UNKNOWN";
295                 switch (mState) {
296                     case TUNNEL_DOWN:
297                         tunnelState = "DOWN";
298                         break;
299                     case TUNNEL_IN_BRINGUP:
300                         tunnelState = "IN BRINGUP";
301                         break;
302                     case TUNNEL_UP:
303                         tunnelState = "UP";
304                         break;
305                     case TUNNEL_IN_BRINGDOWN:
306                         tunnelState = "IN BRINGDOWN";
307                         break;
308                     case TUNNEL_IN_FORCE_CLEAN_WAS_IN_BRINGUP:
309                         tunnelState = "IN FORCE CLEAN WAS IN BRINGUP";
310                         break;
311                 }
312                 sb.append("\tCurrent State of this tunnel: " + mState + " " + tunnelState);
313                 sb.append("\n\tTunnel state is in Handover: " + mIsHandover);
314                 if (mBringUpStateTime != null) {
315                     sb.append("\n\tTunnel bring up initiated at: " + mBringUpStateTime);
316                 } else {
317                     sb.append("\n\tPotential leak. Null mBringUpStateTime");
318                 }
319                 if (mUpStateTime != null) {
320                     sb.append("\n\tTunnel is up at: " + mUpStateTime);
321                 }
322                 if (mUpStateTime != null && mBringUpStateTime != null) {
323                     long tunnelUpTime = mUpStateTime.getTime() - mBringUpStateTime.getTime();
324                     sb.append("\n\tTime taken for the tunnel to come up in ms: " + tunnelUpTime);
325                 }
326                 return sb.toString();
327             }
328         }
329 
330         @VisibleForTesting
331         class IwlanTunnelCallback implements EpdgTunnelManager.TunnelCallback {
332 
333             DataServiceProvider mDataServiceProvider;
334 
IwlanTunnelCallback(DataServiceProvider dsp)335             public IwlanTunnelCallback(DataServiceProvider dsp) {
336                 mDataServiceProvider = dsp;
337             }
338 
339             // TODO: full implementation
340 
onOpened(String apnName, TunnelLinkProperties linkProperties)341             public void onOpened(String apnName, TunnelLinkProperties linkProperties) {
342                 Log.d(
343                         SUB_TAG,
344                         "Tunnel opened!. APN: " + apnName + "linkproperties: " + linkProperties);
345                 synchronized (mTunnelStateForApn) {
346                     TunnelState tunnelState = mTunnelStateForApn.get(apnName);
347                     // tunnelstate should not be null, design violation.
348                     // if its null, we should crash and debug.
349                     tunnelState.setTunnelLinkProperties(linkProperties);
350                     tunnelState.setState(TunnelState.TUNNEL_UP);
351                     mTunnelStats.reportTunnelSetupSuccess(apnName, tunnelState);
352 
353                     deliverCallback(
354                             CALLBACK_TYPE_SETUP_DATACALL_COMPLETE,
355                             DataServiceCallback.RESULT_SUCCESS,
356                             tunnelState.getDataServiceCallback(),
357                             apnTunnelStateToDataCallResponse(apnName));
358                 }
359             }
360 
onClosed(String apnName, IwlanError error)361             public void onClosed(String apnName, IwlanError error) {
362                 Log.d(SUB_TAG, "Tunnel closed!. APN: " + apnName + " Error: " + error);
363                 // this is called, when a tunnel that is up, is closed.
364                 // the expectation is error==NO_ERROR for user initiated/normal close.
365                 synchronized (mTunnelStateForApn) {
366                     TunnelState tunnelState = mTunnelStateForApn.get(apnName);
367                     mTunnelStats.reportTunnelDown(apnName, tunnelState);
368                     mTunnelStateForApn.remove(apnName);
369 
370                     if (tunnelState.getState() == TunnelState.TUNNEL_IN_BRINGUP
371                             || tunnelState.getState()
372                                     == TunnelState.TUNNEL_IN_FORCE_CLEAN_WAS_IN_BRINGUP) {
373                         DataCallResponse.Builder respBuilder = new DataCallResponse.Builder();
374                         respBuilder
375                                 .setId(apnName.hashCode())
376                                 .setProtocolType(tunnelState.getProtocolType());
377 
378                         if (tunnelState.getIsHandover()) {
379                             respBuilder.setHandoverFailureMode(
380                                     DataCallResponse
381                                             .HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER);
382                         } else {
383                             respBuilder.setHandoverFailureMode(
384                                     DataCallResponse
385                                             .HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL);
386                         }
387 
388                         if (tunnelState.getState() == TunnelState.TUNNEL_IN_BRINGUP) {
389                             respBuilder.setCause(
390                                     ErrorPolicyManager.getInstance(mContext, getSlotIndex())
391                                             .getDataFailCause(apnName));
392                             respBuilder.setRetryDurationMillis(
393                                     ErrorPolicyManager.getInstance(mContext, getSlotIndex())
394                                             .getCurrentRetryTimeMs(apnName));
395                         } else if (tunnelState.getState()
396                                 == TunnelState.TUNNEL_IN_FORCE_CLEAN_WAS_IN_BRINGUP) {
397                             respBuilder.setCause(DataFailCause.IWLAN_NETWORK_FAILURE);
398                             respBuilder.setRetryDurationMillis(5000);
399                         }
400 
401                         deliverCallback(
402                                 CALLBACK_TYPE_SETUP_DATACALL_COMPLETE,
403                                 DataServiceCallback.RESULT_SUCCESS,
404                                 tunnelState.getDataServiceCallback(),
405                                 respBuilder.build());
406                         return;
407                     }
408 
409                     // iwlan service triggered teardown
410                     if (tunnelState.getState() == TunnelState.TUNNEL_IN_BRINGDOWN) {
411 
412                         // IO exception happens when IKE library fails to retransmit requests.
413                         // This can happen for multiple reasons:
414                         // 1. Network disconnection due to wifi off.
415                         // 2. Epdg server does not respond.
416                         // 3. Socket send/receive fails.
417                         // Ignore this during tunnel bring down.
418                         if (error.getErrorType() != IwlanError.NO_ERROR
419                                 && error.getErrorType() != IwlanError.IKE_INTERNAL_IO_EXCEPTION) {
420                             Log.e(SUB_TAG, "Unexpected error during tunnel bring down: " + error);
421                         }
422 
423                         deliverCallback(
424                                 CALLBACK_TYPE_DEACTIVATE_DATACALL_COMPLETE,
425                                 DataServiceCallback.RESULT_SUCCESS,
426                                 tunnelState.getDataServiceCallback(),
427                                 null);
428 
429                         return;
430                     }
431 
432                     // just update list of data calls. No way to send error up
433                     notifyDataCallListChanged(getCallList());
434                 }
435             }
436         }
437 
438         private final class DSPHandler extends Handler {
439             private final String TAG =
440                     IwlanDataService.class.getSimpleName()
441                             + DSPHandler.class.getSimpleName()
442                             + getSlotIndex();
443 
444             @Override
handleMessage(Message msg)445             public void handleMessage(Message msg) {
446                 Log.d(TAG, "msg.what = " + msg.what);
447                 switch (msg.what) {
448                     case IwlanEventListener.CARRIER_CONFIG_CHANGED_EVENT:
449                         Log.d(TAG, "On CARRIER_CONFIG_CHANGED_EVENT");
450                         mCarrierConfigReady = true;
451                         dnsPrefetchCheck();
452                         break;
453                     case IwlanEventListener.CARRIER_CONFIG_UNKNOWN_CARRIER_EVENT:
454                         Log.d(TAG, "On CARRIER_CONFIG_UNKNOWN_CARRIER_EVENT");
455                         mCarrierConfigReady = false;
456                         break;
457                     case IwlanEventListener.WIFI_CALLING_ENABLE_EVENT:
458                         Log.d(TAG, "On WIFI_CALLING_ENABLE_EVENT");
459                         mWfcEnabled = true;
460                         dnsPrefetchCheck();
461                         break;
462                     case IwlanEventListener.WIFI_CALLING_DISABLE_EVENT:
463                         Log.d(TAG, "On WIFI_CALLING_DISABLE_EVENT");
464                         mWfcEnabled = false;
465                         break;
466                     default:
467                         Log.d(TAG, "Unknown message received!");
468                         break;
469                 }
470             }
471 
DSPHandler(Looper looper)472             DSPHandler(Looper looper) {
473                 super(looper);
474             }
475         }
476 
477         /** Holds all tunnel related time and count statistics for this IwlanDataServiceProvider */
478         @VisibleForTesting
479         class IwlanDataTunnelStats {
480 
481             // represents the start time from when the following events are recorded
482             private Date mStartTime;
483 
484             // Stats for TunnelSetup Success time (BRING_UP -> UP state)
485             @VisibleForTesting
486             Map<String, LongSummaryStatistics> mTunnelSetupSuccessStats =
487                     new HashMap<String, LongSummaryStatistics>();
488             // Count for Tunnel Setup failures onClosed when in BRING_UP
489             @VisibleForTesting
490             Map<String, Long> mTunnelSetupFailureCounts = new HashMap<String, Long>();
491 
492             // Count for unsol tunnel down onClosed when in UP without deactivate
493             @VisibleForTesting
494             Map<String, Long> mUnsolTunnelDownCounts = new HashMap<String, Long>();
495 
496             // Stats for how long the tunnel is in up state onClosed when in UP
497             @VisibleForTesting
498             Map<String, LongSummaryStatistics> mTunnelUpStats =
499                     new HashMap<String, LongSummaryStatistics>();
500 
501             private long statCount;
502             private final long COUNT_MAX = 1000;
503             private final int APN_COUNT_MAX = 10;
504 
IwlanDataTunnelStats()505             public IwlanDataTunnelStats() {
506                 mStartTime = Calendar.getInstance().getTime();
507                 statCount = 0L;
508             }
509 
reportTunnelSetupSuccess(String apn, TunnelState tunnelState)510             public void reportTunnelSetupSuccess(String apn, TunnelState tunnelState) {
511                 if (statCount > COUNT_MAX || maxApnReached()) {
512                     reset();
513                 }
514                 statCount++;
515 
516                 Date bringUpTime = tunnelState.getBringUpStateTime();
517                 Date upTime = tunnelState.getUpStateTime();
518 
519                 if (bringUpTime != null && upTime != null) {
520                     long tunnelUpTime = upTime.getTime() - bringUpTime.getTime();
521                     if (!mTunnelSetupSuccessStats.containsKey(apn)) {
522                         mTunnelSetupSuccessStats.put(apn, new LongSummaryStatistics());
523                     }
524                     LongSummaryStatistics stats = mTunnelSetupSuccessStats.get(apn);
525                     stats.accept(tunnelUpTime);
526                     mTunnelSetupSuccessStats.put(apn, stats);
527                 }
528             }
529 
reportTunnelDown(String apn, TunnelState tunnelState)530             public void reportTunnelDown(String apn, TunnelState tunnelState) {
531                 if (statCount > COUNT_MAX || maxApnReached()) {
532                     reset();
533                 }
534                 statCount++;
535 
536                 // Setup fail
537                 if (tunnelState.getState() == TunnelState.TUNNEL_IN_BRINGUP) {
538                     if (!mTunnelSetupFailureCounts.containsKey(apn)) {
539                         mTunnelSetupFailureCounts.put(apn, 0L);
540                     }
541                     long count = mTunnelSetupFailureCounts.get(apn);
542                     mTunnelSetupFailureCounts.put(apn, ++count);
543                     return;
544                 }
545 
546                 // Unsolicited tunnel down as tunnel has to be in BRINGDOWN if
547                 // there is a deactivate call associated with this.
548                 if (tunnelState.getState() == TunnelState.TUNNEL_UP) {
549                     if (!mUnsolTunnelDownCounts.containsKey(apn)) {
550                         mUnsolTunnelDownCounts.put(apn, 0L);
551                     }
552                     long count = mUnsolTunnelDownCounts.get(apn);
553                     mUnsolTunnelDownCounts.put(apn, ++count);
554                 }
555                 Date currentTime = Calendar.getInstance().getTime();
556                 Date upTime = tunnelState.getUpStateTime();
557                 if (upTime != null) {
558                     if (!mTunnelUpStats.containsKey(apn)) {
559                         mTunnelUpStats.put(apn, new LongSummaryStatistics());
560                     }
561                     LongSummaryStatistics stats = mTunnelUpStats.get(apn);
562                     stats.accept(currentTime.getTime() - upTime.getTime());
563                     mTunnelUpStats.put(apn, stats);
564                 }
565             }
566 
maxApnReached()567             boolean maxApnReached() {
568                 if (mTunnelSetupSuccessStats.size() >= APN_COUNT_MAX
569                         || mTunnelSetupFailureCounts.size() >= APN_COUNT_MAX
570                         || mUnsolTunnelDownCounts.size() >= APN_COUNT_MAX
571                         || mTunnelUpStats.size() >= APN_COUNT_MAX) {
572                     return true;
573                 }
574                 return false;
575             }
576 
577             @Override
toString()578             public String toString() {
579                 StringBuilder sb = new StringBuilder();
580                 sb.append("IwlanDataTunnelStats:");
581                 sb.append("\n\tmStartTime: " + mStartTime);
582                 sb.append("\n\ttunnelSetupSuccessStats:");
583                 for (Map.Entry<String, LongSummaryStatistics> entry :
584                         mTunnelSetupSuccessStats.entrySet()) {
585                     sb.append("\n\t  Apn: " + entry.getKey());
586                     sb.append("\n\t  " + entry.getValue());
587                 }
588                 sb.append("\n\ttunnelUpStats:");
589                 for (Map.Entry<String, LongSummaryStatistics> entry : mTunnelUpStats.entrySet()) {
590                     sb.append("\n\t  Apn: " + entry.getKey());
591                     sb.append("\n\t  " + entry.getValue());
592                 }
593 
594                 sb.append("\n\ttunnelSetupFailureCounts: ");
595                 for (Map.Entry<String, Long> entry : mTunnelSetupFailureCounts.entrySet()) {
596                     sb.append("\n\t  Apn: " + entry.getKey());
597                     sb.append("\n\t  counts: " + entry.getValue());
598                 }
599                 sb.append("\n\tunsolTunnelDownCounts: ");
600                 for (Map.Entry<String, Long> entry : mTunnelSetupFailureCounts.entrySet()) {
601                     sb.append("\n\t  Apn: " + entry.getKey());
602                     sb.append("\n\t  counts: " + entry.getValue());
603                 }
604                 sb.append("\n\tendTime: " + Calendar.getInstance().getTime());
605                 return sb.toString();
606             }
607 
reset()608             private void reset() {
609                 mStartTime = Calendar.getInstance().getTime();
610                 mTunnelSetupSuccessStats = new HashMap<String, LongSummaryStatistics>();
611                 mTunnelUpStats = new HashMap<String, LongSummaryStatistics>();
612                 mTunnelSetupFailureCounts = new HashMap<String, Long>();
613                 mUnsolTunnelDownCounts = new HashMap<String, Long>();
614                 statCount = 0L;
615             }
616         }
617 
getLooper()618         Looper getLooper() {
619             mHandlerThread = new HandlerThread("DSPHandlerThread");
620             mHandlerThread.start();
621             return mHandlerThread.getLooper();
622         }
623 
624         /**
625          * Constructor
626          *
627          * @param slotIndex SIM slot index the data service provider associated with.
628          */
IwlanDataServiceProvider(int slotIndex, IwlanDataService iwlanDataService)629         public IwlanDataServiceProvider(int slotIndex, IwlanDataService iwlanDataService) {
630             super(slotIndex);
631             SUB_TAG = TAG + "[" + slotIndex + "]";
632 
633             // TODO:
634             // get reference carrier config for this sub
635             // get reference to resolver
636             mIwlanDataService = iwlanDataService;
637             mIwlanTunnelCallback = new IwlanTunnelCallback(this);
638             mEpdgSelector = EpdgSelector.getSelectorInstance(mContext, slotIndex);
639             mTunnelStats = new IwlanDataTunnelStats();
640 
641             // Register IwlanEventListener
642             initHandler();
643             List<Integer> events = new ArrayList<Integer>();
644             events.add(IwlanEventListener.CARRIER_CONFIG_CHANGED_EVENT);
645             events.add(IwlanEventListener.CARRIER_CONFIG_UNKNOWN_CARRIER_EVENT);
646             events.add(IwlanEventListener.WIFI_CALLING_ENABLE_EVENT);
647             events.add(IwlanEventListener.WIFI_CALLING_DISABLE_EVENT);
648             IwlanEventListener.getInstance(mContext, slotIndex).addEventListener(events, mHandler);
649         }
650 
initHandler()651         void initHandler() {
652             mHandler = new DSPHandler(getLooper());
653         }
654 
655         @VisibleForTesting
getTunnelManager()656         EpdgTunnelManager getTunnelManager() {
657             return EpdgTunnelManager.getInstance(mContext, getSlotIndex());
658         }
659 
660         // creates a DataCallResponse for an apn irrespective of state
apnTunnelStateToDataCallResponse(String apn)661         private DataCallResponse apnTunnelStateToDataCallResponse(String apn) {
662             TunnelState tunnelState = mTunnelStateForApn.get(apn);
663             if (tunnelState == null) {
664                 return null;
665             }
666 
667             DataCallResponse.Builder responseBuilder = new DataCallResponse.Builder();
668             responseBuilder
669                     .setId(apn.hashCode())
670                     .setProtocolType(tunnelState.getProtocolType())
671                     .setCause(DataFailCause.NONE);
672 
673             if (tunnelState.getState() != TunnelState.TUNNEL_UP) {
674                 // no need to fill additional params
675                 return responseBuilder.setLinkStatus(DataCallResponse.LINK_STATUS_UNKNOWN).build();
676             }
677 
678             // fill wildcard address for gatewayList (used by DataConnection to add routes)
679             List<InetAddress> gatewayList = new ArrayList<>();
680             List<LinkAddress> linkAddrList =
681                     tunnelState.getTunnelLinkProperties().internalAddresses();
682             if (linkAddrList.stream().anyMatch(t -> t.isIpv4())) {
683                 try {
684                     gatewayList.add(Inet4Address.getByName("0.0.0.0"));
685                 } catch (UnknownHostException e) {
686                     // should never happen for static string 0.0.0.0
687                 }
688             }
689             if (linkAddrList.stream().anyMatch(t -> t.isIpv6())) {
690                 try {
691                     gatewayList.add(Inet6Address.getByName("::"));
692                 } catch (UnknownHostException e) {
693                     // should never happen for static string ::
694                 }
695             }
696 
697             if (tunnelState.getTunnelLinkProperties().sliceInfo().isPresent()) {
698                 responseBuilder.setSliceInfo(
699                         tunnelState.getTunnelLinkProperties().sliceInfo().get());
700             }
701 
702             return responseBuilder
703                     .setAddresses(linkAddrList)
704                     .setDnsAddresses(tunnelState.getTunnelLinkProperties().dnsAddresses())
705                     .setPcscfAddresses(tunnelState.getTunnelLinkProperties().pcscfAddresses())
706                     .setInterfaceName(tunnelState.getTunnelLinkProperties().ifaceName())
707                     .setGatewayAddresses(gatewayList)
708                     .setLinkStatus(DataCallResponse.LINK_STATUS_ACTIVE)
709                     .setMtu(tunnelState.getLinkMtu())
710                     .setMtuV4(tunnelState.getLinkMtu())
711                     .setMtuV6(tunnelState.getLinkMtu())
712                     .setPduSessionId(tunnelState.getPduSessionId())
713                     .build(); // underlying n/w is same
714         }
715 
getCallList()716         private List<DataCallResponse> getCallList() {
717             List<DataCallResponse> dcList = new ArrayList<>();
718             for (String key : mTunnelStateForApn.keySet()) {
719                 DataCallResponse dcRsp = apnTunnelStateToDataCallResponse(key);
720                 if (dcRsp != null) {
721                     Log.d(SUB_TAG, "Apn: " + key + "Link state: " + dcRsp.getLinkStatus());
722                     dcList.add(dcRsp);
723                 }
724             }
725             return dcList;
726         }
727 
deliverCallback( int callbackType, int result, DataServiceCallback callback, DataCallResponse rsp)728         private void deliverCallback(
729                 int callbackType, int result, DataServiceCallback callback, DataCallResponse rsp) {
730             if (callback == null) {
731                 Log.d(SUB_TAG, "deliverCallback: callback is null.  callbackType:" + callbackType);
732                 return;
733             }
734             Log.d(
735                     SUB_TAG,
736                     "Delivering callbackType:"
737                             + callbackType
738                             + " result:"
739                             + result
740                             + " rsp:"
741                             + rsp);
742             switch (callbackType) {
743                 case CALLBACK_TYPE_DEACTIVATE_DATACALL_COMPLETE:
744                     callback.onDeactivateDataCallComplete(result);
745                     // always update current datacalllist
746                     notifyDataCallListChanged(getCallList());
747                     break;
748 
749                 case CALLBACK_TYPE_SETUP_DATACALL_COMPLETE:
750                     if (result == DataServiceCallback.RESULT_SUCCESS && rsp == null) {
751                         Log.d(SUB_TAG, "Warning: null rsp for success case");
752                     }
753                     callback.onSetupDataCallComplete(result, rsp);
754                     // always update current datacalllist
755                     notifyDataCallListChanged(getCallList());
756                     break;
757 
758                 case CALLBACK_TYPE_GET_DATACALL_LIST_COMPLETE:
759                     callback.onRequestDataCallListComplete(result, getCallList());
760                     // TODO: add code for the rest of the cases
761             }
762         }
763 
764         /**
765          * Setup a data connection.
766          *
767          * @param accessNetworkType Access network type that the data call will be established on.
768          *     Must be one of {@link android.telephony.AccessNetworkConstants.AccessNetworkType}.
769          * @param dataProfile Data profile used for data call setup. See {@link DataProfile}
770          * @param isRoaming True if the device is data roaming.
771          * @param allowRoaming True if data roaming is allowed by the user.
772          * @param reason The reason for data setup. Must be {@link #REQUEST_REASON_NORMAL} or {@link
773          *     #REQUEST_REASON_HANDOVER}.
774          * @param linkProperties If {@code reason} is {@link #REQUEST_REASON_HANDOVER}, this is the
775          *     link properties of the existing data connection, otherwise null.
776          * @param pduSessionId The pdu session id to be used for this data call. The standard range
777          *     of values are 1-15 while 0 means no pdu session id was attached to this call.
778          *     Reference: 3GPP TS 24.007 section 11.2.3.1b.
779          * @param sliceInfo The slice info related to this data call.
780          * @param trafficDescriptor TrafficDescriptor for which data connection needs to be
781          *     established. It is used for URSP traffic matching as described in 3GPP TS 24.526
782          *     Section 4.2.2. It includes an optional DNN which, if present, must be used for
783          *     traffic matching; it does not specify the end point to be used for the data call.
784          * @param matchAllRuleAllowed Indicates if using default match-all URSP rule for this
785          *     request is allowed. If false, this request must not use the match-all URSP rule and
786          *     if a non-match-all rule is not found (or if URSP rules are not available) then {@link
787          *     DataCallResponse#getCause()} is {@link
788          *     android.telephony.DataFailCause#MATCH_ALL_RULE_NOT_ALLOWED}. This is needed as some
789          *     requests need to have a hard failure if the intention cannot be met, for example, a
790          *     zero-rating slice.
791          * @param callback The result callback for this request.
792          */
793         @Override
setupDataCall( int accessNetworkType, @NonNull DataProfile dataProfile, boolean isRoaming, boolean allowRoaming, int reason, @Nullable LinkProperties linkProperties, @IntRange(from = 0, to = 15) int pduSessionId, @Nullable NetworkSliceInfo sliceInfo, @Nullable TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed, @NonNull DataServiceCallback callback)794         public void setupDataCall(
795                 int accessNetworkType,
796                 @NonNull DataProfile dataProfile,
797                 boolean isRoaming,
798                 boolean allowRoaming,
799                 int reason,
800                 @Nullable LinkProperties linkProperties,
801                 @IntRange(from = 0, to = 15) int pduSessionId,
802                 @Nullable NetworkSliceInfo sliceInfo,
803                 @Nullable TrafficDescriptor trafficDescriptor,
804                 boolean matchAllRuleAllowed,
805                 @NonNull DataServiceCallback callback) {
806 
807             Log.d(
808                     SUB_TAG,
809                     "Setup data call with network: "
810                             + accessNetworkType
811                             + ", DataProfile: "
812                             + dataProfile
813                             + ", isRoaming:"
814                             + isRoaming
815                             + ", allowRoaming: "
816                             + allowRoaming
817                             + ", reason: "
818                             + reason
819                             + ", linkProperties: "
820                             + linkProperties
821                             + ", pduSessionId: "
822                             + pduSessionId);
823 
824             // Framework will never call bringup on the same APN back 2 back.
825             // but add a safety check
826             if ((accessNetworkType != AccessNetworkType.IWLAN)
827                     || (dataProfile == null)
828                     || (linkProperties == null && reason == DataService.REQUEST_REASON_HANDOVER)) {
829 
830                 deliverCallback(
831                         CALLBACK_TYPE_SETUP_DATACALL_COMPLETE,
832                         DataServiceCallback.RESULT_ERROR_INVALID_ARG,
833                         callback,
834                         null);
835                 return;
836             }
837 
838             synchronized (mTunnelStateForApn) {
839                 boolean isDDS = IwlanHelper.isDefaultDataSlot(mContext, getSlotIndex());
840                 boolean isCSTEnabled =
841                         IwlanHelper.isCrossSimCallingEnabled(mContext, getSlotIndex());
842                 boolean networkConnected = isNetworkConnected(isDDS, isCSTEnabled);
843                 Log.d(
844                         SUB_TAG,
845                         "isDds: "
846                                 + isDDS
847                                 + ", isCstEnabled: "
848                                 + isCSTEnabled
849                                 + ", transport: "
850                                 + sDefaultDataTransport);
851 
852                 if (networkConnected == false
853                         || mTunnelStateForApn.get(dataProfile.getApn()) != null) {
854                     deliverCallback(
855                             CALLBACK_TYPE_SETUP_DATACALL_COMPLETE,
856                             5 /* DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE */,
857                             callback,
858                             null);
859                     return;
860                 }
861 
862                 TunnelSetupRequest.Builder tunnelReqBuilder =
863                         TunnelSetupRequest.builder()
864                                 .setApnName(dataProfile.getApn())
865                                 .setNetwork(sNetwork)
866                                 .setIsRoaming(isRoaming)
867                                 .setPduSessionId(pduSessionId)
868                                 .setApnIpProtocol(
869                                         isRoaming
870                                                 ? dataProfile.getRoamingProtocolType()
871                                                 : dataProfile.getProtocolType());
872 
873                 if (reason == DataService.REQUEST_REASON_HANDOVER) {
874                     // for now assume that, at max,  only one address of eachtype (v4/v6).
875                     // TODO: Check if multiple ips can be sent in ike tunnel setup
876                     for (LinkAddress lAddr : linkProperties.getLinkAddresses()) {
877                         if (lAddr.isIpv4()) {
878                             tunnelReqBuilder.setSrcIpv4Address(lAddr.getAddress());
879                         } else if (lAddr.isIpv6()) {
880                             tunnelReqBuilder.setSrcIpv6Address(lAddr.getAddress());
881                             tunnelReqBuilder.setSrcIpv6AddressPrefixLength(lAddr.getPrefixLength());
882                         }
883                     }
884                 }
885 
886                 int apnTypeBitmask = dataProfile.getSupportedApnTypesBitmask();
887                 boolean isIMS = (apnTypeBitmask & ApnSetting.TYPE_IMS) == ApnSetting.TYPE_IMS;
888                 boolean isEmergency =
889                         (apnTypeBitmask & ApnSetting.TYPE_EMERGENCY) == ApnSetting.TYPE_EMERGENCY;
890                 tunnelReqBuilder.setRequestPcscf(isIMS || isEmergency);
891                 tunnelReqBuilder.setIsEmergency(isEmergency);
892 
893                 setTunnelState(
894                         dataProfile,
895                         callback,
896                         TunnelState.TUNNEL_IN_BRINGUP,
897                         null,
898                         (reason == DataService.REQUEST_REASON_HANDOVER),
899                         pduSessionId);
900 
901                 boolean result =
902                         getTunnelManager()
903                                 .bringUpTunnel(tunnelReqBuilder.build(), getIwlanTunnelCallback());
904                 Log.d(SUB_TAG, "bringup Tunnel with result:" + result);
905                 if (!result) {
906                     deliverCallback(
907                             CALLBACK_TYPE_SETUP_DATACALL_COMPLETE,
908                             DataServiceCallback.RESULT_ERROR_INVALID_ARG,
909                             callback,
910                             null);
911                     return;
912                 }
913             }
914         }
915 
916         /**
917          * Deactivate a data connection. The data service provider must implement this method to
918          * support data connection tear down. When completed or error, the service must invoke the
919          * provided callback to notify the platform.
920          *
921          * @param cid Call id returned in the callback of {@link
922          *     DataServiceProvider#setupDataCall(int, DataProfile, boolean, boolean, int,
923          *     LinkProperties, DataServiceCallback)}.
924          * @param reason The reason for data deactivation. Must be {@link #REQUEST_REASON_NORMAL},
925          *     {@link #REQUEST_REASON_SHUTDOWN} or {@link #REQUEST_REASON_HANDOVER}.
926          * @param callback The result callback for this request. Null if the client does not care
927          */
928         @Override
deactivateDataCall(int cid, int reason, DataServiceCallback callback)929         public void deactivateDataCall(int cid, int reason, DataServiceCallback callback) {
930             Log.d(
931                     SUB_TAG,
932                     "Deactivate data call "
933                             + " reason: "
934                             + reason
935                             + " cid: "
936                             + cid
937                             + "callback: "
938                             + callback);
939 
940             synchronized (mTunnelStateForApn) {
941                 for (String apnName : mTunnelStateForApn.keySet()) {
942                     if (apnName.hashCode() == cid) {
943                         /*
944                         No need to check state since dataconnection in framework serializes
945                         setup and deactivate calls using callId/cid.
946                         */
947                         mTunnelStateForApn.get(apnName).setState(TunnelState.TUNNEL_IN_BRINGDOWN);
948                         mTunnelStateForApn.get(apnName).setDataServiceCallback(callback);
949                         boolean isConnected =
950                                 isNetworkConnected(
951                                         IwlanHelper.isDefaultDataSlot(mContext, getSlotIndex()),
952                                         IwlanHelper.isCrossSimCallingEnabled(
953                                                 mContext, getSlotIndex()));
954                         getTunnelManager().closeTunnel(apnName, !isConnected);
955                         return;
956                     }
957                 }
958 
959                 deliverCallback(
960                         CALLBACK_TYPE_DEACTIVATE_DATACALL_COMPLETE,
961                         DataServiceCallback.RESULT_ERROR_INVALID_ARG,
962                         callback,
963                         null);
964             }
965         }
966 
forceCloseTunnelsInDeactivatingState()967         public void forceCloseTunnelsInDeactivatingState() {
968             synchronized (mTunnelStateForApn) {
969                 for (Map.Entry<String, TunnelState> entry : mTunnelStateForApn.entrySet()) {
970                     TunnelState tunnelState = entry.getValue();
971                     if (tunnelState.getState() == TunnelState.TUNNEL_IN_BRINGDOWN) {
972                         getTunnelManager().closeTunnel(entry.getKey(), true);
973                     }
974                 }
975             }
976         }
977 
forceCloseTunnels()978         void forceCloseTunnels() {
979             synchronized (mTunnelStateForApn) {
980                 for (Map.Entry<String, TunnelState> entry : mTunnelStateForApn.entrySet()) {
981                     getTunnelManager().closeTunnel(entry.getKey(), true);
982                 }
983             }
984         }
985 
986         /**
987          * Get the active data call list.
988          *
989          * @param callback The result callback for this request.
990          */
991         @Override
requestDataCallList(DataServiceCallback callback)992         public void requestDataCallList(DataServiceCallback callback) {
993             deliverCallback(
994                     CALLBACK_TYPE_GET_DATACALL_LIST_COMPLETE,
995                     DataServiceCallback.RESULT_SUCCESS,
996                     callback,
997                     null);
998         }
999 
1000         @VisibleForTesting
setTunnelState( DataProfile dataProfile, DataServiceCallback callback, int tunnelStatus, TunnelLinkProperties linkProperties, boolean isHandover, int pduSessionId)1001         void setTunnelState(
1002                 DataProfile dataProfile,
1003                 DataServiceCallback callback,
1004                 int tunnelStatus,
1005                 TunnelLinkProperties linkProperties,
1006                 boolean isHandover,
1007                 int pduSessionId) {
1008             TunnelState tunnelState = new TunnelState(callback);
1009             tunnelState.setState(tunnelStatus);
1010             tunnelState.setProtocolType(dataProfile.getProtocolType());
1011             tunnelState.setTunnelLinkProperties(linkProperties);
1012             tunnelState.setIsHandover(isHandover);
1013             tunnelState.setPduSessionId(pduSessionId);
1014             mTunnelStateForApn.put(dataProfile.getApn(), tunnelState);
1015         }
1016 
1017         @VisibleForTesting
getIwlanTunnelCallback()1018         public IwlanTunnelCallback getIwlanTunnelCallback() {
1019             return mIwlanTunnelCallback;
1020         }
1021 
1022         @VisibleForTesting
getTunnelStats()1023         IwlanDataTunnelStats getTunnelStats() {
1024             return mTunnelStats;
1025         }
1026 
updateNetwork(Network network)1027         private void updateNetwork(Network network) {
1028             if (network != null) {
1029                 synchronized (mTunnelStateForApn) {
1030                     for (Map.Entry<String, TunnelState> entry : mTunnelStateForApn.entrySet()) {
1031                         TunnelState tunnelState = entry.getValue();
1032                         if (tunnelState.getState() == TunnelState.TUNNEL_IN_BRINGUP) {
1033                             // force close tunnels in bringup since IKE lib only supports
1034                             // updating network for tunnels that are already up.
1035                             // This may not result in actual closing of Ike Session since
1036                             // epdg selection may not be complete yet.
1037                             tunnelState.setState(TunnelState.TUNNEL_IN_FORCE_CLEAN_WAS_IN_BRINGUP);
1038                             getTunnelManager().closeTunnel(entry.getKey(), true);
1039                         } else {
1040                             if (mIwlanDataService.isNetworkConnected(
1041                                     IwlanHelper.isDefaultDataSlot(mContext, getSlotIndex()),
1042                                     IwlanHelper.isCrossSimCallingEnabled(
1043                                             mContext, getSlotIndex()))) {
1044                                 getTunnelManager().updateNetwork(network, entry.getKey());
1045                             }
1046                         }
1047                     }
1048                 }
1049             }
1050         }
1051 
dnsPrefetchCheck()1052         private void dnsPrefetchCheck() {
1053             boolean networkConnected =
1054                     mIwlanDataService.isNetworkConnected(
1055                             IwlanHelper.isDefaultDataSlot(mContext, getSlotIndex()),
1056                             IwlanHelper.isCrossSimCallingEnabled(mContext, getSlotIndex()));
1057             /* Check if we need to do prefecting */
1058             synchronized (mTunnelStateForApn) {
1059                 if (networkConnected == true
1060                         && mCarrierConfigReady == true
1061                         && mWfcEnabled == true
1062                         && mTunnelStateForApn.isEmpty()) {
1063 
1064                     // Get roaming status
1065                     TelephonyManager telephonyManager =
1066                             mContext.getSystemService(TelephonyManager.class);
1067                     telephonyManager =
1068                             telephonyManager.createForSubscriptionId(
1069                                     IwlanHelper.getSubId(mContext, getSlotIndex()));
1070                     boolean isRoaming = telephonyManager.isNetworkRoaming();
1071                     Log.d(TAG, "Trigger EPDG prefetch. Roaming=" + isRoaming);
1072 
1073                     prefetchEpdgServerList(mIwlanDataService.sNetwork, isRoaming);
1074                 }
1075             }
1076         }
1077 
prefetchEpdgServerList(Network network, boolean isRoaming)1078         private void prefetchEpdgServerList(Network network, boolean isRoaming) {
1079             mEpdgSelector.getValidatedServerList(
1080                     0, EpdgSelector.PROTO_FILTER_IPV4V6, isRoaming, false, network, null);
1081             mEpdgSelector.getValidatedServerList(
1082                     0, EpdgSelector.PROTO_FILTER_IPV4V6, isRoaming, true, network, null);
1083         }
1084 
1085         /**
1086          * Called when the instance of data service is destroyed (e.g. got unbind or binder died) or
1087          * when the data service provider is removed.
1088          */
1089         @Override
close()1090         public void close() {
1091             // TODO: call epdgtunnelmanager.releaseInstance or equivalent
1092             mIwlanDataService.removeDataServiceProvider(this);
1093             IwlanEventListener.getInstance(mContext, getSlotIndex()).removeEventListener(mHandler);
1094             mHandlerThread.quit();
1095         }
1096 
dump(FileDescriptor fd, PrintWriter pw, String[] args)1097         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1098             pw.println("---- IwlanDataServiceProvider[" + getSlotIndex() + "] ----");
1099             boolean isDDS = IwlanHelper.isDefaultDataSlot(mContext, getSlotIndex());
1100             boolean isCSTEnabled = IwlanHelper.isCrossSimCallingEnabled(mContext, getSlotIndex());
1101             pw.println("isDefaultDataSub: " + isDDS + " isCrossSimEnabled: " + isCSTEnabled);
1102             pw.println(
1103                     "isNetworkConnected: "
1104                             + isNetworkConnected(isDDS, isCSTEnabled)
1105                             + " Wfc enabled: "
1106                             + mWfcEnabled);
1107             synchronized (mTunnelStateForApn) {
1108                 for (Map.Entry<String, TunnelState> entry : mTunnelStateForApn.entrySet()) {
1109                     pw.println("Tunnel state for APN: " + entry.getKey());
1110                     pw.println(entry.getValue());
1111                 }
1112             }
1113             pw.println(mTunnelStats);
1114             EpdgTunnelManager.getInstance(mContext, getSlotIndex()).dump(fd, pw, args);
1115             ErrorPolicyManager.getInstance(mContext, getSlotIndex()).dump(fd, pw, args);
1116             pw.println("-------------------------------------");
1117         }
1118     }
1119 
1120     @VisibleForTesting
isNetworkConnected(boolean isDds, boolean isCstEnabled)1121     static synchronized boolean isNetworkConnected(boolean isDds, boolean isCstEnabled) {
1122         if (!isDds && isCstEnabled) {
1123             // Only Non-DDS sub with CST enabled, can use any transport.
1124             return sNetworkConnected;
1125         } else {
1126             // For all other cases, only wifi transport can be used.
1127             return ((sDefaultDataTransport == Transport.WIFI) && sNetworkConnected);
1128         }
1129     }
1130 
1131     @VisibleForTesting
1132     /* Note: this api should have valid transport if networkConnected==true */
1133     // Only synchronize on IwlanDataService.class for changes being made to static variables
1134     // Calls to DataServiceProvider object methods (or any objects in the future) should
1135     // not be made within synchronized block protected by IwlanDataService.class
setNetworkConnected( boolean networkConnected, Network network, Transport transport)1136     static void setNetworkConnected(
1137             boolean networkConnected, Network network, Transport transport) {
1138 
1139         boolean hasNetworkChanged = false;
1140         boolean hasTransportChanged = false;
1141         boolean hasNetworkConnectedChanged = false;
1142 
1143         synchronized (IwlanDataService.class) {
1144             if (sNetworkConnected == networkConnected
1145                     && network.equals(sNetwork)
1146                     && sDefaultDataTransport == transport) {
1147                 // Nothing changed
1148                 return;
1149             }
1150 
1151             // safety check
1152             if (networkConnected && transport == Transport.UNSPECIFIED_NETWORK) {
1153                 Log.e(TAG, "setNetworkConnected: Network connected but transport unspecified");
1154                 return;
1155             }
1156 
1157             if (!network.equals(sNetwork)) {
1158                 Log.e(TAG, "setNetworkConnected NW changed from: " + sNetwork + " TO: " + network);
1159                 hasNetworkChanged = true;
1160             }
1161 
1162             if (transport != sDefaultDataTransport) {
1163                 Log.d(
1164                         TAG,
1165                         "Transport was changed from "
1166                                 + sDefaultDataTransport.name()
1167                                 + " to "
1168                                 + transport.name());
1169                 hasTransportChanged = true;
1170             }
1171 
1172             if (sNetworkConnected != networkConnected) {
1173                 Log.d(
1174                         TAG,
1175                         "Network connected state change from "
1176                                 + sNetworkConnected
1177                                 + " to "
1178                                 + networkConnected);
1179                 hasNetworkConnectedChanged = true;
1180             }
1181 
1182             sNetworkConnected = networkConnected;
1183             sDefaultDataTransport = transport;
1184             sNetwork = network;
1185             if (!networkConnected) {
1186                 // reset link protocol type
1187                 sLinkProtocolType = LinkProtocolType.UNKNOWN;
1188             }
1189         }
1190 
1191         if (networkConnected) {
1192             if (hasTransportChanged) {
1193                 // Perform forceClose for tunnels in bringdown.
1194                 // let framework handle explicit teardown
1195                 for (IwlanDataServiceProvider dp : sIwlanDataServiceProviderList) {
1196                     dp.forceCloseTunnelsInDeactivatingState();
1197                 }
1198             }
1199 
1200             if (transport == Transport.WIFI && hasNetworkConnectedChanged) {
1201                 IwlanEventListener.onWifiConnected(mContext);
1202             }
1203             // only prefetch dns and updateNetwork if Network has changed
1204             if (hasNetworkChanged) {
1205                 for (IwlanDataServiceProvider dp : sIwlanDataServiceProviderList) {
1206                     dp.dnsPrefetchCheck();
1207                     dp.updateNetwork(sNetwork);
1208                 }
1209             }
1210         } else {
1211             for (IwlanDataServiceProvider dp : sIwlanDataServiceProviderList) {
1212                 // once network is disconnected, even NAT KA offload fails
1213                 // But we should still let framework do an explicit teardown
1214                 // so as to not affect an ongoing handover
1215                 // only force close tunnels in bring down state
1216                 dp.forceCloseTunnelsInDeactivatingState();
1217             }
1218         }
1219     }
1220 
isLinkProtocolTypeChanged(LinkProperties linkProperties)1221     static boolean isLinkProtocolTypeChanged(LinkProperties linkProperties) {
1222         boolean hasIPV4 = false;
1223         boolean hasIPV6 = false;
1224 
1225         LinkProtocolType linkProtocolType = null;
1226         if (linkProperties != null) {
1227             for (LinkAddress linkAddress : linkProperties.getLinkAddresses()) {
1228                 InetAddress inetaddr = linkAddress.getAddress();
1229                 // skip linklocal and loopback addresses
1230                 if (!inetaddr.isLoopbackAddress() && !inetaddr.isLinkLocalAddress()) {
1231                     if (inetaddr instanceof Inet4Address) {
1232                         hasIPV4 = true;
1233                     } else if (inetaddr instanceof Inet6Address) {
1234                         hasIPV6 = true;
1235                     }
1236                 }
1237             }
1238 
1239             if (hasIPV4 && hasIPV6) {
1240                 linkProtocolType = LinkProtocolType.IPV4V6;
1241             } else if (hasIPV4) {
1242                 linkProtocolType = LinkProtocolType.IPV4;
1243             } else if (hasIPV6) {
1244                 linkProtocolType = LinkProtocolType.IPV6;
1245             }
1246 
1247             if (sLinkProtocolType != linkProtocolType) {
1248                 Log.d(
1249                         TAG,
1250                         "LinkProtocolType was changed from "
1251                                 + sLinkProtocolType
1252                                 + " to "
1253                                 + linkProtocolType);
1254                 sLinkProtocolType = linkProtocolType;
1255                 return true;
1256             }
1257             return false;
1258         }
1259         Log.w(TAG, "linkProperties is NULL.");
1260         return false;
1261     }
1262 
1263     /**
1264      * Get the DataServiceProvider associated with the slotId
1265      *
1266      * @param slotId slot index
1267      * @return DataService.DataServiceProvider associated with the slot
1268      */
getDataServiceProvider(int slotId)1269     public static DataService.DataServiceProvider getDataServiceProvider(int slotId) {
1270         DataServiceProvider ret = null;
1271         if (!sIwlanDataServiceProviderList.isEmpty()) {
1272             for (IwlanDataServiceProvider provider : sIwlanDataServiceProviderList) {
1273                 if (provider.getSlotIndex() == slotId) {
1274                     ret = provider;
1275                     break;
1276                 }
1277             }
1278         }
1279         return ret;
1280     }
1281 
getContext()1282     public static Context getContext() {
1283         return mContext;
1284     }
1285 
1286     @Override
onCreateDataServiceProvider(int slotIndex)1287     public DataServiceProvider onCreateDataServiceProvider(int slotIndex) {
1288         // TODO: validity check on slot index
1289         Log.d(TAG, "Creating provider for " + slotIndex);
1290 
1291         if (mNetworkMonitorCallback == null) {
1292             // start monitoring network
1293             mNetworkCallbackHandlerThread =
1294                     new HandlerThread(IwlanNetworkService.class.getSimpleName());
1295             mNetworkCallbackHandlerThread.start();
1296             Looper looper = mNetworkCallbackHandlerThread.getLooper();
1297             Handler handler = new Handler(looper);
1298 
1299             // register for default network callback
1300             ConnectivityManager connectivityManager =
1301                     mContext.getSystemService(ConnectivityManager.class);
1302             mNetworkMonitorCallback = new IwlanNetworkMonitorCallback();
1303             connectivityManager.registerDefaultNetworkCallback(mNetworkMonitorCallback, handler);
1304             Log.d(TAG, "Registered with Connectivity Service");
1305         }
1306 
1307         IwlanDataServiceProvider dp = new IwlanDataServiceProvider(slotIndex, this);
1308         addIwlanDataServiceProvider(dp);
1309         return dp;
1310     }
1311 
removeDataServiceProvider(IwlanDataServiceProvider dp)1312     public void removeDataServiceProvider(IwlanDataServiceProvider dp) {
1313         sIwlanDataServiceProviderList.remove(dp);
1314         if (sIwlanDataServiceProviderList.isEmpty()) {
1315             // deinit network related stuff
1316             ConnectivityManager connectivityManager =
1317                     mContext.getSystemService(ConnectivityManager.class);
1318             connectivityManager.unregisterNetworkCallback(mNetworkMonitorCallback);
1319             mNetworkCallbackHandlerThread.quit(); // no need to quitSafely
1320             mNetworkCallbackHandlerThread = null;
1321             mNetworkMonitorCallback = null;
1322         }
1323     }
1324 
1325     @VisibleForTesting
addIwlanDataServiceProvider(IwlanDataServiceProvider dp)1326     void addIwlanDataServiceProvider(IwlanDataServiceProvider dp) {
1327         sIwlanDataServiceProviderList.add(dp);
1328     }
1329 
1330     @VisibleForTesting
setAppContext(Context appContext)1331     void setAppContext(Context appContext) {
1332         mContext = appContext;
1333     }
1334 
1335     @VisibleForTesting
getNetworkMonitorCallback()1336     IwlanNetworkMonitorCallback getNetworkMonitorCallback() {
1337         return mNetworkMonitorCallback;
1338     }
1339 
1340     @Override
onCreate()1341     public void onCreate() {
1342         setAppContext(getApplicationContext());
1343         IwlanBroadcastReceiver.startListening(mContext);
1344     }
1345 
1346     @Override
onDestroy()1347     public void onDestroy() {
1348         IwlanBroadcastReceiver.stopListening(mContext);
1349     }
1350 
1351     @Override
onBind(Intent intent)1352     public IBinder onBind(Intent intent) {
1353         Log.d(TAG, "Iwlanservice onBind");
1354         return super.onBind(intent);
1355     }
1356 
1357     @Override
onUnbind(Intent intent)1358     public boolean onUnbind(Intent intent) {
1359         Log.d(TAG, "IwlanService onUnbind");
1360         // force close all the tunnels when there are no clients
1361         // active
1362         for (IwlanDataServiceProvider dp : sIwlanDataServiceProviderList) {
1363             dp.forceCloseTunnels();
1364         }
1365         return super.onUnbind(intent);
1366     }
1367 
1368     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1369     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1370         String transport = "UNSPECIFIED";
1371         if (sDefaultDataTransport == Transport.MOBILE) {
1372             transport = "CELLULAR";
1373         } else if (sDefaultDataTransport == Transport.WIFI) {
1374             transport = "WIFI";
1375         }
1376         pw.println("Default transport: " + transport);
1377         for (IwlanDataServiceProvider provider : sIwlanDataServiceProviderList) {
1378             pw.println();
1379             provider.dump(fd, pw, args);
1380             pw.println();
1381             pw.println();
1382         }
1383     }
1384 }
1385