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