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