• 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 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 
isImsEnableState()130     public boolean isImsEnableState() {
131         synchronized (mSyncObj) {
132             return mImsEnableState;
133         }
134     }
135 
setImsEnableState(boolean imsEnableState)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
RcsStackAdaptor(Context context)165     private RcsStackAdaptor(Context context) {
166         mContext = context;
167 
168         init();
169     }
170 
getInstance(Context context)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 
getListener()203     public StackListener getListener(){
204         return mListenerHandler;
205     }
206 
checkStackAndPublish()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 
isPublished()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 
setPublishState(int publishState)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 
getPublishState()257     public int getPublishState(){
258         synchronized (mSyncObj) {
259             return mPublishingState;
260         }
261     }
262 
checkStackStatus()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 
requestCapability(String[] formatedContacts, int taskId)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 
requestAvailability(String formatedContact, int taskId)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 
requestPublication(RcsPresenceInfo presenceInfo, IRcsPresenceListener listener)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 
launchPersistService(Intent intent)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 
createListeningThread()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 
initImsUceService()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 
doInitImsUceService()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             if (mStackService != null) {
519                 startInitPresenceTimer(0, PRESENCE_INIT_TYPE_RCS_SERVICE_AVAILABLE);
520             }
521         }
522     }
523 
524     private PendingIntent mRetryAlarmIntent = null;
525     public static final String ACTION_RETRY_ALARM = "com.android.service.ims.presence.retry";
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             // we could receive useless retry since we could fail to cancel the retry timer.
536             // We need to ignore such retry if the sub service had been initialized already.
537             if(mStackPresService != null && currentRetry>0){
538                 logger.debug("mStackPresService != null and currentRetry=" + currentRetry +
539                         " ignore it");
540                 return 0;
541             }
542 
543             logger.debug("Init All Services Under RCS uceService=" + uceService);
544             if(uceService == null){
545                 logger.error("initAllServices : uceService is NULL  ");
546                 mIsIniting = false;
547                 mLastInitSubService = -1;
548                 return ret;
549             }
550 
551             try {
552                 if(mStackPresService != null){
553                     logger.print("RemoveListener and QRCSDestroyPresService");
554                     mStackPresService.removeListener(mStackPresenceServiceHandle,
555                             mListenerHandle);
556                     uceService.destroyPresenceService(mStackPresenceServiceHandle);
557 
558                     mStackPresService = null;
559                 }
560 
561                 boolean serviceStatus = false;
562                 serviceStatus = uceService.getServiceStatus();
563                 if (true == serviceStatus && mStackPresService == null) {//init only once.
564                     logger.print("initAllService : serviceStatus =  true ");
565                     logger.debug("Create PresService");
566                     mStackPresenceServiceHandle = mStackService.createPresenceService(
567                             mListenerHandler.mPresenceListener, mListenerHandle);
568                     mStackPresService = mStackService.getPresenceService();
569                     ret = 0;
570                  } else {
571                     logger.error("initAllService : serviceStatus =  false ");
572                 }
573             } catch (RemoteException e) {
574                 logger.error("initAllServices :  DeadObjectException dialog  ");
575                 e.printStackTrace();
576             }
577             mIsIniting = false;
578         }
579         return ret;
580     }
581 
582     // Init sub service when IMS get registered.
checkSubService()583     public void checkSubService() {
584         logger.debug("checkSubService");
585         synchronized (mSyncObj) {
586             if (mStackPresService == null) {
587                 // Cancel the retry timer.
588                 if (mIsIniting) {
589                     if (mRetryAlarmIntent != null) {
590                         mAlarmManager.cancel(mRetryAlarmIntent);
591                         mRetryAlarmIntent = null;
592                     }
593                     mIsIniting = false;
594                 }
595 
596                 // force to init imediately.
597                 startInitPresenceTimer(0, PRESENCE_INIT_TYPE_IMS_REGISTERED);
598             }
599         }
600     }
601 
startInitThread(int times)602     public void startInitThread(int times){
603         final int currentRetry = times;
604         Thread thread = new Thread(() -> {
605             synchronized (mSyncObj) {
606                 if (currentRetry >= 0 && currentRetry <= MAX_RETRY_COUNT) {
607                     refreshUceService();
608 
609                     if (initAllSubRcsServices(mStackService, currentRetry) >= 0) {
610                         logger.debug("init sub rcs service successfully.");
611                         if (mRetryAlarmIntent != null) {
612                             mAlarmManager.cancel(mRetryAlarmIntent);
613                         }
614                     } else {
615                         startInitPresenceTimer(currentRetry + 1, PRESENCE_INIT_TYPE_RETRY);
616                     }
617                 } else {
618                     logger.debug("Retry times=" + currentRetry);
619                     if (mRetryAlarmIntent != null) {
620                         mAlarmManager.cancel(mRetryAlarmIntent);
621                     }
622                 }
623             }
624         }, "initAllSubRcsServices thread");
625 
626         thread.start();
627     }
628 
init()629     private void init() {
630         createListeningThread();
631         logger.debug("after createListeningThread");
632 
633         if(mAlarmManager == null){
634             mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
635         }
636 
637         initImsUceService();
638 
639         setInPowerDown(false);
640         logger.debug("init finished");
641     }
642 
startInitPresenceTimer(int times, int initType)643     private void startInitPresenceTimer(int times, int initType){
644         synchronized (mSyncObj) {
645             logger.print("set the retry alarm, times=" + times + " initType=" + initType +
646                     " mIsIniting=" + mIsIniting);
647             if(mIsIniting){
648                 //initing is on going in 5 seconds, discard this one.
649                 if(mLastInitSubService != -1 &&
650                         System.currentTimeMillis() - mLastInitSubService < 5000){
651                     logger.print("already in initing. ignore it");
652                     return;
653                 }//else suppose the init has problem. so continue
654             }
655 
656             mIsIniting = true;
657 
658             Intent intent = new Intent(ACTION_RETRY_ALARM);
659             intent.putExtra("times", times);
660             intent.setClass(mContext, AlarmBroadcastReceiver.class);
661             mRetryAlarmIntent = PendingIntent.getBroadcast(mContext, 0, intent,
662                     PendingIntent.FLAG_UPDATE_CURRENT);
663 
664             // Wait for 1s to ignore duplicate init request as possible as we can.
665             long timeSkip = 1000;
666             if(times < 0 || times >= MAX_RETRY_COUNT){
667                 times = MAX_RETRY_COUNT;
668             }
669 
670             //Could failed to cancel a timer in 1s. So use exponential retry to make sure it
671             //will be stopped for non-VoLte SIM.
672             timeSkip = (timeSkip << times);
673             logger.debug("timeSkip = " + timeSkip);
674 
675             mLastInitSubService = System.currentTimeMillis();
676 
677             //the timer intent could have a longer delay. call directly at first time
678             if(times == 0) {
679                 startInitThread(0);
680             } else {
681                 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
682                         SystemClock.elapsedRealtime() + timeSkip, mRetryAlarmIntent);
683             }
684         }
685     }
686 
refreshUceService()687     private void refreshUceService() {
688         synchronized (mSyncObj) {
689             logger.debug("refreshUceService mImsUceManager=" + mImsUceManager +
690                     " mStackService=" + mStackService);
691 
692             if (mImsUceManager == null) {
693                 mImsUceManager = ImsUceManager.getInstance(mContext,
694                         SubscriptionManager.from(mContext).getDefaultDataPhoneId());
695                 if (mImsUceManager == null) {
696                     logger.error("Can't init mImsUceManager");
697                     return;
698                 }
699             }
700 
701             if (mStackService == null) {
702                 mImsUceManager.createUceService(false);
703                 mStackService = mImsUceManager.getUceServiceInstance();
704             }
705 
706             logger.debug("refreshUceService mStackService=" + mStackService);
707         }
708     }
709 
clearImsUceService()710     private void clearImsUceService() {
711         synchronized (mSyncObj) {
712             try {
713                 logger.info("clearImsUceService: removing listener and presence service.");
714                 if (mStackPresService != null) {
715                     mStackPresService.removeListener(mStackPresenceServiceHandle,
716                             mListenerHandle);
717                 }
718                 if (mStackService != null) {
719                     mStackService.destroyPresenceService(mStackPresenceServiceHandle);
720                 }
721             } catch (RemoteException e) {
722                 logger.warn("clearImsUceService: Couldn't clean up stack service");
723             }
724             mImsUceManager = null;
725             mStackService = null;
726             mStackPresService = null;
727         }
728     }
729 
finish()730     public void finish() {
731         if(mRetryAlarmIntent != null){
732             mAlarmManager.cancel(mRetryAlarmIntent);
733             mRetryAlarmIntent = null;
734         }
735 
736         if (mRcsServiceReceiver != null) {
737             mContext.unregisterReceiver(mRcsServiceReceiver);
738             mRcsServiceReceiver = null;
739         }
740 
741         clearImsUceService();
742     }
743 
finalize()744     protected void finalize() throws Throwable {
745         super.finalize();
746         finish();
747     }
748 
isInPowerDown()749     static public boolean isInPowerDown() {
750         return sInPowerDown;
751     }
752 
setInPowerDown(boolean inPowerDown)753     static void setInPowerDown(boolean inPowerDown) {
754         sInPowerDown = inPowerDown;
755     }
756 }
757 
758