1 /* 2 * Copyright (C) 2009 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.cts; 18 19 import static androidx.test.InstrumentationRegistry.getContext; 20 import static androidx.test.InstrumentationRegistry.getInstrumentation; 21 22 import static com.android.compatibility.common.util.BlockedNumberUtil.deleteBlockedNumber; 23 import static com.android.compatibility.common.util.BlockedNumberUtil.insertBlockedNumber; 24 25 import static org.hamcrest.Matchers.anyOf; 26 import static org.hamcrest.Matchers.emptyString; 27 import static org.hamcrest.Matchers.equalTo; 28 import static org.hamcrest.Matchers.greaterThan; 29 import static org.hamcrest.Matchers.startsWith; 30 import static org.junit.Assert.assertEquals; 31 import static org.junit.Assert.assertFalse; 32 import static org.junit.Assert.assertNotEquals; 33 import static org.junit.Assert.assertNotNull; 34 import static org.junit.Assert.assertThat; 35 import static org.junit.Assert.assertTrue; 36 import static org.junit.Assert.fail; 37 import static org.junit.Assume.assumeTrue; 38 39 import android.app.AppOpsManager; 40 import android.app.PendingIntent; 41 import android.app.UiAutomation; 42 import android.app.role.RoleManager; 43 import android.content.BroadcastReceiver; 44 import android.content.ComponentName; 45 import android.content.ContentResolver; 46 import android.content.ContentValues; 47 import android.content.Context; 48 import android.content.Intent; 49 import android.content.IntentFilter; 50 import android.content.pm.PackageManager; 51 import android.net.Uri; 52 import android.os.AsyncTask; 53 import android.os.Bundle; 54 import android.os.ParcelFileDescriptor; 55 import android.os.RemoteCallback; 56 import android.os.SystemClock; 57 import android.provider.Telephony; 58 import android.telephony.SmsCbMessage; 59 import android.telephony.SmsManager; 60 import android.telephony.SmsMessage; 61 import android.telephony.TelephonyManager; 62 import android.telephony.cdma.CdmaSmsCbProgramData; 63 import android.text.TextUtils; 64 import android.util.Log; 65 66 import androidx.test.InstrumentationRegistry; 67 68 import org.junit.After; 69 import org.junit.Before; 70 import org.junit.Test; 71 72 import java.io.BufferedReader; 73 import java.io.FileInputStream; 74 import java.io.IOException; 75 import java.io.InputStream; 76 import java.io.InputStreamReader; 77 import java.nio.charset.StandardCharsets; 78 import java.util.ArrayList; 79 import java.util.Date; 80 import java.util.List; 81 import java.util.concurrent.Callable; 82 import java.util.concurrent.CompletableFuture; 83 import java.util.concurrent.TimeUnit; 84 85 /** 86 * Tests for {@link android.telephony.SmsManager}. 87 * 88 * Structured so tests can be reused to test {@link android.telephony.gsm.SmsManager} 89 */ 90 public class SmsManagerTest { 91 92 private static final String TAG = "SmsManagerTest"; 93 private static final String LONG_TEXT = 94 "This is a very long text. This text should be broken into three " + 95 "separate messages.This is a very long text. This text should be broken into " + 96 "three separate messages.This is a very long text. This text should be broken " + 97 "into three separate messages.This is a very long text. This text should be " + 98 "broken into three separate messages.";; 99 private static final String LONG_TEXT_WITH_32BIT_CHARS = 100 "Long dkkshsh jdjsusj kbsksbdf jfkhcu hhdiwoqiwyrygrvn?*?*!\";:'/,." 101 + "__?9#9292736&4;\"$+$+((]\\[\\℅©℅™^®°¥°¥=¢£}}£∆~¶~÷|√×." 102 + " ⛪⛲ "; 103 104 private static final String SMS_SEND_ACTION = "CTS_SMS_SEND_ACTION"; 105 private static final String SMS_DELIVERY_ACTION = "CTS_SMS_DELIVERY_ACTION"; 106 private static final String DATA_SMS_RECEIVED_ACTION = "android.intent.action.DATA_SMS_RECEIVED"; 107 public static final String SMS_DELIVER_DEFAULT_APP_ACTION = "CTS_SMS_DELIVERY_ACTION_DEFAULT_APP"; 108 public static final String LEGACY_SMS_APP = "android.telephony.cts.sms23"; 109 public static final String MODERN_SMS_APP = "android.telephony.cts.sms"; 110 private static final String SMS_RETRIEVER_APP = "android.telephony.cts.smsretriever"; 111 private static final String SMS_RETRIEVER_ACTION = "CTS_SMS_RETRIEVER_ACTION"; 112 private static final String FINANCIAL_SMS_APP = "android.telephony.cts.financialsms"; 113 114 private TelephonyManager mTelephonyManager; 115 private String mDestAddr; 116 private String mText; 117 private SmsBroadcastReceiver mSendReceiver; 118 private SmsBroadcastReceiver mDeliveryReceiver; 119 private SmsBroadcastReceiver mDataSmsReceiver; 120 private SmsBroadcastReceiver mSmsDeliverReceiver; 121 private SmsBroadcastReceiver mSmsReceivedReceiver; 122 private SmsBroadcastReceiver mSmsRetrieverReceiver; 123 private PendingIntent mSentIntent; 124 private PendingIntent mDeliveredIntent; 125 private Intent mSendIntent; 126 private Intent mDeliveryIntent; 127 private Context mContext; 128 private Uri mBlockedNumberUri; 129 private boolean mTestAppSetAsDefaultSmsApp; 130 private boolean mDeliveryReportSupported; 131 private static boolean mReceivedDataSms; 132 private static String mReceivedText; 133 private static boolean sHasShellPermissionIdentity = false; 134 private static long sMessageId = 0L; 135 136 private static final int TIME_OUT = 1000 * 60 * 10; 137 private static final int NO_CALLS_TIMEOUT_MILLIS = 1000; // 1 second 138 139 @Before setUp()140 public void setUp() throws Exception { 141 assumeTrue(getContext().getPackageManager().hasSystemFeature( 142 PackageManager.FEATURE_TELEPHONY_MESSAGING)); 143 144 mContext = getContext(); 145 mTelephonyManager = 146 (TelephonyManager) getContext().getSystemService( 147 Context.TELEPHONY_SERVICE); 148 mDestAddr = mTelephonyManager.getLine1Number(); 149 mText = "This is a test message"; 150 151 // exclude the networks that don't support SMS delivery report 152 String mccmnc = mTelephonyManager.getSimOperator(); 153 mDeliveryReportSupported = !(CarrierCapability.NO_DELIVERY_REPORTS.contains(mccmnc)); 154 155 // register receivers 156 mSendIntent = new Intent(SMS_SEND_ACTION); 157 mDeliveryIntent = new Intent(SMS_DELIVERY_ACTION); 158 159 IntentFilter sendIntentFilter = new IntentFilter(SMS_SEND_ACTION); 160 IntentFilter deliveryIntentFilter = new IntentFilter(SMS_DELIVERY_ACTION); 161 IntentFilter dataSmsReceivedIntentFilter = new IntentFilter(DATA_SMS_RECEIVED_ACTION); 162 IntentFilter smsDeliverIntentFilter = new IntentFilter(SMS_DELIVER_DEFAULT_APP_ACTION); 163 IntentFilter smsReceivedIntentFilter = 164 new IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION); 165 IntentFilter smsRetrieverIntentFilter = new IntentFilter(SMS_RETRIEVER_ACTION); 166 dataSmsReceivedIntentFilter.addDataScheme("sms"); 167 dataSmsReceivedIntentFilter.addDataAuthority("localhost", "19989"); 168 169 mSendReceiver = new SmsBroadcastReceiver(SMS_SEND_ACTION); 170 mDeliveryReceiver = new SmsBroadcastReceiver(SMS_DELIVERY_ACTION); 171 mDataSmsReceiver = new SmsBroadcastReceiver(DATA_SMS_RECEIVED_ACTION); 172 mSmsDeliverReceiver = new SmsBroadcastReceiver(SMS_DELIVER_DEFAULT_APP_ACTION); 173 mSmsReceivedReceiver = new SmsBroadcastReceiver(Telephony.Sms.Intents.SMS_RECEIVED_ACTION); 174 mSmsRetrieverReceiver = new SmsBroadcastReceiver(SMS_RETRIEVER_ACTION); 175 176 mContext.registerReceiver(mSendReceiver, sendIntentFilter); 177 mContext.registerReceiver(mDeliveryReceiver, deliveryIntentFilter); 178 mContext.registerReceiver(mDataSmsReceiver, dataSmsReceivedIntentFilter); 179 mContext.registerReceiver(mSmsDeliverReceiver, smsDeliverIntentFilter); 180 mContext.registerReceiver(mSmsReceivedReceiver, smsReceivedIntentFilter); 181 mContext.registerReceiver(mSmsRetrieverReceiver, smsRetrieverIntentFilter); 182 } 183 184 @After tearDown()185 public void tearDown() throws Exception { 186 if (mBlockedNumberUri != null) { 187 unblockNumber(mBlockedNumberUri); 188 mBlockedNumberUri = null; 189 } 190 if (mTestAppSetAsDefaultSmsApp) { 191 setDefaultSmsApp(false); 192 } 193 194 // unregister receivers 195 if (mSendReceiver != null) { 196 mContext.unregisterReceiver(mSendReceiver); 197 } 198 if (mDeliveryReceiver != null) { 199 mContext.unregisterReceiver(mDeliveryReceiver); 200 } 201 if (mDataSmsReceiver != null) { 202 mContext.unregisterReceiver(mDataSmsReceiver); 203 } 204 if (mSmsDeliverReceiver != null) { 205 mContext.unregisterReceiver(mSmsDeliverReceiver); 206 } 207 if (mSmsReceivedReceiver != null) { 208 mContext.unregisterReceiver(mSmsReceivedReceiver); 209 } 210 if (mSmsRetrieverReceiver != null) { 211 mContext.unregisterReceiver(mSmsRetrieverReceiver); 212 } 213 } 214 215 @Test testDivideMessage()216 public void testDivideMessage() { 217 ArrayList<String> dividedMessages = divideMessage(LONG_TEXT); 218 assertNotNull(dividedMessages); 219 if (TelephonyUtils.isSkt(mTelephonyManager)) { 220 assertTrue(isComplete(dividedMessages, 5, LONG_TEXT) 221 || isComplete(dividedMessages, 3, LONG_TEXT)); 222 } else if (TelephonyUtils.isKt(mTelephonyManager)) { 223 assertTrue(isComplete(dividedMessages, 4, LONG_TEXT) 224 || isComplete(dividedMessages, 3, LONG_TEXT)); 225 } else { 226 assertTrue(isComplete(dividedMessages, 3, LONG_TEXT)); 227 } 228 } 229 230 @Test testDivideUnicodeMessage()231 public void testDivideUnicodeMessage() { 232 ArrayList<String> dividedMessages = divideMessage(LONG_TEXT_WITH_32BIT_CHARS); 233 assertNotNull(dividedMessages); 234 assertTrue(isComplete(dividedMessages, 3, LONG_TEXT_WITH_32BIT_CHARS)); 235 for (String messagePiece : dividedMessages) { 236 assertFalse(Character.isHighSurrogate( 237 messagePiece.charAt(messagePiece.length() - 1))); 238 } 239 } 240 isComplete(List<String> dividedMessages, int numParts, String longText)241 private boolean isComplete(List<String> dividedMessages, int numParts, String longText) { 242 if (dividedMessages.size() != numParts) { 243 return false; 244 } 245 246 String actualMessage = ""; 247 for (int i = 0; i < numParts; i++) { 248 actualMessage += dividedMessages.get(i); 249 } 250 return longText.equals(actualMessage); 251 } 252 253 @Test testSmsRetriever()254 public void testSmsRetriever() throws Exception { 255 assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.", 256 TextUtils.isEmpty(mDestAddr)); 257 258 String mccmnc = mTelephonyManager.getSimOperator(); 259 init(); 260 261 CompletableFuture<Bundle> callbackResult = new CompletableFuture<>(); 262 263 mContext.startActivity(new Intent() 264 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 265 .setComponent(new ComponentName( 266 SMS_RETRIEVER_APP, SMS_RETRIEVER_APP + ".MainActivity")) 267 .putExtra("callback", new RemoteCallback(callbackResult::complete))); 268 269 270 Bundle bundle = callbackResult.get(200, TimeUnit.SECONDS); 271 String token = bundle.getString("token"); 272 assertThat(bundle.getString("class"), startsWith(SMS_RETRIEVER_APP)); 273 assertNotNull(token); 274 275 String composedText = "testprefix1" + mText + token; 276 sendTextMessage(mDestAddr, composedText, null, null); 277 278 assertTrue("[RERUN] SMS retriever message not received. Check signal.", 279 mSmsRetrieverReceiver.waitForCalls(1, TIME_OUT)); 280 } 281 sendAndReceiveSms(boolean addMessageId)282 private void sendAndReceiveSms(boolean addMessageId) throws Exception { 283 // send single text sms 284 init(); 285 if (addMessageId) { 286 long fakeMessageId = 19812L; 287 sendTextMessageWithMessageId(mDestAddr, 288 String.valueOf(SystemClock.elapsedRealtimeNanos()), mSentIntent, 289 mDeliveredIntent, fakeMessageId); 290 } else { 291 sendTextMessage(mDestAddr, String.valueOf(SystemClock.elapsedRealtimeNanos()), 292 mSentIntent, mDeliveredIntent); 293 } 294 assertTrue("[RERUN] Could not send SMS. Check signal.", 295 mSendReceiver.waitForCalls(1, TIME_OUT)); 296 if (mDeliveryReportSupported) { 297 assertTrue("[RERUN] SMS message delivery notification not received. Check signal.", 298 mDeliveryReceiver.waitForCalls(1, TIME_OUT)); 299 } 300 // non-default app should receive only SMS_RECEIVED_ACTION 301 assertTrue(mSmsReceivedReceiver.waitForCalls(1, TIME_OUT)); 302 // Received SMS should always contain a generated messageId 303 assertNotEquals(0L, sMessageId); 304 assertTrue(mSmsDeliverReceiver.waitForCalls(0, 0)); 305 } 306 sendAndReceiveMultipartSms(String mccmnc, boolean addMessageId)307 private void sendAndReceiveMultipartSms(String mccmnc, boolean addMessageId) throws Exception { 308 sMessageId = 0L; 309 int numPartsSent = sendMultipartTextMessageIfSupported(mccmnc, addMessageId); 310 if (numPartsSent > 0) { 311 assertTrue("[RERUN] Could not send multi part SMS. Check signal.", 312 mSendReceiver.waitForCalls(numPartsSent, TIME_OUT)); 313 if (mDeliveryReportSupported) { 314 assertTrue("[RERUN] Multi part SMS message delivery notification not received. " 315 + "Check signal.", mDeliveryReceiver.waitForCalls(numPartsSent, TIME_OUT)); 316 } 317 // non-default app should receive only SMS_RECEIVED_ACTION 318 assertTrue(mSmsReceivedReceiver.waitForCalls(1, TIME_OUT)); 319 assertTrue(mSmsDeliverReceiver.waitForCalls(0, 0)); 320 // Received SMS should contain a generated messageId 321 assertNotEquals(0L, sMessageId); 322 } else { 323 // This GSM network doesn't support Multipart SMS message. 324 // Skip the test. 325 } 326 } 327 sendDataSms(String mccmnc)328 private void sendDataSms(String mccmnc) throws Exception { 329 if (sendDataMessageIfSupported(mccmnc)) { 330 assertTrue("[RERUN] Could not send data SMS. Check signal.", 331 mSendReceiver.waitForCalls(1, TIME_OUT)); 332 if (mDeliveryReportSupported) { 333 assertTrue("[RERUN] Data SMS message delivery notification not received. " + 334 "Check signal.", mDeliveryReceiver.waitForCalls(1, TIME_OUT)); 335 } 336 mDataSmsReceiver.waitForCalls(1, TIME_OUT); 337 assertTrue("[RERUN] Data SMS message not received. Check signal.", mReceivedDataSms); 338 assertEquals(mReceivedText, mText); 339 } else { 340 // This GSM network doesn't support Data(binary) SMS message. 341 // Skip the test. 342 } 343 } 344 345 @Test(timeout = 10 * 60 * 1000) testSendAndReceiveMessages()346 public void testSendAndReceiveMessages() throws Exception { 347 assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.", 348 TextUtils.isEmpty(mDestAddr)); 349 350 String mccmnc = mTelephonyManager.getSimOperator(); 351 352 // send/receive single text sms with and without messageId 353 sendAndReceiveSms(/* addMessageId= */ true); 354 sendAndReceiveSms(/* addMessageId= */ false); 355 356 // due to permission restrictions, currently there is no way to make this test app the 357 // default SMS app 358 359 if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) { 360 // TODO: temp workaround, OCTET encoding for EMS not properly supported 361 return; 362 } 363 364 // send/receive data sms 365 sendDataSms(mccmnc); 366 367 // send/receive multi part text sms with and without messageId 368 sendAndReceiveMultipartSms(mccmnc, /* addMessageId= */ true); 369 sendAndReceiveMultipartSms(mccmnc, /* addMessageId= */ false); 370 } 371 372 @Test testSmsBlocking()373 public void testSmsBlocking() throws Exception { 374 assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.", 375 TextUtils.isEmpty(mDestAddr)); 376 377 // disable suppressing blocking. 378 TelephonyUtils.endBlockSuppression(getInstrumentation()); 379 380 String mccmnc = mTelephonyManager.getSimOperator(); 381 // Setting default SMS App is needed to be able to block numbers. 382 setDefaultSmsApp(true); 383 blockNumber(mDestAddr); 384 385 // single-part SMS blocking 386 init(); 387 sendTextMessage(mDestAddr, String.valueOf(SystemClock.elapsedRealtimeNanos()), 388 mSentIntent, mDeliveredIntent); 389 assertTrue("[RERUN] Could not send SMS. Check signal.", 390 mSendReceiver.waitForCalls(1, TIME_OUT)); 391 assertTrue("Expected no messages to be received due to number blocking.", 392 mSmsReceivedReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS)); 393 assertTrue("Expected no messages to be delivered due to number blocking.", 394 mSmsDeliverReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS)); 395 396 // send data sms 397 if (!sendDataMessageIfSupported(mccmnc)) { 398 assertTrue("[RERUN] Could not send data SMS. Check signal.", 399 mSendReceiver.waitForCalls(1, TIME_OUT)); 400 if (mDeliveryReportSupported) { 401 assertTrue("[RERUN] Data SMS message delivery notification not received. " + 402 "Check signal.", mDeliveryReceiver.waitForCalls(1, TIME_OUT)); 403 } 404 assertTrue("Expected no messages to be delivered due to number blocking.", 405 mSmsDeliverReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS)); 406 } else { 407 // This GSM network doesn't support Data(binary) SMS message. 408 // Skip the test. 409 } 410 411 // multi-part SMS blocking 412 int numPartsSent = sendMultipartTextMessageIfSupported(mccmnc, /* addMessageId= */ false); 413 if (numPartsSent > 0) { 414 assertTrue("[RERUN] Could not send multi part SMS. Check signal.", 415 mSendReceiver.waitForCalls(numPartsSent, TIME_OUT)); 416 417 assertTrue("Expected no messages to be received due to number blocking.", 418 mSmsReceivedReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS)); 419 assertTrue("Expected no messages to be delivered due to number blocking.", 420 mSmsDeliverReceiver.verifyNoCalls(NO_CALLS_TIMEOUT_MILLIS)); 421 } else { 422 // This GSM network doesn't support Multipart SMS message. 423 // Skip the test. 424 } 425 } 426 427 @Test testGetSmsMessagesForFinancialAppPermissionRequestedNotGranted()428 public void testGetSmsMessagesForFinancialAppPermissionRequestedNotGranted() throws Exception { 429 CompletableFuture<Bundle> callbackResult = new CompletableFuture<>(); 430 431 mContext.startActivity(new Intent() 432 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 433 .setComponent(new ComponentName(FINANCIAL_SMS_APP, FINANCIAL_SMS_APP + ".MainActivity")) 434 .putExtra("callback", new RemoteCallback(callbackResult::complete))); 435 436 Bundle bundle = callbackResult.get(500, TimeUnit.SECONDS); 437 438 assertThat(bundle.getString("class"), startsWith(FINANCIAL_SMS_APP)); 439 assertThat(bundle.getInt("rowNum"), equalTo(-1)); 440 } 441 442 @Test testGetSmsMessagesForFinancialAppPermissionRequestedGranted()443 public void testGetSmsMessagesForFinancialAppPermissionRequestedGranted() throws Exception { 444 CompletableFuture<Bundle> callbackResult = new CompletableFuture<>(); 445 String ctsPackageName = getInstrumentation().getContext().getPackageName(); 446 447 executeWithShellPermissionIdentity(() -> { 448 setModeForOps(FINANCIAL_SMS_APP, 449 AppOpsManager.MODE_ALLOWED, 450 AppOpsManager.OPSTR_SMS_FINANCIAL_TRANSACTIONS); 451 }); 452 mContext.startActivity(new Intent() 453 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 454 .setComponent(new ComponentName(FINANCIAL_SMS_APP, FINANCIAL_SMS_APP + ".MainActivity")) 455 .putExtra("callback", new RemoteCallback(callbackResult::complete))); 456 457 458 Bundle bundle = callbackResult.get(500, TimeUnit.SECONDS); 459 460 assertThat(bundle.getString("class"), startsWith(FINANCIAL_SMS_APP)); 461 assertThat(bundle.getInt("rowNum"), equalTo(-1)); 462 } 463 464 @Test testSmsNotPersisted_failsWithoutCarrierPermissions()465 public void testSmsNotPersisted_failsWithoutCarrierPermissions() throws Exception { 466 assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.", 467 TextUtils.isEmpty(mDestAddr)); 468 469 try { 470 getSmsManager().sendTextMessageWithoutPersisting(mDestAddr, null /*scAddress */, 471 mDestAddr, mSentIntent, mDeliveredIntent); 472 fail("We should get a SecurityException due to not having carrier privileges"); 473 } catch (SecurityException e) { 474 // Success 475 } 476 } 477 478 @Test testContentProviderAccessRestriction()479 public void testContentProviderAccessRestriction() throws Exception { 480 Uri dummySmsUri = null; 481 Context context = getInstrumentation().getContext(); 482 ContentResolver contentResolver = context.getContentResolver(); 483 int originalWriteSmsMode = -1; 484 String ctsPackageName = context.getPackageName(); 485 try { 486 // Insert some test sms 487 originalWriteSmsMode = context.getSystemService(AppOpsManager.class) 488 .unsafeCheckOpNoThrow(AppOpsManager.OPSTR_WRITE_SMS, 489 getPackageUid(ctsPackageName), ctsPackageName); 490 setModeForOps(ctsPackageName, 491 AppOpsManager.MODE_ALLOWED, AppOpsManager.OPSTR_WRITE_SMS); 492 ContentValues contentValues = new ContentValues(); 493 contentValues.put(Telephony.TextBasedSmsColumns.ADDRESS, "addr"); 494 contentValues.put(Telephony.TextBasedSmsColumns.READ, 1); 495 contentValues.put(Telephony.TextBasedSmsColumns.SUBJECT, "subj"); 496 contentValues.put(Telephony.TextBasedSmsColumns.BODY, "created_at_" 497 + new Date().toString().replace(" ", "_")); 498 499 dummySmsUri = contentResolver.insert(Telephony.Sms.CONTENT_URI, contentValues); 500 assertNotNull("Failed to insert test sms", dummySmsUri); 501 assertNotEquals("Failed to insert test sms", "0", dummySmsUri.getLastPathSegment()); 502 testSmsAccessAboutDefaultApp(LEGACY_SMS_APP); 503 testSmsAccessAboutDefaultApp(MODERN_SMS_APP); 504 } finally { 505 if (dummySmsUri != null && !"/0".equals(dummySmsUri.getLastPathSegment())) { 506 final Uri finalDummySmsUri = dummySmsUri; 507 executeWithShellPermissionIdentity(() -> contentResolver.delete(finalDummySmsUri, 508 null, null)); 509 } 510 if (originalWriteSmsMode >= 0) { 511 int finalOriginalWriteSmsMode = originalWriteSmsMode; 512 executeWithShellPermissionIdentity(() -> 513 setModeForOps(ctsPackageName, 514 finalOriginalWriteSmsMode, AppOpsManager.OPSTR_WRITE_SMS)); 515 } 516 } 517 } 518 testSmsAccessAboutDefaultApp(String pkg)519 private void testSmsAccessAboutDefaultApp(String pkg) 520 throws Exception { 521 String originalSmsApp = getSmsApp(); 522 assertNotEquals(pkg, originalSmsApp); 523 assertCanAccessSms(pkg); 524 try { 525 setSmsApp(pkg); 526 assertCanAccessSms(pkg); 527 } finally { 528 resetReadWriteSmsAppOps(pkg); 529 setSmsApp(originalSmsApp); 530 } 531 } 532 resetReadWriteSmsAppOps(String pkg)533 private void resetReadWriteSmsAppOps(String pkg) throws Exception { 534 setModeForOps(pkg, AppOpsManager.MODE_DEFAULT, 535 AppOpsManager.OPSTR_READ_SMS, AppOpsManager.OPSTR_WRITE_SMS); 536 } 537 setModeForOps(String pkg, int mode, String... ops)538 private void setModeForOps(String pkg, int mode, String... ops) throws Exception { 539 // We cannot reset these app ops to DEFAULT via current API, so we reset them manually here 540 // temporarily as we will rewrite how the default SMS app is setup later. 541 executeWithShellPermissionIdentity(() -> { 542 int uid = getPackageUid(pkg); 543 AppOpsManager appOpsManager = 544 getInstrumentation().getContext().getSystemService(AppOpsManager.class); 545 for (String op : ops) { 546 appOpsManager.setUidMode(op, uid, mode); 547 } 548 }); 549 } 550 getPackageUid(String pkg)551 private int getPackageUid(String pkg) throws PackageManager.NameNotFoundException { 552 return getInstrumentation().getContext().getPackageManager().getPackageUid(pkg, 0); 553 } 554 getSmsApp()555 private String getSmsApp() throws Exception { 556 return executeWithShellPermissionIdentity(() -> getInstrumentation() 557 .getContext() 558 .getSystemService(RoleManager.class) 559 .getRoleHolders(RoleManager.ROLE_SMS) 560 .get(0)); 561 } 562 setSmsApp(String pkg)563 private void setSmsApp(String pkg) throws Exception { 564 executeWithShellPermissionIdentity(() -> { 565 Context context = getInstrumentation().getContext(); 566 RoleManager roleManager = context.getSystemService(RoleManager.class); 567 CompletableFuture<Boolean> result = new CompletableFuture<>(); 568 if (roleManager.getRoleHoldersAsUser(RoleManager.ROLE_SMS, 569 context.getUser()).contains(pkg)) { 570 result.complete(true); 571 } else { 572 roleManager.addRoleHolderAsUser(RoleManager.ROLE_SMS, pkg, 573 RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, context.getUser(), 574 AsyncTask.THREAD_POOL_EXECUTOR, result::complete); 575 } 576 assertTrue(result.get(5, TimeUnit.SECONDS)); 577 }); 578 } 579 executeWithShellPermissionIdentity(Callable<T> callable)580 private <T> T executeWithShellPermissionIdentity(Callable<T> callable) throws Exception { 581 if (sHasShellPermissionIdentity) { 582 return callable.call(); 583 } 584 UiAutomation uiAutomation = getInstrumentation().getUiAutomation( 585 UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES); 586 uiAutomation.adoptShellPermissionIdentity(); 587 try { 588 sHasShellPermissionIdentity = true; 589 return callable.call(); 590 } finally { 591 uiAutomation.dropShellPermissionIdentity(); 592 sHasShellPermissionIdentity = false; 593 } 594 } 595 executeWithShellPermissionIdentity(RunnableWithException runnable)596 private void executeWithShellPermissionIdentity(RunnableWithException runnable) 597 throws Exception { 598 executeWithShellPermissionIdentity(() -> { 599 runnable.run(); 600 return null; 601 }); 602 } 603 604 private interface RunnableWithException { run()605 void run() throws Exception; 606 } 607 assertCanAccessSms(String pkg)608 private void assertCanAccessSms(String pkg) throws Exception { 609 CompletableFuture<Bundle> callbackResult = new CompletableFuture<>(); 610 mContext.startActivity(new Intent() 611 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 612 .setComponent(new ComponentName(pkg, pkg + ".MainActivity")) 613 .putExtra("callback", new RemoteCallback(callbackResult::complete))); 614 615 Bundle bundle = callbackResult.get(20, TimeUnit.SECONDS); 616 617 assertThat(bundle.getString("class"), startsWith(pkg)); 618 assertThat(bundle.getString("exceptionMessage"), anyOf(equalTo(null), emptyString())); 619 assertThat(bundle.getInt("queryCount"), greaterThan(0)); 620 } 621 init()622 private void init() { 623 mSendReceiver.reset(); 624 mDeliveryReceiver.reset(); 625 mDataSmsReceiver.reset(); 626 mSmsDeliverReceiver.reset(); 627 mSmsReceivedReceiver.reset(); 628 mSmsRetrieverReceiver.reset(); 629 mReceivedDataSms = false; 630 sMessageId = 0L; 631 mSentIntent = PendingIntent.getBroadcast(mContext, 0, mSendIntent, 632 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE_UNAUDITED); 633 mDeliveredIntent = PendingIntent.getBroadcast(mContext, 0, mDeliveryIntent, 634 PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE_UNAUDITED); 635 } 636 637 /** 638 * Returns the number of parts sent in the message. If Multi-part SMS is not supported, 639 * returns 0. 640 */ sendMultipartTextMessageIfSupported(String mccmnc, boolean addMessageId)641 private int sendMultipartTextMessageIfSupported(String mccmnc, boolean addMessageId) { 642 int numPartsSent = 0; 643 if (!CarrierCapability.UNSUPPORT_MULTIPART_SMS_MESSAGES.contains(mccmnc)) { 644 init(); 645 ArrayList<String> parts = divideMessage(LONG_TEXT); 646 numPartsSent = parts.size(); 647 ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>(); 648 ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>(); 649 for (int i = 0; i < numPartsSent; i++) { 650 sentIntents.add(PendingIntent.getBroadcast(mContext, 0, mSendIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED)); 651 deliveryIntents.add(PendingIntent.getBroadcast(mContext, 0, mDeliveryIntent, PendingIntent.FLAG_MUTABLE_UNAUDITED)); 652 } 653 sendMultiPartTextMessage(mDestAddr, parts, sentIntents, deliveryIntents, addMessageId); 654 } 655 return numPartsSent; 656 } 657 sendDataMessageIfSupported(String mccmnc)658 private boolean sendDataMessageIfSupported(String mccmnc) { 659 if (!CarrierCapability.UNSUPPORT_DATA_SMS_MESSAGES.contains(mccmnc)) { 660 byte[] data = mText.getBytes(); 661 short port = 19989; 662 663 init(); 664 sendDataMessage(mDestAddr, port, data, mSentIntent, mDeliveredIntent); 665 return true; 666 } 667 return false; 668 } 669 670 @Test testGetDefault()671 public void testGetDefault() { 672 assertNotNull(getSmsManager()); 673 } 674 675 @Test testGetSetSmscAddress()676 public void testGetSetSmscAddress() { 677 String smsc = null; 678 try { 679 smsc = getSmsManager().getSmscAddress(); 680 fail("SmsManager.getSmscAddress() should throw a SecurityException"); 681 } catch (SecurityException e) { 682 // expected 683 } 684 685 InstrumentationRegistry.getInstrumentation().getUiAutomation() 686 .adoptShellPermissionIdentity("android.permission.READ_PRIVILEGED_PHONE_STATE"); 687 try { 688 smsc = getSmsManager().getSmscAddress(); 689 } catch (SecurityException se) { 690 fail("Caller with READ_PRIVILEGED_PHONE_STATE should be able to call API"); 691 } finally { 692 InstrumentationRegistry.getInstrumentation().getUiAutomation() 693 .dropShellPermissionIdentity(); 694 } 695 696 try { 697 getSmsManager().setSmscAddress(smsc); 698 fail("SmsManager.setSmscAddress() should throw a SecurityException"); 699 } catch (SecurityException e) { 700 // expected 701 } 702 703 InstrumentationRegistry.getInstrumentation().getUiAutomation() 704 .adoptShellPermissionIdentity("android.permission.MODIFY_PHONE_STATE"); 705 try { 706 getSmsManager().setSmscAddress(smsc); 707 } catch (SecurityException se) { 708 fail("Caller with MODIFY_PHONE_STATE should be able to call API"); 709 } finally { 710 InstrumentationRegistry.getInstrumentation().getUiAutomation() 711 .dropShellPermissionIdentity(); 712 } 713 } 714 715 @Test testGetPremiumSmsConsent()716 public void testGetPremiumSmsConsent() { 717 try { 718 getSmsManager().getPremiumSmsConsent("fake package name"); 719 fail("SmsManager.getPremiumSmsConsent() should throw a SecurityException"); 720 } catch (SecurityException e) { 721 // expected 722 } 723 724 InstrumentationRegistry.getInstrumentation().getUiAutomation() 725 .adoptShellPermissionIdentity("android.permission.READ_PRIVILEGED_PHONE_STATE"); 726 try { 727 getSmsManager().getPremiumSmsConsent("fake package name"); 728 fail("Caller with permission but only phone/system uid is allowed"); 729 } catch (SecurityException se) { 730 // expected 731 } finally { 732 InstrumentationRegistry.getInstrumentation().getUiAutomation() 733 .dropShellPermissionIdentity(); 734 } 735 } 736 737 @Test testSetPremiumSmsConsent()738 public void testSetPremiumSmsConsent() { 739 try { 740 getSmsManager().setPremiumSmsConsent("fake package name", 0); 741 fail("SmsManager.setPremiumSmsConsent() should throw a SecurityException"); 742 } catch (SecurityException e) { 743 // expected 744 } 745 746 InstrumentationRegistry.getInstrumentation().getUiAutomation() 747 .adoptShellPermissionIdentity("android.permission.MODIFY_PHONE_STATE"); 748 try { 749 getSmsManager().setPremiumSmsConsent("fake package name", 0); 750 fail("Caller with permission but only phone/system uid is allowed"); 751 } catch (SecurityException se) { 752 // expected 753 } finally { 754 InstrumentationRegistry.getInstrumentation().getUiAutomation() 755 .dropShellPermissionIdentity(); 756 } 757 } 758 759 /** 760 * Verify that SmsManager.getSmsCapacityOnIcc requires Permission. 761 * <p> 762 * Requires Permission: 763 * {@link android.Manifest.permission#READ_PHONE_STATE}. 764 */ 765 @Test testGetSmsCapacityOnIcc()766 public void testGetSmsCapacityOnIcc() { 767 try { 768 getSmsManager().getSmsCapacityOnIcc(); 769 } catch (SecurityException e) { 770 fail("Caller with READ_PHONE_STATE should be able to call API"); 771 } 772 } 773 774 @Test testDisableCellBroadcastRange()775 public void testDisableCellBroadcastRange() { 776 try { 777 int ranType = SmsCbMessage.MESSAGE_FORMAT_3GPP; 778 executeWithShellPermissionIdentity(() -> { 779 getSmsManager().disableCellBroadcastRange( 780 CdmaSmsCbProgramData.CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT, 781 CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT, 782 ranType); 783 }); 784 } catch (Exception e) { 785 // expected 786 } 787 } 788 789 @Test testEnableCellBroadcastRange()790 public void testEnableCellBroadcastRange() { 791 try { 792 int ranType = SmsCbMessage.MESSAGE_FORMAT_3GPP; 793 executeWithShellPermissionIdentity(() -> { 794 getSmsManager().enableCellBroadcastRange( 795 CdmaSmsCbProgramData.CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT, 796 CdmaSmsCbProgramData.CATEGORY_CMAS_EXTREME_THREAT, 797 ranType); 798 }); 799 } catch (Exception e) { 800 // expected 801 } 802 } 803 804 @Test testResetAllCellBroadcastRanges()805 public void testResetAllCellBroadcastRanges() { 806 try { 807 executeWithShellPermissionIdentity(() -> { 808 getSmsManager().resetAllCellBroadcastRanges(); 809 }); 810 } catch (Exception e) { 811 // expected 812 } 813 } 814 815 @Test testCreateForSubscriptionId()816 public void testCreateForSubscriptionId() { 817 int testSubId = 123; 818 SmsManager smsManager = mContext.getSystemService(SmsManager.class) 819 .createForSubscriptionId(testSubId); 820 assertEquals("getSubscriptionId() should be " + testSubId, testSubId, 821 smsManager.getSubscriptionId()); 822 } 823 divideMessage(String text)824 protected ArrayList<String> divideMessage(String text) { 825 return getSmsManager().divideMessage(text); 826 } 827 getSmsManager()828 private android.telephony.SmsManager getSmsManager() { 829 return android.telephony.SmsManager.getDefault(); 830 } 831 sendMultiPartTextMessage(String destAddr, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, boolean addMessageId)832 protected void sendMultiPartTextMessage(String destAddr, ArrayList<String> parts, 833 ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, 834 boolean addMessageId) { 835 if (addMessageId) { 836 long fakeMessageId = 1278; 837 getSmsManager().sendMultipartTextMessage(destAddr, null, parts, sentIntents, 838 deliveryIntents, fakeMessageId); 839 } else if (mContext.getOpPackageName() != null) { 840 getSmsManager().sendMultipartTextMessage(destAddr, null, parts, sentIntents, 841 deliveryIntents, mContext.getOpPackageName(), mContext.getAttributionTag()); 842 } else { 843 getSmsManager().sendMultipartTextMessage(destAddr, null, parts, sentIntents, 844 deliveryIntents); 845 } 846 } 847 sendDataMessage(String destAddr,short port, byte[] data, PendingIntent sentIntent, PendingIntent deliveredIntent)848 protected void sendDataMessage(String destAddr,short port, byte[] data, PendingIntent sentIntent, PendingIntent deliveredIntent) { 849 getSmsManager().sendDataMessage(destAddr, null, port, data, sentIntent, deliveredIntent); 850 } 851 sendTextMessage(String destAddr, String text, PendingIntent sentIntent, PendingIntent deliveredIntent)852 protected void sendTextMessage(String destAddr, String text, PendingIntent sentIntent, 853 PendingIntent deliveredIntent) { 854 getSmsManager().sendTextMessage(destAddr, null, text, sentIntent, deliveredIntent); 855 } 856 sendTextMessageWithMessageId(String destAddr, String text, PendingIntent sentIntent, PendingIntent deliveredIntent, long messageId)857 protected void sendTextMessageWithMessageId(String destAddr, String text, 858 PendingIntent sentIntent, PendingIntent deliveredIntent, long messageId) { 859 getSmsManager().sendTextMessage(destAddr, null, text, sentIntent, deliveredIntent, 860 messageId); 861 } 862 blockNumber(String number)863 private void blockNumber(String number) { 864 mBlockedNumberUri = insertBlockedNumber(mContext, number); 865 if (mBlockedNumberUri == null) { 866 fail("Failed to insert into blocked number provider."); 867 } 868 } 869 unblockNumber(Uri uri)870 private void unblockNumber(Uri uri) { 871 deleteBlockedNumber(mContext, uri); 872 } 873 setDefaultSmsApp(boolean setToSmsApp)874 private void setDefaultSmsApp(boolean setToSmsApp) 875 throws Exception { 876 String command = String.format( 877 "appops set --user 0 %s WRITE_SMS %s", 878 mContext.getPackageName(), 879 setToSmsApp ? "allow" : "default"); 880 assertTrue("Setting default SMS app failed : " + setToSmsApp, 881 executeShellCommand(command).isEmpty()); 882 mTestAppSetAsDefaultSmsApp = setToSmsApp; 883 } 884 executeShellCommand(String command)885 private String executeShellCommand(String command) 886 throws IOException { 887 ParcelFileDescriptor pfd = 888 getInstrumentation().getUiAutomation().executeShellCommand(command); 889 BufferedReader br = null; 890 try (InputStream in = new FileInputStream(pfd.getFileDescriptor());) { 891 br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); 892 String str; 893 StringBuilder out = new StringBuilder(); 894 while ((str = br.readLine()) != null) { 895 out.append(str); 896 } 897 return out.toString(); 898 } finally { 899 if (br != null) { 900 br.close(); 901 } 902 } 903 } 904 905 private static class SmsBroadcastReceiver extends BroadcastReceiver { 906 private int mCalls; 907 private int mExpectedCalls; 908 private String mAction; 909 private Object mLock; 910 SmsBroadcastReceiver(String action)911 SmsBroadcastReceiver(String action) { 912 mAction = action; 913 reset(); 914 mLock = new Object(); 915 } 916 reset()917 void reset() { 918 mExpectedCalls = Integer.MAX_VALUE; 919 mCalls = 0; 920 } 921 922 @Override onReceive(Context context, Intent intent)923 public void onReceive(Context context, Intent intent) { 924 if(mAction.equals(DATA_SMS_RECEIVED_ACTION)){ 925 StringBuilder sb = new StringBuilder(); 926 Bundle bundle = intent.getExtras(); 927 if (bundle != null) { 928 Object[] obj = (Object[]) bundle.get("pdus"); 929 String format = bundle.getString("format"); 930 SmsMessage[] message = new SmsMessage[obj.length]; 931 for (int i = 0; i < obj.length; i++) { 932 message[i] = SmsMessage.createFromPdu((byte[]) obj[i], format); 933 } 934 935 for (SmsMessage currentMessage : message) { 936 byte[] binaryContent = currentMessage.getUserData(); 937 String readableContent = new String(binaryContent); 938 sb.append(readableContent); 939 } 940 } 941 mReceivedDataSms = true; 942 mReceivedText=sb.toString(); 943 } 944 if (mAction.equals(Telephony.Sms.Intents.SMS_RECEIVED_ACTION)) { 945 sMessageId = intent.getLongExtra("messageId", 0L); 946 } 947 Log.i(TAG, "onReceive " + intent.getAction() + " mAction " + mAction); 948 if (intent.getAction().equals(mAction)) { 949 synchronized (mLock) { 950 mCalls += 1; 951 mLock.notify(); 952 } 953 } 954 } 955 verifyNoCalls(long timeout)956 private boolean verifyNoCalls(long timeout) throws InterruptedException { 957 synchronized(mLock) { 958 mLock.wait(timeout); 959 return mCalls == 0; 960 } 961 } 962 waitForCalls(int expectedCalls, long timeout)963 public boolean waitForCalls(int expectedCalls, long timeout) throws InterruptedException { 964 synchronized(mLock) { 965 mExpectedCalls = expectedCalls; 966 long startTime = SystemClock.elapsedRealtime(); 967 968 while (mCalls < mExpectedCalls) { 969 long waitTime = timeout - (SystemClock.elapsedRealtime() - startTime); 970 if (waitTime > 0) { 971 mLock.wait(waitTime); 972 } else { 973 return false; // timed out 974 } 975 } 976 return true; // success 977 } 978 } 979 } 980 } 981