Merge "Clean up ANGLE integration logic." into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index f2cae097..f0e0c30 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -22,6 +22,7 @@
     ":com.android.window.flags.window-aconfig-java{.generated_srcjars}",
     ":com.android.hardware.input-aconfig-java{.generated_srcjars}",
     ":com.android.text.flags-aconfig-java{.generated_srcjars}",
+    ":com.android.net.flags-aconfig-java{.generated_srcjars}",
 ]
 
 filegroup {
@@ -178,3 +179,10 @@
     aconfig_declarations: "android.hardware.biometrics.flags-aconfig",
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
+
+// CoreNetworking
+java_aconfig_library {
+    name: "com.android.net.flags-aconfig-java",
+    aconfig_declarations: "com.android.net.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/api/ApiDocs.bp b/api/ApiDocs.bp
index 30b4423..7142eb5 100644
--- a/api/ApiDocs.bp
+++ b/api/ApiDocs.bp
@@ -124,7 +124,6 @@
             "packages/modules/Media/apex/aidl/stable",
         ],
     },
-    extensions_info_file: ":sdk-extensions-info",
 }
 
 droidstubs {
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index 79eface..a410a58 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -677,6 +677,7 @@
         "api-stubs-docs-non-updatable.api.contribution",
     ],
     visibility: ["//visibility:public"],
+    enable_validation: false,
 }
 
 java_api_library {
@@ -692,6 +693,7 @@
         "system-api-stubs-docs-non-updatable.api.contribution",
     ],
     visibility: ["//visibility:public"],
+    enable_validation: false,
 }
 
 java_api_library {
@@ -709,6 +711,7 @@
         "test-api-stubs-docs-non-updatable.api.contribution",
     ],
     visibility: ["//visibility:public"],
+    enable_validation: false,
 }
 
 java_api_library {
@@ -724,6 +727,7 @@
         "api-stubs-docs-non-updatable.api.contribution",
         "system-api-stubs-docs-non-updatable.api.contribution",
     ],
+    enable_validation: false,
 }
 
 java_api_library {
@@ -743,6 +747,7 @@
         "module-lib-api-stubs-docs-non-updatable.api.contribution",
     ],
     visibility: ["//visibility:public"],
+    enable_validation: false,
 }
 
 java_api_library {
@@ -756,6 +761,7 @@
         "stub-annotations",
     ],
     visibility: ["//visibility:public"],
+    enable_validation: false,
 }
 
 java_api_library {
@@ -780,6 +786,7 @@
     visibility: [
         "//visibility:private",
     ],
+    enable_validation: false,
 }
 
 java_api_library {
@@ -796,6 +803,7 @@
         "android_module_lib_stubs_current.from-text",
     ],
     visibility: ["//visibility:public"],
+    enable_validation: false,
 }
 
 ////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index b5efb73..0414f79 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -50,7 +50,6 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.security.net.config.NetworkSecurityConfigProvider;
-import android.sysprop.VndkProperties;
 import android.text.TextUtils;
 import android.util.AndroidRuntimeException;
 import android.util.ArrayMap;
@@ -901,14 +900,10 @@
         }
 
         // Similar to vendor apks, we should add /product/lib for apks from product partition
-        // when product apps are marked as unbundled. We cannot use the same way from vendor
-        // to check if lib path exists because there is possibility that /product/lib would not
-        // exist from legacy device while product apks are bundled. To make this clear, we use
-        // "ro.product.vndk.version" property. If the property is defined, we regard all product
-        // apks as unbundled.
+        // when product apps are marked as unbundled. Product is separated as long as the
+        // partition exists, so it can be handled with same approach from the vendor partition.
         if (mApplicationInfo.getCodePath() != null
-                && mApplicationInfo.isProduct()
-                && VndkProperties.product_vndk_version().isPresent()) {
+                && mApplicationInfo.isProduct()) {
             isBundledApp = false;
         }
 
diff --git a/core/java/com/android/internal/foldables/OWNERS b/core/java/com/android/internal/foldables/OWNERS
new file mode 100644
index 0000000..6ce1ee4
--- /dev/null
+++ b/core/java/com/android/internal/foldables/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/display/OWNERS
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index 31c2eb2..b7ea04f 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -128,25 +128,6 @@
     }
 
     /**
-     * Queries user state from Keystore 2.0.
-     *
-     * @param userId - Android user id of the user.
-     * @return UserState enum variant as integer if successful or an error
-     */
-    public static int getState(int userId) {
-        StrictMode.noteDiskRead();
-        try {
-            return getService().getState(userId);
-        } catch (ServiceSpecificException e) {
-            Log.e(TAG, "getState failed", e);
-            return e.errorCode;
-        } catch (Exception e) {
-            Log.e(TAG, "Can not connect to keystore", e);
-            return SYSTEM_ERROR;
-        }
-    }
-
-    /**
      * Informs Keystore 2.0 that an off body event was detected.
      */
     public static void onDeviceOffBody() {
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 8045f55..11b8271 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -19,8 +19,6 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.StrictMode;
-import android.os.UserHandle;
-import android.security.maintenance.UserState;
 
 /**
  * @hide This should not be made public in its present form because it
@@ -37,15 +35,6 @@
     // Used for UID field to indicate the calling UID.
     public static final int UID_SELF = -1;
 
-    // States
-    public enum State {
-        @UnsupportedAppUsage
-        UNLOCKED,
-        @UnsupportedAppUsage
-        LOCKED,
-        UNINITIALIZED
-    };
-
     private static final KeyStore KEY_STORE = new KeyStore();
 
     @UnsupportedAppUsage
@@ -55,28 +44,6 @@
 
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public State state(int userId) {
-        int userState = AndroidKeyStoreMaintenance.getState(userId);
-        switch (userState) {
-            case UserState.UNINITIALIZED:
-                return KeyStore.State.UNINITIALIZED;
-            case UserState.LSKF_UNLOCKED:
-                return KeyStore.State.UNLOCKED;
-            case UserState.LSKF_LOCKED:
-                return KeyStore.State.LOCKED;
-            default:
-                throw new AssertionError(userState);
-        }
-    }
-
-    /** @hide */
-    @UnsupportedAppUsage
-    public State state() {
-        return state(UserHandle.myUserId());
-    }
-
-    /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public byte[] get(String key) {
         return null;
     }
diff --git a/media/tests/MediaFrameworkTest/AndroidManifest.xml b/media/tests/MediaFrameworkTest/AndroidManifest.xml
index e886558..7d79a6c 100644
--- a/media/tests/MediaFrameworkTest/AndroidManifest.xml
+++ b/media/tests/MediaFrameworkTest/AndroidManifest.xml
@@ -20,6 +20,7 @@
     <uses-permission android:name="android.permission.RECORD_AUDIO"/>
     <uses-permission android:name="android.permission.CAMERA"/>
     <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
     <uses-permission android:name="android.permission.WAKE_LOCK"/>
diff --git a/media/tests/MediaFrameworkTest/AndroidTest.xml b/media/tests/MediaFrameworkTest/AndroidTest.xml
index 132028c..91c92cc1 100644
--- a/media/tests/MediaFrameworkTest/AndroidTest.xml
+++ b/media/tests/MediaFrameworkTest/AndroidTest.xml
@@ -23,5 +23,6 @@
         <option name="package" value="com.android.mediaframeworktest" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
+        <option name="isolated-storage" value="false"/>
     </test>
 </configuration>
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
index 9be7004..30edfa4 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
@@ -44,7 +44,6 @@
     @Override
     public TestSuite getAllTests() {
         TestSuite suite = new InstrumentationTestSuite(this);
-        addMediaMetadataRetrieverStateUnitTests(suite);
         addMediaRecorderStateUnitTests(suite);
         addMediaPlayerStateUnitTests(suite);
         addMediaScannerUnitTests(suite);
@@ -70,11 +69,6 @@
     }
 
     // Running all unit tests checking the state machine may be time-consuming.
-    private void addMediaMetadataRetrieverStateUnitTests(TestSuite suite) {
-        suite.addTestSuite(MediaMetadataRetrieverTest.class);
-    }
-
-    // Running all unit tests checking the state machine may be time-consuming.
     private void addMediaRecorderStateUnitTests(TestSuite suite) {
         suite.addTestSuite(MediaRecorderPrepareStateUnitTest.class);
         suite.addTestSuite(MediaRecorderResetStateUnitTest.class);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
index bdca474..f70d2d1 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
@@ -16,26 +16,34 @@
 
 package com.android.mediaframeworktest.unit;
 
+import static org.junit.Assert.assertTrue;
+
 import android.graphics.Bitmap;
 import android.media.MediaMetadataRetriever;
-import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
 
+import androidx.test.runner.AndroidJUnit4;
+
 import com.android.mediaframeworktest.MediaNames;
 import com.android.mediaframeworktest.MediaProfileReader;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.io.FileOutputStream;
 import java.io.IOException;
 
-public class MediaMetadataRetrieverTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class MediaMetadataRetrieverTest {
 
     private static final String TAG = "MediaMetadataRetrieverTest";
 
     // Test album art extraction.
     @MediumTest
-    public static void testGetEmbeddedPicture() throws Exception {
+    @Test
+    public void testGetEmbeddedPicture() throws Exception {
         Log.v(TAG, "testGetEmbeddedPicture starts.");
         MediaMetadataRetriever retriever = new MediaMetadataRetriever();
         boolean supportWMA = MediaProfileReader.getWMAEnable();
@@ -78,7 +86,8 @@
 
     // Test frame capture
     @LargeTest
-    public static void testThumbnailCapture() throws Exception {
+    @Test
+    public void testThumbnailCapture() throws Exception {
         MediaMetadataRetriever retriever = new MediaMetadataRetriever();
         boolean supportWMA = MediaProfileReader.getWMAEnable();
         boolean supportWMV = MediaProfileReader.getWMVEnable();
@@ -134,7 +143,8 @@
     }
 
     @LargeTest
-    public static void testMetadataRetrieval() throws Exception {
+    @Test
+    public void testMetadataRetrieval() throws Exception {
         boolean supportWMA = MediaProfileReader.getWMAEnable();
         boolean supportWMV = MediaProfileReader.getWMVEnable();
         boolean hasFailed = false;
@@ -169,7 +179,8 @@
     // If the specified call order and valid media file is used, no exception
     // should be thrown.
     @MediumTest
-    public static void testBasicNormalMethodCallSequence() throws Exception {
+    @Test
+    public void testBasicNormalMethodCallSequence() throws Exception {
         boolean hasFailed = false;
         MediaMetadataRetriever retriever = new MediaMetadataRetriever();
         try {
@@ -197,7 +208,8 @@
     // If setDataSource() has not been called, both getFrameAtTime() and extractMetadata() must
     // return null.
     @MediumTest
-    public static void testBasicAbnormalMethodCallSequence() {
+    @Test
+    public void testBasicAbnormalMethodCallSequence() {
         boolean hasFailed = false;
         MediaMetadataRetriever retriever = new MediaMetadataRetriever();
         if (retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM) != null) {
@@ -213,7 +225,8 @@
 
     // Test setDataSource()
     @MediumTest
-    public static void testSetDataSource() throws IOException {
+    @Test
+    public void testSetDataSource() throws IOException {
         MediaMetadataRetriever retriever = new MediaMetadataRetriever();
         boolean hasFailed = false;
 
diff --git a/omapi/aidl/Android.bp b/omapi/aidl/Android.bp
index 58bcd1d..e71597a 100644
--- a/omapi/aidl/Android.bp
+++ b/omapi/aidl/Android.bp
@@ -24,6 +24,11 @@
     backend: {
         java: {
             sdk_version: "module_current",
+            apex_available: [
+                "//apex_available:platform",
+                "com.android.nfcservices",
+            ],
+
         },
         rust: {
             enabled: true,
diff --git a/services/core/java/com/android/server/pm/MovePackageHelper.java b/services/core/java/com/android/server/pm/MovePackageHelper.java
index 481bd97..fef53d1 100644
--- a/services/core/java/com/android/server/pm/MovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/MovePackageHelper.java
@@ -89,6 +89,21 @@
         if (packageState == null || packageState.getPkg() == null) {
             throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
         }
+        final int[] installedUserIds = PackageStateUtils.queryInstalledUsers(packageState,
+                mPm.mUserManager.getUserIds(), true);
+        final UserHandle userForMove;
+        if (installedUserIds.length > 0) {
+            userForMove = UserHandle.of(installedUserIds[0]);
+        } else {
+            throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST,
+                    "Package is not installed for any user");
+        }
+        for (int userId : installedUserIds) {
+            if (snapshot.shouldFilterApplicationIncludingUninstalled(packageState, callingUid,
+                    userId)) {
+                throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
+            }
+        }
         final AndroidPackage pkg = packageState.getPkg();
         if (packageState.isSystem()) {
             throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
@@ -137,8 +152,6 @@
         final String label = String.valueOf(pm.getApplicationLabel(
                 AndroidPackageUtils.generateAppInfoWithoutState(pkg)));
         final int targetSdkVersion = pkg.getTargetSdkVersion();
-        final int[] installedUserIds = PackageStateUtils.queryInstalledUsers(packageState,
-                mPm.mUserManager.getUserIds(), true);
         final String fromCodePath;
         if (codeFile.getParentFile().getName().startsWith(
                 PackageManagerService.RANDOM_DIR_PREFIX)) {
@@ -305,8 +318,8 @@
         final PackageLite lite = ret.isSuccess() ? ret.getResult() : null;
         final InstallingSession installingSession = new InstallingSession(origin, move,
                 installObserver, installFlags, /* developmentInstallFlags= */ 0, installSource,
-                volumeUuid, user, packageAbiOverride,  PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED,
-                lite, mPm);
+                volumeUuid, userForMove, packageAbiOverride,
+                PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED, lite, mPm);
         installingSession.movePackage();
     }
 
diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS
index 26abe51..f6c3640 100644
--- a/services/core/java/com/android/server/wm/OWNERS
+++ b/services/core/java/com/android/server/wm/OWNERS
@@ -18,4 +18,4 @@
 yunfanc@google.com
 
 per-file BackgroundActivityStartController.java = set noparent
-per-file BackgroundActivityStartController.java = brufino@google.com, ogunwale@google.com, louischang@google.com, lus@google.com
+per-file BackgroundActivityStartController.java = brufino@google.com, topjohnwu@google.com, achim@google.com, ogunwale@google.com, louischang@google.com, lus@google.com
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1068700..d4a88c7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5206,7 +5206,11 @@
     public void displayReady() {
         synchronized (mGlobalLock) {
             if (mMaxUiWidth > 0) {
-                mRoot.forAllDisplays(displayContent -> displayContent.setMaxUiWidth(mMaxUiWidth));
+                mRoot.forAllDisplays(dc -> {
+                    if (dc.mDisplay.getType() == Display.TYPE_INTERNAL) {
+                        dc.setMaxUiWidth(mMaxUiWidth);
+                    }
+                });
             }
             applyForcedPropertiesForDefaultDisplay();
             mAnimator.ready();
diff --git a/services/core/jni/OWNERS b/services/core/jni/OWNERS
index d9acf41..bc29490 100644
--- a/services/core/jni/OWNERS
+++ b/services/core/jni/OWNERS
@@ -20,6 +20,7 @@
 per-file com_android_server_location_* = file:/location/java/android/location/OWNERS
 per-file com_android_server_locksettings_* = file:/services/core/java/com/android/server/locksettings/OWNERS
 per-file com_android_server_net_* = file:/services/core/java/com/android/server/net/OWNERS
+per-file com_android_server_pdb_* = file:/services/core/java/com/android/server/pdb/OWNERS
 per-file com_android_server_pm_* = file:/services/core/java/com/android/server/pm/OWNERS
 per-file com_android_server_power_* = file:/services/core/java/com/android/server/power/OWNERS
 per-file com_android_server_powerstats_* = file:/services/core/java/com/android/server/powerstats/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/pdb/OWNERS b/services/tests/servicestests/src/com/android/server/pdb/OWNERS
new file mode 100644
index 0000000..6dfb888
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pdb/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pdb/OWNERS
diff --git a/tools/lint/global/integration_tests/Android.bp b/tools/lint/global/integration_tests/Android.bp
index ca96559..40281d2 100644
--- a/tools/lint/global/integration_tests/Android.bp
+++ b/tools/lint/global/integration_tests/Android.bp
@@ -12,25 +12,58 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-java_library {
-    name: "AndroidGlobalLintTestNoAidl",
-    srcs: ["TestNoAidl/**/*.java"],
+// Integration tests for @EnforcePermission linters.
+// Each test defines its own java_library. The XML lint report from this
+// java_library is wrapped under a Python library with a unique pkg_path (this
+// is to avoid a name conflict for the report file). All the tests are
+// referenced and executed by AndroidGlobalLintCheckerIntegrationTest.
+
+java_defaults {
+    name: "AndroidGlobalLintIntegrationTestDefault",
     libs: [
         "framework-annotations-lib",
     ],
     lint: {
-        // It is expected that lint returns an error when processing this
+        // It is expected that lint returns an error when processing the
         // library. Silence it here, the lint output is verified in tests.py.
         suppress_exit_code: true,
     },
 }
 
+java_library {
+    name: "AndroidGlobalLintTestNoAidl",
+    srcs: ["TestNoAidl/**/*.java"],
+    defaults: ["AndroidGlobalLintIntegrationTestDefault"],
+}
+
+python_library_host {
+    name: "AndroidGlobalLintTestNoAidl_py",
+    data: [":AndroidGlobalLintTestNoAidl{.lint}"],
+    pkg_path: "no_aidl",
+}
+
+java_library {
+    name: "AndroidGlobalLintTestMissingAnnotation",
+    srcs: [
+        "TestMissingAnnotation/**/*.java",
+        "TestMissingAnnotation/**/*.aidl",
+    ],
+    defaults: ["AndroidGlobalLintIntegrationTestDefault"],
+}
+
+python_library_host {
+    name: "AndroidGlobalLintTestMissingAnnotation_py",
+    data: [":AndroidGlobalLintTestMissingAnnotation{.lint}"],
+    pkg_path: "missing_annotation",
+}
+
 python_test_host {
     name: "AndroidGlobalLintCheckerIntegrationTest",
     srcs: ["tests.py"],
     main: "tests.py",
-    data: [
-        ":AndroidGlobalLintTestNoAidl{.lint}",
+    libs: [
+        "AndroidGlobalLintTestNoAidl_py",
+        "AndroidGlobalLintTestMissingAnnotation_py",
     ],
     version: {
         py3: {
diff --git a/tools/lint/global/integration_tests/TestMissingAnnotation/TestMissingAnnotation.java b/tools/lint/global/integration_tests/TestMissingAnnotation/TestMissingAnnotation.java
new file mode 100644
index 0000000..9e4854c
--- /dev/null
+++ b/tools/lint/global/integration_tests/TestMissingAnnotation/TestMissingAnnotation.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2023 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.android.lint.integration_tests;
+
+/**
+ * A class that implements an AIDL interface, but is missing the @EnforcePermission annotation.
+ */
+class TestMissingAnnotation extends IFoo.Stub {
+
+    @Override
+    public void Method() {
+    }
+
+}
diff --git a/tools/lint/global/integration_tests/TestMissingAnnotation/com/google/android/lint/integration_tests/IFoo.aidl b/tools/lint/global/integration_tests/TestMissingAnnotation/com/google/android/lint/integration_tests/IFoo.aidl
new file mode 100644
index 0000000..95ec2c2
--- /dev/null
+++ b/tools/lint/global/integration_tests/TestMissingAnnotation/com/google/android/lint/integration_tests/IFoo.aidl
@@ -0,0 +1,7 @@
+package com.google.android.lint.integration_tests;
+
+interface IFoo {
+
+    @EnforcePermission("INTERNET")
+    void Method();
+}
diff --git a/tools/lint/global/integration_tests/tests.py b/tools/lint/global/integration_tests/tests.py
index fc3eeb4..cdb16b8 100644
--- a/tools/lint/global/integration_tests/tests.py
+++ b/tools/lint/global/integration_tests/tests.py
@@ -19,16 +19,28 @@
 class TestLinterReports(unittest.TestCase):
     """Integration tests for the linters used by @EnforcePermission."""
 
-    def test_no_aidl(self):
-        report = pkgutil.get_data("lint", "lint-report.xml").decode()
+    def _read_report(self, pkg_path):
+        report = pkgutil.get_data(pkg_path, "lint/lint-report.xml").decode()
         issues = xml.etree.ElementTree.fromstring(report)
         self.assertEqual(issues.tag, "issues")
+        return issues
+
+    def test_no_aidl(self):
+        issues = self._read_report("no_aidl")
         self.assertEqual(len(issues), 1)
 
         issue = issues[0]
         self.assertEqual(issue.attrib["id"], "MisusingEnforcePermissionAnnotation")
         self.assertEqual(issue.attrib["severity"], "Error")
 
+    def test_missing_annotation(self):
+        issues = self._read_report("missing_annotation")
+        self.assertEqual(len(issues), 1)
+
+        issue = issues[0]
+        self.assertEqual(issue.attrib["id"], "MissingEnforcePermissionAnnotation")
+        self.assertEqual(issue.attrib["severity"], "Error")
+
 
 if __name__ == '__main__':
     unittest.main(verbosity=2)