CellularNetworkService.java revision 269ee0aa10b0cc586eef68d55f153b1bdbc2085c
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.DataRegStateResult;
22import android.hardware.radio.V1_0.RegState;
23import android.hardware.radio.V1_0.VoiceRegStateResult;
24import android.os.AsyncResult;
25import android.os.Handler;
26import android.os.HandlerThread;
27import android.os.Looper;
28import android.os.Message;
29import android.telephony.AccessNetworkConstants.TransportType;
30import android.telephony.CellIdentity;
31import android.telephony.CellIdentityCdma;
32import android.telephony.CellIdentityGsm;
33import android.telephony.CellIdentityLte;
34import android.telephony.CellIdentityTdscdma;
35import android.telephony.CellIdentityWcdma;
36import android.telephony.NetworkRegistrationState;
37import android.telephony.NetworkService;
38import android.telephony.NetworkServiceCallback;
39import android.telephony.Rlog;
40import android.telephony.ServiceState;
41import android.telephony.SubscriptionManager;
42
43import java.util.concurrent.ConcurrentHashMap;
44
45/**
46 * Implementation of network services for Cellular. It's a service that handles network requests
47 * for Cellular. It passes the requests to inner CellularNetworkServiceProvider which has a
48 * handler thread for each slot.
49 */
50public class CellularNetworkService extends NetworkService {
51    private static final boolean DBG = false;
52
53    private static final String TAG = CellularNetworkService.class.getSimpleName();
54
55    private static final int GET_CS_REGISTRATION_STATE_DONE = 1;
56    private static final int GET_PS_REGISTRATION_STATE_DONE = 2;
57    private static final int NETWORK_REGISTRATION_STATE_CHANGED = 3;
58
59    private class CellularNetworkServiceProvider extends NetworkServiceProvider {
60
61        private final ConcurrentHashMap<Message, NetworkServiceCallback> mCallbackMap =
62                new ConcurrentHashMap<>();
63
64        private final Looper mLooper;
65
66        private final HandlerThread mHandlerThread;
67
68        private final Handler mHandler;
69
70        private final Phone mPhone;
71
72        CellularNetworkServiceProvider(int slotId) {
73            super(slotId);
74
75            mPhone = PhoneFactory.getPhone(getSlotId());
76
77            mHandlerThread = new HandlerThread(CellularNetworkService.class.getSimpleName());
78            mHandlerThread.start();
79            mLooper = mHandlerThread.getLooper();
80            mHandler = new Handler(mLooper) {
81                @Override
82                public void handleMessage(Message message) {
83                    NetworkServiceCallback callback = mCallbackMap.remove(message);
84
85                    AsyncResult ar;
86                    switch (message.what) {
87                        case GET_CS_REGISTRATION_STATE_DONE:
88                        case GET_PS_REGISTRATION_STATE_DONE:
89                            if (callback == null) return;
90                            ar = (AsyncResult) message.obj;
91                            int domain = (message.what == GET_CS_REGISTRATION_STATE_DONE)
92                                    ? NetworkRegistrationState.DOMAIN_CS
93                                    : NetworkRegistrationState.DOMAIN_PS;
94                            NetworkRegistrationState netState =
95                                    getRegistrationStateFromResult(ar.result, domain);
96
97                            int resultCode;
98                            if (ar.exception != null || netState == null) {
99                                resultCode = NetworkServiceCallback.RESULT_ERROR_FAILED;
100                            } else {
101                                resultCode = NetworkServiceCallback.RESULT_SUCCESS;
102                            }
103
104                            try {
105                                if (DBG) {
106                                    log("Calling callback.onGetNetworkRegistrationStateComplete."
107                                            + "resultCode = " + resultCode
108                                            + ", netState = " + netState);
109                                }
110                                callback.onGetNetworkRegistrationStateComplete(
111                                         resultCode, netState);
112                            } catch (Exception e) {
113                                loge("Exception: " + e);
114                            }
115                            break;
116                        case NETWORK_REGISTRATION_STATE_CHANGED:
117                            notifyNetworkRegistrationStateChanged();
118                            break;
119                        default:
120                            return;
121                    }
122                }
123            };
124
125            mPhone.mCi.registerForNetworkStateChanged(
126                    mHandler, NETWORK_REGISTRATION_STATE_CHANGED, null);
127        }
128
129        private int getRegStateFromHalRegState(int halRegState) {
130            switch (halRegState) {
131                case RegState.NOT_REG_MT_NOT_SEARCHING_OP:
132                case RegState.NOT_REG_MT_NOT_SEARCHING_OP_EM:
133                    return NetworkRegistrationState.REG_STATE_NOT_REG_NOT_SEARCHING;
134                case RegState.REG_HOME:
135                    return NetworkRegistrationState.REG_STATE_HOME;
136                case RegState.NOT_REG_MT_SEARCHING_OP:
137                case RegState.NOT_REG_MT_SEARCHING_OP_EM:
138                    return NetworkRegistrationState.REG_STATE_NOT_REG_SEARCHING;
139                case RegState.REG_DENIED:
140                case RegState.REG_DENIED_EM:
141                    return NetworkRegistrationState.REG_STATE_DENIED;
142                case RegState.UNKNOWN:
143                case RegState.UNKNOWN_EM:
144                    return NetworkRegistrationState.REG_STATE_UNKNOWN;
145                case RegState.REG_ROAMING:
146                    return NetworkRegistrationState.REG_STATE_ROAMING;
147                default:
148                    return NetworkRegistrationState.REG_STATE_NOT_REG_NOT_SEARCHING;
149            }
150        }
151
152        private boolean isEmergencyOnly(int halRegState) {
153            switch (halRegState) {
154                case RegState.NOT_REG_MT_NOT_SEARCHING_OP_EM:
155                case RegState.NOT_REG_MT_SEARCHING_OP_EM:
156                case RegState.REG_DENIED_EM:
157                case RegState.UNKNOWN_EM:
158                    return true;
159                case RegState.NOT_REG_MT_NOT_SEARCHING_OP:
160                case RegState.REG_HOME:
161                case RegState.NOT_REG_MT_SEARCHING_OP:
162                case RegState.REG_DENIED:
163                case RegState.UNKNOWN:
164                case RegState.REG_ROAMING:
165                default:
166                    return false;
167            }
168        }
169
170        private int[] getAvailableServices(int regState, int domain,
171                boolean emergencyOnly) {
172            int[] availableServices = null;
173
174            // In emergency only states, only SERVICE_TYPE_EMERGENCY is available.
175            // Otherwise, certain services are available only if it's registered on home or roaming
176            // network.
177            if (emergencyOnly) {
178                availableServices = new int[] {NetworkRegistrationState.SERVICE_TYPE_EMERGENCY};
179            } else if (regState == NetworkRegistrationState.REG_STATE_ROAMING
180                    || regState != NetworkRegistrationState.REG_STATE_HOME) {
181                if (domain == NetworkRegistrationState.DOMAIN_PS) {
182                    availableServices = new int[] {NetworkRegistrationState.SERVICE_TYPE_DATA};
183                } else if (domain == NetworkRegistrationState.DOMAIN_CS) {
184                    availableServices = new int[] {
185                            NetworkRegistrationState.SERVICE_TYPE_VOICE,
186                            NetworkRegistrationState.SERVICE_TYPE_SMS,
187                            NetworkRegistrationState.SERVICE_TYPE_VIDEO
188                    };
189                }
190            }
191
192            return availableServices;
193        }
194
195        private int getAccessNetworkTechnologyFromRat(int rilRat) {
196            return ServiceState.rilRadioTechnologyToNetworkType(rilRat);
197        }
198
199        private NetworkRegistrationState getRegistrationStateFromResult(Object result, int domain) {
200            if (result == null) {
201                return null;
202            }
203
204            // TODO: unify when voiceRegStateResult and DataRegStateResult are unified.
205            if (domain == NetworkRegistrationState.DOMAIN_CS) {
206                VoiceRegStateResult voiceRegState = (VoiceRegStateResult) result;
207                int transportType = TransportType.WWAN;
208                int regState = getRegStateFromHalRegState(voiceRegState.regState);
209                int accessNetworkTechnology = getAccessNetworkTechnologyFromRat(voiceRegState.rat);
210                int reasonForDenial = voiceRegState.reasonForDenial;
211                boolean emergencyOnly = isEmergencyOnly(voiceRegState.regState);
212                boolean cssSupported = voiceRegState.cssSupported;
213                int roamingIndicator = voiceRegState.roamingIndicator;
214                int systemIsInPrl = voiceRegState.systemIsInPrl;
215                int defaultRoamingIndicator = voiceRegState.defaultRoamingIndicator;
216                int[] availableServices = getAvailableServices(
217                        regState, domain, emergencyOnly);
218                CellIdentity cellIdentity =
219                        convertHalCellIdentityToCellIdentity(voiceRegState.cellIdentity);
220
221                return new NetworkRegistrationState(transportType, domain, regState,
222                        accessNetworkTechnology, reasonForDenial, emergencyOnly, availableServices,
223                        cellIdentity, cssSupported, roamingIndicator, systemIsInPrl,
224                        defaultRoamingIndicator);
225            } else if (domain == NetworkRegistrationState.DOMAIN_PS) {
226                DataRegStateResult dataRegState = (DataRegStateResult) result;
227                int transportType = TransportType.WWAN;
228                int regState = getRegStateFromHalRegState(dataRegState.regState);
229                int accessNetworkTechnology = getAccessNetworkTechnologyFromRat(dataRegState.rat);
230                int reasonForDenial = dataRegState.reasonDataDenied;
231                boolean emergencyOnly = isEmergencyOnly(dataRegState.regState);
232                int maxDataCalls = dataRegState.maxDataCalls;
233                int[] availableServices = getAvailableServices(regState, domain, emergencyOnly);
234                CellIdentity cellIdentity =
235                        convertHalCellIdentityToCellIdentity(dataRegState.cellIdentity);
236                return new NetworkRegistrationState(transportType, domain, regState,
237                        accessNetworkTechnology, reasonForDenial, emergencyOnly, availableServices,
238                        cellIdentity, maxDataCalls);
239            } else {
240                return null;
241            }
242        }
243
244        private CellIdentity convertHalCellIdentityToCellIdentity(
245                android.hardware.radio.V1_0.CellIdentity cellIdentity) {
246            CellIdentity result = null;
247            switch(cellIdentity.cellInfoType) {
248                case CellInfoType.GSM: {
249                    if (cellIdentity.cellIdentityGsm.size() == 1) {
250                        android.hardware.radio.V1_0.CellIdentityGsm cellIdentityGsm =
251                                cellIdentity.cellIdentityGsm.get(0);
252                        result = new CellIdentityGsm(cellIdentityGsm.lac, cellIdentityGsm.cid,
253                                cellIdentityGsm.arfcn, cellIdentityGsm.bsic, cellIdentityGsm.mcc,
254                                cellIdentityGsm.mnc, null, null);
255                    }
256                    break;
257                }
258                case CellInfoType.WCDMA: {
259                    if (cellIdentity.cellIdentityWcdma.size() == 1) {
260                        android.hardware.radio.V1_0.CellIdentityWcdma cellIdentityWcdma =
261                                cellIdentity.cellIdentityWcdma.get(0);
262                        result = new CellIdentityWcdma(cellIdentityWcdma.lac, cellIdentityWcdma.cid,
263                                cellIdentityWcdma.psc, cellIdentityWcdma.uarfcn,
264                                cellIdentityWcdma.mcc, cellIdentityWcdma.mnc, null, null);
265                    }
266                    break;
267                }
268                case CellInfoType.TD_SCDMA: {
269                    if (cellIdentity.cellIdentityTdscdma.size() == 1) {
270                        android.hardware.radio.V1_0.CellIdentityTdscdma cellIdentityTdscdma =
271                                cellIdentity.cellIdentityTdscdma.get(0);
272                        result = new  CellIdentityTdscdma(cellIdentityTdscdma.mcc,
273                                cellIdentityTdscdma.mnc, cellIdentityTdscdma.lac,
274                                cellIdentityTdscdma.cid, cellIdentityTdscdma.cpid);
275                    }
276                    break;
277                }
278                case CellInfoType.LTE: {
279                    if (cellIdentity.cellIdentityLte.size() == 1) {
280                        android.hardware.radio.V1_0.CellIdentityLte cellIdentityLte =
281                                cellIdentity.cellIdentityLte.get(0);
282
283                        result = new CellIdentityLte(cellIdentityLte.ci, cellIdentityLte.pci,
284                                cellIdentityLte.tac, cellIdentityLte.earfcn, Integer.MAX_VALUE,
285                                cellIdentityLte.mcc, cellIdentityLte.mnc, null, null);
286                    }
287                    break;
288                }
289                case CellInfoType.CDMA: {
290                    if (cellIdentity.cellIdentityCdma.size() == 1) {
291                        android.hardware.radio.V1_0.CellIdentityCdma cellIdentityCdma =
292                                cellIdentity.cellIdentityCdma.get(0);
293
294                        result = new CellIdentityCdma(cellIdentityCdma.networkId,
295                                cellIdentityCdma.systemId, cellIdentityCdma.baseStationId,
296                                cellIdentityCdma.longitude, cellIdentityCdma.latitude);
297                    }
298                    break;
299                }
300                case CellInfoType.NONE:
301                default:
302                    break;
303            }
304
305            return result;
306        }
307
308        public void getNetworkRegistrationState(int domain, NetworkServiceCallback callback) {
309            if (DBG) log("getNetworkRegistrationState for domain " + domain);
310            Message message = null;
311
312            if (domain == NetworkRegistrationState.DOMAIN_CS) {
313                message = Message.obtain(mHandler, GET_CS_REGISTRATION_STATE_DONE);
314                mCallbackMap.put(message, callback);
315                mPhone.mCi.getVoiceRegistrationState(message);
316            } else if (domain == NetworkRegistrationState.DOMAIN_PS) {
317                message = Message.obtain(mHandler, GET_PS_REGISTRATION_STATE_DONE);
318                mCallbackMap.put(message, callback);
319                mPhone.mCi.getDataRegistrationState(message);
320            } else {
321                loge("getNetworkRegistrationState invalid domain " + domain);
322                callback.onGetNetworkRegistrationStateComplete(
323                        NetworkServiceCallback.RESULT_ERROR_INVALID_ARG, null);
324            }
325        }
326
327        @CallSuper
328        protected void onDestroy() {
329            super.onDestroy();
330
331            mCallbackMap.clear();
332            mHandlerThread.quit();
333            mPhone.mCi.unregisterForNetworkStateChanged(mHandler);
334        }
335    }
336
337    @Override
338    protected NetworkServiceProvider createNetworkServiceProvider(int slotId) {
339        if (DBG) log("Cellular network service created for slot " + slotId);
340        if (!SubscriptionManager.isValidSlotIndex(slotId)) {
341            loge("Tried to Cellular network service with invalid slotId " + slotId);
342            return null;
343        }
344        return new CellularNetworkServiceProvider(slotId);
345    }
346
347    private void log(String s) {
348        Rlog.d(TAG, s);
349    }
350
351    private void loge(String s) {
352        Rlog.e(TAG, s);
353    }
354}
355