1 /*
2  * Copyright 2017 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.hardware.radio.V1_0.CellInfoType;
20 import android.hardware.radio.V1_0.RegState;
21 import android.hardware.radio.V1_4.DataRegStateResult.VopsInfo.hidl_discriminator;
22 import android.os.AsyncResult;
23 import android.os.Handler;
24 import android.os.HandlerThread;
25 import android.os.Looper;
26 import android.os.Message;
27 import android.telephony.AccessNetworkConstants;
28 import android.telephony.AccessNetworkConstants.AccessNetworkType;
29 import android.telephony.CellIdentity;
30 import android.telephony.CellIdentityCdma;
31 import android.telephony.CellIdentityGsm;
32 import android.telephony.CellIdentityLte;
33 import android.telephony.CellIdentityTdscdma;
34 import android.telephony.CellIdentityWcdma;
35 import android.telephony.LteVopsSupportInfo;
36 import android.telephony.NetworkRegistrationInfo;
37 import android.telephony.NetworkService;
38 import android.telephony.NetworkServiceCallback;
39 import android.telephony.Rlog;
40 import android.telephony.ServiceState;
41 import android.telephony.SubscriptionManager;
42 import android.telephony.TelephonyManager;
43 
44 import java.util.ArrayList;
45 import java.util.List;
46 import java.util.concurrent.ConcurrentHashMap;
47 
48 /**
49  * Implementation of network services for Cellular. It's a service that handles network requests
50  * for Cellular. It passes the requests to inner CellularNetworkServiceProvider which has a
51  * handler thread for each slot.
52  */
53 public class CellularNetworkService extends NetworkService {
54     private static final boolean DBG = false;
55 
56     private static final String TAG = CellularNetworkService.class.getSimpleName();
57 
58     private static final int GET_CS_REGISTRATION_STATE_DONE = 1;
59     private static final int GET_PS_REGISTRATION_STATE_DONE = 2;
60     private static final int NETWORK_REGISTRATION_STATE_CHANGED = 3;
61 
62     private class CellularNetworkServiceProvider extends NetworkServiceProvider {
63 
64         private final ConcurrentHashMap<Message, NetworkServiceCallback> mCallbackMap =
65                 new ConcurrentHashMap<>();
66 
67         private final Looper mLooper;
68 
69         private final HandlerThread mHandlerThread;
70 
71         private final Handler mHandler;
72 
73         private final Phone mPhone;
74 
CellularNetworkServiceProvider(int slotId)75         CellularNetworkServiceProvider(int slotId) {
76             super(slotId);
77 
78             mPhone = PhoneFactory.getPhone(getSlotIndex());
79 
80             mHandlerThread = new HandlerThread(CellularNetworkService.class.getSimpleName());
81             mHandlerThread.start();
82             mLooper = mHandlerThread.getLooper();
83             mHandler = new Handler(mLooper) {
84                 @Override
85                 public void handleMessage(Message message) {
86                     NetworkServiceCallback callback = mCallbackMap.remove(message);
87 
88                     AsyncResult ar;
89                     switch (message.what) {
90                         case GET_CS_REGISTRATION_STATE_DONE:
91                         case GET_PS_REGISTRATION_STATE_DONE:
92                             if (callback == null) return;
93                             ar = (AsyncResult) message.obj;
94                             int domain = (message.what == GET_CS_REGISTRATION_STATE_DONE)
95                                     ? NetworkRegistrationInfo.DOMAIN_CS
96                                     : NetworkRegistrationInfo.DOMAIN_PS;
97                             NetworkRegistrationInfo netState =
98                                     getRegistrationStateFromResult(ar.result, domain);
99 
100                             int resultCode;
101                             if (ar.exception != null || netState == null) {
102                                 resultCode = NetworkServiceCallback.RESULT_ERROR_FAILED;
103                             } else {
104                                 resultCode = NetworkServiceCallback.RESULT_SUCCESS;
105                             }
106 
107                             try {
108                                 if (DBG) {
109                                     log("Calling onRequestNetworkRegistrationInfoComplete."
110                                             + "resultCode = " + resultCode
111                                             + ", netState = " + netState);
112                                 }
113                                 callback.onRequestNetworkRegistrationInfoComplete(
114                                          resultCode, netState);
115                             } catch (Exception e) {
116                                 loge("Exception: " + e);
117                             }
118                             break;
119                         case NETWORK_REGISTRATION_STATE_CHANGED:
120                             notifyNetworkRegistrationInfoChanged();
121                             break;
122                         default:
123                             return;
124                     }
125                 }
126             };
127 
128             mPhone.mCi.registerForNetworkStateChanged(
129                     mHandler, NETWORK_REGISTRATION_STATE_CHANGED, null);
130         }
131 
getRegStateFromHalRegState(int halRegState)132         private int getRegStateFromHalRegState(int halRegState) {
133             switch (halRegState) {
134                 case RegState.NOT_REG_MT_NOT_SEARCHING_OP:
135                 case RegState.NOT_REG_MT_NOT_SEARCHING_OP_EM:
136                     return NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING;
137                 case RegState.REG_HOME:
138                     return NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
139                 case RegState.NOT_REG_MT_SEARCHING_OP:
140                 case RegState.NOT_REG_MT_SEARCHING_OP_EM:
141                     return NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING;
142                 case RegState.REG_DENIED:
143                 case RegState.REG_DENIED_EM:
144                     return NetworkRegistrationInfo.REGISTRATION_STATE_DENIED;
145                 case RegState.UNKNOWN:
146                 case RegState.UNKNOWN_EM:
147                     return NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN;
148                 case RegState.REG_ROAMING:
149                     return NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING;
150                 default:
151                     return NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING;
152             }
153         }
154 
isEmergencyOnly(int halRegState)155         private boolean isEmergencyOnly(int halRegState) {
156             switch (halRegState) {
157                 case RegState.NOT_REG_MT_NOT_SEARCHING_OP_EM:
158                 case RegState.NOT_REG_MT_SEARCHING_OP_EM:
159                 case RegState.REG_DENIED_EM:
160                 case RegState.UNKNOWN_EM:
161                     return true;
162                 case RegState.NOT_REG_MT_NOT_SEARCHING_OP:
163                 case RegState.REG_HOME:
164                 case RegState.NOT_REG_MT_SEARCHING_OP:
165                 case RegState.REG_DENIED:
166                 case RegState.UNKNOWN:
167                 case RegState.REG_ROAMING:
168                 default:
169                     return false;
170             }
171         }
172 
getAvailableServices(int regState, int domain, boolean emergencyOnly)173         private List<Integer> getAvailableServices(int regState, int domain,
174                                                    boolean emergencyOnly) {
175             List<Integer> availableServices = new ArrayList<>();
176 
177             // In emergency only states, only SERVICE_TYPE_EMERGENCY is available.
178             // Otherwise, certain services are available only if it's registered on home or roaming
179             // network.
180             if (emergencyOnly) {
181                 availableServices.add(NetworkRegistrationInfo.SERVICE_TYPE_EMERGENCY);
182             } else if (regState == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING
183                     || regState == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) {
184                 if (domain == NetworkRegistrationInfo.DOMAIN_PS) {
185                     availableServices.add(NetworkRegistrationInfo.SERVICE_TYPE_DATA);
186                 } else if (domain == NetworkRegistrationInfo.DOMAIN_CS) {
187                     availableServices.add(NetworkRegistrationInfo.SERVICE_TYPE_VOICE);
188                     availableServices.add(NetworkRegistrationInfo.SERVICE_TYPE_SMS);
189                     availableServices.add(NetworkRegistrationInfo.SERVICE_TYPE_VIDEO);
190                 }
191             }
192 
193             return availableServices;
194         }
195 
getRegistrationStateFromResult(Object result, int domain)196         private NetworkRegistrationInfo getRegistrationStateFromResult(Object result, int domain) {
197             if (result == null) {
198                 return null;
199             }
200 
201             // TODO: unify when voiceRegStateResult and DataRegStateResult are unified.
202             if (domain == NetworkRegistrationInfo.DOMAIN_CS) {
203                 return createRegistrationStateFromVoiceRegState(result);
204             } else if (domain == NetworkRegistrationInfo.DOMAIN_PS) {
205                 return createRegistrationStateFromDataRegState(result);
206             } else {
207                 return null;
208             }
209         }
210 
createRegistrationStateFromVoiceRegState(Object result)211         private NetworkRegistrationInfo createRegistrationStateFromVoiceRegState(Object result) {
212             int transportType = AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
213             int domain = NetworkRegistrationInfo.DOMAIN_CS;
214 
215             if (result instanceof android.hardware.radio.V1_0.VoiceRegStateResult) {
216                 android.hardware.radio.V1_0.VoiceRegStateResult voiceRegState =
217                         (android.hardware.radio.V1_0.VoiceRegStateResult) result;
218                 int regState = getRegStateFromHalRegState(voiceRegState.regState);
219                 int networkType = ServiceState.rilRadioTechnologyToNetworkType(voiceRegState.rat);
220                 if (networkType == TelephonyManager.NETWORK_TYPE_LTE_CA) {
221                     networkType = TelephonyManager.NETWORK_TYPE_LTE;
222                 }
223                 int reasonForDenial = voiceRegState.reasonForDenial;
224                 boolean emergencyOnly = isEmergencyOnly(voiceRegState.regState);
225                 boolean cssSupported = voiceRegState.cssSupported;
226                 int roamingIndicator = voiceRegState.roamingIndicator;
227                 int systemIsInPrl = voiceRegState.systemIsInPrl;
228                 int defaultRoamingIndicator = voiceRegState.defaultRoamingIndicator;
229                 List<Integer> availableServices = getAvailableServices(
230                         regState, domain, emergencyOnly);
231                 CellIdentity cellIdentity =
232                         convertHalCellIdentityToCellIdentity(voiceRegState.cellIdentity);
233 
234                 return new NetworkRegistrationInfo(domain, transportType, regState,
235                         networkType, reasonForDenial, emergencyOnly, availableServices,
236                         cellIdentity, cssSupported, roamingIndicator, systemIsInPrl,
237                         defaultRoamingIndicator);
238             } else if (result instanceof android.hardware.radio.V1_2.VoiceRegStateResult) {
239                 android.hardware.radio.V1_2.VoiceRegStateResult voiceRegState =
240                         (android.hardware.radio.V1_2.VoiceRegStateResult) result;
241                 int regState = getRegStateFromHalRegState(voiceRegState.regState);
242                 int networkType = ServiceState.rilRadioTechnologyToNetworkType(voiceRegState.rat);
243                 if (networkType == TelephonyManager.NETWORK_TYPE_LTE_CA) {
244                     networkType = TelephonyManager.NETWORK_TYPE_LTE;
245                 }
246                 int reasonForDenial = voiceRegState.reasonForDenial;
247                 boolean emergencyOnly = isEmergencyOnly(voiceRegState.regState);
248                 boolean cssSupported = voiceRegState.cssSupported;
249                 int roamingIndicator = voiceRegState.roamingIndicator;
250                 int systemIsInPrl = voiceRegState.systemIsInPrl;
251                 int defaultRoamingIndicator = voiceRegState.defaultRoamingIndicator;
252                 List<Integer> availableServices = getAvailableServices(
253                         regState, domain, emergencyOnly);
254                 CellIdentity cellIdentity =
255                         convertHalCellIdentityToCellIdentity(voiceRegState.cellIdentity);
256 
257                 return new NetworkRegistrationInfo(domain, transportType, regState,
258                         networkType, reasonForDenial, emergencyOnly, availableServices,
259                         cellIdentity, cssSupported, roamingIndicator, systemIsInPrl,
260                         defaultRoamingIndicator);
261             }
262 
263             return null;
264         }
265 
createRegistrationStateFromDataRegState(Object result)266         private NetworkRegistrationInfo createRegistrationStateFromDataRegState(Object result) {
267             int domain = NetworkRegistrationInfo.DOMAIN_PS;
268             int regState = NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN;
269             int transportType = AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
270             int networkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
271             int reasonForDenial = 0;
272             boolean isUsingCarrierAggregation = false;
273             boolean emergencyOnly = false;
274             int maxDataCalls = 0;
275             CellIdentity cellIdentity;
276             boolean isEndcAvailable = false;
277             boolean isNrAvailable = false;
278             boolean isDcNrRestricted = false;
279 
280             LteVopsSupportInfo lteVopsSupportInfo =
281                     new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE,
282                             LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE);
283 
284             if (result instanceof android.hardware.radio.V1_0.DataRegStateResult) {
285                 android.hardware.radio.V1_0.DataRegStateResult dataRegState =
286                         (android.hardware.radio.V1_0.DataRegStateResult) result;
287                 regState = getRegStateFromHalRegState(dataRegState.regState);
288                 networkType = ServiceState.rilRadioTechnologyToNetworkType(dataRegState.rat);
289                 reasonForDenial = dataRegState.reasonDataDenied;
290                 emergencyOnly = isEmergencyOnly(dataRegState.regState);
291                 maxDataCalls = dataRegState.maxDataCalls;
292 
293                 cellIdentity = convertHalCellIdentityToCellIdentity(dataRegState.cellIdentity);
294             } else if (result instanceof android.hardware.radio.V1_2.DataRegStateResult) {
295                 android.hardware.radio.V1_2.DataRegStateResult dataRegState =
296                         (android.hardware.radio.V1_2.DataRegStateResult) result;
297                 regState = getRegStateFromHalRegState(dataRegState.regState);
298                 networkType = ServiceState.rilRadioTechnologyToNetworkType(dataRegState.rat);
299                 reasonForDenial = dataRegState.reasonDataDenied;
300                 emergencyOnly = isEmergencyOnly(dataRegState.regState);
301                 maxDataCalls = dataRegState.maxDataCalls;
302                 cellIdentity = convertHalCellIdentityToCellIdentity(dataRegState.cellIdentity);
303             } else if (result instanceof android.hardware.radio.V1_4.DataRegStateResult) {
304                 android.hardware.radio.V1_4.DataRegStateResult dataRegState =
305                         (android.hardware.radio.V1_4.DataRegStateResult) result;
306                 regState = getRegStateFromHalRegState(dataRegState.base.regState);
307                 networkType = ServiceState.rilRadioTechnologyToNetworkType(dataRegState.base.rat);
308 
309                 reasonForDenial = dataRegState.base.reasonDataDenied;
310                 emergencyOnly = isEmergencyOnly(dataRegState.base.regState);
311                 maxDataCalls = dataRegState.base.maxDataCalls;
312                 cellIdentity = convertHalCellIdentityToCellIdentity(dataRegState.base.cellIdentity);
313                 android.hardware.radio.V1_4.NrIndicators nrIndicators = dataRegState.nrIndicators;
314 
315                 // Check for lteVopsInfo only if its initialized and RAT is EUTRAN
316                 if (dataRegState.vopsInfo.getDiscriminator() == hidl_discriminator.lteVopsInfo
317                         && ServiceState.rilRadioTechnologyToAccessNetworkType(dataRegState.base.rat)
318                             == AccessNetworkType.EUTRAN) {
319                     android.hardware.radio.V1_4.LteVopsInfo vopsSupport =
320                             dataRegState.vopsInfo.lteVopsInfo();
321                     lteVopsSupportInfo = convertHalLteVopsSupportInfo(vopsSupport.isVopsSupported,
322                         vopsSupport.isEmcBearerSupported);
323                 } else {
324                     lteVopsSupportInfo =
325                         new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE,
326                         LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE);
327                 }
328 
329                 isEndcAvailable = nrIndicators.isEndcAvailable;
330                 isNrAvailable = nrIndicators.isNrAvailable;
331                 isDcNrRestricted = nrIndicators.isDcNrRestricted;
332             } else {
333                 loge("Unknown type of DataRegStateResult " + result);
334                 return null;
335             }
336 
337             List<Integer> availableServices = getAvailableServices(
338                     regState, domain, emergencyOnly);
339 
340             if (networkType == TelephonyManager.NETWORK_TYPE_LTE_CA) {
341                 isUsingCarrierAggregation = true;
342                 networkType = TelephonyManager.NETWORK_TYPE_LTE;
343             }
344 
345             return new NetworkRegistrationInfo(domain, transportType, regState, networkType,
346                     reasonForDenial, emergencyOnly, availableServices, cellIdentity, maxDataCalls,
347                     isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo,
348                     isUsingCarrierAggregation);
349         }
350 
convertHalLteVopsSupportInfo( boolean vopsSupport, boolean emcBearerSupport)351         private LteVopsSupportInfo convertHalLteVopsSupportInfo(
352                 boolean vopsSupport, boolean emcBearerSupport) {
353             int vops = LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED;
354             int emergency = LteVopsSupportInfo.LTE_STATUS_NOT_SUPPORTED;
355 
356             if (vopsSupport) {
357                 vops = LteVopsSupportInfo.LTE_STATUS_SUPPORTED;
358             }
359             if (emcBearerSupport) {
360                 emergency = LteVopsSupportInfo.LTE_STATUS_SUPPORTED;
361             }
362             return new LteVopsSupportInfo(vops, emergency);
363         }
364 
convertHalCellIdentityToCellIdentity( android.hardware.radio.V1_0.CellIdentity cellIdentity)365         private CellIdentity convertHalCellIdentityToCellIdentity(
366                 android.hardware.radio.V1_0.CellIdentity cellIdentity) {
367             if (cellIdentity == null) {
368                 return null;
369             }
370 
371             CellIdentity result = null;
372             switch(cellIdentity.cellInfoType) {
373                 case CellInfoType.GSM: {
374                     if (cellIdentity.cellIdentityGsm.size() == 1) {
375                         android.hardware.radio.V1_0.CellIdentityGsm cellIdentityGsm =
376                                 cellIdentity.cellIdentityGsm.get(0);
377                         result = new CellIdentityGsm(cellIdentityGsm);
378                     }
379                     break;
380                 }
381                 case CellInfoType.WCDMA: {
382                     if (cellIdentity.cellIdentityWcdma.size() == 1) {
383                         android.hardware.radio.V1_0.CellIdentityWcdma cellIdentityWcdma =
384                                 cellIdentity.cellIdentityWcdma.get(0);
385                         result = new CellIdentityWcdma(cellIdentityWcdma);
386                     }
387                     break;
388                 }
389                 case CellInfoType.TD_SCDMA: {
390                     if (cellIdentity.cellIdentityTdscdma.size() == 1) {
391                         android.hardware.radio.V1_0.CellIdentityTdscdma cellIdentityTdscdma =
392                                 cellIdentity.cellIdentityTdscdma.get(0);
393                         result = new  CellIdentityTdscdma(cellIdentityTdscdma);
394                     }
395                     break;
396                 }
397                 case CellInfoType.LTE: {
398                     if (cellIdentity.cellIdentityLte.size() == 1) {
399                         android.hardware.radio.V1_0.CellIdentityLte cellIdentityLte =
400                                 cellIdentity.cellIdentityLte.get(0);
401                         result = new CellIdentityLte(cellIdentityLte);
402                     }
403                     break;
404                 }
405                 case CellInfoType.CDMA: {
406                     if (cellIdentity.cellIdentityCdma.size() == 1) {
407                         android.hardware.radio.V1_0.CellIdentityCdma cellIdentityCdma =
408                                 cellIdentity.cellIdentityCdma.get(0);
409                         result = new CellIdentityCdma(cellIdentityCdma);
410                     }
411                     break;
412                 }
413                 case CellInfoType.NONE:
414                 default:
415                     break;
416             }
417 
418             return result;
419         }
420 
convertHalCellIdentityToCellIdentity( android.hardware.radio.V1_2.CellIdentity cellIdentity)421         private CellIdentity convertHalCellIdentityToCellIdentity(
422                 android.hardware.radio.V1_2.CellIdentity cellIdentity) {
423             if (cellIdentity == null) {
424                 return null;
425             }
426 
427             CellIdentity result = null;
428             switch(cellIdentity.cellInfoType) {
429                 case CellInfoType.GSM: {
430                     if (cellIdentity.cellIdentityGsm.size() == 1) {
431                         android.hardware.radio.V1_2.CellIdentityGsm cellIdentityGsm =
432                                 cellIdentity.cellIdentityGsm.get(0);
433                         result = new CellIdentityGsm(cellIdentityGsm);
434                     }
435                     break;
436                 }
437                 case CellInfoType.WCDMA: {
438                     if (cellIdentity.cellIdentityWcdma.size() == 1) {
439                         android.hardware.radio.V1_2.CellIdentityWcdma cellIdentityWcdma =
440                                 cellIdentity.cellIdentityWcdma.get(0);
441                         result = new CellIdentityWcdma(cellIdentityWcdma);
442                     }
443                     break;
444                 }
445                 case CellInfoType.TD_SCDMA: {
446                     if (cellIdentity.cellIdentityTdscdma.size() == 1) {
447                         android.hardware.radio.V1_2.CellIdentityTdscdma cellIdentityTdscdma =
448                                 cellIdentity.cellIdentityTdscdma.get(0);
449                         result = new  CellIdentityTdscdma(cellIdentityTdscdma);
450                     }
451                     break;
452                 }
453                 case CellInfoType.LTE: {
454                     if (cellIdentity.cellIdentityLte.size() == 1) {
455                         android.hardware.radio.V1_2.CellIdentityLte cellIdentityLte =
456                                 cellIdentity.cellIdentityLte.get(0);
457                         result = new CellIdentityLte(cellIdentityLte);
458                     }
459                     break;
460                 }
461                 case CellInfoType.CDMA: {
462                     if (cellIdentity.cellIdentityCdma.size() == 1) {
463                         android.hardware.radio.V1_2.CellIdentityCdma cellIdentityCdma =
464                                 cellIdentity.cellIdentityCdma.get(0);
465                         result = new CellIdentityCdma(cellIdentityCdma);
466                     }
467                     break;
468                 }
469                 case CellInfoType.NONE:
470                 default:
471                     break;
472             }
473 
474             return result;
475         }
476 
477         @Override
requestNetworkRegistrationInfo(int domain, NetworkServiceCallback callback)478         public void requestNetworkRegistrationInfo(int domain, NetworkServiceCallback callback) {
479             if (DBG) log("requestNetworkRegistrationInfo for domain " + domain);
480             Message message = null;
481 
482             if (domain == NetworkRegistrationInfo.DOMAIN_CS) {
483                 message = Message.obtain(mHandler, GET_CS_REGISTRATION_STATE_DONE);
484                 mCallbackMap.put(message, callback);
485                 mPhone.mCi.getVoiceRegistrationState(message);
486             } else if (domain == NetworkRegistrationInfo.DOMAIN_PS) {
487                 message = Message.obtain(mHandler, GET_PS_REGISTRATION_STATE_DONE);
488                 mCallbackMap.put(message, callback);
489                 mPhone.mCi.getDataRegistrationState(message);
490             } else {
491                 loge("requestNetworkRegistrationInfo invalid domain " + domain);
492                 callback.onRequestNetworkRegistrationInfoComplete(
493                         NetworkServiceCallback.RESULT_ERROR_INVALID_ARG, null);
494             }
495         }
496 
497         @Override
close()498         public void close() {
499             mCallbackMap.clear();
500             mHandlerThread.quit();
501             mPhone.mCi.unregisterForNetworkStateChanged(mHandler);
502         }
503     }
504 
505     @Override
onCreateNetworkServiceProvider(int slotIndex)506     public NetworkServiceProvider onCreateNetworkServiceProvider(int slotIndex) {
507         if (DBG) log("Cellular network service created for slot " + slotIndex);
508         if (!SubscriptionManager.isValidSlotIndex(slotIndex)) {
509             loge("Tried to Cellular network service with invalid slotId " + slotIndex);
510             return null;
511         }
512         return new CellularNetworkServiceProvider(slotIndex);
513     }
514 
log(String s)515     private void log(String s) {
516         Rlog.d(TAG, s);
517     }
518 
loge(String s)519     private void loge(String s) {
520         Rlog.e(TAG, s);
521     }
522 }
523