Error prone checks for mutability flags on PI
Add a mutability flag check for all method calls that create a PendingIntent.
Bug: 160794467
Test: atest error_prone_android_framework_test:com.google.errorprone.bugpatterns.android.PendingIntentMutabilityCheckerTest
Change-Id: I26a51a6dddb2793e9a56e72876f3f9d2aea4e3fb
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityChecker.java
new file mode 100644
index 0000000..2561b41
--- /dev/null
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityChecker.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.errorprone.bugpatterns.android;
+
+import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
+import static com.google.errorprone.matchers.FieldMatchers.staticField;
+import static com.google.errorprone.matchers.Matchers.anyOf;
+import static com.google.errorprone.matchers.Matchers.contains;
+import static com.google.errorprone.matchers.Matchers.methodInvocation;
+import static com.google.errorprone.matchers.Matchers.staticMethod;
+
+
+import com.google.auto.service.AutoService;
+import com.google.errorprone.BugPattern;
+import com.google.errorprone.VisitorState;
+import com.google.errorprone.bugpatterns.BugChecker;
+import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
+import com.google.errorprone.matchers.Description;
+import com.google.errorprone.matchers.Matcher;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.MethodInvocationTree;
+
+import java.util.regex.Pattern;
+
+/**
+ * Any method calls to create a PendingIntent require that one of the
+ * mutability flags, FLAG_MUTABLE or FLAG_IMMUTABLE, be explicitly specified.
+ * This checker verifies that one of these mutability flags are used when
+ * creating PendingIntents.
+ */
+@AutoService(BugChecker.class)
+@BugPattern(
+ name = "AndroidFrameworkPendingIntentMutability",
+ summary = "Verifies that FLAG_MUTABLE or FLAG_IMMUTABLE is always set",
+ severity = WARNING)
+public final class PendingIntentMutabilityChecker extends BugChecker
+ implements MethodInvocationTreeMatcher {
+
+ private static final Matcher<ExpressionTree> PENDING_INTENT_METHOD = methodInvocation(
+ staticMethod()
+ .onClass("android.app.PendingIntent")
+ .withNameMatching(Pattern.compile(
+ "^(getActivity|getActivityAsUser|getActivities|getActivitiesAsUser|"
+ + "getBroadcast|getBroadcastAsUser|getService|getForegroundService).*")));
+
+ private static final Matcher<ExpressionTree> VALID_FLAGS = anyOf(
+ staticField("android.app.PendingIntent", "FLAG_MUTABLE"),
+ staticField("android.app.PendingIntent", "FLAG_IMMUTABLE"));
+
+ private static final Matcher<ExpressionTree> CONTAINS_VALID_FLAGS = contains(
+ ExpressionTree.class, VALID_FLAGS);
+
+ @Override
+ public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
+ if (PENDING_INTENT_METHOD.matches(tree, state)) {
+ final ExpressionTree arg = tree.getArguments().get(3);
+ if (!(VALID_FLAGS.matches(arg, state) || CONTAINS_VALID_FLAGS.matches(arg, state))) {
+ return buildDescription(arg)
+ .setMessage("To improve security, PendingIntents must declare one of"
+ + " FLAG_MUTABLE or FLAG_IMMUTABLE explicitly; see"
+ + " go/immutable-pendingintents for more details")
+ .build();
+ }
+ }
+ return Description.NO_MATCH;
+ }
+}
diff --git a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityCheckerTest.java b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityCheckerTest.java
new file mode 100644
index 0000000..a8badf6
--- /dev/null
+++ b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityCheckerTest.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.errorprone.bugpatterns.android;
+
+import com.google.errorprone.CompilationTestHelper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class PendingIntentMutabilityCheckerTest {
+ private CompilationTestHelper mCompilationHelper;
+
+ @Before
+ public void setUp() {
+ mCompilationHelper = CompilationTestHelper.newInstance(
+ PendingIntentMutabilityChecker.class, getClass());
+ }
+
+ @Test
+ public void testGetActivity() {
+ mCompilationHelper
+ .addSourceFile("/android/app/PendingIntent.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/Bundle.java")
+ .addSourceLines("Example.java",
+ "import android.app.PendingIntent;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public class Example {",
+ " Context context;",
+ " Intent intent;",
+ " void example() {",
+ " PendingIntent.getActivity(context, 42, intent, PendingIntent.FLAG_MUTABLE);",
+ " PendingIntent.getActivity(context, 42, intent, PendingIntent.FLAG_IMMUTABLE);",
+ " PendingIntent.getActivity(context, 42, intent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);",
+ " PendingIntent.getActivity(context, 42, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);",
+ " PendingIntent.getActivity(context, 42, intent, 0 | PendingIntent.FLAG_MUTABLE);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivity(context, 42, intent, PendingIntent.FLAG_ONE_SHOT);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivity(context, 42, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_NO_CREATE);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivity(context, 42, intent, 0);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testGetActivityAsUser() {
+ mCompilationHelper
+ .addSourceFile("/android/app/PendingIntent.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/Bundle.java")
+ .addSourceLines("Example.java",
+ "import android.app.PendingIntent;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public class Example {",
+ " Context context;",
+ " Intent intent;",
+ " void example() {",
+ " PendingIntent.getActivityAsUser(context, 42, intent, PendingIntent.FLAG_MUTABLE, null, null);",
+ " PendingIntent.getActivityAsUser(context, 42, intent, PendingIntent.FLAG_IMMUTABLE, null, null);",
+ " PendingIntent.getActivityAsUser(context, 42, intent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT, null, null);",
+ " PendingIntent.getActivityAsUser(context, 42, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT, null, null);",
+ " PendingIntent.getActivityAsUser(context, 42, intent, 0 | PendingIntent.FLAG_MUTABLE, null, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivityAsUser(context, 42, intent, PendingIntent.FLAG_ONE_SHOT, null, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivityAsUser(context, 42, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_NO_CREATE, null, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivityAsUser(context, 42, intent, 0, null, null);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testGetActivities() {
+ mCompilationHelper
+ .addSourceFile("/android/app/PendingIntent.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/Bundle.java")
+ .addSourceLines("Example.java",
+ "import android.app.PendingIntent;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public class Example {",
+ " Context context;",
+ " Intent[] intents;",
+ " void example() {",
+ " PendingIntent.getActivities(context, 42, intents, PendingIntent.FLAG_MUTABLE, null);",
+ " PendingIntent.getActivities(context, 42, intents, PendingIntent.FLAG_IMMUTABLE, null);",
+ " PendingIntent.getActivities(context, 42, intents, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT, null);",
+ " PendingIntent.getActivities(context, 42, intents, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT, null);",
+ " PendingIntent.getActivities(context, 42, intents, 0 | PendingIntent.FLAG_MUTABLE, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivities(context, 42, intents, PendingIntent.FLAG_ONE_SHOT, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivities(context, 42, intents, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_NO_CREATE, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivities(context, 42, intents, 0, null);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testGetActivitiesAsUser() {
+ mCompilationHelper
+ .addSourceFile("/android/app/PendingIntent.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/Bundle.java")
+ .addSourceLines("Example.java",
+ "import android.app.PendingIntent;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public class Example {",
+ " Context context;",
+ " Intent[] intents;",
+ " void example() {",
+ " PendingIntent.getActivitiesAsUser(context, 42, intents, PendingIntent.FLAG_MUTABLE, null, null);",
+ " PendingIntent.getActivitiesAsUser(context, 42, intents, PendingIntent.FLAG_IMMUTABLE, null, null);",
+ " PendingIntent.getActivitiesAsUser(context, 42, intents, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT, null, null);",
+ " PendingIntent.getActivitiesAsUser(context, 42, intents, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT, null, null);",
+ " PendingIntent.getActivitiesAsUser(context, 42, intents, 0 | PendingIntent.FLAG_MUTABLE, null, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivitiesAsUser(context, 42, intents, PendingIntent.FLAG_ONE_SHOT, null, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivitiesAsUser(context, 42, intents, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_NO_CREATE, null, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivitiesAsUser(context, 42, intents, 0, null, null);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+
+ @Test
+ public void testGetBroadcast() {
+ mCompilationHelper
+ .addSourceFile("/android/app/PendingIntent.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/Bundle.java")
+ .addSourceLines("Example.java",
+ "import android.app.PendingIntent;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public class Example {",
+ " Context context;",
+ " Intent intent;",
+ " void example() {",
+ " PendingIntent.getBroadcast(context, 42, intent, PendingIntent.FLAG_MUTABLE);",
+ " PendingIntent.getBroadcast(context, 42, intent, PendingIntent.FLAG_IMMUTABLE);",
+ " PendingIntent.getBroadcast(context, 42, intent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);",
+ " PendingIntent.getBroadcast(context, 42, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);",
+ " PendingIntent.getBroadcast(context, 42, intent, 0 | PendingIntent.FLAG_MUTABLE);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getBroadcast(context, 42, intent, PendingIntent.FLAG_ONE_SHOT);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getBroadcast(context, 42, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_NO_CREATE);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getBroadcast(context, 42, intent, 0);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testGetBroadcastAsUser() {
+ mCompilationHelper
+ .addSourceFile("/android/app/PendingIntent.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/Bundle.java")
+ .addSourceLines("Example.java",
+ "import android.app.PendingIntent;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public class Example {",
+ " Context context;",
+ " Intent intent;",
+ " void example() {",
+ " PendingIntent.getBroadcastAsUser(context, 42, intent, PendingIntent.FLAG_MUTABLE, null);",
+ " PendingIntent.getBroadcastAsUser(context, 42, intent, PendingIntent.FLAG_IMMUTABLE, null);",
+ " PendingIntent.getBroadcastAsUser(context, 42, intent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT, null);",
+ " PendingIntent.getBroadcastAsUser(context, 42, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT, null);",
+ " PendingIntent.getBroadcastAsUser(context, 42, intent, 0 | PendingIntent.FLAG_MUTABLE, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getBroadcastAsUser(context, 42, intent, PendingIntent.FLAG_ONE_SHOT, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getBroadcastAsUser(context, 42, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_NO_CREATE, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getBroadcastAsUser(context, 42, intent, 0, null);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testGetService() {
+ mCompilationHelper
+ .addSourceFile("/android/app/PendingIntent.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/Bundle.java")
+ .addSourceLines("Example.java",
+ "import android.app.PendingIntent;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public class Example {",
+ " Context context;",
+ " Intent intent;",
+ " void example() {",
+ " PendingIntent.getService(context, 42, intent, PendingIntent.FLAG_MUTABLE);",
+ " PendingIntent.getService(context, 42, intent, PendingIntent.FLAG_IMMUTABLE);",
+ " PendingIntent.getService(context, 42, intent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);",
+ " PendingIntent.getService(context, 42, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);",
+ " PendingIntent.getService(context, 42, intent, 0 | PendingIntent.FLAG_MUTABLE);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getService(context, 42, intent, PendingIntent.FLAG_ONE_SHOT);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getService(context, 42, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_NO_CREATE);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getService(context, 42, intent, 0);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testGetForegroundService() {
+ mCompilationHelper
+ .addSourceFile("/android/app/PendingIntent.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/Bundle.java")
+ .addSourceLines("Example.java",
+ "import android.app.PendingIntent;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public class Example {",
+ " Context context;",
+ " Intent intent;",
+ " void example() {",
+ " PendingIntent.getForegroundService(context, 42, intent, PendingIntent.FLAG_MUTABLE);",
+ " PendingIntent.getForegroundService(context, 42, intent, PendingIntent.FLAG_IMMUTABLE);",
+ " PendingIntent.getForegroundService(context, 42, intent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);",
+ " PendingIntent.getForegroundService(context, 42, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);",
+ " PendingIntent.getForegroundService(context, 42, intent, 0 | PendingIntent.FLAG_MUTABLE);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getForegroundService(context, 42, intent, PendingIntent.FLAG_ONE_SHOT);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getForegroundService(context, 42, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_NO_CREATE);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getForegroundService(context, 42, intent, 0);",
+ " }",
+ "}")
+ .doTest();
+ }
+}
diff --git a/errorprone/tests/res/android/app/PendingIntent.java b/errorprone/tests/res/android/app/PendingIntent.java
new file mode 100644
index 0000000..a0cdedf
--- /dev/null
+++ b/errorprone/tests/res/android/app/PendingIntent.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+public class PendingIntent {
+ public static final int FLAG_ONE_SHOT = 1<<30;
+ public static final int FLAG_IMMUTABLE = 1<<26;
+ public static final int FLAG_MUTABLE = 1<<25;
+ public static final int FLAG_NO_CREATE = 1<<29;
+
+ public static PendingIntent getActivity(Context context, int requestCode,
+ Intent intent, int flags) {
+ throw new UnsupportedOperationException();
+ }
+
+ public static PendingIntent getActivityAsUser(Context context, int requestCode,
+ Intent intent, int flags, Bundle options, UserHandle user) {
+ throw new UnsupportedOperationException();
+ }
+
+ public static PendingIntent getActivities(Context context, int requestCode,
+ Intent[] intents, int flags, Bundle options) {
+ throw new UnsupportedOperationException();
+ }
+
+ public static PendingIntent getActivitiesAsUser(Context context, int requestCode,
+ Intent[] intents, int flags, Bundle options, UserHandle user) {
+ throw new UnsupportedOperationException();
+ }
+
+ public static PendingIntent getBroadcast(Context context, int requestCode,
+ Intent intent, int flags) {
+ throw new UnsupportedOperationException();
+ }
+
+ public static PendingIntent getBroadcastAsUser(Context context, int requestCode,
+ Intent intent, int flags, UserHandle userHandle) {
+ throw new UnsupportedOperationException();
+ }
+
+ public static PendingIntent getService(Context context, int requestCode,
+ Intent intent, int flags) {
+ throw new UnsupportedOperationException();
+ }
+
+ public static PendingIntent getForegroundService(Context context, int requestCode,
+ Intent intent, int flags) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/errorprone/tests/res/android/content/Intent.java b/errorprone/tests/res/android/content/Intent.java
new file mode 100644
index 0000000..9d22d04
--- /dev/null
+++ b/errorprone/tests/res/android/content/Intent.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+public class Intent {
+}
diff --git a/errorprone/tests/res/android/os/Bundle.java b/errorprone/tests/res/android/os/Bundle.java
new file mode 100644
index 0000000..6d2f7b8
--- /dev/null
+++ b/errorprone/tests/res/android/os/Bundle.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+public class Bundle {
+}