• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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