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