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