1 /* 2 * Copyright (C) 2015 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.os.cts; 18 19 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; 20 import static android.Manifest.permission.SYSTEM_ALERT_WINDOW; 21 import static android.content.Context.WINDOW_SERVICE; 22 import static android.view.Display.DEFAULT_DISPLAY; 23 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; 24 import static android.view.WindowManager.LayoutParams.TYPE_PHONE; 25 26 import static com.google.common.truth.Truth.assertThat; 27 import static com.google.common.truth.Truth.assertWithMessage; 28 29 import static org.junit.Assert.assertTrue; 30 import static org.junit.Assert.fail; 31 32 import android.app.Activity; 33 import android.app.Instrumentation; 34 import android.app.Service; 35 import android.app.WallpaperManager; 36 import android.content.ComponentName; 37 import android.content.Context; 38 import android.content.Intent; 39 import android.content.IntentFilter; 40 import android.content.ServiceConnection; 41 import android.content.pm.PackageManager; 42 import android.content.res.Configuration; 43 import android.hardware.display.DisplayManager; 44 import android.net.TrafficStats; 45 import android.net.Uri; 46 import android.os.Binder; 47 import android.os.IBinder; 48 import android.os.RemoteException; 49 import android.os.StrictMode; 50 import android.os.StrictMode.ThreadPolicy.Builder; 51 import android.os.StrictMode.ViolationInfo; 52 import android.os.strictmode.CleartextNetworkViolation; 53 import android.os.strictmode.CustomViolation; 54 import android.os.strictmode.DiskReadViolation; 55 import android.os.strictmode.DiskWriteViolation; 56 import android.os.strictmode.ExplicitGcViolation; 57 import android.os.strictmode.FileUriExposedViolation; 58 import android.os.strictmode.InstanceCountViolation; 59 import android.os.strictmode.LeakedClosableViolation; 60 import android.os.strictmode.NetworkViolation; 61 import android.os.strictmode.NonSdkApiUsedViolation; 62 import android.os.strictmode.UnsafeIntentLaunchViolation; 63 import android.os.strictmode.UntaggedSocketViolation; 64 import android.os.strictmode.Violation; 65 import android.platform.test.annotations.AppModeFull; 66 import android.platform.test.annotations.AppModeInstant; 67 import android.platform.test.annotations.Presubmit; 68 import android.system.Os; 69 import android.system.OsConstants; 70 import android.util.Log; 71 import android.view.Display; 72 import android.view.GestureDetector; 73 import android.view.View; 74 import android.view.ViewConfiguration; 75 import android.view.WindowManager; 76 import android.window.WindowProviderService; 77 78 import androidx.test.core.app.ApplicationProvider; 79 import androidx.test.platform.app.InstrumentationRegistry; 80 import androidx.test.rule.ServiceTestRule; 81 import androidx.test.runner.AndroidJUnit4; 82 83 import org.junit.After; 84 import org.junit.Before; 85 import org.junit.Test; 86 import org.junit.runner.RunWith; 87 88 import java.io.BufferedOutputStream; 89 import java.io.File; 90 import java.io.FileDescriptor; 91 import java.io.FileInputStream; 92 import java.io.FileNotFoundException; 93 import java.io.FileOutputStream; 94 import java.io.IOException; 95 import java.net.HttpURLConnection; 96 import java.net.Socket; 97 import java.net.URL; 98 import java.util.ArrayList; 99 import java.util.List; 100 import java.util.concurrent.ArrayBlockingQueue; 101 import java.util.concurrent.BlockingQueue; 102 import java.util.concurrent.CountDownLatch; 103 import java.util.concurrent.ExecutionException; 104 import java.util.concurrent.Executors; 105 import java.util.concurrent.LinkedBlockingQueue; 106 import java.util.concurrent.TimeUnit; 107 import java.util.function.Consumer; 108 109 /** Tests for {@link StrictMode} */ 110 @RunWith(AndroidJUnit4.class) 111 public class StrictModeTest { 112 private static final String TAG = "StrictModeTest"; 113 private static final String REMOTE_SERVICE_ACTION = "android.app.REMOTESERVICE"; 114 private static final String UNSAFE_INTENT_LAUNCH = "UnsafeIntentLaunch"; 115 116 private StrictMode.ThreadPolicy mThreadPolicy; 117 private StrictMode.VmPolicy mVmPolicy; 118 119 private Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation(); 120 private GestureDetector.OnGestureListener mGestureListener = 121 new GestureDetector.SimpleOnGestureListener(); 122 private static final String WM_CLASS_NAME = WindowManager.class.getSimpleName(); 123 getContext()124 private Context getContext() { 125 return ApplicationProvider.getApplicationContext(); 126 } 127 128 @Before setUp()129 public void setUp() { 130 mThreadPolicy = StrictMode.getThreadPolicy(); 131 mVmPolicy = StrictMode.getVmPolicy(); 132 } 133 134 @After tearDown()135 public void tearDown() { 136 StrictMode.setThreadPolicy(mThreadPolicy); 137 StrictMode.setVmPolicy(mVmPolicy); 138 } 139 140 public interface ThrowingRunnable { run()141 void run() throws Exception; 142 } 143 144 @Test testThreadBuilder()145 public void testThreadBuilder() throws Exception { 146 StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().detectDiskReads().penaltyLog().build(); 147 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(policy).build()); 148 149 final File test = File.createTempFile("foo", "bar"); 150 inspectViolation( 151 test::exists, 152 info -> { 153 assertThat(info.getViolationDetails()).isNull(); 154 assertThat(info.getStackTrace()).contains("DiskReadViolation"); 155 }); 156 } 157 158 @Test testThreadBuilder_detectUnbufferedIo()159 public void testThreadBuilder_detectUnbufferedIo() throws Exception { 160 StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder() 161 .penaltyLog() 162 .detectUnbufferedIo() 163 .build(); 164 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(policy).build()); 165 166 final File test = File.createTempFile("foo", "bar"); 167 inspectViolation( 168 () -> { 169 writeUnbuffered(test); 170 }, 171 info -> { 172 assertThat(info.getViolationDetails()).isNull(); 173 assertThat(info.getStackTrace()).contains("UnbufferedIoViolation"); 174 }); 175 } 176 177 @Test testThreadBuilder_permitUnbufferedIo()178 public void testThreadBuilder_permitUnbufferedIo() throws Exception { 179 StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder() 180 .penaltyLog() 181 .permitUnbufferedIo() 182 .build(); 183 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(policy).build()); 184 185 final File test = File.createTempFile("foo", "bar"); 186 inspectViolation( 187 () -> { 188 writeUnbuffered(test); 189 }, 190 info -> { 191 assertThat(info).isNull(); 192 }); 193 } 194 writeUnbuffered(File file)195 private void writeUnbuffered(File file) throws Exception { 196 if (file.exists()) { 197 file.delete(); 198 } 199 200 try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file))) { 201 for (int i = 0; i < 11; i++) { 202 out.write(1); 203 out.write(2); 204 out.write(3); 205 out.write(4); 206 out.flush(); 207 } 208 } finally { 209 if (file.exists()) { 210 file.delete(); 211 } 212 } 213 } 214 215 @Test testUnclosedCloseable()216 public void testUnclosedCloseable() throws Exception { 217 //clean before test 218 System.gc(); 219 System.runFinalization(); 220 221 StrictMode.setVmPolicy( 222 new StrictMode.VmPolicy.Builder().detectLeakedClosableObjects().build()); 223 224 inspectViolation( 225 () -> leakCloseable("leaked.txt"), 226 info -> { 227 assertThat(info.getViolationDetails()) 228 .isEqualTo( 229 "A resource was acquired at attached stack trace but never released. See java.io.Closeable for information on avoiding resource leaks."); 230 assertThat(info.getStackTrace()) 231 .contains("Explicit termination method 'close' not called"); 232 assertThat(info.getStackTrace()).contains("leakCloseable"); 233 assertThat(info.getViolationClass()) 234 .isAssignableTo(LeakedClosableViolation.class); 235 }); 236 } 237 leakCloseable(String fileName)238 private void leakCloseable(String fileName) throws InterruptedException { 239 final CountDownLatch finalizedSignal = new CountDownLatch(1); 240 try { 241 new FileOutputStream(new File(getContext().getFilesDir(), fileName)) { 242 @Override 243 protected void finalize() throws IOException { 244 super.finalize(); 245 finalizedSignal.countDown(); 246 } 247 }; 248 } catch (FileNotFoundException e) { 249 throw new RuntimeException(e); 250 } 251 Runtime.getRuntime().gc(); 252 Runtime.getRuntime().runFinalization(); 253 // Sometimes it needs extra prodding. 254 if (!finalizedSignal.await(5, TimeUnit.SECONDS)) { 255 Runtime.getRuntime().gc(); 256 Runtime.getRuntime().runFinalization(); 257 } 258 } 259 260 @Test testClassInstanceLimit()261 public void testClassInstanceLimit() throws Exception { 262 StrictMode.setVmPolicy( 263 new StrictMode.VmPolicy.Builder() 264 .setClassInstanceLimit(LimitedClass.class, 1) 265 .build()); 266 List<LimitedClass> references = new ArrayList<>(); 267 assertNoViolation(() -> references.add(new LimitedClass())); 268 references.add(new LimitedClass()); 269 inspectViolation( 270 StrictMode::conditionallyCheckInstanceCounts, 271 info -> assertThat(info.getViolationClass()) 272 .isAssignableTo(InstanceCountViolation.class)); 273 } 274 275 private static final class LimitedClass {} 276 277 /** Insecure connection should be detected */ 278 @AppModeFull 279 @Test testCleartextNetwork()280 public void testCleartextNetwork() throws Exception { 281 if (!hasInternetConnection()) { 282 Log.i(TAG, "testCleartextNetwork() ignored on device without Internet"); 283 return; 284 } 285 286 StrictMode.setVmPolicy( 287 new StrictMode.VmPolicy.Builder().detectCleartextNetwork().penaltyLog().build()); 288 289 inspectViolation( 290 () -> 291 ((HttpURLConnection) new URL("http://example.com/").openConnection()) 292 .getResponseCode(), 293 info -> assertThat(info.getViolationClass()) 294 .isAssignableTo(CleartextNetworkViolation.class)); 295 } 296 297 /** Secure connection should be ignored */ 298 @Test testEncryptedNetwork()299 public void testEncryptedNetwork() throws Exception { 300 if (!hasInternetConnection()) { 301 Log.i(TAG, "testEncryptedNetwork() ignored on device without Internet"); 302 return; 303 } 304 305 StrictMode.setVmPolicy( 306 new StrictMode.VmPolicy.Builder().detectCleartextNetwork().penaltyLog().build()); 307 308 assertNoViolation( 309 () -> 310 ((HttpURLConnection) new URL("https://example.com/").openConnection()) 311 .getResponseCode()); 312 } 313 314 @Test testFileUriExposure()315 public void testFileUriExposure() throws Exception { 316 StrictMode.setVmPolicy( 317 new StrictMode.VmPolicy.Builder().detectFileUriExposure().penaltyLog().build()); 318 319 final Uri badUri = Uri.fromFile(new File("/sdcard/meow.jpg")); 320 inspectViolation( 321 () -> { 322 Intent intent = new Intent(Intent.ACTION_VIEW); 323 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 324 intent.setDataAndType(badUri, "image/jpeg"); 325 getContext().startActivity(intent); 326 }, 327 info -> { 328 assertThat(info.getStackTrace()).contains(badUri + " exposed beyond app"); 329 }); 330 331 final Uri goodUri = Uri.parse("content://com.example/foobar"); 332 assertNoViolation( 333 () -> { 334 Intent intent = new Intent(Intent.ACTION_VIEW); 335 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 336 intent.setDataAndType(goodUri, "image/jpeg"); 337 getContext().startActivity(intent); 338 }); 339 } 340 341 @Test testFileUriExposure_Chooser()342 public void testFileUriExposure_Chooser() throws Exception { 343 StrictMode.setVmPolicy( 344 new StrictMode.VmPolicy.Builder().detectFileUriExposure().penaltyLog().build()); 345 346 final Uri badUri = Uri.fromFile(new File("/sdcard/meow.jpg")); 347 inspectViolation( 348 () -> { 349 Intent intent = new Intent(Intent.ACTION_SEND); 350 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 351 intent.setType("image/jpeg"); 352 intent.putExtra(Intent.EXTRA_STREAM, badUri); 353 354 Intent chooser = Intent.createChooser(intent, "CTS"); 355 chooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 356 getContext().startActivity(chooser); 357 }, 358 info -> { 359 assertThat(info.getStackTrace()).contains(badUri + " exposed beyond app"); 360 }); 361 } 362 363 @Test testContentUriWithoutPermission()364 public void testContentUriWithoutPermission() throws Exception { 365 StrictMode.setVmPolicy( 366 new StrictMode.VmPolicy.Builder() 367 .detectContentUriWithoutPermission() 368 .penaltyLog() 369 .build()); 370 371 final Uri uri = Uri.parse("content://com.example/foobar"); 372 inspectViolation( 373 () -> { 374 Intent intent = new Intent(Intent.ACTION_VIEW); 375 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 376 intent.setDataAndType(uri, "image/jpeg"); 377 getContext().startActivity(intent); 378 }, 379 info -> 380 assertThat(info.getStackTrace()) 381 .contains(uri + " exposed beyond app")); 382 383 assertNoViolation( 384 () -> { 385 Intent intent = new Intent(Intent.ACTION_VIEW); 386 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 387 intent.setDataAndType(uri, "image/jpeg"); 388 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 389 getContext().startActivity(intent); 390 }); 391 } 392 393 @AppModeFull 394 @Test testUntaggedSocketsHttp()395 public void testUntaggedSocketsHttp() throws Exception { 396 if (!hasInternetConnection()) { 397 Log.i(TAG, "testUntaggedSockets() ignored on device without Internet"); 398 return; 399 } 400 401 StrictMode.setVmPolicy( 402 new StrictMode.VmPolicy.Builder().detectUntaggedSockets().penaltyLog().build()); 403 404 inspectViolation( 405 () -> 406 ((HttpURLConnection) new URL("http://example.com/").openConnection()) 407 .getResponseCode(), 408 info -> assertThat(info.getViolationClass()) 409 .isAssignableTo(UntaggedSocketViolation.class)); 410 411 assertNoViolation( 412 () -> { 413 TrafficStats.setThreadStatsTag(0xDECAFBAD); 414 try { 415 ((HttpURLConnection) new URL("http://example.com/").openConnection()) 416 .getResponseCode(); 417 } finally { 418 TrafficStats.clearThreadStatsTag(); 419 } 420 }); 421 } 422 423 @Test testUntaggedSocketsRaw()424 public void testUntaggedSocketsRaw() throws Exception { 425 if (!hasInternetConnection()) { 426 Log.i(TAG, "testUntaggedSockets() ignored on device without Internet"); 427 return; 428 } 429 430 StrictMode.setVmPolicy( 431 new StrictMode.VmPolicy.Builder().detectUntaggedSockets().penaltyLog().build()); 432 433 assertNoViolation( 434 () -> { 435 TrafficStats.setThreadStatsTag(0xDECAFBAD); 436 try (Socket socket = new Socket("example.com", 80)) { 437 socket.getOutputStream().close(); 438 } finally { 439 TrafficStats.clearThreadStatsTag(); 440 } 441 }); 442 443 inspectViolation( 444 () -> { 445 try (Socket socket = new Socket("example.com", 80)) { 446 socket.getOutputStream().close(); 447 } 448 }, 449 info -> assertThat(info.getViolationClass()) 450 .isAssignableTo(UntaggedSocketViolation.class)); 451 } 452 453 private static final int PERMISSION_USER_ONLY = 0600; 454 455 @Test testRead()456 public void testRead() throws Exception { 457 final File test = File.createTempFile("foo", "bar"); 458 final File dir = test.getParentFile(); 459 460 final FileInputStream is = new FileInputStream(test); 461 final FileDescriptor fd = 462 Os.open(test.getAbsolutePath(), OsConstants.O_RDONLY, PERMISSION_USER_ONLY); 463 464 StrictMode.setThreadPolicy( 465 new StrictMode.ThreadPolicy.Builder().detectDiskReads().penaltyLog().build()); 466 inspectViolation( 467 test::exists, 468 info -> { 469 assertThat(info.getViolationDetails()).isNull(); 470 assertThat(info.getStackTrace()).contains("DiskReadViolation"); 471 }); 472 473 Consumer<ViolationInfo> assertDiskReadPolicy = info -> assertThat( 474 info.getViolationClass()).isAssignableTo(DiskReadViolation.class); 475 inspectViolation(test::exists, assertDiskReadPolicy); 476 inspectViolation(test::length, assertDiskReadPolicy); 477 inspectViolation(dir::list, assertDiskReadPolicy); 478 inspectViolation(is::read, assertDiskReadPolicy); 479 480 inspectViolation(() -> new FileInputStream(test), assertDiskReadPolicy); 481 inspectViolation( 482 () -> Os.open(test.getAbsolutePath(), OsConstants.O_RDONLY, PERMISSION_USER_ONLY), 483 assertDiskReadPolicy); 484 inspectViolation(() -> Os.read(fd, new byte[10], 0, 1), assertDiskReadPolicy); 485 } 486 487 @Test testWrite()488 public void testWrite() throws Exception { 489 File file = File.createTempFile("foo", "bar"); 490 491 final FileOutputStream os = new FileOutputStream(file); 492 final FileDescriptor fd = 493 Os.open(file.getAbsolutePath(), OsConstants.O_RDWR, PERMISSION_USER_ONLY); 494 495 StrictMode.setThreadPolicy( 496 new StrictMode.ThreadPolicy.Builder().detectDiskWrites().penaltyLog().build()); 497 498 inspectViolation( 499 file::createNewFile, 500 info -> { 501 assertThat(info.getViolationDetails()).isNull(); 502 assertThat(info.getStackTrace()).contains("DiskWriteViolation"); 503 }); 504 505 Consumer<ViolationInfo> assertDiskWritePolicy = info -> assertThat( 506 info.getViolationClass()).isAssignableTo(DiskWriteViolation.class); 507 508 inspectViolation(() -> File.createTempFile("foo", "bar"), assertDiskWritePolicy); 509 inspectViolation(() -> new FileOutputStream(file), assertDiskWritePolicy); 510 inspectViolation(file::delete, assertDiskWritePolicy); 511 inspectViolation(file::createNewFile, assertDiskWritePolicy); 512 inspectViolation(() -> os.write(32), assertDiskWritePolicy); 513 514 inspectViolation( 515 () -> Os.open(file.getAbsolutePath(), OsConstants.O_RDWR, PERMISSION_USER_ONLY), 516 assertDiskWritePolicy); 517 inspectViolation(() -> Os.write(fd, new byte[10], 0, 1), assertDiskWritePolicy); 518 inspectViolation(() -> Os.fsync(fd), assertDiskWritePolicy); 519 inspectViolation( 520 () -> file.renameTo(new File(file.getParent(), "foobar")), assertDiskWritePolicy); 521 } 522 523 @AppModeFull 524 @Test testNetwork()525 public void testNetwork() throws Exception { 526 if (!hasInternetConnection()) { 527 Log.i(TAG, "testUntaggedSockets() ignored on device without Internet"); 528 return; 529 } 530 531 StrictMode.setThreadPolicy( 532 new StrictMode.ThreadPolicy.Builder().detectNetwork().penaltyLog().build()); 533 534 inspectViolation( 535 () -> { 536 try (Socket socket = new Socket("example.com", 80)) { 537 socket.getOutputStream().close(); 538 } 539 }, 540 info -> assertThat(info.getViolationClass()) 541 .isAssignableTo(NetworkViolation.class)); 542 inspectViolation( 543 () -> 544 ((HttpURLConnection) new URL("http://example.com/").openConnection()) 545 .getResponseCode(), 546 info -> assertThat(info.getViolationClass()) 547 .isAssignableTo(NetworkViolation.class)); 548 } 549 550 @Test testExplicitGc()551 public void testExplicitGc() throws Exception { 552 StrictMode.setThreadPolicy( 553 new StrictMode.ThreadPolicy.Builder().detectExplicitGc().penaltyLog().build()); 554 555 inspectViolation( 556 () -> { Runtime.getRuntime().gc(); }, 557 info -> assertThat(info.getViolationClass()) 558 .isAssignableTo(ExplicitGcViolation.class)); 559 } 560 561 @Test testViolationAcrossBinder()562 public void testViolationAcrossBinder() throws Exception { 563 runWithRemoteServiceBound( 564 getContext(), 565 service -> { 566 StrictMode.setThreadPolicy( 567 new Builder().detectDiskWrites().penaltyLog().build()); 568 569 try { 570 inspectViolation( 571 () -> service.performDiskWrite(), 572 (info) -> { 573 assertThat(info.getViolationClass()) 574 .isAssignableTo(DiskWriteViolation.class); 575 assertThat(info.getViolationDetails()) 576 .isNull(); // Disk write has no message. 577 assertThat(info.getStackTrace()) 578 .contains("DiskWriteViolation"); 579 assertThat(info.getStackTrace()) 580 .contains( 581 "at android.os.StrictMode$AndroidBlockGuardPolicy.onWriteToDisk"); 582 assertThat(info.getStackTrace()) 583 .contains("# via Binder call with stack:"); 584 assertThat(info.getStackTrace()) 585 .contains( 586 "at android.os.cts.ISecondary$Stub$Proxy.performDiskWrite"); 587 }); 588 assertNoViolation(() -> service.getPid()); 589 } catch (Exception e) { 590 throw new RuntimeException(e); 591 } 592 }); 593 } 594 checkNonSdkApiUsageViolation(boolean blacklist, String className, String methodName, Class<?>... paramTypes)595 private void checkNonSdkApiUsageViolation(boolean blacklist, String className, 596 String methodName, Class<?>... paramTypes) throws Exception { 597 Class<?> clazz = Class.forName(className); 598 inspectViolation( 599 () -> { 600 try { 601 java.lang.reflect.Method m = clazz.getDeclaredMethod(methodName, paramTypes); 602 if (blacklist) { 603 fail(); 604 } 605 } catch (NoSuchMethodException expected) { 606 if (!blacklist) { 607 fail(); 608 } 609 } 610 }, 611 info -> { 612 assertThat(info).isNotNull(); 613 assertThat(info.getViolationClass()) 614 .isAssignableTo(NonSdkApiUsedViolation.class); 615 assertThat(info.getViolationDetails()).contains(methodName); 616 assertThat(info.getStackTrace()).contains("checkNonSdkApiUsageViolation"); 617 } 618 ); 619 } 620 621 @Test testNonSdkApiUsage()622 public void testNonSdkApiUsage() throws Exception { 623 StrictMode.VmPolicy oldVmPolicy = StrictMode.getVmPolicy(); 624 StrictMode.ThreadPolicy oldThreadPolicy = StrictMode.getThreadPolicy(); 625 try { 626 StrictMode.setVmPolicy( 627 new StrictMode.VmPolicy.Builder().detectNonSdkApiUsage().build()); 628 checkNonSdkApiUsageViolation( 629 true, "dalvik.system.VMRuntime", "setHiddenApiExemptions", String[].class); 630 // verify that mutliple uses of a light greylist API are detected. 631 checkNonSdkApiUsageViolation(false, "dalvik.system.VMRuntime", "getRuntime"); 632 checkNonSdkApiUsageViolation(false, "dalvik.system.VMRuntime", "getRuntime"); 633 634 // Verify that the VM policy is turned off after a call to permitNonSdkApiUsage. 635 StrictMode.setVmPolicy( 636 new StrictMode.VmPolicy.Builder().permitNonSdkApiUsage().build()); 637 assertNoViolation(() -> { 638 Class<?> clazz = Class.forName("dalvik.system.VMRuntime"); 639 try { 640 clazz.getDeclaredMethod("getRuntime"); 641 } catch (NoSuchMethodException maybe) { 642 } 643 }); 644 } finally { 645 StrictMode.setVmPolicy(oldVmPolicy); 646 StrictMode.setThreadPolicy(oldThreadPolicy); 647 } 648 } 649 650 @Test testThreadPenaltyListener()651 public void testThreadPenaltyListener() throws Exception { 652 final BlockingQueue<Violation> violations = new ArrayBlockingQueue<>(1); 653 StrictMode.setThreadPolicy( 654 new StrictMode.ThreadPolicy.Builder().detectCustomSlowCalls() 655 .penaltyListener(getContext().getMainExecutor(), (v) -> { 656 violations.add(v); 657 }).build()); 658 659 StrictMode.noteSlowCall("foo"); 660 661 final Violation v = violations.poll(5, TimeUnit.SECONDS); 662 assertTrue(v instanceof CustomViolation); 663 } 664 665 @Test testVmPenaltyListener()666 public void testVmPenaltyListener() throws Exception { 667 final BlockingQueue<Violation> violations = new ArrayBlockingQueue<>(1); 668 StrictMode.setVmPolicy( 669 new StrictMode.VmPolicy.Builder().detectFileUriExposure() 670 .penaltyListener(getContext().getMainExecutor(), (v) -> { 671 violations.add(v); 672 }).build()); 673 674 Intent intent = new Intent(Intent.ACTION_VIEW); 675 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 676 intent.setDataAndType(Uri.fromFile(new File("/sdcard/meow.jpg")), "image/jpeg"); 677 getContext().startActivity(intent); 678 679 final Violation v = violations.poll(5, TimeUnit.SECONDS); 680 assertTrue(v instanceof FileUriExposedViolation); 681 } 682 683 @AppModeInstant 684 @Test testNoCleartextHttpTrafficAllowed()685 public void testNoCleartextHttpTrafficAllowed() throws Exception { 686 if (!hasInternetConnection()) { 687 Log.i(TAG, "testNoCleartextHttpTrafficAllowed() ignored on device without Internet"); 688 return; 689 } 690 691 StrictMode.setVmPolicy( 692 new StrictMode.VmPolicy.Builder().detectCleartextNetwork().penaltyLog().build()); 693 694 try { 695 inspectViolation( 696 () -> 697 ((HttpURLConnection) new URL("http://example.com/").openConnection()) 698 .getResponseCode(), 699 info -> assertThat(info.getViolationClass()) 700 .isAssignableTo(CleartextNetworkViolation.class)); 701 fail("Instant app was able to send cleartext http traffic."); 702 } catch (IOException ex) { 703 // Expected 704 } 705 } 706 707 @Presubmit 708 @Test testIncorrectContextUse_Application_ThrowViolation()709 public void testIncorrectContextUse_Application_ThrowViolation() throws Exception { 710 StrictMode.setVmPolicy( 711 new StrictMode.VmPolicy.Builder() 712 .detectIncorrectContextUse() 713 .penaltyLog() 714 .build()); 715 716 final Context applicationContext = getContext(); 717 718 assertViolation("Tried to access visual service " + WM_CLASS_NAME, 719 () -> applicationContext.getSystemService(WindowManager.class)); 720 721 assertViolation( 722 "The API:ViewConfiguration needs a proper configuration.", 723 () -> ViewConfiguration.get(applicationContext)); 724 725 mInstrumentation.runOnMainSync(() -> { 726 try { 727 assertViolation("The API:GestureDetector#init needs a proper configuration.", 728 () -> new GestureDetector(applicationContext, mGestureListener)); 729 } catch (Exception e) { 730 fail("Failed because of " + e); 731 } 732 }); 733 734 if (isWallpaperSupported()) { 735 assertViolation("Tried to access UI related API:", () -> 736 applicationContext.getSystemService(WallpaperManager.class) 737 .getDesiredMinimumWidth()); 738 } 739 } 740 741 @Presubmit 742 @Test testIncorrectContextUse_DisplayContext_ThrowViolation()743 public void testIncorrectContextUse_DisplayContext_ThrowViolation() throws Exception { 744 StrictMode.setVmPolicy( 745 new StrictMode.VmPolicy.Builder() 746 .detectIncorrectContextUse() 747 .penaltyLog() 748 .build()); 749 750 final Display display = getContext().getSystemService(DisplayManager.class) 751 .getDisplay(DEFAULT_DISPLAY); 752 final Context displayContext = getContext().createDisplayContext(display); 753 754 assertViolation("Tried to access visual service " + WM_CLASS_NAME, 755 () -> displayContext.getSystemService(WindowManager.class)); 756 757 assertViolation( 758 "The API:ViewConfiguration needs a proper configuration.", 759 () -> ViewConfiguration.get(displayContext)); 760 761 mInstrumentation.runOnMainSync(() -> { 762 try { 763 assertViolation("The API:GestureDetector#init needs a proper configuration.", 764 () -> new GestureDetector(displayContext, mGestureListener)); 765 } catch (Exception e) { 766 fail("Failed because of " + e); 767 } 768 }); 769 770 if (isWallpaperSupported()) { 771 assertViolation("Tried to access UI related API:", () -> 772 displayContext.getSystemService(WallpaperManager.class) 773 .getDesiredMinimumWidth()); 774 } 775 } 776 777 @Presubmit 778 @Test testIncorrectContextUse_WindowContext_NoViolation()779 public void testIncorrectContextUse_WindowContext_NoViolation() throws Exception { 780 StrictMode.setVmPolicy( 781 new StrictMode.VmPolicy.Builder() 782 .detectIncorrectContextUse() 783 .penaltyLog() 784 .build()); 785 786 final Context windowContext = createWindowContext(); 787 788 assertNoViolation(() -> windowContext.getSystemService(WINDOW_SERVICE)); 789 790 assertNoViolation(() -> ViewConfiguration.get(windowContext)); 791 792 mInstrumentation.runOnMainSync(() -> { 793 try { 794 assertNoViolation(() -> new GestureDetector(windowContext, mGestureListener)); 795 } catch (Exception e) { 796 fail("Failed because of " + e); 797 } 798 }); 799 800 if (isWallpaperSupported()) { 801 assertNoViolation(() -> windowContext.getSystemService(WallpaperManager.class) 802 .getDesiredMinimumWidth()); 803 } 804 } 805 806 @Presubmit 807 @Test testIncorrectContextUse_Activity_NoViolation()808 public void testIncorrectContextUse_Activity_NoViolation() throws Exception { 809 StrictMode.setVmPolicy( 810 new StrictMode.VmPolicy.Builder() 811 .detectIncorrectContextUse() 812 .penaltyLog() 813 .build()); 814 815 Intent intent = new Intent(getContext(), SimpleTestActivity.class); 816 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 817 final Activity activity = mInstrumentation.startActivitySync(intent); 818 819 assertNoViolation(() -> activity.getSystemService(WINDOW_SERVICE)); 820 821 assertNoViolation(() -> ViewConfiguration.get(activity)); 822 823 mInstrumentation.runOnMainSync(() -> { 824 try { 825 assertNoViolation(() -> new GestureDetector(activity, mGestureListener)); 826 } catch (Exception e) { 827 fail("Failed because of " + e); 828 } 829 }); 830 831 if (isWallpaperSupported()) { 832 assertNoViolation(() -> activity.getSystemService(WallpaperManager.class) 833 .getDesiredMinimumWidth()); 834 } 835 } 836 837 @Presubmit 838 @Test testIncorrectContextUse_UiDerivedContext_NoViolation()839 public void testIncorrectContextUse_UiDerivedContext_NoViolation() throws Exception { 840 StrictMode.setVmPolicy( 841 new StrictMode.VmPolicy.Builder() 842 .detectIncorrectContextUse() 843 .penaltyLog() 844 .build()); 845 846 final Configuration config = new Configuration(); 847 config.setToDefaults(); 848 final Context uiDerivedConfigContext = 849 createWindowContext().createConfigurationContext(config); 850 851 assertNoViolation(() -> uiDerivedConfigContext.getSystemService(WINDOW_SERVICE)); 852 853 assertNoViolation(() -> ViewConfiguration.get(uiDerivedConfigContext)); 854 855 mInstrumentation.runOnMainSync(() -> { 856 try { 857 assertNoViolation(() -> 858 new GestureDetector(uiDerivedConfigContext, mGestureListener)); 859 } catch (Exception e) { 860 fail("Failed because of " + e); 861 } 862 }); 863 864 if (isWallpaperSupported()) { 865 assertNoViolation(() -> uiDerivedConfigContext.getSystemService(WallpaperManager.class) 866 .getDesiredMinimumWidth()); 867 } 868 869 final Context uiDerivedAttrContext = createWindowContext() 870 .createAttributionContext(null /* attributeTag */); 871 872 assertNoViolation(() -> uiDerivedAttrContext.getSystemService(WINDOW_SERVICE)); 873 874 assertNoViolation(() -> ViewConfiguration.get(uiDerivedAttrContext)); 875 876 mInstrumentation.runOnMainSync(() -> { 877 try { 878 assertNoViolation(() -> 879 new GestureDetector(uiDerivedAttrContext, mGestureListener)); 880 } catch (Exception e) { 881 fail("Failed because of " + e); 882 } 883 }); 884 885 if (isWallpaperSupported()) { 886 assertNoViolation(() -> uiDerivedAttrContext.getSystemService(WallpaperManager.class) 887 .getDesiredMinimumWidth()); 888 } 889 } 890 891 @Presubmit 892 @Test testIncorrectContextUse_UiDerivedDisplayContext_ThrowViolation()893 public void testIncorrectContextUse_UiDerivedDisplayContext_ThrowViolation() throws Exception { 894 StrictMode.setVmPolicy( 895 new StrictMode.VmPolicy.Builder() 896 .detectIncorrectContextUse() 897 .penaltyLog() 898 .build()); 899 900 final Display display = getContext().getSystemService(DisplayManager.class) 901 .getDisplay(DEFAULT_DISPLAY); 902 final Context uiDerivedDisplayContext = createWindowContext().createDisplayContext(display); 903 904 assertViolation("Tried to access visual service " + WM_CLASS_NAME, 905 () -> uiDerivedDisplayContext.getSystemService(WindowManager.class)); 906 907 assertViolation( 908 "The API:ViewConfiguration needs a proper configuration.", 909 () -> ViewConfiguration.get(uiDerivedDisplayContext)); 910 911 mInstrumentation.runOnMainSync(() -> { 912 try { 913 assertViolation("The API:GestureDetector#init needs a proper configuration.", 914 () -> new GestureDetector(uiDerivedDisplayContext, mGestureListener)); 915 } catch (Exception e) { 916 fail("Failed because of " + e); 917 } 918 }); 919 920 if (isWallpaperSupported()) { 921 assertViolation("Tried to access UI related API:", () -> 922 uiDerivedDisplayContext.getSystemService(WallpaperManager.class) 923 .getDesiredMinimumWidth()); 924 } 925 } 926 927 @Presubmit 928 @Test testIncorrectContextUse_ConfigContext()929 public void testIncorrectContextUse_ConfigContext() throws Exception { 930 StrictMode.setVmPolicy( 931 new StrictMode.VmPolicy.Builder() 932 .detectIncorrectContextUse() 933 .penaltyLog() 934 .build()); 935 936 final Configuration configuration = new Configuration(); 937 configuration.setToDefaults(); 938 final Context configContext = getContext().createConfigurationContext(configuration); 939 940 assertViolation("Tried to access visual service " + WM_CLASS_NAME, 941 () -> configContext.getSystemService(WindowManager.class)); 942 943 // Make the ViewConfiguration to be cached so that we won't call WindowManager 944 ViewConfiguration.get(configContext); 945 946 assertNoViolation(() -> ViewConfiguration.get(configContext)); 947 948 mInstrumentation.runOnMainSync(() -> { 949 try { 950 assertNoViolation(() -> new GestureDetector(configContext, mGestureListener)); 951 } catch (Exception e) { 952 fail("Failed because of " + e); 953 } 954 }); 955 956 if (isWallpaperSupported()) { 957 assertViolation("Tried to access UI related API:", () -> 958 configContext.getSystemService(WallpaperManager.class) 959 .getDesiredMinimumWidth()); 960 } 961 } 962 963 @Presubmit 964 @Test testIncorrectContextUse_ConfigDerivedDisplayContext()965 public void testIncorrectContextUse_ConfigDerivedDisplayContext() throws Exception { 966 StrictMode.setVmPolicy( 967 new StrictMode.VmPolicy.Builder() 968 .detectIncorrectContextUse() 969 .penaltyLog() 970 .build()); 971 972 final Display display = getContext().getSystemService(DisplayManager.class) 973 .getDisplay(DEFAULT_DISPLAY); 974 final Configuration configuration = new Configuration(); 975 configuration.setToDefaults(); 976 final Context configDerivedDisplayContext = getContext() 977 .createConfigurationContext(configuration).createDisplayContext(display); 978 979 assertViolation("Tried to access visual service " + WM_CLASS_NAME, 980 () -> configDerivedDisplayContext.getSystemService(WindowManager.class)); 981 982 assertViolation( 983 "The API:ViewConfiguration needs a proper configuration.", 984 () -> ViewConfiguration.get(configDerivedDisplayContext)); 985 986 mInstrumentation.runOnMainSync(() -> { 987 try { 988 assertViolation("The API:GestureDetector#init needs a proper configuration.", 989 () -> new GestureDetector(configDerivedDisplayContext, mGestureListener)); 990 } catch (Exception e) { 991 fail("Failed because of " + e); 992 } 993 }); 994 995 if (isWallpaperSupported()) { 996 assertViolation("Tried to access UI related API:", () -> 997 configDerivedDisplayContext.getSystemService(WallpaperManager.class) 998 .getDesiredMinimumWidth()); 999 } 1000 } 1001 1002 @Test testIncorrectContextUse_Service_ThrowViolation()1003 public void testIncorrectContextUse_Service_ThrowViolation() throws Exception { 1004 StrictMode.setVmPolicy( 1005 new StrictMode.VmPolicy.Builder() 1006 .detectIncorrectContextUse() 1007 .penaltyLog() 1008 .build()); 1009 1010 final Intent intent = new Intent(getContext(), TestService.class); 1011 final ServiceTestRule serviceRule = new ServiceTestRule(); 1012 TestService service = ((TestService.TestToken) serviceRule.bindService(intent)) 1013 .getService(); 1014 try { 1015 assertViolation("Tried to access visual service " + WM_CLASS_NAME, 1016 () -> service.getSystemService(WindowManager.class)); 1017 1018 assertViolation( 1019 "The API:ViewConfiguration needs a proper configuration.", 1020 () -> ViewConfiguration.get(service)); 1021 1022 mInstrumentation.runOnMainSync(() -> { 1023 try { 1024 assertViolation("The API:GestureDetector#init needs a proper configuration.", 1025 () -> new GestureDetector(service, 1026 mGestureListener)); 1027 } catch (Exception e) { 1028 fail("Failed because of " + e); 1029 } 1030 }); 1031 1032 if (isWallpaperSupported()) { 1033 assertViolation("Tried to access UI related API:", () -> 1034 service.getSystemService(WallpaperManager.class) 1035 .getDesiredMinimumWidth()); 1036 } 1037 } finally { 1038 serviceRule.unbindService(); 1039 } 1040 } 1041 1042 @Test testIncorrectContextUse_WindowProviderService_NoViolation()1043 public void testIncorrectContextUse_WindowProviderService_NoViolation() throws Exception { 1044 StrictMode.setVmPolicy( 1045 new StrictMode.VmPolicy.Builder() 1046 .detectIncorrectContextUse() 1047 .penaltyLog() 1048 .build()); 1049 1050 final Intent intent = new Intent(getContext(), TestWindowService.class); 1051 final ServiceTestRule serviceRule = new ServiceTestRule(); 1052 TestWindowService service = ((TestWindowService.TestToken) serviceRule.bindService(intent)) 1053 .getService(); 1054 try { 1055 assertNoViolation(() -> service.getSystemService(WindowManager.class)); 1056 1057 final View view = new View(service); 1058 final WindowManager.LayoutParams correctType = 1059 new WindowManager.LayoutParams(TYPE_APPLICATION_OVERLAY); 1060 final WindowManager.LayoutParams wrongType = 1061 new WindowManager.LayoutParams(TYPE_PHONE); 1062 WindowManager wm = service.getSystemService(WindowManager.class); 1063 1064 mInstrumentation.runOnMainSync(() -> { 1065 try { 1066 // Hold INTERNAL_SYSTEM_WINDOW and SYSTEM_ALERT_WINDOW permission to 1067 // add TYPE_APPLICATION_OVERLAY and TYPE_PHONE window. 1068 mInstrumentation.getUiAutomation().adoptShellPermissionIdentity( 1069 INTERNAL_SYSTEM_WINDOW, SYSTEM_ALERT_WINDOW); 1070 1071 assertNoViolation(() -> wm.addView(view, correctType)); 1072 wm.removeViewImmediate(view); 1073 1074 assertViolation("WindowContext's window type must match type in " 1075 + "WindowManager.LayoutParams", () -> wm.addView(view, wrongType)); 1076 1077 assertNoViolation(() -> new GestureDetector(service, mGestureListener)); 1078 } catch (Exception e) { 1079 fail("Failed because of " + e); 1080 } finally { 1081 mInstrumentation.getUiAutomation().dropShellPermissionIdentity(); 1082 } 1083 }); 1084 assertNoViolation(() -> ViewConfiguration.get(service)); 1085 1086 if (isWallpaperSupported()) { 1087 assertNoViolation(() -> service.getSystemService(WallpaperManager.class) 1088 .getDesiredMinimumWidth()); 1089 } 1090 } finally { 1091 serviceRule.unbindService(); 1092 } 1093 } 1094 1095 /** 1096 * Returns {@code true} to indicate that wallpaper is supported. 1097 * <p> 1098 * Note that we check the nullity of {@link WallpaperManager} because it may not be obtainable 1099 * if the test is targeting at least {@link android.os.Build.VERSION_CODES#P} and running in 1100 * instant mode. 1101 */ isWallpaperSupported()1102 private boolean isWallpaperSupported() { 1103 final WallpaperManager wallpaperManager = WallpaperManager.getInstance(getContext()); 1104 return wallpaperManager != null && wallpaperManager.isWallpaperSupported(); 1105 } 1106 1107 @Test testUnsafeIntentLaunch_ParceledIntentToActivity_ThrowsViolation()1108 public void testUnsafeIntentLaunch_ParceledIntentToActivity_ThrowsViolation() throws Exception { 1109 // The UnsafeIntentLaunch StrictMode check is intended to detect and report unparceling and 1110 // launching of Intents from the delivered Intent. This test verifies a violation is 1111 // reported when an inner Intent is unparceled from the Intent delivered to an Activity and 1112 // used to start another Activity. This test also uses its own OnVmViolationListener to 1113 // obtain the actual StrictMode Violation to verify the getIntent method of the 1114 // UnsafeIntentLaunchViolation returns the Intent that triggered the Violation. 1115 final LinkedBlockingQueue<Violation> violations = new LinkedBlockingQueue<>(); 1116 StrictMode.setVmPolicy( 1117 new StrictMode.VmPolicy.Builder() 1118 .detectUnsafeIntentLaunch() 1119 .penaltyListener(Executors.newSingleThreadExecutor(), 1120 violation -> violations.add(violation)) 1121 .build()); 1122 Context context = getContext(); 1123 Intent intent = IntentLaunchActivity.getUnsafeIntentLaunchTestIntent(context); 1124 Intent innerIntent = intent.getParcelableExtra(IntentLaunchActivity.EXTRA_INNER_INTENT); 1125 1126 context.startActivity(intent); 1127 Violation violation = violations.poll(5, TimeUnit.SECONDS); 1128 assertThat(violation).isInstanceOf(UnsafeIntentLaunchViolation.class); 1129 // The inner Intent will only have the target component set; since the Intent references 1130 // may not be the same compare the component of the Intent that triggered the violation 1131 // against the inner Intent obtained above. 1132 assertThat(((UnsafeIntentLaunchViolation) violation).getIntent().getComponent()).isEqualTo( 1133 innerIntent.getComponent()); 1134 } 1135 1136 @Test testUnsafeIntentLaunch_ParceledIntentToActivityCheckDisabled_NoViolation()1137 public void testUnsafeIntentLaunch_ParceledIntentToActivityCheckDisabled_NoViolation() 1138 throws Exception { 1139 // This test verifies the StrictMode violation is not reported when unsafe intent launching 1140 // is permitted through the VmPolicy Builder permit API. 1141 StrictMode.setVmPolicy( 1142 new StrictMode.VmPolicy.Builder() 1143 .permitUnsafeIntentLaunch() 1144 .penaltyLog() 1145 .build()); 1146 Context context = getContext(); 1147 Intent intent = IntentLaunchActivity.getUnsafeIntentLaunchTestIntent(context); 1148 1149 assertNoViolation(() -> context.startActivity(intent)); 1150 } 1151 1152 @Test testUnsafeIntentLaunch_ParceledIntentToBoundService_ThrowsViolation()1153 public void testUnsafeIntentLaunch_ParceledIntentToBoundService_ThrowsViolation() 1154 throws Exception { 1155 // This test verifies a violation is reported when an inner Intent is unparceled from the 1156 // Intent delivered to a bound Service and used to bind to another service. 1157 StrictMode.setVmPolicy( 1158 new StrictMode.VmPolicy.Builder() 1159 .detectUnsafeIntentLaunch() 1160 .penaltyLog() 1161 .build()); 1162 Context context = getContext(); 1163 Intent intent = IntentLaunchService.getTestIntent(context); 1164 1165 assertViolation(UNSAFE_INTENT_LAUNCH, 1166 () -> context.bindService(intent, IntentLaunchService.getServiceConnection(), 1167 Context.BIND_AUTO_CREATE)); 1168 } 1169 1170 @Test testUnsafeIntentLaunch_ParceledIntentToStartedService_ThrowsViolation()1171 public void testUnsafeIntentLaunch_ParceledIntentToStartedService_ThrowsViolation() 1172 throws Exception { 1173 // This test verifies a violation is reported when an inner Intent is unparceled from the 1174 // Intent delivered to a started Service and used to start another service. 1175 StrictMode.setVmPolicy( 1176 new StrictMode.VmPolicy.Builder() 1177 .detectUnsafeIntentLaunch() 1178 .penaltyLog() 1179 .build()); 1180 Context context = getContext(); 1181 Intent intent = IntentLaunchService.getTestIntent(context); 1182 1183 assertViolation(UNSAFE_INTENT_LAUNCH, () -> context.startService(intent)); 1184 } 1185 1186 @Test 1187 @AppModeFull(reason = "Instant apps can only declare runtime receivers") testUnsafeIntentLaunch_ParceledIntentToStaticReceiver_ThrowsViolation()1188 public void testUnsafeIntentLaunch_ParceledIntentToStaticReceiver_ThrowsViolation() 1189 throws Exception { 1190 // This test verifies a violation is reported when an inner Intent is unparceled from the 1191 // Intent delivered to a statically declared BroadcastReceiver and used to send another 1192 // broadcast. 1193 StrictMode.setVmPolicy( 1194 new StrictMode.VmPolicy.Builder() 1195 .detectUnsafeIntentLaunch() 1196 .penaltyLog() 1197 .build()); 1198 Context context = getContext(); 1199 Intent intent = new Intent(context, IntentLaunchReceiver.class); 1200 Intent innerIntent = new Intent("android.os.cts.TEST_BROADCAST_ACTION"); 1201 intent.putExtra(IntentLaunchReceiver.INNER_INTENT_KEY, innerIntent); 1202 1203 assertViolation(UNSAFE_INTENT_LAUNCH, () -> context.sendBroadcast(intent)); 1204 } 1205 1206 @Test testUnsafeIntentLaunch_ParceledIntentToDynamicReceiver_ThrowsViolation()1207 public void testUnsafeIntentLaunch_ParceledIntentToDynamicReceiver_ThrowsViolation() 1208 throws Exception { 1209 // This test verifies a violation is reported when an inner Intent is unparceled from the 1210 // Intent delivered to a dynamically registered BroadcastReceiver and used to send another 1211 // broadcast. 1212 StrictMode.setVmPolicy( 1213 new StrictMode.VmPolicy.Builder() 1214 .detectUnsafeIntentLaunch() 1215 .penaltyLog() 1216 .build()); 1217 Context context = getContext(); 1218 String receiverAction = "android.os.cts.TEST_INTENT_LAUNCH_RECEIVER_ACTION"; 1219 context.registerReceiver(new IntentLaunchReceiver(), new IntentFilter(receiverAction)); 1220 Intent intent = new Intent(receiverAction); 1221 Intent innerIntent = new Intent("android.os.cts.TEST_BROADCAST_ACTION"); 1222 intent.putExtra(IntentLaunchReceiver.INNER_INTENT_KEY, innerIntent); 1223 1224 assertViolation(UNSAFE_INTENT_LAUNCH, () -> context.sendBroadcast(intent)); 1225 } 1226 1227 @Test testUnsafeIntentLaunch_ParceledIntentDataCopy_ThrowsViolation()1228 public void testUnsafeIntentLaunch_ParceledIntentDataCopy_ThrowsViolation() throws Exception { 1229 // This test verifies a violation is reported when data is copied from a parceled Intent 1230 // without sanitation or validation to a new Intent that is being created to launch a new 1231 // component. 1232 StrictMode.setVmPolicy( 1233 new StrictMode.VmPolicy.Builder() 1234 .detectUnsafeIntentLaunch() 1235 .penaltyLog() 1236 .build()); 1237 Context context = getContext(); 1238 Intent intent = IntentLaunchActivity.getUnsafeDataCopyFromIntentTestIntent(context); 1239 1240 assertViolation(UNSAFE_INTENT_LAUNCH, () -> context.startActivity(intent)); 1241 } 1242 1243 @Test testUnsafeIntentLaunch_UnsafeDataCopy_ThrowsViolation()1244 public void testUnsafeIntentLaunch_UnsafeDataCopy_ThrowsViolation() throws Exception { 1245 // This test verifies a violation is reported when data is copied from unparceled extras 1246 // without sanitation or validation to a new Intent that is being created to launch a new 1247 // component. 1248 StrictMode.setVmPolicy( 1249 new StrictMode.VmPolicy.Builder() 1250 .detectUnsafeIntentLaunch() 1251 .penaltyLog() 1252 .build()); 1253 Context context = getContext(); 1254 Intent intent = IntentLaunchActivity.getUnsafeDataCopyFromExtrasTestIntent(context); 1255 1256 assertViolation(UNSAFE_INTENT_LAUNCH, () -> context.startActivity(intent)); 1257 } 1258 1259 @Test testUnsafeIntentLaunch_DataCopyFromIntentDeliveredToProtectedComponent_NoViolation()1260 public void testUnsafeIntentLaunch_DataCopyFromIntentDeliveredToProtectedComponent_NoViolation() 1261 throws Exception { 1262 // This test verifies a violation is not reported when data is copied from the Intent 1263 // delivered to a protected component. 1264 StrictMode.setVmPolicy( 1265 new StrictMode.VmPolicy.Builder() 1266 .detectUnsafeIntentLaunch() 1267 .penaltyLog() 1268 .build()); 1269 Context context = getContext(); 1270 Intent intent = 1271 IntentLaunchActivity.getDataCopyFromDeliveredIntentWithUnparceledExtrasTestIntent( 1272 context); 1273 1274 assertNoViolation(() -> context.startActivity(intent)); 1275 } 1276 1277 @Test testUnsafeIntentLaunch_UnsafeIntentFromUriLaunch_ThrowsViolation()1278 public void testUnsafeIntentLaunch_UnsafeIntentFromUriLaunch_ThrowsViolation() 1279 throws Exception { 1280 // Intents can also be delivered as URI strings and parsed with Intent#parseUri. This test 1281 // verifies if an Intent is parsed from a URI string and launched without any additional 1282 // sanitation / validation then a violation is reported. 1283 StrictMode.setVmPolicy( 1284 new StrictMode.VmPolicy.Builder() 1285 .detectUnsafeIntentLaunch() 1286 .penaltyLog() 1287 .build()); 1288 Context context = getContext(); 1289 Intent intent = 1290 IntentLaunchActivity.getUnsafeIntentFromUriLaunchTestIntent(context); 1291 1292 assertViolation(UNSAFE_INTENT_LAUNCH, () -> context.startActivity(intent)); 1293 } 1294 1295 @Test testUnsafeIntentLaunch_SafeIntentFromUriLaunch_NoViolation()1296 public void testUnsafeIntentLaunch_SafeIntentFromUriLaunch_NoViolation() throws Exception { 1297 // The documentation for Intent#URI_ALLOW_UNSAFE recommend using the CATEGORY_BROWSABLE 1298 // when launching an Intent parsed from a URI; while an explicit Intent will still be 1299 // delivered to the target component with this category set an implicit Intent will be 1300 // limited to components with Intent-filters that handle this category. This test verifies 1301 // an implicit Intent parsed from a URI with the browsable category set does not result in 1302 // an UnsafeIntentLaunch StrictMode violation. 1303 StrictMode.setVmPolicy( 1304 new StrictMode.VmPolicy.Builder() 1305 .detectUnsafeIntentLaunch() 1306 .penaltyLog() 1307 .build()); 1308 Context context = getContext(); 1309 Intent intent = 1310 IntentLaunchActivity.getSafeIntentFromUriLaunchTestIntent(context); 1311 1312 assertNoViolation(() -> context.startActivity(intent)); 1313 } 1314 createWindowContext()1315 private Context createWindowContext() { 1316 final Display display = getContext().getSystemService(DisplayManager.class) 1317 .getDisplay(DEFAULT_DISPLAY); 1318 return getContext().createDisplayContext(display) 1319 .createWindowContext(TYPE_APPLICATION_OVERLAY, null /* options */); 1320 } 1321 runWithRemoteServiceBound(Context context, Consumer<ISecondary> consumer)1322 private static void runWithRemoteServiceBound(Context context, Consumer<ISecondary> consumer) 1323 throws ExecutionException, InterruptedException, RemoteException { 1324 BlockingQueue<IBinder> binderHolder = new ArrayBlockingQueue<>(1); 1325 ServiceConnection secondaryConnection = 1326 new ServiceConnection() { 1327 public void onServiceConnected(ComponentName className, IBinder service) { 1328 binderHolder.add(service); 1329 } 1330 1331 public void onServiceDisconnected(ComponentName className) { 1332 binderHolder.drainTo(new ArrayList<>()); 1333 } 1334 }; 1335 Intent intent = new Intent(REMOTE_SERVICE_ACTION); 1336 intent.setPackage(context.getPackageName()); 1337 1338 Intent secondaryIntent = new Intent(ISecondary.class.getName()); 1339 secondaryIntent.setPackage(context.getPackageName()); 1340 assertThat( 1341 context.bindService( 1342 secondaryIntent, secondaryConnection, Context.BIND_AUTO_CREATE)) 1343 .isTrue(); 1344 IBinder binder = binderHolder.take(); 1345 assertThat(binder.queryLocalInterface(binder.getInterfaceDescriptor())).isNull(); 1346 consumer.accept(ISecondary.Stub.asInterface(binder)); 1347 context.unbindService(secondaryConnection); 1348 context.stopService(intent); 1349 } 1350 assertViolation(String expected, ThrowingRunnable r)1351 private static void assertViolation(String expected, ThrowingRunnable r) throws Exception { 1352 inspectViolation(r, info -> assertThat(info.getStackTrace()).contains(expected)); 1353 } 1354 assertNoViolation(ThrowingRunnable r)1355 private static void assertNoViolation(ThrowingRunnable r) throws Exception { 1356 inspectViolation( 1357 r, info -> assertWithMessage("Unexpected violation").that(info).isNull()); 1358 } 1359 inspectViolation( ThrowingRunnable violating, Consumer<ViolationInfo> consume)1360 private static void inspectViolation( 1361 ThrowingRunnable violating, Consumer<ViolationInfo> consume) throws Exception { 1362 final LinkedBlockingQueue<ViolationInfo> violations = new LinkedBlockingQueue<>(); 1363 StrictMode.setViolationLogger(violations::add); 1364 1365 try { 1366 violating.run(); 1367 consume.accept(violations.poll(5, TimeUnit.SECONDS)); 1368 } finally { 1369 StrictMode.setViolationLogger(null); 1370 } 1371 } 1372 hasInternetConnection()1373 private boolean hasInternetConnection() { 1374 final PackageManager pm = getContext().getPackageManager(); 1375 return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY) 1376 || pm.hasSystemFeature(PackageManager.FEATURE_WIFI) 1377 || pm.hasSystemFeature(PackageManager.FEATURE_ETHERNET); 1378 } 1379 1380 public static class TestService extends Service { 1381 private final TestToken mToken = new TestToken(); 1382 1383 @Override onBind(Intent intent)1384 public IBinder onBind(Intent intent) { 1385 return mToken; 1386 } 1387 1388 public class TestToken extends Binder { getService()1389 TestService getService() { 1390 return TestService.this; 1391 } 1392 } 1393 } 1394 1395 public static class TestWindowService extends WindowProviderService { 1396 private final TestToken mToken = new TestToken(); 1397 1398 @Override onBind(Intent intent)1399 public IBinder onBind(Intent intent) { 1400 return mToken; 1401 } 1402 1403 @Override getWindowType()1404 public int getWindowType() { 1405 return TYPE_APPLICATION_OVERLAY; 1406 } 1407 1408 public class TestToken extends Binder { getService()1409 TestWindowService getService() { 1410 return TestWindowService.this; 1411 } 1412 } 1413 } 1414 } 1415