CellularNetworkService.java revision 6f3f4d42433c54a08b4e98f6dac6260aa1de4bf6
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, boolean emergencyOnly) {
171            int[] availableServices = null;
172
173            // In emergency only states, only SERVICE_TYPE_EMERGENCY is available.
174            // Otherwise, certain services are available only if it's registered on home or roaming
175            // network.
176            if (emergencyOnly) {
177                availableServices = new int[] {NetworkRegistrationState.SERVICE_TYPE_EMERGENCY};
178            } else if (regState == NetworkRegistrationState.REG_STATE_ROAMING
179                    || regState == NetworkRegistrationState.REG_STATE_HOME) {
180                if (domain == NetworkRegistrationState.DOMAIN_PS) {
181                    availableServices = new int[] {NetworkRegistrationState.SERVICE_TYPE_DATA};
182                } else if (domain == NetworkRegistrationState.DOMAIN_CS) {
183                    availableServices = new int[] {
184                            NetworkRegistrationState.SERVICE_TYPE_VOICE,
185                            NetworkRegistrationState.SERVICE_TYPE_SMS,
186                            NetworkRegistrationState.SERVICE_TYPE_VIDEO
187                    };
188                }
189            }
190
191            return availableServices;
192        }
193
194        private int getAccessNetworkTechnologyFromRat(int rilRat) {
195            return ServiceState.rilRadioTechnologyToNetworkType(rilRat);
196        }
197
198        private NetworkRegistrationState getRegistrationStateFromResult(Object result, int domain) {
199            if (result == null) {
200                return null;
201            }
202
203            // TODO: unify when voiceRegStateResult and DataRegStateResult are unified.
204            if (domain == NetworkRegistrationState.DOMAIN_CS) {
205                VoiceRegStateResult voiceRegState = (VoiceRegStateResult) result;
206                int transportType = TransportType.WWAN;
207                int regState = getRegStateFromHalRegState(voiceRegState.regState);
208                int accessNetworkTechnology = getAccessNetworkTechnologyFromRat(voiceRegState.rat);
209                int reasonForDenial = voiceRegState.reasonForDenial;
210                boolean emergencyOnly = isEmergencyOnly(voiceRegState.regState);
211                boolean cssSupported = voiceRegState.cssSupported;
212                int roamingIndicator = voiceRegState.roamingIndicator;
213                int systemIsInPrl = voiceRegState.systemIsInPrl;
214                int defaultRoamingIndicator = voiceRegState.defaultRoamingIndicator;
215                int[] availableServices = getAvailableServices(
216                        regState, domain, emergencyOnly);
217                CellIdentity cellIdentity =
218                        convertHalCellIdentityToCellIdentity(voiceRegState.cellIdentity);
219
220                return new NetworkRegistrationState(transportType, domain, regState,
221                        accessNetworkTechnology, reasonForDenial, emergencyOnly, availableServices,
222                        cellIdentity, cssSupported, roamingIndicator, systemIsInPrl,
223                        defaultRoamingIndicator);
224            } else if (domain == NetworkRegistrationState.DOMAIN_PS) {
225                DataRegStateResult dataRegState = (DataRegStateResult) result;
226                int transportType = TransportType.WWAN;
227                int regState = getRegStateFromHalRegState(dataRegState.regState);
228                int accessNetworkTechnology = getAccessNetworkTechnologyFromRat(dataRegState.rat);
229                int reasonForDenial = dataRegState.reasonDataDenied;
230                boolean emergencyOnly = isEmergencyOnly(dataRegState.regState);
231                int maxDataCalls = dataRegState.maxDataCalls;
232                int[] availableServices = getAvailableServices(regState, domain, emergencyOnly);
233                CellIdentity cellIdentity =
234                        convertHalCellIdentityToCellIdentity(dataRegState.cellIdentity);
235                return new NetworkRegistrationState(transportType, domain, regState,
236                        accessNetworkTechnology, reasonForDenial, emergencyOnly, availableServices,
237                        cellIdentity, maxDataCalls);
238            } else {
239                return null;
240            }
241        }
242
243        private CellIdentity convertHalCellIdentityToCellIdentity(
244                android.hardware.radio.V1_0.CellIdentity cellIdentity) {
245            if (cellIdentity == null) {
246                return null;
247            }
248
249            CellIdentity result = null;
250            switch(cellIdentity.cellInfoType) {
251                case CellInfoType.GSM: {
252                    if (cellIdentity.cellIdentityGsm.size() == 1) {
253                        android.hardware.radio.V1_0.CellIdentityGsm cellIdentityGsm =
254                                cellIdentity.cellIdentityGsm.get(0);
255                        result = new CellIdentityGsm(cellIdentityGsm.lac, cellIdentityGsm.cid,
256                                cellIdentityGsm.arfcn, cellIdentityGsm.bsic, cellIdentityGsm.mcc,
257                                cellIdentityGsm.mnc, null, null);
258                    }
259                    break;
260                }
261                case CellInfoType.WCDMA: {
262                    if (cellIdentity.cellIdentityWcdma.size() == 1) {
263                        android.hardware.radio.V1_0.CellIdentityWcdma cellIdentityWcdma =
264                                cellIdentity.cellIdentityWcdma.get(0);
265                        result = new CellIdentityWcdma(cellIdentityWcdma.lac, cellIdentityWcdma.cid,
266                                cellIdentityWcdma.psc, cellIdentityWcdma.uarfcn,
267                                cellIdentityWcdma.mcc, cellIdentityWcdma.mnc, null, null);
268                    }
269                    break;
270                }
271                case CellInfoType.TD_SCDMA: {
272                    if (cellIdentity.cellIdentityTdscdma.size() == 1) {
273                        android.hardware.radio.V1_0.CellIdentityTdscdma cellIdentityTdscdma =
274                                cellIdentity.cellIdentityTdscdma.get(0);
275                        result = new  CellIdentityTdscdma(cellIdentityTdscdma.mcc,
276                                cellIdentityTdscdma.mnc, cellIdentityTdscdma.lac,
277                                cellIdentityTdscdma.cid, cellIdentityTdscdma.cpid);
278                    }
279                    break;
280                }
281                case CellInfoType.LTE: {
282                    if (cellIdentity.cellIdentityLte.size() == 1) {
283                        android.hardware.radio.V1_0.CellIdentityLte cellIdentityLte =
284                                cellIdentity.cellIdentityLte.get(0);
285
286                        result = new CellIdentityLte(cellIdentityLte.ci, cellIdentityLte.pci,
287                                cellIdentityLte.tac, cellIdentityLte.earfcn, Integer.MAX_VALUE,
288                                cellIdentityLte.mcc, cellIdentityLte.mnc, null, null);
289                    }
290                    break;
291                }
292                case CellInfoType.CDMA: {
293                    if (cellIdentity.cellIdentityCdma.size() == 1) {
294                        android.hardware.radio.V1_0.CellIdentityCdma cellIdentityCdma =
295                                cellIdentity.cellIdentityCdma.get(0);
296
297                        result = new CellIdentityCdma(cellIdentityCdma.networkId,
298                                cellIdentityCdma.systemId, cellIdentityCdma.baseStationId,
299                                cellIdentityCdma.longitude, cellIdentityCdma.latitude);
300                    }
301                    break;
302                }
303                case CellInfoType.NONE:
304                default:
305                    break;
306            }
307
308            return result;
309        }
310
311        @Override
312        public void getNetworkRegistrationState(int domain, NetworkServiceCallback callback) {
313            if (DBG) log("getNetworkRegistrationState for domain " + domain);
314            Message message = null;
315
316            if (domain == NetworkRegistrationState.DOMAIN_CS) {
317                message = Message.obtain(mHandler, GET_CS_REGISTRATION_STATE_DONE);
318                mCallbackMap.put(message, callback);
319                mPhone.mCi.getVoiceRegistrationState(message);
320            } else if (domain == NetworkRegistrationState.DOMAIN_PS) {
321                message = Message.obtain(mHandler, GET_PS_REGISTRATION_STATE_DONE);
322                mCallbackMap.put(message, callback);
323                mPhone.mCi.getDataRegistrationState(message);
324            } else {
325                loge("getNetworkRegistrationState invalid domain " + domain);
326                callback.onGetNetworkRegistrationStateComplete(
327                        NetworkServiceCallback.RESULT_ERROR_INVALID_ARG, null);
328            }
329        }
330
331        @CallSuper
332        protected void onDestroy() {
333            super.onDestroy();
334
335            mCallbackMap.clear();
336            mHandlerThread.quit();
337            mPhone.mCi.unregisterForNetworkStateChanged(mHandler);
338        }
339    }
340
341    @Override
342    protected NetworkServiceProvider createNetworkServiceProvider(int slotId) {
343        if (DBG) log("Cellular network service created for slot " + slotId);
344        if (!SubscriptionManager.isValidSlotIndex(slotId)) {
345            loge("Tried to Cellular network service with invalid slotId " + slotId);
346            return null;
347        }
348        return new CellularNetworkServiceProvider(slotId);
349    }
350
351    private void log(String s) {
352        Rlog.d(TAG, s);
353    }
354
355    private void loge(String s) {
356        Rlog.e(TAG, s);
357    }
358}
359