1 /* 2 * Copyright (C) 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 package com.android.phone.otasp; 17 18 import static com.android.phone.PhoneGlobals.getPhone; 19 20 import android.app.Service; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.os.AsyncResult; 24 import android.os.Handler; 25 import android.os.IBinder; 26 import android.os.Message; 27 import android.telephony.ServiceState; 28 import android.telephony.SubscriptionManager; 29 import android.telephony.TelephonyManager; 30 31 import com.android.internal.telephony.GsmCdmaConnection; 32 import com.android.internal.telephony.Phone; 33 import com.android.internal.telephony.PhoneConstants; 34 import com.android.internal.telephony.ServiceStateTracker; 35 import com.android.phone.PhoneGlobals; 36 import com.android.phone.PhoneUtils; 37 38 /** 39 * otasp activation service handles all logic related with OTASP call. 40 * OTASP is a CDMA-specific feature: OTA or OTASP == Over The Air service provisioning 41 * In practice, in a normal successful OTASP call, events come in as follows: 42 * - SPL_UNLOCKED within a couple of seconds after the call starts 43 * - PRL_DOWNLOADED and MDN_DOWNLOADED and COMMITTED within a span of 2 seconds 44 * - poll cdma subscription from RIL after COMMITTED 45 * - SIM reloading with provisioned MDN and MIN 46 */ 47 public class OtaspActivationService extends Service { 48 private static final String TAG = OtaspActivationService.class.getSimpleName(); 49 private static final boolean DBG = true; 50 /** 51 * non-interactive otasp number 52 */ 53 private static final String OTASP_NUMBER = GsmCdmaConnection.OTASP_NUMBER; 54 55 /** 56 * Otasp call follows with SIM reloading which might triggers a retry loop on activation 57 * failure. A max retry limit could help prevent retry loop. 58 */ 59 private static final int OTASP_CALL_RETRIES_MAX = 3; 60 private static final int OTASP_CALL_RETRY_PERIOD_IN_MS = 3000; 61 private static int sOtaspCallRetries = 0; 62 63 /* events */ 64 private static final int EVENT_CALL_STATE_CHANGED = 0; 65 private static final int EVENT_CDMA_OTASP_CALL_RETRY = 1; 66 private static final int EVENT_CDMA_PROVISION_STATUS_UPDATE = 2; 67 private static final int EVENT_SERVICE_STATE_CHANGED = 3; 68 private static final int EVENT_START_OTASP_CALL = 4; 69 70 /* use iccid to detect hot sim swap */ 71 private static String sIccId = null; 72 73 private Phone mPhone; 74 /* committed flag indicates Otasp call succeed */ 75 private boolean mIsOtaspCallCommitted = false; 76 77 @Override onCreate()78 public void onCreate() { 79 logd("otasp service onCreate"); 80 mPhone = PhoneGlobals.getPhone(); 81 ServiceStateTracker sst = mPhone.getServiceStateTracker(); 82 if (sst != null && sst.getOtasp() != TelephonyManager.OTASP_NEEDED) { 83 logd("OTASP is not needed."); 84 return; 85 } 86 if ((sIccId == null) || !sIccId.equals(mPhone.getIccSerialNumber())) { 87 // reset to allow activation retry on new sim 88 sIccId = mPhone.getIccSerialNumber(); 89 sOtaspCallRetries = 0; 90 } 91 sOtaspCallRetries++; 92 logd("OTASP call tried " + sOtaspCallRetries + " times"); 93 if (sOtaspCallRetries > OTASP_CALL_RETRIES_MAX) { 94 logd("OTASP call exceeds max retries => activation failed"); 95 updateActivationState(this, false); 96 onComplete(); 97 return; 98 } 99 mHandler.sendEmptyMessage(EVENT_START_OTASP_CALL); 100 } 101 102 @Override onStartCommand(Intent intent, int flags, int startId)103 public int onStartCommand(Intent intent, int flags, int startId) { 104 return START_REDELIVER_INTENT; 105 } 106 107 @Override onBind(Intent intent)108 public IBinder onBind(Intent intent) { 109 return null; 110 } 111 112 private Handler mHandler = new Handler() { 113 @Override 114 public void handleMessage(Message msg) { 115 switch (msg.what) { 116 case EVENT_SERVICE_STATE_CHANGED: 117 logd("EVENT_SERVICE_STATE_CHANGED"); 118 onStartOtaspCall(); 119 break; 120 case EVENT_START_OTASP_CALL: 121 logd("EVENT_START_OTASP_CALL"); 122 onStartOtaspCall(); 123 break; 124 case EVENT_CALL_STATE_CHANGED: 125 logd("OTASP_CALL_STATE_CHANGED"); 126 onOtaspCallStateChanged(); 127 break; 128 case EVENT_CDMA_PROVISION_STATUS_UPDATE: 129 logd("OTASP_ACTIVATION_STATUS_UPDATE_EVENT"); 130 onCdmaProvisionStatusUpdate((AsyncResult) msg.obj); 131 break; 132 case EVENT_CDMA_OTASP_CALL_RETRY: 133 logd("EVENT_CDMA_OTASP_CALL_RETRY"); 134 onStartOtaspCall(); 135 break; 136 default: 137 loge("invalid msg: " + msg.what + " not handled."); 138 } 139 } 140 }; 141 142 /** 143 * Starts the OTASP call without any UI. 144 * platform only support background non-interactive otasp call, but users could still dial 145 * interactive OTASP number through dialer if carrier allows (some carrier will 146 * explicitly block any outgoing *288XX number). 147 */ onStartOtaspCall()148 private void onStartOtaspCall() { 149 unregisterAll(); 150 if (mPhone.getServiceState().getState() != ServiceState.STATE_IN_SERVICE) { 151 loge("OTASP call failure, wait for network available."); 152 mPhone.registerForServiceStateChanged(mHandler, EVENT_SERVICE_STATE_CHANGED, null); 153 return; 154 } 155 // otasp call follows with CDMA OTA PROVISION STATUS update which signals activation result 156 mPhone.registerForCdmaOtaStatusChange(mHandler, EVENT_CDMA_PROVISION_STATUS_UPDATE, null); 157 mPhone.registerForPreciseCallStateChanged(mHandler, EVENT_CALL_STATE_CHANGED, null); 158 logd("startNonInteractiveOtasp: placing call to '" + OTASP_NUMBER + "'..."); 159 int callStatus = PhoneUtils.placeOtaspCall(this, 160 getPhone(), 161 OTASP_NUMBER); 162 if (callStatus == PhoneUtils.CALL_STATUS_DIALED) { 163 if (DBG) logd(" ==> success return from placeCall(): callStatus = " + callStatus); 164 } else { 165 loge(" ==> failure return from placeCall(): callStatus = " + callStatus); 166 mHandler.sendEmptyMessageDelayed(EVENT_CDMA_OTASP_CALL_RETRY, 167 OTASP_CALL_RETRY_PERIOD_IN_MS); 168 } 169 } 170 171 /** 172 * register for cdma ota provision status 173 * see RIL_CDMA_OTA_ProvisionStatus in include/telephony/ril.h 174 */ onCdmaProvisionStatusUpdate(AsyncResult r)175 private void onCdmaProvisionStatusUpdate(AsyncResult r) { 176 int[] otaStatus = (int[]) r.result; 177 logd("onCdmaProvisionStatusUpdate: " + otaStatus[0]); 178 if (Phone.CDMA_OTA_PROVISION_STATUS_COMMITTED == otaStatus[0]) { 179 mIsOtaspCallCommitted = true; 180 } 181 } 182 183 /** 184 * update activation state upon call disconnected. 185 * check the mIsOtaspCallCommitted bit, and if that's true it means that activation 186 * was successful. 187 */ onOtaspCallStateChanged()188 private void onOtaspCallStateChanged() { 189 logd("onOtaspCallStateChanged: " + mPhone.getState()); 190 if (mPhone.getState().equals(PhoneConstants.State.IDLE)) { 191 if (mIsOtaspCallCommitted) { 192 logd("Otasp activation succeed"); 193 updateActivationState(this, true); 194 } else { 195 logd("Otasp activation failed"); 196 updateActivationState(this, false); 197 } 198 onComplete(); 199 } 200 } 201 onComplete()202 private void onComplete() { 203 logd("otasp service onComplete"); 204 unregisterAll(); 205 stopSelf(); 206 } 207 unregisterAll()208 private void unregisterAll() { 209 mPhone.unregisterForCdmaOtaStatusChange(mHandler); 210 mPhone.unregisterForSubscriptionInfoReady(mHandler); 211 mPhone.unregisterForServiceStateChanged(mHandler); 212 mPhone.unregisterForPreciseCallStateChanged(mHandler); 213 mHandler.removeCallbacksAndMessages(null); 214 } 215 updateActivationState(Context context, boolean success)216 public static void updateActivationState(Context context, boolean success) { 217 final TelephonyManager mTelephonyMgr = TelephonyManager.from(context); 218 int state = (success) ? TelephonyManager.SIM_ACTIVATION_STATE_ACTIVATED : 219 TelephonyManager.SIM_ACTIVATION_STATE_DEACTIVATED; 220 int subId = SubscriptionManager.getDefaultSubscriptionId(); 221 mTelephonyMgr.setVoiceActivationState(subId, state); 222 mTelephonyMgr.setDataActivationState(subId, state); 223 } 224 logd(String s)225 private static void logd(String s) { 226 android.util.Log.d(TAG, s); 227 } 228 loge(String s)229 private static void loge(String s) { 230 android.util.Log.e(TAG, s); 231 } 232 } 233