• 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.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