1 /* 2 * Copyright (C) 2016 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 com.android.internal.telephony.gsm; 18 19 import static android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED; 20 import static android.telephony.SmsManager.SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE; 21 22 import static com.android.internal.telephony.SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW; 23 import static com.android.internal.telephony.TelephonyTestUtils.waitForMs; 24 25 import static org.junit.Assert.assertEquals; 26 import static org.junit.Assert.assertTrue; 27 import static org.mockito.Matchers.any; 28 import static org.mockito.Matchers.anyInt; 29 import static org.mockito.Matchers.anyString; 30 import static org.mockito.Mockito.doAnswer; 31 import static org.mockito.Mockito.doReturn; 32 import static org.mockito.Mockito.times; 33 import static org.mockito.Mockito.verify; 34 import static org.mockito.Mockito.when; 35 36 import android.app.Activity; 37 import android.app.ActivityManager; 38 import android.app.PendingIntent; 39 import android.content.BroadcastReceiver; 40 import android.content.ComponentName; 41 import android.content.Context; 42 import android.content.Intent; 43 import android.content.IntentFilter; 44 import android.content.pm.PackageManager; 45 import android.content.pm.ServiceInfo; 46 import android.location.Country; 47 import android.location.CountryDetector; 48 import android.os.HandlerThread; 49 import android.os.Message; 50 import android.os.RemoteException; 51 import android.os.SystemProperties; 52 import android.provider.Settings; 53 import android.service.carrier.CarrierMessagingService; 54 import android.service.carrier.ICarrierMessagingCallback; 55 import android.service.carrier.ICarrierMessagingService; 56 import android.telephony.SmsManager; 57 import android.testing.AndroidTestingRunner; 58 import android.testing.TestableLooper; 59 import android.util.Singleton; 60 61 import androidx.test.filters.FlakyTest; 62 import androidx.test.filters.MediumTest; 63 import androidx.test.filters.SmallTest; 64 65 import com.android.internal.telephony.ContextFixture; 66 import com.android.internal.telephony.ISub; 67 import com.android.internal.telephony.SMSDispatcher; 68 import com.android.internal.telephony.SmsDispatchersController; 69 import com.android.internal.telephony.TelephonyTest; 70 import com.android.internal.telephony.TelephonyTestUtils; 71 import com.android.internal.telephony.TestApplication; 72 73 import org.junit.After; 74 import org.junit.Before; 75 import org.junit.Ignore; 76 import org.junit.Test; 77 import org.junit.runner.RunWith; 78 import org.mockito.ArgumentCaptor; 79 import org.mockito.Mock; 80 import org.mockito.invocation.InvocationOnMock; 81 import org.mockito.stubbing.Answer; 82 83 import java.util.ArrayList; 84 import java.util.HashMap; 85 import java.util.List; 86 87 @RunWith(AndroidTestingRunner.class) 88 @TestableLooper.RunWithLooper 89 public class GsmSmsDispatcherTest extends TelephonyTest { 90 91 private static final long TIMEOUT_MS = 500; 92 private static final String CARRIER_APP_PACKAGE_NAME = "com.android.carrier"; 93 94 @Mock 95 private android.telephony.SmsMessage mSmsMessage; 96 @Mock 97 private SmsMessage mGsmSmsMessage; 98 @Mock 99 private SmsDispatchersController mSmsDispatchersController; 100 @Mock 101 private GsmInboundSmsHandler mGsmInboundSmsHandler; 102 @Mock 103 private CountryDetector mCountryDetector; 104 @Mock 105 private SMSDispatcher.SmsTracker mSmsTracker; 106 @Mock 107 private ISub.Stub mISubStub; 108 @Mock 109 private ICarrierMessagingService.Stub mICarrierAppMessagingService; 110 111 private Object mLock = new Object(); 112 private boolean mReceivedTestIntent; 113 private static final String TEST_INTENT = "com.android.internal.telephony.TEST_INTENT"; 114 private BroadcastReceiver mTestReceiver = new BroadcastReceiver() { 115 @Override 116 public void onReceive(Context context, Intent intent) { 117 logd("onReceive"); 118 synchronized (mLock) { 119 mReceivedTestIntent = true; 120 mLock.notifyAll(); 121 } 122 } 123 }; 124 125 private GsmSMSDispatcher mGsmSmsDispatcher; 126 private GsmSmsDispatcherTestHandler mGsmSmsDispatcherTestHandler; 127 128 private class GsmSmsDispatcherTestHandler extends HandlerThread { 129 GsmSmsDispatcherTestHandler(String name)130 private GsmSmsDispatcherTestHandler(String name) { 131 super(name); 132 } 133 134 @Override onLooperPrepared()135 public void onLooperPrepared() { 136 mGsmSmsDispatcher = new GsmSMSDispatcher(mPhone, mSmsDispatchersController, 137 mGsmInboundSmsHandler); 138 setReady(true); 139 } 140 } 141 142 @Before setUp()143 public void setUp() throws Exception { 144 145 super.setUp(getClass().getSimpleName()); 146 147 // Note that this replaces only cached services in ServiceManager. If a service is not found 148 // in the cache, a real instance is used. 149 mServiceManagerMockedServices.put("isub", mISubStub); 150 151 doReturn(mSmsUsageMonitor).when(mSmsDispatchersController).getUsageMonitor(); 152 mGsmSmsDispatcherTestHandler = new GsmSmsDispatcherTestHandler(getClass().getSimpleName()); 153 mGsmSmsDispatcherTestHandler.start(); 154 waitUntilReady(); 155 mGsmSmsDispatcher = new GsmSMSDispatcher(mPhone, mSmsDispatchersController, 156 mGsmInboundSmsHandler); 157 processAllMessages(); 158 } 159 160 @After tearDown()161 public void tearDown() throws Exception { 162 mGsmSmsDispatcher = null; 163 mGsmSmsDispatcherTestHandler.quit(); 164 mGsmSmsDispatcherTestHandler.join(); 165 super.tearDown(); 166 } 167 168 @Test @SmallTest testSmsStatus()169 public void testSmsStatus() { 170 mSimulatedCommands.notifySmsStatus(new byte[]{(byte)0xFF, (byte)0xFF, (byte)0xFF}); 171 processAllMessages(); 172 verify(mSimulatedCommandsVerifier).acknowledgeLastIncomingGsmSms(true, 0, null); 173 } 174 175 @Test @MediumTest testSendSmsToRegularNumber_doesNotNotifyblockedNumberProvider()176 public void testSendSmsToRegularNumber_doesNotNotifyblockedNumberProvider() throws Exception { 177 setupMockPackagePermissionChecks(); 178 179 mContextFixture.setSystemService(Context.COUNTRY_DETECTOR, mCountryDetector); 180 when(mCountryDetector.detectCountry()) 181 .thenReturn(new Country("US", Country.COUNTRY_SOURCE_SIM)); 182 183 mGsmSmsDispatcher.sendText("6501002000", "121" /*scAddr*/, "test sms", 184 null, null, null, null, false, -1, false, -1, false, 0L); 185 186 verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(), any(Message.class)); 187 // Blocked number provider is notified about the emergency contact asynchronously. 188 TelephonyTestUtils.waitForMs(50); 189 assertEquals(0, mFakeBlockedNumberContentProvider.mNumEmergencyContactNotifications); 190 } 191 192 @FlakyTest 193 @Ignore 194 @Test @MediumTest testSendSmsToEmergencyNumber_notifiesBlockedNumberProvider()195 public void testSendSmsToEmergencyNumber_notifiesBlockedNumberProvider() throws Exception { 196 setupMockPackagePermissionChecks(); 197 198 mContextFixture.setSystemService(Context.COUNTRY_DETECTOR, mCountryDetector); 199 when(mCountryDetector.detectCountry()) 200 .thenReturn(new Country("US", Country.COUNTRY_SOURCE_SIM)); 201 202 mGsmSmsDispatcher.sendText( 203 getEmergencyNumberFromSystemPropertiesOrDefault(), "121" /*scAddr*/, "test sms", 204 null, null, null, null, false, -1, false, -1, false, 0L); 205 206 verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(), any(Message.class)); 207 // Blocked number provider is notified about the emergency contact asynchronously. 208 TelephonyTestUtils.waitForMs(50); 209 assertEquals(1, mFakeBlockedNumberContentProvider.mNumEmergencyContactNotifications); 210 } 211 212 @Test @SmallTest testSmsMessageValidityPeriod()213 public void testSmsMessageValidityPeriod() throws Exception { 214 int vp; 215 vp = SmsMessage.getRelativeValidityPeriod(-5); 216 assertEquals(-1, vp); 217 218 vp = SmsMessage.getRelativeValidityPeriod(100); 219 assertEquals(100 / 5 - 1, vp); 220 } 221 getEmergencyNumberFromSystemPropertiesOrDefault()222 private String getEmergencyNumberFromSystemPropertiesOrDefault() { 223 String systemEmergencyNumbers = SystemProperties.get("ril.ecclist"); 224 if (systemEmergencyNumbers == null) { 225 return "911"; 226 } else { 227 return systemEmergencyNumbers.split(",")[0]; 228 } 229 } 230 registerTestIntentReceiver()231 private void registerTestIntentReceiver() throws Exception { 232 // unmock ActivityManager to be able to register receiver, create real PendingIntent and 233 // receive TEST_INTENT 234 restoreInstance(Singleton.class, "mInstance", mIActivityManagerSingleton); 235 restoreInstance(ActivityManager.class, "IActivityManagerSingleton", null); 236 Context realContext = TestApplication.getAppContext(); 237 realContext.registerReceiver(mTestReceiver, new IntentFilter(TEST_INTENT)); 238 } 239 240 @Test 241 @SmallTest 242 @FlakyTest 243 @Ignore testSendTextWithInvalidDestAddr()244 public void testSendTextWithInvalidDestAddr() throws Exception { 245 registerTestIntentReceiver(); 246 PendingIntent pendingIntent = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0, 247 new Intent(TEST_INTENT), 0); 248 // send invalid dest address: + 249 mReceivedTestIntent = false; 250 mGsmSmsDispatcher.sendText("+", "222" /*scAddr*/, TAG, 251 pendingIntent, null, null, null, false, -1, false, -1, false, 0L); 252 waitForMs(500); 253 verify(mSimulatedCommandsVerifier, times(0)).sendSMS(anyString(), anyString(), 254 any(Message.class)); 255 synchronized (mLock) { 256 assertEquals(true, mReceivedTestIntent); 257 assertEquals(SmsManager.RESULT_ERROR_NULL_PDU, mTestReceiver.getResultCode()); 258 } 259 } 260 261 @Test testSendRawPduWithEventStopSending()262 public void testSendRawPduWithEventStopSending() throws Exception { 263 setupMockPackagePermissionChecks(); 264 mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL); 265 266 // return a fake value to pass getData() 267 HashMap data = new HashMap<String, String>(); 268 data.put("pdu", new byte[1]); 269 when(mSmsTracker.getData()).thenReturn(data); 270 271 // Set values to return to simulate EVENT_STOP_SENDING 272 when(mSmsUsageMonitor.checkDestination(any(), any())) 273 .thenReturn(SMS_CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE); 274 when(mSmsUsageMonitor.getPremiumSmsPermission(any())) 275 .thenReturn(PREMIUM_SMS_PERMISSION_NEVER_ALLOW); 276 when(mSmsTracker.getAppPackageName()).thenReturn(""); 277 278 // Settings.Global.DEVICE_PROVISIONED to 1 279 Settings.Global.putInt(mContext.getContentResolver(), 280 Settings.Global.DEVICE_PROVISIONED, 1); 281 282 mGsmSmsDispatcher.sendRawPdu(new SMSDispatcher.SmsTracker[] {mSmsTracker}); 283 //waitForHandlerAction(mGsmSmsDispatcher, TIMEOUT_MS); 284 processAllMessages(); 285 286 verify(mSmsUsageMonitor, times(1)).checkDestination(any(), any()); 287 verify(mSmsUsageMonitor, times(1)).getPremiumSmsPermission(any()); 288 ArgumentCaptor<Integer> argumentCaptor = ArgumentCaptor 289 .forClass(Integer.class); 290 verify(mSmsTracker, times(1)).onFailed(any(), argumentCaptor.capture(), anyInt()); 291 assertEquals(RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED, (int) argumentCaptor.getValue()); 292 } 293 294 @Test @SmallTest 295 @FlakyTest 296 @Ignore testSendMultipartTextWithInvalidText()297 public void testSendMultipartTextWithInvalidText() throws Exception { 298 registerTestIntentReceiver(); 299 300 // initiate parameters for an invalid text MO SMS (the 2nd segmeant has 161 characters) 301 ArrayList<String> parts = new ArrayList<>(); 302 parts.add("valid segment1"); 303 parts.add("too long segment2 12345678912345678912345678912345678912345678912345678912345678" 304 + "91234567891234567891234567891234567891234567891234567891234567891234567891234567" 305 + "8"); 306 307 ArrayList<PendingIntent> sentIntents = new ArrayList<>(); 308 PendingIntent sentIntent = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0, 309 new Intent(TEST_INTENT), PendingIntent.FLAG_IMMUTABLE); 310 sentIntents.add(sentIntent); 311 sentIntents.add(sentIntent); 312 313 // send SMS and check sentIntent 314 mReceivedTestIntent = false; 315 mGsmSmsDispatcher.sendMultipartText("+123" /*destAddr*/, "222" /*scAddr*/, parts, 316 sentIntents, null, null, null, false, -1, false, -1, 0L); 317 318 waitForMs(500); 319 synchronized (mLock) { 320 assertEquals(true, mReceivedTestIntent); 321 assertEquals(SmsManager.RESULT_ERROR_GENERIC_FAILURE, mTestReceiver.getResultCode()); 322 } 323 } 324 mockCarrierApp()325 private void mockCarrierApp() 326 throws RemoteException { 327 mContextFixture.addService( 328 CarrierMessagingService.SERVICE_INTERFACE, 329 new ComponentName(CARRIER_APP_PACKAGE_NAME, "CarrierAppFilterClass"), 330 CARRIER_APP_PACKAGE_NAME, 331 mICarrierAppMessagingService, 332 new ServiceInfo()); 333 when(mICarrierAppMessagingService.asBinder()).thenReturn(mICarrierAppMessagingService); 334 mockUiccWithCarrierApp(); 335 } 336 mockUiccWithCarrierApp()337 private void mockUiccWithCarrierApp() { 338 when(mUiccController.getUiccCard(mPhone.getPhoneId())).thenReturn(mUiccCard); 339 List<String> carrierPackages = new ArrayList<>(); 340 carrierPackages.add(CARRIER_APP_PACKAGE_NAME); 341 when(mUiccCard.getCarrierPackageNamesForIntent( 342 any(PackageManager.class), any(Intent.class))).thenReturn(carrierPackages); 343 } 344 mockCarrierAppStubResults(final int result, ICarrierMessagingService.Stub stub, boolean callOnFilterComplete)345 private void mockCarrierAppStubResults(final int result, ICarrierMessagingService.Stub stub, 346 boolean callOnFilterComplete) 347 throws RemoteException { 348 when(stub.queryLocalInterface(anyString())).thenReturn(stub); 349 when(stub.asBinder()).thenReturn(stub); 350 // for single part 351 doAnswer(new Answer<Void>() { 352 @Override 353 public Void answer(InvocationOnMock invocation) throws Throwable { 354 Object[] args = invocation.getArguments(); 355 ICarrierMessagingCallback callback = (ICarrierMessagingCallback) args[4]; 356 if (callOnFilterComplete) { 357 callback.onSendSmsComplete(result, 0); 358 } 359 return null; 360 } 361 }).when(stub).sendTextSms( 362 anyString(), anyInt(), anyString(), anyInt(), 363 any(ICarrierMessagingCallback.class)); 364 365 // for multi part 366 doAnswer(new Answer<Void>() { 367 @Override 368 public Void answer(InvocationOnMock invocation) throws Throwable { 369 Object[] args = invocation.getArguments(); 370 ICarrierMessagingCallback callback = (ICarrierMessagingCallback) args[4]; 371 if (callOnFilterComplete) { 372 callback.onSendMultipartSmsComplete(result, null); 373 } 374 return null; 375 } 376 }).when(stub).sendMultipartTextSms( 377 any(), anyInt(), anyString(), anyInt(), 378 any(ICarrierMessagingCallback.class)); 379 } 380 381 @Test 382 @SmallTest testSendSmsByCarrierApp()383 public void testSendSmsByCarrierApp() throws Exception { 384 mockCarrierApp(); 385 mockCarrierAppStubResults(CarrierMessagingService.SEND_STATUS_OK, 386 mICarrierAppMessagingService, true); 387 registerTestIntentReceiver(); 388 389 PendingIntent pendingIntent = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0, 390 new Intent(TEST_INTENT), PendingIntent.FLAG_MUTABLE); 391 mReceivedTestIntent = false; 392 393 mGsmSmsDispatcher.sendText("6501002000", "121" /*scAddr*/, "test sms", 394 pendingIntent, null, null, null, false, -1, false, -1, false, 0L); 395 processAllMessages(); 396 synchronized (mLock) { 397 if (!mReceivedTestIntent) { 398 // long wait since sometimes broadcasts can take a long time if the system is loaded 399 mLock.wait(60000); 400 } 401 assertEquals(true, mReceivedTestIntent); 402 int resultCode = mTestReceiver.getResultCode(); 403 assertTrue("Unexpected result code: " + resultCode, 404 resultCode == SmsManager.RESULT_ERROR_NONE || resultCode == Activity.RESULT_OK); 405 verify(mSimulatedCommandsVerifier, times(0)).sendSMS(anyString(), anyString(), 406 any(Message.class)); 407 } 408 } 409 410 @Test 411 @SmallTest testSendSmsByCarrierAppNoResponse()412 public void testSendSmsByCarrierAppNoResponse() throws Exception { 413 mockCarrierApp(); 414 // do not mock result, instead reduce the timeout for test 415 mGsmSmsDispatcher.mCarrierMessagingTimeout = 100; 416 417 mGsmSmsDispatcher.sendText("6501002000", "121" /*scAddr*/, "test sms", 418 null, null, null, null, false, -1, false, -1, false, 0L); 419 // wait for timeout 420 waitForMs(150); 421 verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(), any(Message.class)); 422 } 423 424 @Test 425 @SmallTest testSendSmsByCarrierAppBindingFailed()426 public void testSendSmsByCarrierAppBindingFailed() throws Exception { 427 mContextFixture.mockBindingFailureForPackage(CARRIER_APP_PACKAGE_NAME); 428 // mock presence of carrier app, but do not create a mock service to make binding fail 429 mockUiccWithCarrierApp(); 430 431 mGsmSmsDispatcher.sendText("6501002000", "121" /*scAddr*/, "test sms", 432 null, null, null, null, false, -1, false, -1, false, 0L); 433 processAllMessages(); 434 verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(), any(Message.class)); 435 } 436 sendMultipartTextSms(boolean withSentIntents)437 private void sendMultipartTextSms(boolean withSentIntents) { 438 // initiate parameters for a multipart sms 439 ArrayList<String> parts = new ArrayList<>(); 440 parts.add("segment1"); 441 parts.add("segment2"); 442 443 ArrayList<PendingIntent> sentIntents = new ArrayList<>(); 444 PendingIntent sentIntent1 = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0, 445 new Intent(TEST_INTENT), PendingIntent.FLAG_MUTABLE); 446 PendingIntent sentIntent2 = PendingIntent.getBroadcast(TestApplication.getAppContext(), 0, 447 new Intent(TEST_INTENT), PendingIntent.FLAG_MUTABLE); 448 sentIntents.add(sentIntent1); 449 sentIntents.add(sentIntent2); 450 451 mGsmSmsDispatcher.sendMultipartText("6501002000" /*destAddr*/, "222" /*scAddr*/, parts, 452 withSentIntents ? sentIntents : null, null, null, null, false, -1, false, -1, 0L); 453 } 454 455 @Test 456 @SmallTest testSendMultipartSmsByCarrierApp()457 public void testSendMultipartSmsByCarrierApp() throws Exception { 458 mockCarrierApp(); 459 mockCarrierAppStubResults(CarrierMessagingService.SEND_STATUS_OK, 460 mICarrierAppMessagingService, true); 461 registerTestIntentReceiver(); 462 463 // send SMS and check sentIntent 464 mReceivedTestIntent = false; 465 sendMultipartTextSms(true); 466 processAllMessages(); 467 synchronized (mLock) { 468 if (!mReceivedTestIntent) { 469 // long wait since sometimes broadcasts can take a long time if the system is loaded 470 mLock.wait(60000); 471 } 472 assertEquals(true, mReceivedTestIntent); 473 int resultCode = mTestReceiver.getResultCode(); 474 assertTrue("Unexpected result code: " + resultCode, 475 resultCode == SmsManager.RESULT_ERROR_NONE || resultCode == Activity.RESULT_OK); 476 verify(mSimulatedCommandsVerifier, times(0)).sendSMS(anyString(), anyString(), 477 any(Message.class)); 478 } 479 } 480 481 @Test 482 @SmallTest testSendMultipartSmsByCarrierAppNoResponse()483 public void testSendMultipartSmsByCarrierAppNoResponse() throws Exception { 484 mockCarrierApp(); 485 // do not mock result, instead reduce the timeout for test 486 mGsmSmsDispatcher.mCarrierMessagingTimeout = 100; 487 488 sendMultipartTextSms(false); 489 490 // wait for timeout 491 waitForMs(150); 492 verify(mSimulatedCommandsVerifier).sendSMSExpectMore(anyString(), anyString(), 493 any(Message.class)); 494 verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(), 495 any(Message.class)); 496 } 497 498 @Test 499 @SmallTest testSendMultipartSmsByCarrierAppBindingFailed()500 public void testSendMultipartSmsByCarrierAppBindingFailed() throws Exception { 501 mContextFixture.mockBindingFailureForPackage(CARRIER_APP_PACKAGE_NAME); 502 // mock presence of carrier app, but do not create a mock service to make binding fail 503 mockUiccWithCarrierApp(); 504 505 sendMultipartTextSms(false); 506 507 processAllMessages(); 508 verify(mSimulatedCommandsVerifier).sendSMSExpectMore(anyString(), anyString(), 509 any(Message.class)); 510 verify(mSimulatedCommandsVerifier).sendSMS(anyString(), anyString(), 511 any(Message.class)); 512 } 513 } 514