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