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