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