1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.telephony.ims.cts; 18 19 import android.app.Service; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.os.Binder; 23 import android.os.Handler; 24 import android.os.HandlerThread; 25 import android.os.IBinder; 26 import android.os.Looper; 27 import android.os.Message; 28 import android.telephony.ims.ImsService; 29 import android.telephony.ims.feature.MmTelFeature; 30 import android.telephony.ims.feature.RcsFeature; 31 import android.telephony.ims.stub.ImsConfigImplBase; 32 import android.telephony.ims.stub.ImsFeatureConfiguration; 33 import android.telephony.ims.stub.ImsRegistrationImplBase; 34 import android.telephony.ims.stub.SipTransportImplBase; 35 import android.util.Log; 36 37 import androidx.annotation.NonNull; 38 import androidx.annotation.Nullable; 39 40 import java.util.HashSet; 41 import java.util.concurrent.CountDownLatch; 42 import java.util.concurrent.Executor; 43 import java.util.concurrent.TimeUnit; 44 45 /** 46 * A Test ImsService that will verify ImsService functionality. 47 */ 48 public class TestImsService extends Service { 49 50 private static final String TAG = "CtsImsTestImsService"; 51 private static MessageExecutor sMessageExecutor = null; 52 53 private TestImsRegistration mImsRegistrationImplBase; 54 private TestRcsFeature mTestRcsFeature; 55 private TestMmTelFeature mTestMmTelFeature; 56 private TestImsConfig mTestImsConfig; 57 private TestSipTransport mTestSipTransport; 58 private ImsService mTestImsService; 59 private ImsService mTestImsServiceCompat; 60 private Executor mExecutor = Runnable::run; 61 private boolean mIsEnabled = false; 62 private boolean mSetNullRcsBinding = false; 63 private boolean mIsSipTransportImplemented = false; 64 private boolean mIsTestTypeExecutor = false; 65 private boolean mIsImsServiceCompat = false; 66 private long mCapabilities = 0; 67 private ImsFeatureConfiguration mFeatureConfig; 68 protected boolean mIsTelephonyBound = false; 69 private HashSet<Integer> mSubIDs = new HashSet<Integer>(); 70 protected final Object mLock = new Object(); 71 72 public static final int LATCH_FEATURES_READY = 0; 73 public static final int LATCH_ENABLE_IMS = 1; 74 public static final int LATCH_DISABLE_IMS = 2; 75 public static final int LATCH_CREATE_MMTEL = 3; 76 public static final int LATCH_CREATE_RCS = 4; 77 public static final int LATCH_REMOVE_MMTEL = 5; 78 public static final int LATCH_REMOVE_RCS = 6; 79 public static final int LATCH_MMTEL_READY = 7; 80 public static final int LATCH_RCS_READY = 8; 81 public static final int LATCH_MMTEL_CAP_SET = 9; 82 public static final int LATCH_RCS_CAP_SET = 10; 83 public static final int LATCH_UCE_LISTENER_SET = 11; 84 public static final int LATCH_UCE_REQUEST_PUBLISH = 12; 85 public static final int LATCH_ON_UNBIND = 13; 86 public static final int LATCH_LAST_MESSAGE_EXECUTE = 14; 87 private static final int LATCH_MAX = 15; 88 private static final int WAIT_FOR_EXIT_TEST = 2000; 89 protected static final CountDownLatch[] sLatches = new CountDownLatch[LATCH_MAX]; 90 static { 91 for (int i = 0; i < LATCH_MAX; i++) { 92 sLatches[i] = new CountDownLatch(1); 93 } 94 } 95 96 interface RemovedListener { onRemoved()97 void onRemoved(); 98 } 99 interface ReadyListener { onReady()100 void onReady(); 101 } 102 interface CapabilitiesSetListener { onSet()103 void onSet(); 104 } 105 interface RcsCapabilityExchangeEventListener { onSet()106 void onSet(); 107 } 108 interface DeviceCapPublishListener { onPublish()109 void onPublish(); 110 } 111 112 // This is defined here instead TestImsService extending ImsService directly because the GTS 113 // tests were failing to run on pre-P devices. Not sure why, but TestImsService is loaded 114 // even if it isn't used. 115 private class ImsServiceUT extends ImsService { 116 ImsServiceUT(Context context)117 ImsServiceUT(Context context) { 118 // As explained above, ImsServiceUT is created in order to get around classloader 119 // restrictions. Attach the base context from the wrapper ImsService. 120 if (getBaseContext() == null) { 121 attachBaseContext(context); 122 } 123 124 if (mIsTestTypeExecutor) { 125 mImsRegistrationImplBase = new TestImsRegistration(mExecutor); 126 mTestSipTransport = new TestSipTransport(mExecutor); 127 mTestImsConfig = new TestImsConfig(mExecutor); 128 } else { 129 mImsRegistrationImplBase = new TestImsRegistration(); 130 mTestImsConfig = new TestImsConfig(); 131 mTestSipTransport = new TestSipTransport(); 132 } 133 } 134 135 @Override querySupportedImsFeatures()136 public ImsFeatureConfiguration querySupportedImsFeatures() { 137 return getFeatureConfig(); 138 } 139 140 @Override getImsServiceCapabilities()141 public long getImsServiceCapabilities() { 142 return mCapabilities; 143 } 144 145 @Override readyForFeatureCreation()146 public void readyForFeatureCreation() { 147 synchronized (mLock) { 148 countDownLatch(LATCH_FEATURES_READY); 149 } 150 } 151 152 @Override enableImsForSubscription(int slotId, int subId)153 public void enableImsForSubscription(int slotId, int subId) { 154 synchronized (mLock) { 155 countDownLatch(LATCH_ENABLE_IMS); 156 mSubIDs.add(subId); 157 setIsEnabled(true); 158 } 159 } 160 161 @Override disableImsForSubscription(int slotId, int subId)162 public void disableImsForSubscription(int slotId, int subId) { 163 synchronized (mLock) { 164 countDownLatch(LATCH_DISABLE_IMS); 165 mSubIDs.add(subId); 166 setIsEnabled(false); 167 } 168 } 169 170 @Override createRcsFeatureForSubscription(int slotId, int subId)171 public RcsFeature createRcsFeatureForSubscription(int slotId, int subId) { 172 TestImsService.ReadyListener readyListener = () -> { 173 synchronized (mLock) { 174 countDownLatch(LATCH_RCS_READY); 175 } 176 }; 177 178 TestImsService.RemovedListener removedListener = () -> { 179 synchronized (mLock) { 180 countDownLatch(LATCH_REMOVE_RCS); 181 mTestRcsFeature = null; 182 } 183 }; 184 185 TestImsService.CapabilitiesSetListener setListener = () -> { 186 synchronized (mLock) { 187 countDownLatch(LATCH_RCS_CAP_SET); 188 } 189 }; 190 191 TestImsService.RcsCapabilityExchangeEventListener capExchangeEventListener = () -> { 192 synchronized (mLock) { 193 countDownLatch(LATCH_UCE_LISTENER_SET); 194 } 195 }; 196 197 synchronized (mLock) { 198 countDownLatch(LATCH_CREATE_RCS); 199 mSubIDs.add(subId); 200 201 if (mIsTestTypeExecutor) { 202 mTestRcsFeature = new TestRcsFeature(readyListener, removedListener, 203 setListener, capExchangeEventListener, mExecutor); 204 } else { 205 mTestRcsFeature = new TestRcsFeature(readyListener, removedListener, 206 setListener, capExchangeEventListener); 207 } 208 209 // Setup UCE request listener 210 mTestRcsFeature.setDeviceCapPublishListener(() -> { 211 synchronized (mLock) { 212 countDownLatch(LATCH_UCE_REQUEST_PUBLISH); 213 } 214 }); 215 216 if (mSetNullRcsBinding) { 217 return null; 218 } 219 return mTestRcsFeature; 220 } 221 } 222 223 @Override getConfigForSubscription(int slotId, int subId)224 public ImsConfigImplBase getConfigForSubscription(int slotId, int subId) { 225 mSubIDs.add(subId); 226 return mTestImsConfig; 227 } 228 229 @Override createMmTelFeatureForSubscription(int slotId, int subId)230 public MmTelFeature createMmTelFeatureForSubscription(int slotId, int subId) { 231 TestImsService.ReadyListener readyListener = () -> { 232 synchronized (mLock) { 233 countDownLatch(LATCH_MMTEL_READY); 234 } 235 }; 236 237 TestImsService.RemovedListener removedListener = () -> { 238 synchronized (mLock) { 239 countDownLatch(LATCH_REMOVE_MMTEL); 240 mTestMmTelFeature = null; 241 } 242 }; 243 244 TestImsService.CapabilitiesSetListener capSetListener = () -> { 245 synchronized (mLock) { 246 countDownLatch(LATCH_MMTEL_CAP_SET); 247 } 248 }; 249 250 synchronized (mLock) { 251 countDownLatch(LATCH_CREATE_MMTEL); 252 mSubIDs.add(subId); 253 if (mIsTestTypeExecutor) { 254 mTestMmTelFeature = new TestMmTelFeature(readyListener, removedListener, 255 capSetListener, mExecutor); 256 } else { 257 mTestMmTelFeature = new TestMmTelFeature(readyListener, removedListener, 258 capSetListener); 259 } 260 261 return mTestMmTelFeature; 262 } 263 } 264 265 @Override getRegistrationForSubscription(int slotId, int subId)266 public ImsRegistrationImplBase getRegistrationForSubscription(int slotId, int subId) { 267 mSubIDs.add(subId); 268 return mImsRegistrationImplBase; 269 } 270 271 @Nullable 272 @Override getSipTransport(int slotId)273 public SipTransportImplBase getSipTransport(int slotId) { 274 if (mIsSipTransportImplemented) { 275 return mTestSipTransport; 276 } else { 277 return null; 278 } 279 } 280 281 @Override getExecutor()282 public @NonNull Executor getExecutor() { 283 if (mIsTestTypeExecutor) { 284 return mExecutor; 285 } else { 286 mExecutor = Runnable::run; 287 return mExecutor; 288 } 289 } 290 } 291 292 private class ImsServiceUT_compat extends ImsService { 293 ImsServiceUT_compat(Context context)294 ImsServiceUT_compat(Context context) { 295 // As explained above, ImsServiceUT is created in order to get around classloader 296 // restrictions. Attach the base context from the wrapper ImsService. 297 if (getBaseContext() == null) { 298 attachBaseContext(context); 299 } 300 301 if (mIsTestTypeExecutor) { 302 mImsRegistrationImplBase = new TestImsRegistration(mExecutor); 303 mTestSipTransport = new TestSipTransport(mExecutor); 304 mTestImsConfig = new TestImsConfig(mExecutor); 305 } else { 306 mImsRegistrationImplBase = new TestImsRegistration(); 307 mTestImsConfig = new TestImsConfig(); 308 mTestSipTransport = new TestSipTransport(); 309 } 310 } 311 312 @Override querySupportedImsFeatures()313 public ImsFeatureConfiguration querySupportedImsFeatures() { 314 return getFeatureConfig(); 315 } 316 317 @Override getImsServiceCapabilities()318 public long getImsServiceCapabilities() { 319 return mCapabilities; 320 } 321 322 @Override readyForFeatureCreation()323 public void readyForFeatureCreation() { 324 synchronized (mLock) { 325 countDownLatch(LATCH_FEATURES_READY); 326 } 327 } 328 329 @Override enableIms(int slotId)330 public void enableIms(int slotId) { 331 synchronized (mLock) { 332 countDownLatch(LATCH_ENABLE_IMS); 333 setIsEnabled(true); 334 } 335 } 336 337 @Override disableIms(int slotId)338 public void disableIms(int slotId) { 339 synchronized (mLock) { 340 countDownLatch(LATCH_DISABLE_IMS); 341 setIsEnabled(false); 342 } 343 } 344 345 @Override createRcsFeature(int slotId)346 public RcsFeature createRcsFeature(int slotId) { 347 348 TestImsService.ReadyListener readyListener = () -> { 349 synchronized (mLock) { 350 countDownLatch(LATCH_RCS_READY); 351 } 352 }; 353 354 TestImsService.RemovedListener removedListener = () -> { 355 synchronized (mLock) { 356 countDownLatch(LATCH_REMOVE_RCS); 357 mTestRcsFeature = null; 358 } 359 }; 360 361 TestImsService.CapabilitiesSetListener setListener = () -> { 362 synchronized (mLock) { 363 countDownLatch(LATCH_RCS_CAP_SET); 364 } 365 }; 366 367 TestImsService.RcsCapabilityExchangeEventListener capExchangeEventListener = () -> { 368 synchronized (mLock) { 369 countDownLatch(LATCH_UCE_LISTENER_SET); 370 } 371 }; 372 373 synchronized (mLock) { 374 countDownLatch(LATCH_CREATE_RCS); 375 376 if (mIsTestTypeExecutor) { 377 mTestRcsFeature = new TestRcsFeature(readyListener, removedListener, 378 setListener, capExchangeEventListener, mExecutor); 379 } else { 380 mTestRcsFeature = new TestRcsFeature(readyListener, removedListener, 381 setListener, capExchangeEventListener); 382 } 383 384 // Setup UCE request listener 385 mTestRcsFeature.setDeviceCapPublishListener(() -> { 386 synchronized (mLock) { 387 countDownLatch(LATCH_UCE_REQUEST_PUBLISH); 388 } 389 }); 390 391 if (mSetNullRcsBinding) { 392 return null; 393 } 394 return mTestRcsFeature; 395 } 396 } 397 398 @Override getConfig(int slotId)399 public ImsConfigImplBase getConfig(int slotId) { 400 return mTestImsConfig; 401 } 402 403 @Override createMmTelFeature(int slotId)404 public MmTelFeature createMmTelFeature(int slotId) { 405 TestImsService.ReadyListener readyListener = () -> { 406 synchronized (mLock) { 407 countDownLatch(LATCH_MMTEL_READY); 408 } 409 }; 410 411 TestImsService.RemovedListener removedListener = () -> { 412 synchronized (mLock) { 413 countDownLatch(LATCH_REMOVE_MMTEL); 414 mTestMmTelFeature = null; 415 } 416 }; 417 418 TestImsService.CapabilitiesSetListener capSetListener = () -> { 419 synchronized (mLock) { 420 countDownLatch(LATCH_MMTEL_CAP_SET); 421 } 422 }; 423 424 synchronized (mLock) { 425 countDownLatch(LATCH_CREATE_MMTEL); 426 if (mIsTestTypeExecutor) { 427 mTestMmTelFeature = new TestMmTelFeature(readyListener, removedListener, 428 capSetListener, mExecutor); 429 } else { 430 mTestMmTelFeature = new TestMmTelFeature(readyListener, removedListener, 431 capSetListener); 432 } 433 434 return mTestMmTelFeature; 435 } 436 } 437 438 @Override getRegistration(int slotId)439 public ImsRegistrationImplBase getRegistration(int slotId) { 440 return mImsRegistrationImplBase; 441 } 442 443 @Nullable 444 @Override getSipTransport(int slotId)445 public SipTransportImplBase getSipTransport(int slotId) { 446 if (mIsSipTransportImplemented) { 447 return mTestSipTransport; 448 } else { 449 return null; 450 } 451 } 452 453 @Override getExecutor()454 public @NonNull Executor getExecutor() { 455 if (mIsTestTypeExecutor) { 456 return mExecutor; 457 } else { 458 mExecutor = Runnable::run; 459 return mExecutor; 460 } 461 } 462 } 463 createLooper(String name)464 private static Looper createLooper(String name) { 465 HandlerThread thread = new HandlerThread(name); 466 thread.start(); 467 468 Looper looper = thread.getLooper(); 469 470 if (looper == null) { 471 return Looper.getMainLooper(); 472 } 473 return looper; 474 } 475 476 /** 477 * Executes the tasks in the other thread rather than the calling thread. 478 */ 479 public class MessageExecutor extends Handler implements Executor { MessageExecutor(String name)480 public MessageExecutor(String name) { 481 super(createLooper(name)); 482 } 483 484 @Override execute(Runnable r)485 public void execute(Runnable r) { 486 Message m = Message.obtain(this, 0, r); 487 m.sendToTarget(); 488 } 489 490 @Override handleMessage(Message msg)491 public void handleMessage(Message msg) { 492 if (msg.obj instanceof Runnable) { 493 executeInternal((Runnable) msg.obj); 494 } else { 495 Log.d(TAG, "[MessageExecutor] handleMessage :: " 496 + "Not runnable object; ignore the msg=" + msg); 497 } 498 } 499 executeInternal(Runnable r)500 private void executeInternal(Runnable r) { 501 try { 502 r.run(); 503 } catch (Throwable t) { 504 Log.d(TAG, "[MessageExecutor] executeInternal :: run task=" + r); 505 t.printStackTrace(); 506 } 507 } 508 } 509 510 private final LocalBinder mBinder = new LocalBinder(); 511 // For local access of this Service. 512 class LocalBinder extends Binder { getService()513 TestImsService getService() { 514 return TestImsService.this; 515 } 516 } 517 518 /** 519 * Returns IMS service for CTS test purpose. 520 * @return test Ims service. 521 */ getImsService()522 public ImsService getImsService() { 523 synchronized (mLock) { 524 if (mTestImsService != null) { 525 return mTestImsService; 526 } 527 mTestImsService = new ImsServiceUT(this); 528 return mTestImsService; 529 } 530 } 531 getImsServiceCompat()532 protected ImsService getImsServiceCompat() { 533 synchronized (mLock) { 534 if (mTestImsServiceCompat != null) { 535 return mTestImsServiceCompat; 536 } 537 mTestImsServiceCompat = new ImsServiceUT_compat(this); 538 return mTestImsServiceCompat; 539 } 540 } 541 542 @Override onBind(Intent intent)543 public IBinder onBind(Intent intent) { 544 synchronized (mLock) { 545 if ("android.telephony.ims.ImsService".equals(intent.getAction())) { 546 mIsTelephonyBound = true; 547 if (mIsImsServiceCompat) { 548 if (ImsUtils.VDBG) { 549 Log.d(TAG, "onBind-Remote-Compat"); 550 } 551 return getImsServiceCompat().onBind(intent); 552 } else { 553 if (ImsUtils.VDBG) { 554 Log.d(TAG, "onBind-Remote"); 555 } 556 return getImsService().onBind(intent); 557 } 558 } 559 if (ImsUtils.VDBG) { 560 Log.i(TAG, "onBind-Local"); 561 } 562 return mBinder; 563 } 564 } 565 566 @Override onUnbind(Intent intent)567 public boolean onUnbind(Intent intent) { 568 synchronized (mLock) { 569 if ("android.telephony.ims.ImsService".equals(intent.getAction())) { 570 if (ImsUtils.VDBG) Log.i(TAG, "onUnbind-Remote"); 571 mIsTelephonyBound = false; 572 countDownLatch(LATCH_ON_UNBIND); 573 } else { 574 if (ImsUtils.VDBG) Log.i(TAG, "onUnbind-Local"); 575 } 576 // return false so that onBind is called next time. 577 return false; 578 } 579 } 580 resetState()581 public void resetState() { 582 synchronized (mLock) { 583 mTestMmTelFeature = null; 584 mTestRcsFeature = null; 585 mIsEnabled = false; 586 mSetNullRcsBinding = false; 587 mIsSipTransportImplemented = false; 588 mIsTestTypeExecutor = false; 589 mIsImsServiceCompat = false; 590 mCapabilities = 0; 591 for (int i = 0; i < LATCH_MAX; i++) { 592 sLatches[i] = new CountDownLatch(1); 593 } 594 595 if (sMessageExecutor != null) { 596 sMessageExecutor.getLooper().quitSafely(); 597 sMessageExecutor = null; 598 } 599 mSubIDs.clear(); 600 } 601 } 602 isTelephonyBound()603 public boolean isTelephonyBound() { 604 return mIsTelephonyBound; 605 } 606 setExecutorTestType(boolean type)607 public void setExecutorTestType(boolean type) { 608 mIsTestTypeExecutor = type; 609 if (mIsTestTypeExecutor) { 610 if (sMessageExecutor == null) { 611 sMessageExecutor = new MessageExecutor("TestImsService"); 612 } 613 mExecutor = sMessageExecutor; 614 } 615 } 616 waitForExecutorFinish()617 public void waitForExecutorFinish() { 618 if (mIsTestTypeExecutor && sMessageExecutor != null) { 619 sMessageExecutor.postDelayed(() -> countDownLatch(LATCH_LAST_MESSAGE_EXECUTE), null , 620 WAIT_FOR_EXIT_TEST); 621 waitForLatchCountdown(LATCH_LAST_MESSAGE_EXECUTE); 622 } 623 } 624 setImsServiceCompat()625 public void setImsServiceCompat() { 626 synchronized (mLock) { 627 mIsImsServiceCompat = true; 628 } 629 } 630 631 // Sets the feature configuration. Make sure to call this before initiating Bind to this 632 // ImsService. setFeatureConfig(ImsFeatureConfiguration f)633 public void setFeatureConfig(ImsFeatureConfiguration f) { 634 synchronized (mLock) { 635 mFeatureConfig = f; 636 } 637 } 638 getFeatureConfig()639 public ImsFeatureConfiguration getFeatureConfig() { 640 synchronized (mLock) { 641 return mFeatureConfig; 642 } 643 } 644 isEnabled()645 public boolean isEnabled() { 646 synchronized (mLock) { 647 return mIsEnabled; 648 } 649 } 650 setNullRcsBinding()651 public void setNullRcsBinding() { 652 synchronized (mLock) { 653 mSetNullRcsBinding = true; 654 } 655 } 656 setIsEnabled(boolean isEnabled)657 public void setIsEnabled(boolean isEnabled) { 658 synchronized (mLock) { 659 mIsEnabled = isEnabled; 660 } 661 } 662 addCapabilities(long capabilities)663 public void addCapabilities(long capabilities) { 664 synchronized (mLock) { 665 mCapabilities |= capabilities; 666 } 667 } 668 setSipTransportImplemented()669 public void setSipTransportImplemented() { 670 synchronized (mLock) { 671 mIsSipTransportImplemented = true; 672 } 673 } 674 waitForLatchCountdown(int latchIndex)675 public boolean waitForLatchCountdown(int latchIndex) { 676 return waitForLatchCountdown(latchIndex, ImsUtils.TEST_TIMEOUT_MS); 677 } 678 waitForLatchCountdown(int latchIndex, long waitMs)679 public boolean waitForLatchCountdown(int latchIndex, long waitMs) { 680 boolean complete = false; 681 try { 682 CountDownLatch latch; 683 synchronized (mLock) { 684 latch = sLatches[latchIndex]; 685 } 686 long startTime = System.currentTimeMillis(); 687 complete = latch.await(waitMs, TimeUnit.MILLISECONDS); 688 if (ImsUtils.VDBG) { 689 Log.i(TAG, "Latch " + latchIndex + " took " 690 + (System.currentTimeMillis() - startTime) + " ms to count down."); 691 } 692 } catch (InterruptedException e) { 693 // complete == false 694 } 695 synchronized (mLock) { 696 sLatches[latchIndex] = new CountDownLatch(1); 697 } 698 return complete; 699 } 700 countDownLatch(int latchIndex)701 public void countDownLatch(int latchIndex) { 702 synchronized (mLock) { 703 sLatches[latchIndex].countDown(); 704 } 705 } 706 getMmTelFeature()707 public TestMmTelFeature getMmTelFeature() { 708 synchronized (mLock) { 709 return mTestMmTelFeature; 710 } 711 } 712 getRcsFeature()713 public TestRcsFeature getRcsFeature() { 714 synchronized (mLock) { 715 return mTestRcsFeature; 716 } 717 } 718 getSipTransport()719 public TestSipTransport getSipTransport() { 720 synchronized (mLock) { 721 return mTestSipTransport; 722 } 723 } 724 getImsRegistration()725 public TestImsRegistration getImsRegistration() { 726 synchronized (mLock) { 727 return mImsRegistrationImplBase; 728 } 729 } 730 getConfig()731 public ImsConfigImplBase getConfig() { 732 return mTestImsConfig; 733 } 734 getSubIDs()735 public HashSet<Integer> getSubIDs() { 736 return mSubIDs; 737 } 738 } 739