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