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 android.app.AlarmManager;
32 import android.app.PendingIntent;
33 import android.content.BroadcastReceiver;
34 import android.content.ComponentName;
35 import android.content.Context;
36 import android.content.Intent;
37 import android.content.IntentFilter;
38 import android.os.Handler;
39 import android.os.HandlerThread;
40 import android.os.Looper;
41 import android.os.Message;
42 import android.os.RemoteException;
43 import android.os.SystemClock;
44 import android.telephony.SubscriptionInfo;
45 import android.telephony.SubscriptionManager;
46 import android.telephony.TelephonyManager;
47 import android.telephony.ims.RcsContactPresenceTuple;
48 import android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities;
49 import android.telephony.ims.RcsContactUceCapability;
50 
51 import com.android.ims.ResultCode;
52 import com.android.ims.RcsPresence;
53 import com.android.ims.internal.Logger;
54 import com.android.ims.internal.uce.common.CapInfo;
55 import com.android.ims.internal.uce.common.StatusCode;
56 import com.android.ims.internal.uce.common.UceLong;
57 import com.android.ims.internal.uce.presence.IPresenceService;
58 import com.android.ims.internal.uce.presence.PresCapInfo;
59 import com.android.ims.internal.uce.uceservice.IUceService;
60 import com.android.ims.internal.uce.uceservice.ImsUceManager;
61 import com.android.service.ims.presence.PresenceBase;
62 import com.android.service.ims.presence.PresencePublisher;
63 import com.android.service.ims.presence.SubscribePublisher;
64 
65 public class RcsStackAdaptor implements PresencePublisher, SubscribePublisher {
66     private static final boolean DEBUG = true;
67 
68     private static final String PERSIST_SERVICE_NAME =
69             "com.android.service.ims.presence.PersistService";
70     private static final String PERSIST_SERVICE_PACKAGE = "com.android.service.ims.presence";
71 
72     /**
73      * PendingIntent action used to retry getting the UCE service. Need an associated
74      * BroadcastReceiver.
75      */
76     public static final String ACTION_RETRY_ALARM = "com.android.service.ims.presence.retry";
77 
78     // The logger
79     private Logger logger = Logger.getLogger(this.getClass().getName());
80 
81     private static final int PRESENCE_INIT_IMS_UCE_SERVICE = 1;
82 
83     private Context mContext = null;
84 
85     // true when the stack presence service got available. (Called IQPresListener_ServiceAvailable)
86     private volatile boolean mImsEnableState = false;
87 
88     // provision status can be set by both subscribe and pubilish
89     // for unprovisioned for 403 or 404
90     private volatile int mPublishingState = PresenceBase.PUBLISH_STATE_NOT_PUBLISHED;
91 
92     // It is initializing the stack presence service.
93     private volatile boolean mIsIniting = false;
94 
95     // The time which the stack presence service got initialized.
96     private volatile long mLastInitSubService = -1; //last time which inited the sub service
97 
98     // Used for synchronizing
99     private final Object mSyncObj = new Object();
100 
101     // We need wait RCS stack become unavailable before close RCS service.
102     static private boolean sInPowerDown = false;
103 
104     // This could happen when the stack first launch or modem panic.
105     private static final int PRESENCE_INIT_TYPE_RCS_SERVICE_AVAILABLE =1;
106 
107     // The initialization was triggered by retry.
108     private static final int PRESENCE_INIT_TYPE_RETRY = 2;
109 
110     // The initialization was triggered by retry.
111     private static final int PRESENCE_INIT_TYPE_SUB_CHANGED = 3;
112 
113     // The maximum retry count for initializing the stack service.
114     private static final int MAX_RETRY_COUNT = 6;//Maximum time is 64s
115 
isImsEnableState()116     public boolean isImsEnableState() {
117         synchronized (mSyncObj) {
118             return mImsEnableState;
119         }
120     }
121 
setImsEnableState(boolean imsEnableState)122     public void setImsEnableState(boolean imsEnableState) {
123         synchronized (mSyncObj) {
124             logger.debug("imsEnableState=" + imsEnableState);
125             mImsEnableState = imsEnableState;
126         }
127     }
128 
129     // The UCE manager for RCS stack.
130     private ImsUceManager mImsUceManager = null;
131 
132     // The stack RCS Service instance.
133     private IUceService mStackService = null;
134 
135     // The stack presence service
136     private IPresenceService mStackPresService = null;
137 
138     // The stack Presence Service handle.
139     private int  mStackPresenceServiceHandle;
140 
141     // The listener which listen to the response for presence service.
142     private StackListener mListenerHandler = null;
143 
144     // The handler of the listener.
145     private UceLong mListenerHandle = new UceLong();
146 
147     // The singleton.
148     private static RcsStackAdaptor sInstance = null;
149 
150     // the subscription on MSIM devices that is used for presence, since there is no MSIM support.
151     private int mAssociatedSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
152 
153     // Only start connecting to the stack after we have received ACTION_UCE_SERVICE_UP.
154     private boolean mStackAvailable = false;
155 
156     // Constructor
RcsStackAdaptor(Context context)157     private RcsStackAdaptor(Context context) {
158         mContext = context;
159 
160         init();
161     }
162 
getInstance(Context context)163     public static synchronized RcsStackAdaptor getInstance(Context context) {
164         if ((sInstance == null) && (context != null)) {
165             sInstance = new RcsStackAdaptor(context);
166         }
167 
168         return sInstance;
169     }
170 
171     private Handler mMsgHandler = new Handler(Looper.getMainLooper()) {
172         @Override
173         public void handleMessage(Message msg) {
174             super.handleMessage(msg);
175 
176             logger.debug( "Thread=" + Thread.currentThread().getName() + " received "
177                     + msg);
178             if(msg == null){
179                 logger.error("msg=null");
180                 return;
181            }
182 
183             switch (msg.what) {
184                 case PRESENCE_INIT_IMS_UCE_SERVICE:
185                     logger.debug("handleMessage  msg=PRESENCE_INIT_IMS_UCE_SERVICE" );
186                     registerBroadcastReceiver();
187                     doInitImsUceService();
188                 break;
189 
190                 default:
191                     logger.debug("handleMessage unknown msg=" + msg.what);
192             }
193         }
194     };
195 
getListener()196     public StackListener getListener(){
197         return mListenerHandler;
198     }
199 
handleAssociatedSubscriptionChanged(int newSubId)200     public void handleAssociatedSubscriptionChanged(int newSubId) {
201         synchronized (mSyncObj) {
202             if (mAssociatedSubscription == newSubId) {
203                 return;
204             }
205             mAssociatedSubscription = newSubId;
206 
207             if (!SubscriptionManager.isValidSubscriptionId(mAssociatedSubscription)) {
208                 destroyStackConnection();
209                 return;
210             }
211 
212             SubscriptionManager subscriptionManager = mContext.getSystemService(
213                     SubscriptionManager.class);
214             if (subscriptionManager == null) {
215                 logger.error("handleAssociatedSubscriptionChanged: error getting sub manager");
216                 return;
217             }
218             if (mStackAvailable) {
219                 startInitPresenceTimer(0, PRESENCE_INIT_TYPE_SUB_CHANGED);
220             }
221         }
222     }
223 
224     @Override
getStackStatusForCapabilityRequest()225     public int getStackStatusForCapabilityRequest() {
226         if (!RcsSettingUtils.getCapabilityDiscoveryEnabled(mAssociatedSubscription)) {
227             logger.error("getCapabilityDiscoveryEnabled = false");
228             return ResultCode.ERROR_SERVICE_NOT_ENABLED;
229         }
230 
231         int ret = checkStackStatus();
232         if (ret != ResultCode.SUCCESS) {
233             logger.error("checkStackAndPublish ret=" + ret);
234             return ret;
235         }
236 
237         if (!isPublished()) {
238             logger.error("checkStackAndPublish ERROR_SERVICE_NOT_PUBLISHED");
239             return ResultCode.ERROR_SERVICE_NOT_PUBLISHED;
240         }
241 
242         return ResultCode.SUCCESS;
243     }
244 
isPublished()245     private boolean isPublished() {
246         if (getPublisherState() != PresenceBase.PUBLISH_STATE_200_OK) {
247             logger.error("Didnt' publish properly");
248             return false;
249         }
250 
251         return true;
252     }
253 
254     @Override
updatePublisherState(@resenceBase.PresencePublishState int publishState)255     public void updatePublisherState(@PresenceBase.PresencePublishState int publishState) {
256         synchronized (mSyncObj) {
257             logger.print("mPublishingState=" + mPublishingState + " publishState=" + publishState);
258             if (mPublishingState != publishState ) {
259                 Intent publishIntent = new Intent(RcsPresence.ACTION_PUBLISH_STATE_CHANGED);
260                 publishIntent.putExtra(RcsPresence.EXTRA_PUBLISH_STATE, publishState);
261                 // Start PersistService and broadcast to other receivers that are listening
262                 // dynamically.
263                 mContext.sendStickyBroadcast(publishIntent);
264                 launchPersistService(publishIntent);
265             }
266             mPublishingState = publishState;
267         }
268     }
269 
270     @Override
getPublisherState()271     public @PresenceBase.PresencePublishState int getPublisherState() {
272         synchronized (mSyncObj) {
273             return mPublishingState;
274         }
275     }
276 
checkStackStatus()277     private int checkStackStatus() {
278         synchronized (mSyncObj) {
279             if (!RcsSettingUtils.isEabProvisioned(mContext, mAssociatedSubscription)) {
280                 logger.error("Didn't get EAB provisioned by DM");
281                 return ResultCode.ERROR_SERVICE_NOT_ENABLED;
282             }
283 
284             // Don't send request to RCS stack when it is under powering off.
285             // RCS stack is sending UNPUBLISH. It could get race PUBLISH trigger under the case.
286             if (sInPowerDown) {
287                 logger.error("checkStackStatus: under powering off");
288                 return ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
289             }
290 
291             if (mStackService == null) {
292                 logger.error("checkStackStatus: mStackService == null");
293                 return ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
294             }
295 
296             if (mStackPresService == null) {
297                 logger.error("Didn't init sub rcs service.");
298                 return ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
299             }
300 
301             if (!mImsEnableState) {
302                 logger.error("mImsEnableState = false");
303                 return ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
304             }
305         }
306 
307         return ResultCode.SUCCESS;
308     }
309 
310     @Override
requestCapability(String[] formattedContacts, int taskId)311     public int requestCapability(String[] formattedContacts, int taskId) {
312         logger.print("requestCapability formattedContacts=" + formattedContacts);
313 
314         int ret = ResultCode.SUCCESS;
315         try {
316             synchronized (mSyncObj) {
317                 StatusCode retCode;
318                 if (formattedContacts.length == 1) {
319                     retCode = mStackPresService.getContactCap(
320                             mStackPresenceServiceHandle, formattedContacts[0], taskId);
321                 } else {
322                     retCode = mStackPresService.getContactListCap(
323                             mStackPresenceServiceHandle, formattedContacts, taskId);
324                 }
325 
326                 logger.print("GetContactListCap retCode=" + retCode);
327 
328                 ret = RcsUtils.statusCodeToResultCode(retCode.getStatusCode());
329             }
330 
331             logger.debug("requestCapability ret=" + ret);
332         }catch(Exception e){
333             logger.error("requestCapability exception", e);
334             ret = ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
335         }
336 
337         return  ret;
338     }
339 
340     @Override
requestAvailability(String formattedContact, int taskId)341     public int requestAvailability(String formattedContact, int taskId) {
342         logger.debug("requestAvailability ...");
343 
344         int ret = ResultCode.SUCCESS;
345         try{
346             synchronized (mSyncObj) {
347                 StatusCode retCode = mStackPresService.getContactCap(
348                         mStackPresenceServiceHandle, formattedContact, taskId);
349                 logger.print("getContactCap retCode=" + retCode);
350 
351                 ret = RcsUtils.statusCodeToResultCode(retCode.getStatusCode());
352             }
353             logger.debug("requestAvailability ret=" + ret);
354         }catch(Exception e){
355             logger.error("requestAvailability exception", e);
356             ret = ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
357         }
358 
359         return  ret;
360     }
361 
362     @Override
requestPublication(RcsContactUceCapability capabilities, String myUri, int taskId)363     public int requestPublication(RcsContactUceCapability capabilities, String myUri, int taskId) {
364         logger.debug("requestPublication ...");
365 
366          // Don't use checkStackAndPublish()
367          // since it will check publish status which in dead loop.
368          int ret = checkStackStatus();
369          if(ret != ResultCode.SUCCESS){
370              logger.error("requestPublication ret=" + ret);
371              return ret;
372          }
373         if (myUri == null) {
374             logger.error("Didn't find number or impu.");
375             return ResultCode.PUBLISH_GENERIC_FAILURE;
376         }
377         try {
378             PresCapInfo pMyCapInfo = new PresCapInfo();
379             // Fill cap info
380             pMyCapInfo.setContactUri(myUri);
381 
382             CapInfo capInfo = new CapInfo();
383             capInfo.setIpVoiceSupported(isVolteSupported(capabilities));
384             capInfo.setIpVideoSupported(isVtSupported(capabilities));
385             capInfo.setCdViaPresenceSupported(true);
386 
387             capInfo.setFtSupported(false); // TODO: support FT
388             capInfo.setImSupported(false);//TODO: support chat
389             capInfo.setFullSnFGroupChatSupported(false); //TODO: support chat
390 
391             pMyCapInfo.setCapInfo(capInfo);
392 
393             logger.print( "myNumUri = " + myUri
394                     + " audioSupported =  " + capInfo.isIpVoiceSupported()
395                     + " videoSupported=  " + capInfo.isIpVideoSupported()
396                     );
397 
398 
399             synchronized (mSyncObj) {
400                 StatusCode status = mStackPresService.publishMyCap(
401                         mStackPresenceServiceHandle, pMyCapInfo, taskId);
402                 logger.print("PublishMyCap status=" + status.getStatusCode());
403                 ret = RcsUtils.statusCodeToResultCode(status.getStatusCode());
404             }
405 
406             logger.debug("requestPublication ret=" + ret);
407             if (ret != ResultCode.SUCCESS) {
408                 logger.error("requestPublication remove taskId=" + taskId);
409                 return ret;
410             }
411         } catch (RemoteException e) {
412             e.printStackTrace();
413             logger.error("Exception when call mStackPresService.getContactCap");
414             logger.error("requestPublication remove taskId=" + taskId);
415 
416             return ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
417         }
418 
419         return  ResultCode.SUCCESS;
420     }
421 
isVolteSupported(RcsContactUceCapability capabilities)422     private boolean isVolteSupported(RcsContactUceCapability capabilities) {
423         RcsContactPresenceTuple presenceTuple = capabilities.getCapabilityTuple(
424                 RcsContactPresenceTuple.SERVICE_ID_MMTEL);
425         if (presenceTuple != null) {
426             ServiceCapabilities serviceCaps = presenceTuple.getServiceCapabilities();
427             if (serviceCaps != null && serviceCaps.isAudioCapable()) {
428                 return true;
429             }
430         }
431         return false;
432     }
433 
isVtSupported(RcsContactUceCapability capabilities)434     private boolean isVtSupported(RcsContactUceCapability capabilities) {
435         RcsContactPresenceTuple presenceTuple = capabilities.getCapabilityTuple(
436                 RcsContactPresenceTuple.SERVICE_ID_MMTEL);
437         if (presenceTuple != null) {
438             ServiceCapabilities serviceCaps = presenceTuple.getServiceCapabilities();
439             if (serviceCaps != null && serviceCaps.isVideoCapable()) {
440                 return true;
441             }
442         }
443         return false;
444     }
445 
launchPersistService(Intent intent)446     private void launchPersistService(Intent intent) {
447         ComponentName component = new ComponentName(PERSIST_SERVICE_PACKAGE,
448                 PERSIST_SERVICE_NAME);
449         intent.setComponent(component);
450         mContext.startService(intent);
451     }
452 
createListeningThread()453     private void createListeningThread() {
454         HandlerThread listenerThread = new HandlerThread("Listener",
455                 android.os.Process.THREAD_PRIORITY_BACKGROUND);
456 
457         listenerThread.start();
458         Looper listenerLooper = listenerThread.getLooper();
459         mListenerHandler = new StackListener(mContext, listenerLooper);
460     }
461 
initImsUceService()462     private void initImsUceService(){
463         // Send message to avoid ANR
464         Message reinitMessage = mMsgHandler.obtainMessage(
465                 PRESENCE_INIT_IMS_UCE_SERVICE, null);
466         mMsgHandler.sendMessage(reinitMessage);
467     }
468 
registerBroadcastReceiver()469     private void registerBroadcastReceiver() {
470         synchronized (mSyncObj) {
471             logger.debug("registerBroadcastReceiver");
472 
473             IntentFilter filter = new IntentFilter();
474             filter.addAction(ImsUceManager.ACTION_UCE_SERVICE_UP);
475             filter.addAction(ImsUceManager.ACTION_UCE_SERVICE_DOWN);
476 
477             mRcsServiceReceiver = new BroadcastReceiver() {
478                 @Override
479                 public void onReceive(Context context, Intent intent) {
480                     // do something based on the intent's action
481                     logger.print("onReceive intent " + intent);
482                     String action = intent.getAction();
483                     if (ImsUceManager.ACTION_UCE_SERVICE_UP.equals(action)) {
484                         mStackAvailable = true;
485                         startInitPresenceTimer(0, PRESENCE_INIT_TYPE_RCS_SERVICE_AVAILABLE);
486                     } else if (ImsUceManager.ACTION_UCE_SERVICE_DOWN.equals(action)) {
487                         mStackAvailable = false;
488                         clearImsUceService();
489                     } else {
490                         logger.debug("unknown intent " + intent);
491                     }
492                 }
493             };
494 
495             mContext.registerReceiver(mRcsServiceReceiver, filter);
496         }
497     }
498 
doInitImsUceService()499     private void doInitImsUceService(){
500         synchronized (mSyncObj) {
501             if (mStackService != null) {
502                 logger.debug("registerBroadcastReceiver mStackService != null");
503                 return;
504             }
505 
506             if (mImsUceManager == null) {
507                 mImsUceManager = ImsUceManager.getInstance(mContext);
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     private AlarmManager mAlarmManager = null;
525     private BroadcastReceiver mRcsServiceReceiver = null;
526 
527     /*
528      * Init All Sub service of RCS
529      */
initAllSubRcsServices(IUceService uceService, int currentRetry)530     int initAllSubRcsServices(IUceService uceService, int currentRetry) {
531         int ret = -1;
532         synchronized (mSyncObj) {
533             logger.print("Create UCE service connection for sub " + mAssociatedSubscription);
534             if (uceService == null) {
535                 logger.error("initAllSubRcsServices : uceService is NULL");
536                 mIsIniting = false;
537                 mLastInitSubService = -1;
538                 return ret;
539             }
540 
541             try {
542                 destroyStackConnection();
543 
544                 if (!SubscriptionManager.isValidSubscriptionId(mAssociatedSubscription)) {
545                     logger.print("initAllService : invalid sub id, stopping creation...");
546                     mIsIniting = false;
547                     mLastInitSubService = -1;
548                     // Do not create a new presence service for invalid sub id.
549                     return 0;
550                 }
551 
552                 boolean serviceAvailable;
553                 serviceAvailable = uceService.getServiceStatus();
554                 //init only once and ensure connection to UCE  service is available.
555                 if (serviceAvailable && mStackPresService == null && mStackService != null) {
556                     logger.print("initAllSubRcsServices : create ");
557                     int handle = createStackConnection();
558                     logger.print("initAllSubRcsServices: handle=" + mStackPresenceServiceHandle +
559                             ", service=" + mStackPresService);
560                     // If the service handle is -1, then creating the service failed somehow.
561                     // schedule a retry.
562                     if (handle < 0) {
563                         logger.error("initAllService : service handle < 0, retrying...");
564                         mIsIniting = false;
565                         mLastInitSubService = -1;
566                         return ret;
567                     }
568                     ret = 0;
569                  } else {
570                     logger.error("initAllService : serviceStatus =  false - serviceStatus: "
571                             + serviceAvailable + ", mStackPresService: " + mStackPresService
572                             + ", mStackService: " + mStackService);
573                 }
574             } catch (RemoteException e) {
575                 logger.error("initAllServices :  DeadObjectException dialog  ");
576                 e.printStackTrace();
577             }
578             mIsIniting = false;
579         }
580         return ret;
581     }
582 
destroyStackConnection()583     private void destroyStackConnection() {
584         synchronized (mSyncObj) {
585             try {
586                 if (mStackPresService != null) {
587                     logger.print("RemoveListener and presence service");
588                     mStackPresService.removeListener(mStackPresenceServiceHandle,
589                             mListenerHandle);
590                 }
591                 if (mStackService != null) {
592                     mStackService.destroyPresenceService(mStackPresenceServiceHandle);
593                 }
594                 mStackPresService = null;
595             } catch (RemoteException e) {
596                 logger.error("destroyStackConnection :  exception " + e.getMessage());
597                 e.printStackTrace();
598             }
599         }
600     }
601 
createStackConnection()602     private int createStackConnection() throws RemoteException {
603         TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
604         SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class);
605         if (tm == null) return -1;
606         if (sm == null) return -1;
607         SubscriptionInfo info = sm.getActiveSubscriptionInfo(mAssociatedSubscription);
608         if (info == null) {
609             logger.error("handleAssociatedSubscriptionChanged: sub id does not have valid info");
610             return -1;
611         }
612         String associatedIccId = info.getIccId();
613         boolean isMsim = tm.getSupportedModemCount() > 1;
614         synchronized (mSyncObj) {
615             if (isMsim) {
616                 mStackPresenceServiceHandle = mStackService.createPresenceServiceForSubscription(
617                         mListenerHandler.mPresenceListener, mListenerHandle, associatedIccId);
618             } else {
619                 // createPresenceServiceForSubscription doesnt seem to work on older single sim
620                 // devices. Use deprecated API for these devices.
621                 mStackPresenceServiceHandle = mStackService.createPresenceService(
622                         mListenerHandler.mPresenceListener, mListenerHandle);
623             }
624             // If the service handle is -1, then creating the service failed somehow.
625             if (mStackPresenceServiceHandle < 0) {
626                 return mStackPresenceServiceHandle;
627             }
628             if (isMsim) {
629                 mStackPresService = mStackService.getPresenceServiceForSubscription(
630                         associatedIccId);
631             } else {
632                 // getPresenceServiceForSubscription doesnt seem to work on older single SIM
633                 // devices. Use deprecated API for these devices.
634                 mStackPresService = mStackService.getPresenceService();
635             }
636             return mStackPresenceServiceHandle;
637         }
638     }
639 
startInitThread(int times)640     public void startInitThread(int times){
641         final int currentRetry = times;
642         Thread thread = new Thread(() -> {
643             synchronized (mSyncObj) {
644                 if (currentRetry >= 0 && currentRetry <= MAX_RETRY_COUNT) {
645                     refreshUceService();
646 
647                     if (initAllSubRcsServices(mStackService, currentRetry) >= 0) {
648                         logger.debug("init sub rcs service successfully.");
649                         if (mRetryAlarmIntent != null) {
650                             mAlarmManager.cancel(mRetryAlarmIntent);
651                         }
652                     } else {
653                         startInitPresenceTimer(currentRetry + 1, PRESENCE_INIT_TYPE_RETRY);
654                     }
655                 } else {
656                     logger.debug("Retry times=" + currentRetry);
657                     if (mRetryAlarmIntent != null) {
658                         mAlarmManager.cancel(mRetryAlarmIntent);
659                     }
660                 }
661             }
662         }, "initAllSubRcsServices thread");
663 
664         thread.start();
665     }
666 
init()667     private void init() {
668         createListeningThread();
669         logger.debug("after createListeningThread");
670 
671         if(mAlarmManager == null){
672             mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
673         }
674 
675         initImsUceService();
676 
677         setInPowerDown(false);
678         logger.debug("init finished");
679     }
680 
startInitPresenceTimer(int times, int initType)681     private void startInitPresenceTimer(int times, int initType){
682         synchronized (mSyncObj) {
683             logger.print("set the retry alarm, times=" + times + " initType=" + initType +
684                     " mIsIniting=" + mIsIniting);
685             if(mIsIniting){
686                 //initing is on going in 5 seconds, discard this one.
687                 if(mLastInitSubService != -1 &&
688                         System.currentTimeMillis() - mLastInitSubService < 5000){
689                     logger.print("already in initing. ignore it");
690                     return;
691                 }//else suppose the init has problem. so continue
692             }
693 
694             mIsIniting = true;
695 
696             Intent intent = new Intent(ACTION_RETRY_ALARM);
697             intent.putExtra("times", times);
698             intent.setPackage(mContext.getPackageName());
699             mRetryAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent,
700                     PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
701 
702             // Wait for 1s to ignore duplicate init request as possible as we can.
703             long timeSkip = 1000;
704             if(times < 0 || times >= MAX_RETRY_COUNT){
705                 times = MAX_RETRY_COUNT;
706             }
707 
708             //Could failed to cancel a timer in 1s. So use exponential retry to make sure it
709             //will be stopped for non-VoLte SIM.
710             timeSkip = (timeSkip << times);
711             logger.debug("timeSkip = " + timeSkip);
712 
713             mLastInitSubService = System.currentTimeMillis();
714 
715             //the timer intent could have a longer delay. call directly at first time
716             if(times == 0) {
717                 startInitThread(0);
718             } else {
719                 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
720                         SystemClock.elapsedRealtime() + timeSkip, mRetryAlarmIntent);
721             }
722         }
723     }
724 
refreshUceService()725     private void refreshUceService() {
726         synchronized (mSyncObj) {
727             logger.debug("refreshUceService mImsUceManager=" + mImsUceManager +
728                     " mStackService=" + mStackService);
729 
730             if (mImsUceManager == null) {
731                 mImsUceManager = ImsUceManager.getInstance(mContext);
732                 if (mImsUceManager == null) {
733                     logger.error("Can't init mImsUceManager");
734                     return;
735                 }
736             }
737 
738             if (mStackService == null) {
739                 mImsUceManager.createUceService(false);
740                 mStackService = mImsUceManager.getUceServiceInstance();
741             }
742 
743             logger.debug("refreshUceService mStackService=" + mStackService);
744         }
745     }
746 
clearImsUceService()747     private void clearImsUceService() {
748         destroyStackConnection();
749         mImsUceManager = null;
750         mStackService = null;
751         mStackPresService = null;
752     }
753 
finish()754     public void finish() {
755         if(mRetryAlarmIntent != null){
756             mAlarmManager.cancel(mRetryAlarmIntent);
757             mRetryAlarmIntent = null;
758         }
759 
760         if (mRcsServiceReceiver != null) {
761             mContext.unregisterReceiver(mRcsServiceReceiver);
762             mRcsServiceReceiver = null;
763         }
764 
765         clearImsUceService();
766     }
767 
finalize()768     protected void finalize() throws Throwable {
769         super.finalize();
770         finish();
771     }
772 
isInPowerDown()773     static public boolean isInPowerDown() {
774         return sInPowerDown;
775     }
776 
setInPowerDown(boolean inPowerDown)777     static void setInPowerDown(boolean inPowerDown) {
778         sInPowerDown = inPowerDown;
779     }
780 }
781 
782