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 getImsService()518 protected ImsService getImsService() { 519 synchronized (mLock) { 520 if (mTestImsService != null) { 521 return mTestImsService; 522 } 523 mTestImsService = new ImsServiceUT(this); 524 return mTestImsService; 525 } 526 } 527 getImsServiceCompat()528 protected ImsService getImsServiceCompat() { 529 synchronized (mLock) { 530 if (mTestImsServiceCompat != null) { 531 return mTestImsServiceCompat; 532 } 533 mTestImsServiceCompat = new ImsServiceUT_compat(this); 534 return mTestImsServiceCompat; 535 } 536 } 537 538 @Override onBind(Intent intent)539 public IBinder onBind(Intent intent) { 540 synchronized (mLock) { 541 if ("android.telephony.ims.ImsService".equals(intent.getAction())) { 542 mIsTelephonyBound = true; 543 if (mIsImsServiceCompat) { 544 if (ImsUtils.VDBG) { 545 Log.d(TAG, "onBind-Remote-Compat"); 546 } 547 return getImsServiceCompat().onBind(intent); 548 } else { 549 if (ImsUtils.VDBG) { 550 Log.d(TAG, "onBind-Remote"); 551 } 552 return getImsService().onBind(intent); 553 } 554 } 555 if (ImsUtils.VDBG) { 556 Log.i(TAG, "onBind-Local"); 557 } 558 return mBinder; 559 } 560 } 561 562 @Override onUnbind(Intent intent)563 public boolean onUnbind(Intent intent) { 564 synchronized (mLock) { 565 if ("android.telephony.ims.ImsService".equals(intent.getAction())) { 566 if (ImsUtils.VDBG) Log.i(TAG, "onUnbind-Remote"); 567 mIsTelephonyBound = false; 568 countDownLatch(LATCH_ON_UNBIND); 569 } else { 570 if (ImsUtils.VDBG) Log.i(TAG, "onUnbind-Local"); 571 } 572 // return false so that onBind is called next time. 573 return false; 574 } 575 } 576 resetState()577 public void resetState() { 578 synchronized (mLock) { 579 mTestMmTelFeature = null; 580 mTestRcsFeature = null; 581 mIsEnabled = false; 582 mSetNullRcsBinding = false; 583 mIsSipTransportImplemented = false; 584 mIsTestTypeExecutor = false; 585 mIsImsServiceCompat = false; 586 mCapabilities = 0; 587 for (int i = 0; i < LATCH_MAX; i++) { 588 sLatches[i] = new CountDownLatch(1); 589 } 590 591 if (sMessageExecutor != null) { 592 sMessageExecutor.getLooper().quitSafely(); 593 sMessageExecutor = null; 594 } 595 mSubIDs.clear(); 596 } 597 } 598 isTelephonyBound()599 public boolean isTelephonyBound() { 600 return mIsTelephonyBound; 601 } 602 setExecutorTestType(boolean type)603 public void setExecutorTestType(boolean type) { 604 mIsTestTypeExecutor = type; 605 if (mIsTestTypeExecutor) { 606 if (sMessageExecutor == null) { 607 sMessageExecutor = new MessageExecutor("TestImsService"); 608 } 609 mExecutor = sMessageExecutor; 610 } 611 } 612 waitForExecutorFinish()613 public void waitForExecutorFinish() { 614 if (mIsTestTypeExecutor && sMessageExecutor != null) { 615 sMessageExecutor.postDelayed(() -> countDownLatch(LATCH_LAST_MESSAGE_EXECUTE), null , 616 WAIT_FOR_EXIT_TEST); 617 waitForLatchCountdown(LATCH_LAST_MESSAGE_EXECUTE); 618 } 619 } 620 setImsServiceCompat()621 public void setImsServiceCompat() { 622 synchronized (mLock) { 623 mIsImsServiceCompat = true; 624 } 625 } 626 627 // Sets the feature configuration. Make sure to call this before initiating Bind to this 628 // ImsService. setFeatureConfig(ImsFeatureConfiguration f)629 public void setFeatureConfig(ImsFeatureConfiguration f) { 630 synchronized (mLock) { 631 mFeatureConfig = f; 632 } 633 } 634 getFeatureConfig()635 public ImsFeatureConfiguration getFeatureConfig() { 636 synchronized (mLock) { 637 return mFeatureConfig; 638 } 639 } 640 isEnabled()641 public boolean isEnabled() { 642 synchronized (mLock) { 643 return mIsEnabled; 644 } 645 } 646 setNullRcsBinding()647 public void setNullRcsBinding() { 648 synchronized (mLock) { 649 mSetNullRcsBinding = true; 650 } 651 } 652 setIsEnabled(boolean isEnabled)653 public void setIsEnabled(boolean isEnabled) { 654 synchronized (mLock) { 655 mIsEnabled = isEnabled; 656 } 657 } 658 addCapabilities(long capabilities)659 public void addCapabilities(long capabilities) { 660 synchronized (mLock) { 661 mCapabilities |= capabilities; 662 } 663 } 664 setSipTransportImplemented()665 public void setSipTransportImplemented() { 666 synchronized (mLock) { 667 mIsSipTransportImplemented = true; 668 } 669 } 670 waitForLatchCountdown(int latchIndex)671 public boolean waitForLatchCountdown(int latchIndex) { 672 return waitForLatchCountdown(latchIndex, ImsUtils.TEST_TIMEOUT_MS); 673 } 674 waitForLatchCountdown(int latchIndex, long waitMs)675 public boolean waitForLatchCountdown(int latchIndex, long waitMs) { 676 boolean complete = false; 677 try { 678 CountDownLatch latch; 679 synchronized (mLock) { 680 latch = sLatches[latchIndex]; 681 } 682 long startTime = System.currentTimeMillis(); 683 complete = latch.await(waitMs, TimeUnit.MILLISECONDS); 684 if (ImsUtils.VDBG) { 685 Log.i(TAG, "Latch " + latchIndex + " took " 686 + (System.currentTimeMillis() - startTime) + " ms to count down."); 687 } 688 } catch (InterruptedException e) { 689 // complete == false 690 } 691 synchronized (mLock) { 692 sLatches[latchIndex] = new CountDownLatch(1); 693 } 694 return complete; 695 } 696 countDownLatch(int latchIndex)697 public void countDownLatch(int latchIndex) { 698 synchronized (mLock) { 699 sLatches[latchIndex].countDown(); 700 } 701 } 702 getMmTelFeature()703 public TestMmTelFeature getMmTelFeature() { 704 synchronized (mLock) { 705 return mTestMmTelFeature; 706 } 707 } 708 getRcsFeature()709 public TestRcsFeature getRcsFeature() { 710 synchronized (mLock) { 711 return mTestRcsFeature; 712 } 713 } 714 getSipTransport()715 public TestSipTransport getSipTransport() { 716 synchronized (mLock) { 717 return mTestSipTransport; 718 } 719 } 720 getImsRegistration()721 public TestImsRegistration getImsRegistration() { 722 synchronized (mLock) { 723 return mImsRegistrationImplBase; 724 } 725 } 726 getConfig()727 public ImsConfigImplBase getConfig() { 728 return mTestImsConfig; 729 } 730 getSubIDs()731 public HashSet<Integer> getSubIDs() { 732 return mSubIDs; 733 } 734 } 735