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