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