Home | History | Annotate | Download | only in otasp
      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
     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
     94     public int onStartCommand(Intent intent, int flags, int startId) {
     95         return START_REDELIVER_INTENT;
     96     }
     97 
     98     @Override
     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      */
    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      */
    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      */
    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 
    195     private void onComplete() {
    196         logd("otasp service onComplete");
    197         unregisterAll();
    198         stopSelf();
    199     }
    200 
    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 
    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 
    218     private static void logd(String s) {
    219         android.util.Log.d(TAG, s);
    220     }
    221 
    222     private static void loge(String s) {
    223         android.util.Log.e(TAG, s);
    224     }
    225 }
    226