Home | History | Annotate | Download | only in ims
      1 /*
      2  * Copyright (c) 2015, Motorola Mobility LLC
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *     - Redistributions of source code must retain the above copyright
      8  *       notice, this list of conditions and the following disclaimer.
      9  *     - Redistributions in binary form must reproduce the above copyright
     10  *       notice, this list of conditions and the following disclaimer in the
     11  *       documentation and/or other materials provided with the distribution.
     12  *     - Neither the name of Motorola Mobility nor the
     13  *       names of its contributors may be used to endorse or promote products
     14  *       derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MOTOROLA MOBILITY LLC BE LIABLE
     20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
     26  * DAMAGE.
     27  */
     28 
     29 package com.android.service.ims;
     30 
     31 import java.util.List;
     32 import java.util.concurrent.Semaphore;
     33 import java.util.concurrent.TimeUnit;
     34 
     35 import android.content.BroadcastReceiver;
     36 import android.content.ComponentName;
     37 import android.content.pm.PackageManager;
     38 import android.content.pm.ResolveInfo;
     39 import android.content.pm.ServiceInfo;
     40 import android.content.Context;
     41 import android.content.Intent;
     42 import android.app.PendingIntent;
     43 import android.content.IntentFilter;
     44 import android.content.ServiceConnection;
     45 import android.os.Handler;
     46 import android.os.HandlerThread;
     47 import android.os.IBinder;
     48 import android.os.Looper;
     49 import android.os.Message;
     50 import android.os.RemoteException;
     51 import android.telephony.TelephonyManager;
     52 import android.app.AlarmManager;
     53 import android.os.SystemClock;
     54 import android.os.SystemProperties;
     55 import com.android.ims.ImsConfig;
     56 import com.android.ims.ImsManager;
     57 import com.android.ims.ImsException;
     58 import android.telephony.SubscriptionManager;
     59 
     60 import com.android.ims.IRcsPresenceListener;
     61 import com.android.ims.RcsPresence;
     62 import com.android.ims.RcsManager.ResultCode;
     63 import com.android.ims.RcsPresence.PublishState;
     64 
     65 import com.android.ims.internal.Logger;
     66 import com.android.ims.internal.ContactNumberUtils;
     67 import com.android.service.ims.presence.PresencePublication;
     68 import com.android.service.ims.R;
     69 
     70 import com.android.ims.internal.uce.presence.IPresenceService;
     71 import com.android.ims.internal.uce.presence.PresCapInfo;
     72 import com.android.ims.internal.uce.common.CapInfo;
     73 import com.android.ims.internal.uce.uceservice.IUceService;
     74 import com.android.ims.internal.uce.uceservice.ImsUceManager;
     75 import com.android.ims.internal.uce.common.UceLong;
     76 import com.android.ims.internal.uce.common.StatusCode;
     77 
     78 import com.android.ims.IRcsPresenceListener;
     79 import com.android.ims.RcsPresenceInfo;
     80 
     81 import com.android.service.ims.presence.StackListener;
     82 import com.android.service.ims.presence.PresenceInfoParser;
     83 import com.android.service.ims.presence.AlarmBroadcastReceiver;
     84 
     85 public class RcsStackAdaptor{
     86     private static final boolean DEBUG = true;
     87 
     88     private static final String PERSIST_SERVICE_NAME =
     89             "com.android.service.ims.presence.PersistService";
     90     private static final String PERSIST_SERVICE_PACKAGE = "com.android.service.ims.presence";
     91 
     92     // The logger
     93     private Logger logger = Logger.getLogger(this.getClass().getName());
     94 
     95     private static final int PRESENCE_INIT_IMS_UCE_SERVICE = 1;
     96 
     97     private Context mContext = null;
     98 
     99     // true when the stack presence service got available. (Called IQPresListener_ServiceAvailable)
    100     private volatile boolean mImsEnableState = false;
    101 
    102     // provision status can be set by both subscribe and pubilish
    103     // for unprovisioned for 403 or 404
    104     private volatile int mPublishingState = PublishState.PUBLISH_STATE_NOT_PUBLISHED;
    105 
    106     // It is initializing the stack presence service.
    107     private volatile boolean mIsIniting = false;
    108 
    109     // The time which the stack presence service got initialized.
    110     private volatile long mLastInitSubService = -1; //last time which inited the sub service
    111 
    112     // Used for synchronizing
    113     private final Object mSyncObj = new Object();
    114 
    115     // We need wait RCS stack become unavailable before close RCS service.
    116     static private boolean sInPowerDown = false;
    117 
    118     // This could happen when the stack first launch or modem panic.
    119     private static final int PRESENCE_INIT_TYPE_RCS_SERVICE_AVAILABLE =1;
    120 
    121     // The initialization was triggered by retry.
    122     private static final int PRESENCE_INIT_TYPE_RETRY = 2;
    123 
    124     // The initialization was triggered by retry.
    125     private static final int PRESENCE_INIT_TYPE_IMS_REGISTERED = 3;
    126 
    127     // The maximum retry count for initializing the stack service.
    128     private static final int MAX_RETRY_COUNT = 6;//Maximum time is 64s
    129 
    130     public boolean isImsEnableState() {
    131         synchronized (mSyncObj) {
    132             return mImsEnableState;
    133         }
    134     }
    135 
    136     public void setImsEnableState(boolean imsEnableState) {
    137         synchronized (mSyncObj) {
    138             logger.debug("imsEnableState=" + imsEnableState);
    139             mImsEnableState = imsEnableState;
    140         }
    141     }
    142 
    143     // The UCE manager for RCS stack.
    144     private ImsUceManager mImsUceManager = null;
    145 
    146     // The stack RCS Service instance.
    147     private IUceService mStackService = null;
    148 
    149     // The stack presence service
    150     private IPresenceService mStackPresService = null;
    151 
    152     // The stack Presence Service handle.
    153     private int  mStackPresenceServiceHandle;
    154 
    155     // The listener which listen to the response for presence service.
    156     private StackListener mListenerHandler = null;
    157 
    158     // The handler of the listener.
    159     private UceLong mListenerHandle = new UceLong();
    160 
    161     // The singleton.
    162     private static RcsStackAdaptor sInstance = null;
    163 
    164     // Constructor
    165     private RcsStackAdaptor(Context context) {
    166         mContext = context;
    167 
    168         init();
    169     }
    170 
    171     public static synchronized RcsStackAdaptor getInstance(Context context) {
    172         if ((sInstance == null) && (context != null)) {
    173             sInstance = new RcsStackAdaptor(context);
    174         }
    175 
    176         return sInstance;
    177     }
    178 
    179     private Handler mMsgHandler = new Handler() {
    180         @Override
    181         public void handleMessage(Message msg) {
    182             super.handleMessage(msg);
    183 
    184             logger.debug( "Thread=" + Thread.currentThread().getName() + " received "
    185                     + msg);
    186             if(msg == null){
    187                 logger.error("msg=null");
    188                 return;
    189            }
    190 
    191             switch (msg.what) {
    192                 case PRESENCE_INIT_IMS_UCE_SERVICE:
    193                     logger.debug("handleMessage  msg=PRESENCE_INIT_IMS_UCE_SERVICE" );
    194                     doInitImsUceService();
    195                 break;
    196 
    197                 default:
    198                     logger.debug("handleMessage unknown msg=" + msg.what);
    199             }
    200         }
    201     };
    202 
    203     public StackListener getListener(){
    204         return mListenerHandler;
    205     }
    206 
    207     public int checkStackAndPublish(){
    208         if (!RcsSettingUtils.getCapabilityDiscoveryEnabled(mContext)) {
    209             logger.error("getCapabilityDiscoveryEnabled = false");
    210             return ResultCode.ERROR_SERVICE_NOT_ENABLED;
    211         }
    212 
    213         int ret = checkStackStatus();
    214         if (ret != ResultCode.SUCCESS) {
    215             logger.error("checkStackAndPublish ret=" + ret);
    216             return ret;
    217         }
    218 
    219         if (!isPublished()) {
    220             logger.error(
    221                     "checkStackAndPublish ERROR_SERVICE_NOT_PUBLISHED");
    222             return ResultCode.ERROR_SERVICE_NOT_PUBLISHED;
    223         }
    224 
    225         return ResultCode.SUCCESS;
    226     }
    227 
    228     private boolean isPublished(){
    229         if(getPublishState() != PublishState.PUBLISH_STATE_200_OK){
    230             logger.error("Didnt' publish properly");
    231             return false;
    232         }
    233 
    234         return true;
    235     }
    236 
    237     public void setPublishState(int publishState) {
    238         synchronized (mSyncObj) {
    239             logger.print("mPublishingState=" + mPublishingState + " publishState=" + publishState);
    240             if (mPublishingState != publishState) {
    241                 // save it for recovery when PresenceService crash.
    242                 SystemProperties.set("rcs.publish.status",
    243                         String.valueOf(publishState));
    244 
    245                 Intent publishIntent = new Intent(RcsPresence.ACTION_PUBLISH_STATE_CHANGED);
    246                 publishIntent.putExtra(RcsPresence.EXTRA_PUBLISH_STATE, publishState);
    247                 // Start PersistService and broadcast to other receivers that are listening
    248                 // dynamically.
    249                 mContext.sendStickyBroadcast(publishIntent);
    250                 launchPersistService(publishIntent);
    251             }
    252 
    253             mPublishingState = publishState;
    254         }
    255     }
    256 
    257     public int getPublishState(){
    258         synchronized (mSyncObj) {
    259             return mPublishingState;
    260         }
    261     }
    262 
    263     public int checkStackStatus(){
    264         synchronized (mSyncObj) {
    265             if (!RcsSettingUtils.isEabProvisioned(mContext)) {
    266                 logger.error("Didn't get EAB provisioned by DM");
    267                 return ResultCode.ERROR_SERVICE_NOT_ENABLED;
    268             }
    269 
    270             // Don't send request to RCS stack when it is under powering off.
    271             // RCS stack is sending UNPUBLISH. It could get race PUBLISH trigger under the case.
    272             if (sInPowerDown) {
    273                 logger.error("checkStackStatus: under powering off");
    274                 return ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
    275             }
    276 
    277             if (mStackService == null) {
    278                 logger.error("checkStackStatus: mStackService == null");
    279                 return ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
    280             }
    281 
    282             if (mStackPresService == null) {
    283                 logger.error("Didn't init sub rcs service.");
    284                 return ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
    285             }
    286 
    287             if (!mImsEnableState) {
    288                 logger.error("mImsEnableState = false");
    289                 return ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
    290             }
    291         }
    292 
    293         return ResultCode.SUCCESS;
    294     }
    295 
    296     public int requestCapability(String[] formatedContacts, int taskId){
    297         logger.print("requestCapability formatedContacts=" + formatedContacts);
    298 
    299         int ret = ResultCode.SUCCESS;
    300         try {
    301             synchronized (mSyncObj) {
    302                 StatusCode retCode;
    303                 if (formatedContacts.length == 1) {
    304                     retCode = mStackPresService.getContactCap(
    305                             mStackPresenceServiceHandle, formatedContacts[0], taskId);
    306                 } else {
    307                     retCode = mStackPresService.getContactListCap(
    308                             mStackPresenceServiceHandle, formatedContacts, taskId);
    309                 }
    310 
    311                 logger.print("GetContactListCap retCode=" + retCode);
    312 
    313                 ret = RcsUtils.statusCodeToResultCode(retCode.getStatusCode());
    314             }
    315 
    316             logger.debug("requestCapability ret=" + ret);
    317         }catch(Exception e){
    318             logger.error("requestCapability exception", e);
    319             ret = ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
    320         }
    321 
    322         return  ret;
    323     }
    324 
    325     public int requestAvailability(String formatedContact, int taskId){
    326         logger.debug("requestAvailability ...");
    327 
    328         int ret = ResultCode.SUCCESS;
    329         try{
    330             synchronized (mSyncObj) {
    331                 StatusCode retCode = mStackPresService.getContactCap(
    332                         mStackPresenceServiceHandle, formatedContact, taskId);
    333                 logger.print("getContactCap retCode=" + retCode);
    334 
    335                 ret = RcsUtils.statusCodeToResultCode(retCode.getStatusCode());
    336             }
    337             logger.debug("requestAvailability ret=" + ret);
    338         }catch(Exception e){
    339             logger.error("requestAvailability exception", e);
    340             ret = ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
    341         }
    342 
    343         return  ret;
    344     }
    345 
    346     public int requestPublication(RcsPresenceInfo presenceInfo, IRcsPresenceListener listener) {
    347         logger.debug("requestPublication ...");
    348 
    349          // Don't use checkStackAndPublish()
    350          // since it will check publish status which in dead loop.
    351          int ret = checkStackStatus();
    352          if(ret != ResultCode.SUCCESS){
    353              logger.error("requestPublication ret=" + ret);
    354              return ret;
    355          }
    356 
    357         TelephonyManager teleMgr = (TelephonyManager) mContext.getSystemService(
    358             Context.TELEPHONY_SERVICE);
    359         if(teleMgr == null){
    360             logger.error("teleMgr = null");
    361             return PresencePublication.PUBLISH_GENIRIC_FAILURE;
    362         }
    363 
    364         String myNumUri = null;
    365         String myDomain = teleMgr.getIsimDomain();
    366         logger.debug("myDomain=" + myDomain);
    367         if(myDomain != null && myDomain.length() !=0){
    368             String[] impu = teleMgr.getIsimImpu();
    369 
    370             if(impu !=null){
    371                 for(int i=0; i<impu.length; i++){
    372                     logger.debug("impu[" + i + "]=" + impu[i]);
    373                     if(impu[i] != null && impu[i].startsWith("sip:") &&
    374                             impu[i].endsWith(myDomain)){
    375                         myNumUri = impu[i];
    376                         break;
    377                     }
    378                 }
    379             }
    380         }
    381 
    382         String myNumber = PresenceInfoParser.getPhoneFromUri(myNumUri);
    383 
    384         if(myNumber == null){
    385             myNumber = ContactNumberUtils.getDefault().format(teleMgr.getLine1Number());
    386             if(myDomain != null && myDomain.length() !=0){
    387                 myNumUri = "sip:" + myNumber + "@" + myDomain;
    388             }else{
    389                 myNumUri = "tel:" + myNumber;
    390             }
    391         }
    392 
    393         logger.print("myNumUri=" + myNumUri + " myNumber=" + myNumber);
    394         if(myNumUri == null || myNumber == null){
    395             logger.error("Didn't find number or impu.");
    396             return PresencePublication.PUBLISH_GENIRIC_FAILURE;
    397         }
    398 
    399         int taskId = TaskManager.getDefault().addPublishTask(myNumber, listener);
    400         try{
    401             PresCapInfo pMyCapInfo = new PresCapInfo();
    402             // Fill cap info
    403             pMyCapInfo.setContactUri(myNumUri);
    404 
    405             CapInfo capInfo = new CapInfo();
    406             capInfo.setIpVoiceSupported(presenceInfo.getServiceState(
    407                     RcsPresenceInfo.ServiceType.VOLTE_CALL)
    408                     == RcsPresenceInfo.ServiceState.ONLINE);
    409             capInfo.setIpVideoSupported(presenceInfo.getServiceState(
    410                     RcsPresenceInfo.ServiceType.VT_CALL)
    411                     == RcsPresenceInfo.ServiceState.ONLINE);
    412             capInfo.setCdViaPresenceSupported(true);
    413 
    414             capInfo.setFtSupported(false); // TODO: support FT
    415             capInfo.setImSupported(false);//TODO: support chat
    416             capInfo.setFullSnFGroupChatSupported(false); //TODO: support chat
    417 
    418             pMyCapInfo.setCapInfo(capInfo);
    419 
    420             logger.print( "myNumUri = " + myNumUri
    421                     + " audioSupported =  " + capInfo.isIpVoiceSupported()
    422                     + " videoSupported=  " + capInfo.isIpVideoSupported()
    423                     );
    424 
    425 
    426             synchronized (mSyncObj) {
    427                 StatusCode status = mStackPresService.publishMyCap(
    428                         mStackPresenceServiceHandle, pMyCapInfo, taskId);
    429                 logger.print("PublishMyCap status=" + status.getStatusCode());
    430                 ret = RcsUtils.statusCodeToResultCode(status.getStatusCode());
    431             }
    432 
    433             logger.debug("requestPublication ret=" + ret);
    434             if(ret != ResultCode.SUCCESS){
    435                 logger.error("requestPublication remove taskId=" + taskId);
    436                 TaskManager.getDefault().removeTask(taskId);
    437                 return ret;
    438             }
    439         }catch(RemoteException e){
    440             e.printStackTrace();
    441             logger.error("Exception when call mStackPresService.getContactCap");
    442             logger.error("requestPublication remove taskId=" + taskId);
    443             TaskManager.getDefault().removeTask(taskId);
    444 
    445             return ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
    446         }
    447 
    448         return  ResultCode.SUCCESS;
    449     }
    450 
    451     private void launchPersistService(Intent intent) {
    452         ComponentName component = new ComponentName(PERSIST_SERVICE_PACKAGE,
    453                 PERSIST_SERVICE_NAME);
    454         intent.setComponent(component);
    455         mContext.startService(intent);
    456     }
    457 
    458     private void createListeningThread() {
    459         HandlerThread listenerThread = new HandlerThread("Listener",
    460                 android.os.Process.THREAD_PRIORITY_BACKGROUND);
    461 
    462         listenerThread.start();
    463         Looper listenerLooper = listenerThread.getLooper();
    464         mListenerHandler = new StackListener(mContext, listenerLooper);
    465     }
    466 
    467     private void initImsUceService(){
    468         // Send message to avoid ANR
    469         Message reinitMessage = mMsgHandler.obtainMessage(
    470                 PRESENCE_INIT_IMS_UCE_SERVICE, null);
    471         mMsgHandler.sendMessage(reinitMessage);
    472     }
    473 
    474     private void doInitImsUceService(){
    475         synchronized (mSyncObj) {
    476             logger.debug("doInitImsUceService");
    477 
    478             if (mStackService != null) {
    479                 logger.debug("doInitImsUceService mStackService != null");
    480                 return;
    481             }
    482 
    483             IntentFilter filter = new IntentFilter();
    484             filter.addAction(ImsUceManager.ACTION_UCE_SERVICE_UP);
    485             filter.addAction(ImsUceManager.ACTION_UCE_SERVICE_DOWN);
    486 
    487             mRcsServiceReceiver = new BroadcastReceiver() {
    488                 @Override
    489                 public void onReceive(Context context, Intent intent) {
    490                     // do something based on the intent's action
    491                     logger.print("onReceive intent " + intent);
    492                     String action = intent.getAction();
    493                     if (ImsUceManager.ACTION_UCE_SERVICE_UP.equals(action)) {
    494                         startInitPresenceTimer(0, PRESENCE_INIT_TYPE_RCS_SERVICE_AVAILABLE);
    495                     } else if (ImsUceManager.ACTION_UCE_SERVICE_DOWN.equals(action)) {
    496                         clearImsUceService();
    497                     } else {
    498                         logger.debug("unknown intent " + intent);
    499                     }
    500                 }
    501             };
    502 
    503             mContext.registerReceiver(mRcsServiceReceiver, filter);
    504 
    505             if (mImsUceManager == null) {
    506                 mImsUceManager = ImsUceManager.getInstance(mContext,
    507                         SubscriptionManager.from(mContext).getDefaultDataPhoneId());
    508                 if (mImsUceManager == null) {
    509                     logger.error("Can't init mImsUceManager");
    510                     return;
    511                 }
    512             }
    513 
    514             mImsUceManager.createUceService(false);
    515             mStackService = mImsUceManager.getUceServiceInstance();
    516             logger.debug("doInitImsUceService mStackService=" + mStackService);
    517 
    518             // Do not connect to vendor UCE stack until ACTION_UCE_SERVICE_UP is called.
    519             // The intent is sticky, so if we crash, we will get the UCE_SERVICE_UP intent again.
    520         }
    521     }
    522 
    523     private PendingIntent mRetryAlarmIntent = null;
    524     public static final String ACTION_RETRY_ALARM = "com.android.service.ims.presence.retry";
    525     private AlarmManager mAlarmManager = null;
    526     private BroadcastReceiver mRcsServiceReceiver = null;
    527 
    528     /*
    529      * Init All Sub service of RCS
    530      */
    531     int initAllSubRcsServices(IUceService uceService, int currentRetry) {
    532         int ret = -1;
    533         synchronized (mSyncObj) {
    534             // we could receive useless retry since we could fail to cancel the retry timer.
    535             // We need to ignore such retry if the sub service had been initialized already.
    536             if(mStackPresService != null && currentRetry>0){
    537                 logger.debug("mStackPresService != null and currentRetry=" + currentRetry +
    538                         " ignore it");
    539                 return 0;
    540             }
    541 
    542             logger.debug("Init All Services Under RCS uceService=" + uceService);
    543             if(uceService == null){
    544                 logger.error("initAllServices : uceService is NULL  ");
    545                 mIsIniting = false;
    546                 mLastInitSubService = -1;
    547                 return ret;
    548             }
    549 
    550             try {
    551                 if(mStackPresService != null){
    552                     logger.print("RemoveListener and QRCSDestroyPresService");
    553                     mStackPresService.removeListener(mStackPresenceServiceHandle,
    554                             mListenerHandle);
    555                     uceService.destroyPresenceService(mStackPresenceServiceHandle);
    556 
    557                     mStackPresService = null;
    558                 }
    559 
    560                 boolean serviceStatus = false;
    561                 serviceStatus = uceService.getServiceStatus();
    562                 //init only once and ensure connection to UCE  service is available.
    563                 if (true == serviceStatus && mStackPresService == null && mStackService != null) {
    564                     logger.print("initAllService : serviceStatus =  true ");
    565                     logger.debug("Create PresService");
    566                     mStackPresenceServiceHandle = mStackService.createPresenceService(
    567                             mListenerHandler.mPresenceListener, mListenerHandle);
    568                     // If the service handle is -1, then creating the service failed somehow.
    569                     // schedule a retry.
    570                     if (mStackPresenceServiceHandle < 0) {
    571                         logger.error("initAllService : service handle < 0, retrying...");
    572                         mIsIniting = false;
    573                         mLastInitSubService = -1;
    574                         return ret;
    575                     }
    576                     mStackPresService = mStackService.getPresenceService();
    577                     ret = 0;
    578                  } else {
    579                     logger.error("initAllService : serviceStatus =  false - serviceStatus: "
    580                             + serviceStatus + ", mStackPresService: " + mStackPresService
    581                             + ", mStackService: " + mStackService);
    582                 }
    583             } catch (RemoteException e) {
    584                 logger.error("initAllServices :  DeadObjectException dialog  ");
    585                 e.printStackTrace();
    586             }
    587             mIsIniting = false;
    588         }
    589         return ret;
    590     }
    591 
    592     public void startInitThread(int times){
    593         final int currentRetry = times;
    594         Thread thread = new Thread(() -> {
    595             synchronized (mSyncObj) {
    596                 if (currentRetry >= 0 && currentRetry <= MAX_RETRY_COUNT) {
    597                     refreshUceService();
    598 
    599                     if (initAllSubRcsServices(mStackService, currentRetry) >= 0) {
    600                         logger.debug("init sub rcs service successfully.");
    601                         if (mRetryAlarmIntent != null) {
    602                             mAlarmManager.cancel(mRetryAlarmIntent);
    603                         }
    604                     } else {
    605                         startInitPresenceTimer(currentRetry + 1, PRESENCE_INIT_TYPE_RETRY);
    606                     }
    607                 } else {
    608                     logger.debug("Retry times=" + currentRetry);
    609                     if (mRetryAlarmIntent != null) {
    610                         mAlarmManager.cancel(mRetryAlarmIntent);
    611                     }
    612                 }
    613             }
    614         }, "initAllSubRcsServices thread");
    615 
    616         thread.start();
    617     }
    618 
    619     private void init() {
    620         createListeningThread();
    621         logger.debug("after createListeningThread");
    622 
    623         if(mAlarmManager == null){
    624             mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
    625         }
    626 
    627         initImsUceService();
    628 
    629         setInPowerDown(false);
    630         logger.debug("init finished");
    631     }
    632 
    633     private void startInitPresenceTimer(int times, int initType){
    634         synchronized (mSyncObj) {
    635             logger.print("set the retry alarm, times=" + times + " initType=" + initType +
    636                     " mIsIniting=" + mIsIniting);
    637             if(mIsIniting){
    638                 //initing is on going in 5 seconds, discard this one.
    639                 if(mLastInitSubService != -1 &&
    640                         System.currentTimeMillis() - mLastInitSubService < 5000){
    641                     logger.print("already in initing. ignore it");
    642                     return;
    643                 }//else suppose the init has problem. so continue
    644             }
    645 
    646             mIsIniting = true;
    647 
    648             Intent intent = new Intent(ACTION_RETRY_ALARM);
    649             intent.putExtra("times", times);
    650             intent.setClass(mContext, AlarmBroadcastReceiver.class);
    651             mRetryAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent,
    652                     PendingIntent.FLAG_UPDATE_CURRENT);
    653 
    654             // Wait for 1s to ignore duplicate init request as possible as we can.
    655             long timeSkip = 1000;
    656             if(times < 0 || times >= MAX_RETRY_COUNT){
    657                 times = MAX_RETRY_COUNT;
    658             }
    659 
    660             //Could failed to cancel a timer in 1s. So use exponential retry to make sure it
    661             //will be stopped for non-VoLte SIM.
    662             timeSkip = (timeSkip << times);
    663             logger.debug("timeSkip = " + timeSkip);
    664 
    665             mLastInitSubService = System.currentTimeMillis();
    666 
    667             //the timer intent could have a longer delay. call directly at first time
    668             if(times == 0) {
    669                 startInitThread(0);
    670             } else {
    671                 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
    672                         SystemClock.elapsedRealtime() + timeSkip, mRetryAlarmIntent);
    673             }
    674         }
    675     }
    676 
    677     private void refreshUceService() {
    678         synchronized (mSyncObj) {
    679             logger.debug("refreshUceService mImsUceManager=" + mImsUceManager +
    680                     " mStackService=" + mStackService);
    681 
    682             if (mImsUceManager == null) {
    683                 mImsUceManager = ImsUceManager.getInstance(mContext,
    684                         SubscriptionManager.from(mContext).getDefaultDataPhoneId());
    685                 if (mImsUceManager == null) {
    686                     logger.error("Can't init mImsUceManager");
    687                     return;
    688                 }
    689             }
    690 
    691             if (mStackService == null) {
    692                 mImsUceManager.createUceService(false);
    693                 mStackService = mImsUceManager.getUceServiceInstance();
    694             }
    695 
    696             logger.debug("refreshUceService mStackService=" + mStackService);
    697         }
    698     }
    699 
    700     private void clearImsUceService() {
    701         synchronized (mSyncObj) {
    702             try {
    703                 logger.info("clearImsUceService: removing listener and presence service.");
    704                 if (mStackPresService != null) {
    705                     mStackPresService.removeListener(mStackPresenceServiceHandle,
    706                             mListenerHandle);
    707                 }
    708                 if (mStackService != null) {
    709                     mStackService.destroyPresenceService(mStackPresenceServiceHandle);
    710                 }
    711             } catch (RemoteException e) {
    712                 logger.warn("clearImsUceService: Couldn't clean up stack service");
    713             }
    714             mImsUceManager = null;
    715             mStackService = null;
    716             mStackPresService = null;
    717         }
    718     }
    719 
    720     public void finish() {
    721         if(mRetryAlarmIntent != null){
    722             mAlarmManager.cancel(mRetryAlarmIntent);
    723             mRetryAlarmIntent = null;
    724         }
    725 
    726         if (mRcsServiceReceiver != null) {
    727             mContext.unregisterReceiver(mRcsServiceReceiver);
    728             mRcsServiceReceiver = null;
    729         }
    730 
    731         clearImsUceService();
    732     }
    733 
    734     protected void finalize() throws Throwable {
    735         super.finalize();
    736         finish();
    737     }
    738 
    739     static public boolean isInPowerDown() {
    740         return sInPowerDown;
    741     }
    742 
    743     static void setInPowerDown(boolean inPowerDown) {
    744         sInPowerDown = inPowerDown;
    745     }
    746 }
    747 
    748