Merge "BatteryService: expose capacity level API" into main
diff --git a/cmds/uiautomator/library/Android.bp b/cmds/uiautomator/library/Android.bp
index 966bf13..5c5b220 100644
--- a/cmds/uiautomator/library/Android.bp
+++ b/cmds/uiautomator/library/Android.bp
@@ -28,9 +28,9 @@
         "testrunner-src/**/*.java",
     ],
     libs: [
-        "android.test.runner",
+        "android.test.runner.stubs.system",
         "junit",
-        "android.test.base",
+        "android.test.base.stubs.system",
         "unsupportedappusage",
     ],
     installable: false,
@@ -56,9 +56,9 @@
         ":uiautomator-stubs",
     ],
     libs: [
-        "android.test.runner",
+        "android.test.runner.stubs",
         "junit",
-        "android.test.base",
+        "android.test.base.stubs",
     ],
     sdk_version: "current",
     installable: false,
diff --git a/core/api/current.txt b/core/api/current.txt
index 2d8db84..9881a90 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -33192,6 +33192,7 @@
   }
 
   public interface IBinder {
+    method @FlaggedApi("android.os.binder_frozen_state_change_callback") public default void addFrozenStateChangeCallback(@NonNull android.os.IBinder.FrozenStateChangeCallback) throws android.os.RemoteException;
     method public void dump(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException;
     method public void dumpAsync(@NonNull java.io.FileDescriptor, @Nullable String[]) throws android.os.RemoteException;
     method @Nullable public String getInterfaceDescriptor() throws android.os.RemoteException;
@@ -33200,6 +33201,7 @@
     method public void linkToDeath(@NonNull android.os.IBinder.DeathRecipient, int) throws android.os.RemoteException;
     method public boolean pingBinder();
     method @Nullable public android.os.IInterface queryLocalInterface(@NonNull String);
+    method @FlaggedApi("android.os.binder_frozen_state_change_callback") public default boolean removeFrozenStateChangeCallback(@NonNull android.os.IBinder.FrozenStateChangeCallback);
     method public boolean transact(int, @NonNull android.os.Parcel, @Nullable android.os.Parcel, int) throws android.os.RemoteException;
     method public boolean unlinkToDeath(@NonNull android.os.IBinder.DeathRecipient, int);
     field public static final int DUMP_TRANSACTION = 1598311760; // 0x5f444d50
@@ -33217,6 +33219,12 @@
     method public default void binderDied(@NonNull android.os.IBinder);
   }
 
+  @FlaggedApi("android.os.binder_frozen_state_change_callback") public static interface IBinder.FrozenStateChangeCallback {
+    method public void onFrozenStateChanged(@NonNull android.os.IBinder, int);
+    field public static final int STATE_FROZEN = 0; // 0x0
+    field public static final int STATE_UNFROZEN = 1; // 0x1
+  }
+
   public interface IInterface {
     method public android.os.IBinder asBinder();
   }
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 6f11d3a..af93c96 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -35,7 +35,6 @@
 import android.util.ArraySet;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 import com.android.server.vcn.util.PersistableBundleUtils;
 
@@ -434,7 +433,14 @@
     @NonNull
     public int[] getExposedCapabilities() {
         // Sorted set guarantees ordering
-        return ArrayUtils.convertToIntArray(new ArrayList<>(mExposedCapabilities));
+        final int[] caps = new int[mExposedCapabilities.size()];
+
+        int i = 0;
+        for (int c : mExposedCapabilities) {
+            caps[i++] = c;
+        }
+
+        return caps;
     }
 
     /**
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkSpecifier.java b/core/java/android/net/vcn/VcnUnderlyingNetworkSpecifier.java
index a975637..e1d1b3c6 100644
--- a/core/java/android/net/vcn/VcnUnderlyingNetworkSpecifier.java
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkSpecifier.java
@@ -24,7 +24,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.annotations.VisibleForTesting.Visibility;
-import com.android.internal.util.ArrayUtils;
 
 import java.util.Arrays;
 import java.util.Objects;
@@ -114,8 +113,13 @@
     @Override
     public boolean canBeSatisfiedBy(NetworkSpecifier other) {
         if (other instanceof TelephonyNetworkSpecifier) {
-            return ArrayUtils.contains(
-                    mSubIds, ((TelephonyNetworkSpecifier) other).getSubscriptionId());
+            final int targetSubId = ((TelephonyNetworkSpecifier) other).getSubscriptionId();
+            for (int subId : mSubIds) {
+                if (targetSubId == subId) {
+                    return true;
+                }
+            }
+            return false;
         }
         // TODO(b/180140053): Allow matching against WifiNetworkAgentSpecifier
 
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index c22f46c..80546cd 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -650,13 +650,13 @@
      * weakly referenced by JNI so the strong references here are needed to keep the callbacks
      * around until the proxy is GC'ed.
      */
-    private List<IFrozenStateChangeCallback> mFrozenStateChangeCallbacks =
+    private List<FrozenStateChangeCallback> mFrozenStateChangeCallbacks =
             Collections.synchronizedList(new ArrayList<>());
 
     /**
-     * See {@link IBinder#addFrozenStateChangeCallback(IFrozenStateChangeCallback)}
+     * See {@link IBinder#addFrozenStateChangeCallback(FrozenStateChangeCallback)}
      */
-    public void addFrozenStateChangeCallback(IFrozenStateChangeCallback callback)
+    public void addFrozenStateChangeCallback(FrozenStateChangeCallback callback)
             throws RemoteException {
         addFrozenStateChangeCallbackNative(callback);
         mFrozenStateChangeCallbacks.add(callback);
@@ -665,16 +665,16 @@
     /**
      * See {@link IBinder#removeFrozenStateChangeCallback}
      */
-    public boolean removeFrozenStateChangeCallback(IFrozenStateChangeCallback callback) {
+    public boolean removeFrozenStateChangeCallback(FrozenStateChangeCallback callback) {
         mFrozenStateChangeCallbacks.remove(callback);
         return removeFrozenStateChangeCallbackNative(callback);
     }
 
-    private native void addFrozenStateChangeCallbackNative(IFrozenStateChangeCallback callback)
+    private native void addFrozenStateChangeCallbackNative(FrozenStateChangeCallback callback)
             throws RemoteException;
 
     private native boolean removeFrozenStateChangeCallbackNative(
-            IFrozenStateChangeCallback callback);
+            FrozenStateChangeCallback callback);
 
     /**
      * Perform a dump on the remote object
@@ -762,10 +762,9 @@
     }
 
     private static void invokeFrozenStateChangeCallback(
-            IFrozenStateChangeCallback callback, IBinder binderProxy, int stateIndex) {
+            FrozenStateChangeCallback callback, IBinder binderProxy, int stateIndex) {
         try {
-            callback.onFrozenStateChanged(binderProxy,
-                    IFrozenStateChangeCallback.State.values()[stateIndex]);
+            callback.onFrozenStateChanged(binderProxy, stateIndex);
         } catch (RuntimeException exc) {
             Log.w("BinderNative", "Uncaught exception from frozen state change callback",
                     exc);
diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java
index 8185e8e..a997f4c 100644
--- a/core/java/android/os/IBinder.java
+++ b/core/java/android/os/IBinder.java
@@ -16,11 +16,15 @@
 
 package android.os;
 
+import android.annotation.FlaggedApi;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
 
 import java.io.FileDescriptor;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
  * Base interface for a remotable object, the core part of a lightweight
@@ -377,9 +381,24 @@
      */
     public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags);
 
-    /** @hide */
-    interface IFrozenStateChangeCallback {
-        enum State {FROZEN, UNFROZEN};
+    /**
+     * A callback interface for receiving frozen state change events.
+     */
+    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+    interface FrozenStateChangeCallback {
+        /**
+         * @hide
+         */
+        @IntDef(prefix = {"STATE_"}, value = {
+                STATE_FROZEN,
+                STATE_UNFROZEN,
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        @interface State {
+        }
+
+        int STATE_FROZEN = 0;
+        int STATE_UNFROZEN = 1;
 
         /**
          * Interface for receiving a callback when the process hosting an IBinder
@@ -387,13 +406,13 @@
          * @param who The IBinder whose hosting process has changed state.
          * @param state The latest state.
          */
-        void onFrozenStateChanged(@NonNull IBinder who, State state);
+        void onFrozenStateChanged(@NonNull IBinder who, @State int state);
     }
 
     /**
-     * {@link addFrozenStateChangeCallback} provides a callback mechanism to notify about process
-     * frozen/unfrozen events. Upon registration and any subsequent state changes, the callback is
-     * invoked with the latest process frozen state.
+     * This method provides a callback mechanism to notify about process frozen/unfrozen events.
+     * Upon registration and any subsequent state changes, the callback is invoked with the latest
+     * process frozen state.
      *
      * <p>If the listener process (the one using this API) is itself frozen, state change events
      * might be combined into a single one with the latest frozen state. This single event would
@@ -410,19 +429,19 @@
      *
      * <p>@throws {@link UnsupportedOperationException} if the kernel binder driver does not support
      * this feature.
-     * @hide
      */
-    default void addFrozenStateChangeCallback(@NonNull IFrozenStateChangeCallback callback)
+    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+    default void addFrozenStateChangeCallback(@NonNull FrozenStateChangeCallback callback)
             throws RemoteException {
         throw new UnsupportedOperationException();
     }
 
     /**
-     * Unregister a {@link IFrozenStateChangeCallback}. The callback will no longer be invoked when
+     * Unregister a {@link FrozenStateChangeCallback}. The callback will no longer be invoked when
      * the hosting process changes its frozen state.
-     * @hide
      */
-    default boolean removeFrozenStateChangeCallback(@NonNull IFrozenStateChangeCallback callback) {
+    @FlaggedApi(Flags.FLAG_BINDER_FROZEN_STATE_CHANGE_CALLBACK)
+    default boolean removeFrozenStateChangeCallback(@NonNull FrozenStateChangeCallback callback) {
         throw new UnsupportedOperationException();
     }
 }
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index 11b1b08..b5c278a 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -169,6 +169,14 @@
 }
 
 flag {
+    name: "binder_frozen_state_change_callback"
+    is_exported: true
+    namespace: "system_performance"
+    description: "Guards the frozen state change callback API."
+    bug: "361157077"
+}
+
+flag {
     name: "message_queue_tail_tracking"
     namespace: "system_performance"
     description: "track tail of message queue."
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 17c4ee9..3871806 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -288,7 +288,6 @@
                 "libasync_safe",
                 "libbinderthreadstateutils",
                 "libdmabufinfo",
-                "libgif",
                 "libgui_window_info_static",
                 "libkernelconfigs",
                 "libseccomp_policy",
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 921b77d..ef50a95 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -1747,9 +1747,9 @@
     {"linkToDeathNative",   "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
     {"unlinkToDeathNative", "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
     {"addFrozenStateChangeCallbackNative",
-        "(Landroid/os/IBinder$IFrozenStateChangeCallback;)V", (void*)android_os_BinderProxy_addFrozenStateChangeCallback},
+        "(Landroid/os/IBinder$FrozenStateChangeCallback;)V", (void*)android_os_BinderProxy_addFrozenStateChangeCallback},
     {"removeFrozenStateChangeCallbackNative",
-        "(Landroid/os/IBinder$IFrozenStateChangeCallback;)Z", (void*)android_os_BinderProxy_removeFrozenStateChangeCallback},
+        "(Landroid/os/IBinder$FrozenStateChangeCallback;)Z", (void*)android_os_BinderProxy_removeFrozenStateChangeCallback},
     {"getNativeFinalizer",  "()J", (void*)android_os_BinderProxy_getNativeFinalizer},
     {"getExtension",        "()Landroid/os/IBinder;", (void*)android_os_BinderProxy_getExtension},
 };
@@ -1774,7 +1774,7 @@
                                    "(Landroid/os/IBinder$DeathRecipient;Landroid/os/IBinder;)V");
     gBinderProxyOffsets.mInvokeFrozenStateChangeCallback =
             GetStaticMethodIDOrDie(env, clazz, "invokeFrozenStateChangeCallback",
-                                   "(Landroid/os/IBinder$IFrozenStateChangeCallback;Landroid/os/"
+                                   "(Landroid/os/IBinder$FrozenStateChangeCallback;Landroid/os/"
                                    "IBinder;I)V");
     gBinderProxyOffsets.mNativeData = GetFieldIDOrDie(env, clazz, "mNativeData", "J");
 
diff --git a/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java b/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java
index 77e8a40..fe54aa8 100644
--- a/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java
+++ b/core/tests/coretests/BinderFrozenStateChangeCallbackTestApp/src/com/android/frameworks/coretests/bfscctestapp/BfsccTestAppCmdService.java
@@ -30,31 +30,30 @@
 
 public class BfsccTestAppCmdService extends Service {
     private IBfsccTestAppCmdService.Stub mBinder = new IBfsccTestAppCmdService.Stub() {
-        private final LinkedBlockingQueue<IBinder.IFrozenStateChangeCallback.State> mNotifications =
+        private final LinkedBlockingQueue<Integer> mNotifications =
                 new LinkedBlockingQueue<>();
 
         @Override
         public void listenTo(IBinder binder) throws RemoteException {
             binder.addFrozenStateChangeCallback(
-                    (IBinder who, IBinder.IFrozenStateChangeCallback.State state)
-                            -> mNotifications.offer(state));
+                    (IBinder who, int state) -> mNotifications.offer(state));
         }
 
         @Override
         public boolean[] waitAndConsumeNotifications() {
             List<Boolean> results = new ArrayList<>();
             try {
-                IBinder.IFrozenStateChangeCallback.State state =
-                        mNotifications.poll(5, TimeUnit.SECONDS);
+                Integer state = mNotifications.poll(5, TimeUnit.SECONDS);
                 if (state != null) {
-                    results.add(state == IBinder.IFrozenStateChangeCallback.State.FROZEN);
+                    results.add(
+                            state.intValue() == IBinder.FrozenStateChangeCallback.STATE_FROZEN);
                 }
             } catch (InterruptedException e) {
                 return null;
             }
             while (mNotifications.size() > 0) {
-                results.add(mNotifications.poll()
-                        == IBinder.IFrozenStateChangeCallback.State.FROZEN);
+                results.add(mNotifications.poll().intValue()
+                        == IBinder.FrozenStateChangeCallback.STATE_FROZEN);
             }
             boolean[] convertedResults = new boolean[results.size()];
             for (int i = 0; i < results.size(); i++) {
diff --git a/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java b/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java
index ee2e7e0..195a18a 100644
--- a/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java
+++ b/core/tests/coretests/src/android/os/BinderFrozenStateChangeNotificationTest.java
@@ -52,7 +52,7 @@
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
- * Tests functionality of {@link android.os.IBinder.IFrozenStateChangeCallback}.
+ * Tests functionality of {@link android.os.IBinder.FrozenStateChangeCallback}.
  */
 @RunWith(AndroidJUnit4.class)
 @IgnoreUnderRavenwood(blockedBy = ActivityManager.class)
@@ -157,7 +157,7 @@
     @Test
     public void onStateChangeNotCalledAfterCallbackRemoved() throws Exception {
         final LinkedBlockingQueue<Boolean> results = new LinkedBlockingQueue<>();
-        IBinder.IFrozenStateChangeCallback callback;
+        IBinder.FrozenStateChangeCallback callback;
         if ((callback = createCallback(mBfsccTestAppCmdService.asBinder(), results)) == null) {
             return;
         }
@@ -171,7 +171,7 @@
     public void multipleCallbacks() throws Exception {
         final LinkedBlockingQueue<Boolean> results1 = new LinkedBlockingQueue<>();
         final LinkedBlockingQueue<Boolean> results2 = new LinkedBlockingQueue<>();
-        IBinder.IFrozenStateChangeCallback callback1;
+        IBinder.FrozenStateChangeCallback callback1;
         if ((callback1 = createCallback(mBfsccTestAppCmdService.asBinder(), results1)) == null) {
             return;
         }
@@ -197,8 +197,8 @@
     public void onStateChangeCalledWithTheRightBinder() throws Exception {
         final IBinder binder = mBfsccTestAppCmdService.asBinder();
         final LinkedBlockingQueue<IBinder> results = new LinkedBlockingQueue<>();
-        IBinder.IFrozenStateChangeCallback callback =
-                (IBinder who, IBinder.IFrozenStateChangeCallback.State state) -> results.offer(who);
+        IBinder.FrozenStateChangeCallback callback =
+                (IBinder who, int state) -> results.offer(who);
         try {
             binder.addFrozenStateChangeCallback(callback);
         } catch (UnsupportedOperationException e) {
@@ -221,12 +221,12 @@
         }
     }
 
-    private IBinder.IFrozenStateChangeCallback createCallback(IBinder binder, Queue<Boolean> queue)
+    private IBinder.FrozenStateChangeCallback createCallback(IBinder binder, Queue<Boolean> queue)
             throws RemoteException {
         try {
-            final IBinder.IFrozenStateChangeCallback callback =
-                    (IBinder who, IBinder.IFrozenStateChangeCallback.State state) ->
-                            queue.offer(state == IBinder.IFrozenStateChangeCallback.State.FROZEN);
+            final IBinder.FrozenStateChangeCallback callback =
+                    (IBinder who, int state) ->
+                            queue.offer(state == IBinder.FrozenStateChangeCallback.STATE_FROZEN);
             binder.addFrozenStateChangeCallback(callback);
             return callback;
         } catch (UnsupportedOperationException e) {
diff --git a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
index d12cba0..d007067 100644
--- a/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BinderDeathDispatcherTest.java
@@ -125,12 +125,12 @@
         }
 
         @Override
-        public void addFrozenStateChangeCallback(IFrozenStateChangeCallback callback)
+        public void addFrozenStateChangeCallback(FrozenStateChangeCallback callback)
                 throws RemoteException {
         }
 
         @Override
-        public boolean removeFrozenStateChangeCallback(IFrozenStateChangeCallback callback) {
+        public boolean removeFrozenStateChangeCallback(FrozenStateChangeCallback callback) {
             return false;
         }
 
diff --git a/libs/hwui/hwui/DrawTextFunctor.h b/libs/hwui/hwui/DrawTextFunctor.h
index cfca480..d264058 100644
--- a/libs/hwui/hwui/DrawTextFunctor.h
+++ b/libs/hwui/hwui/DrawTextFunctor.h
@@ -62,6 +62,7 @@
     }
     paint->setStrokeJoin(SkPaint::kRound_Join);
     paint->setLooper(nullptr);
+    paint->setBlendMode(SkBlendMode::kSrcOver);
 }
 
 class DrawTextFunctor {
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index bc8a7af..9603c0a 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -60,8 +60,13 @@
     method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public java.util.List<java.lang.String> getActiveNfceeList();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void maybeTriggerFirmwareUpdate();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcOemExtension.Callback);
+    method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void setControllerAlwaysOn(int);
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void synchronizeScreenState();
     method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void unregisterCallback(@NonNull android.nfc.NfcOemExtension.Callback);
+    field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int DISABLE = 0; // 0x0
+    field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int ENABLE_DEFAULT = 1; // 0x1
+    field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int ENABLE_EE = 3; // 0x3
+    field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int ENABLE_TRANSPARENT = 2; // 0x2
     field public static final int HCE_ACTIVATE = 1; // 0x1
     field public static final int HCE_DATA_TRANSFERRED = 2; // 0x2
     field public static final int HCE_DEACTIVATE = 3; // 0x3
diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
index e2ec952..246efc7 100644
--- a/nfc/java/android/nfc/INfcAdapter.aidl
+++ b/nfc/java/android/nfc/INfcAdapter.aidl
@@ -73,7 +73,7 @@
     boolean setNfcSecure(boolean enable);
     NfcAntennaInfo getNfcAntennaInfo();
 
-    boolean setControllerAlwaysOn(boolean value);
+    void setControllerAlwaysOn(int mode);
     boolean isControllerAlwaysOn();
     boolean isControllerAlwaysOnSupported();
     void registerControllerAlwaysOnListener(in INfcControllerAlwaysOnListener listener);
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index f478793..de85f1e 100644
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
@@ -559,6 +559,18 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface TagIntentAppPreferenceResult {}
 
+    /**
+     * Mode Type for {@link NfcOemExtension#setControllerAlwaysOn(int)}.
+     * @hide
+     */
+    public static final int CONTROLLER_ALWAYS_ON_MODE_DEFAULT = 1;
+
+    /**
+     * Mode Type for {@link NfcOemExtension#setControllerAlwaysOn(int)}.
+     * @hide
+     */
+    public static final int CONTROLLER_ALWAYS_ON_DISABLE = 0;
+
     // Guarded by sLock
     static boolean sIsInitialized = false;
     static boolean sHasNfcFeature;
@@ -2330,7 +2342,8 @@
      * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
      * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
      * are unavailable
-     * @return void
+     * @return true if feature is supported by the device and operation has bee initiated,
+     * false if the feature is not supported by the device.
      * @hide
      */
     @SystemApi
@@ -2339,8 +2352,13 @@
         if (!sHasNfcFeature && !sHasCeFeature) {
             throw new UnsupportedOperationException();
         }
-        return callServiceReturn(() ->  sService.setControllerAlwaysOn(value), false);
-
+        int mode = value ? CONTROLLER_ALWAYS_ON_MODE_DEFAULT : CONTROLLER_ALWAYS_ON_DISABLE;
+        try {
+            callService(() -> sService.setControllerAlwaysOn(mode));
+        } catch (UnsupportedOperationException e) {
+            return false;
+        }
+        return true;
     }
 
     /**
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
index d51b704..45038d4 100644
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -70,6 +70,58 @@
     private boolean mRfDiscoveryStarted = false;
 
     /**
+     * Mode Type for {@link #setControllerAlwaysOn(int)}.
+     * Enables the controller in default mode when NFC is disabled (existing API behavior).
+     * works same as {@link NfcAdapter#setControllerAlwaysOn(boolean)}.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    public static final int ENABLE_DEFAULT = NfcAdapter.CONTROLLER_ALWAYS_ON_MODE_DEFAULT;
+
+    /**
+     * Mode Type for {@link #setControllerAlwaysOn(int)}.
+     * Enables the controller in transparent mode when NFC is disabled.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    public static final int ENABLE_TRANSPARENT = 2;
+
+    /**
+     * Mode Type for {@link #setControllerAlwaysOn(int)}.
+     * Enables the controller and initializes and enables the EE subsystem when NFC is disabled.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    public static final int ENABLE_EE = 3;
+
+    /**
+     * Mode Type for {@link #setControllerAlwaysOn(int)}.
+     * Disable the Controller Always On Mode.
+     * works same as {@link NfcAdapter#setControllerAlwaysOn(boolean)}.
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    public static final int DISABLE = NfcAdapter.CONTROLLER_ALWAYS_ON_DISABLE;
+
+    /**
+     * Possible controller modes for {@link #setControllerAlwaysOn(int)}.
+     *
+     * @hide
+     */
+    @IntDef(prefix = { "" }, value = {
+        ENABLE_DEFAULT,
+        ENABLE_TRANSPARENT,
+        ENABLE_EE,
+        DISABLE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ControllerMode{}
+
+    /**
      * Event that Host Card Emulation is activated.
      */
     public static final int HCE_ACTIVATE = 1;
@@ -389,6 +441,32 @@
             NfcAdapter.sService.fetchActiveNfceeList(), new ArrayList<String>());
     }
 
+    /**
+     * Sets NFC controller always on feature.
+     * <p>This API is for the NFCC internal state management. It allows to discriminate
+     * the controller function from the NFC function by keeping the NFC controller on without
+     * any NFC RF enabled if necessary.
+     * <p>This call is asynchronous, register listener {@link NfcAdapter.ControllerAlwaysOnListener}
+     * by {@link NfcAdapter#registerControllerAlwaysOnListener} to find out when the operation is
+     * complete.
+     * @param mode one of {@link ControllerMode} modes
+     * @throws UnsupportedOperationException if
+     *   <li> if FEATURE_NFC, FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
+     *   FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
+     *   are unavailable </li>
+     *   <li> if the feature is unavailable @see NfcAdapter#isNfcControllerAlwaysOnSupported() </li>
+     * @hide
+     */
+    @SystemApi
+    @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
+    @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
+    public void setControllerAlwaysOn(@ControllerMode int mode) {
+        if (!NfcAdapter.sHasNfcFeature && !NfcAdapter.sHasCeFeature) {
+            throw new UnsupportedOperationException();
+        }
+        NfcAdapter.callService(() -> NfcAdapter.sService.setControllerAlwaysOn(mode));
+    }
+
     private final class NfcOemExtensionCallback extends INfcOemExtensionCallback.Stub {
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
index 103449b..ee8ce17 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/MenuViewTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.Mockito.verify;
 
 import android.app.UiModeManager;
+import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.graphics.drawable.GradientDrawable;
 import android.platform.test.annotations.EnableFlags;
@@ -78,6 +79,12 @@
         mNightMode = mUiModeManager.getNightMode();
         mUiModeManager.setNightMode(MODE_NIGHT_YES);
 
+        // Programmatically update the resource's configuration to night mode to reduce flakiness
+        Configuration nightConfig = new Configuration(mContext.getResources().getConfiguration());
+        nightConfig.uiMode = Configuration.UI_MODE_NIGHT_YES;
+        mContext.getResources().updateConfiguration(nightConfig,
+                mContext.getResources().getDisplayMetrics(), null);
+
         mSpyContext = spy(mContext);
         doNothing().when(mSpyContext).startActivity(any());
 
@@ -101,6 +108,8 @@
 
     @Test
     public void insetsOnDarkTheme_menuOnLeft_matchInsets() {
+        // In dark theme, the inset is not 0 to avoid weird spacing issue between the menu and
+        // the edge of the screen.
         mMenuView.onConfigurationChanged(/* newConfig= */ null);
         final InstantInsetLayerDrawable insetLayerDrawable =
                 (InstantInsetLayerDrawable) mMenuView.getBackground();
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 158d444..1e25f1c 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -140,7 +140,7 @@
         try {
             db.delete(TABLE, COLUMN_KEY + "=? AND " + COLUMN_USERID + "=?",
                     new String[] {key, Integer.toString(userId)});
-            db.insert(TABLE, null, cv);
+            db.insertOrThrow(TABLE, null, cv);
             db.setTransactionSuccessful();
             mCache.putKeyValue(key, value, userId);
         } finally {
diff --git a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
index 96a25da..1e82b89 100644
--- a/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
+++ b/services/core/java/com/android/server/vcn/TelephonySubscriptionTracker.java
@@ -322,9 +322,16 @@
 
         if (SubscriptionManager.isValidSubscriptionId(subId)) {
             // Get only configs as needed to save memory.
-            final PersistableBundle carrierConfig =
-                    CarrierConfigManager.getCarrierConfigSubset(mContext, subId,
-                            VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS);
+            PersistableBundle carrierConfig = new PersistableBundle();
+            try {
+                carrierConfig =
+                        mCarrierConfigManager.getConfigForSubId(
+                                subId, VcnManager.VCN_RELATED_CARRIER_CONFIG_KEYS);
+
+            } catch (RuntimeException exception) {
+                Slog.w(TAG, "CarrierConfigLoader is not available.");
+            }
+
             if (mDeps.isConfigForIdentifiedCarrier(carrierConfig)) {
                 mReadySubIdsBySlotId.put(slotId, subId);
 
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt
index 290e7be..9467434 100644
--- a/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt
@@ -22,6 +22,7 @@
 import com.google.android.lint.aidl.EnforcePermissionDetector
 import com.google.android.lint.aidl.PermissionAnnotationDetector
 import com.google.android.lint.aidl.SimpleManualPermissionEnforcementDetector
+import com.google.android.lint.aidl.SimpleRequiresNoPermissionDetector
 import com.google.auto.service.AutoService
 
 @AutoService(IssueRegistry::class)
@@ -34,6 +35,7 @@
             EnforcePermissionDetector.ISSUE_MISUSING_ENFORCE_PERMISSION,
             PermissionAnnotationDetector.ISSUE_MISSING_PERMISSION_ANNOTATION,
             SimpleManualPermissionEnforcementDetector.ISSUE_SIMPLE_MANUAL_PERMISSION_ENFORCEMENT,
+            SimpleRequiresNoPermissionDetector.ISSUE_SIMPLE_REQUIRES_NO_PERMISSION,
     )
 
     override val api: Int
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetector.kt
new file mode 100644
index 0000000..1a13c02
--- /dev/null
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetector.kt
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2024 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.aidl
+
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import org.jetbrains.uast.UastCallKind
+import org.jetbrains.uast.UBlockExpression
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UMethod
+import org.jetbrains.uast.visitor.AbstractUastVisitor
+
+/**
+ * Ensures all AIDL implementations hosted by system_server which don't call other methods are
+ * annotated with @RequiresNoPermission. AIDL Interfaces part of `exemptAidlInterfaces` are skipped
+ * during this search to ensure the detector targets only new AIDL Interfaces.
+ */
+class SimpleRequiresNoPermissionDetector : AidlImplementationDetector() {
+    override fun visitAidlMethod(
+        context: JavaContext,
+        node: UMethod,
+        interfaceName: String,
+        body: UBlockExpression
+    ) {
+        if (!isSystemServicePath(context)) return
+        if (context.evaluator.isAbstract(node)) return
+
+        val fullyQualifiedInterfaceName =
+            getContainingAidlInterfaceQualified(context, node) ?: return
+        if (exemptAidlInterfaces.contains(fullyQualifiedInterfaceName)) return
+
+        if (node.hasAnnotation(ANNOTATION_REQUIRES_NO_PERMISSION)) return
+
+        if (!isCallingMethod(node)) {
+            context.report(
+                ISSUE_SIMPLE_REQUIRES_NO_PERMISSION,
+                node,
+                context.getLocation(node),
+                """
+                    Method ${node.name} doesn't perform any permission checks, meaning it should \
+                    be annotated with @RequiresNoPermission.
+                """.trimMargin()
+            )
+        }
+    }
+
+    private fun isCallingMethod(node: UMethod): Boolean {
+        val uCallExpressionVisitor = UCallExpressionVisitor()
+        node.accept(uCallExpressionVisitor)
+
+        return uCallExpressionVisitor.isCallingMethod
+    }
+
+    /**
+     * Visits the body of a `UMethod` and determines if it encounters a `UCallExpression` which is
+     * a `UastCallKind.METHOD_CALL`. `isCallingMethod` will hold the result of the search procedure.
+     */
+    private class UCallExpressionVisitor : AbstractUastVisitor() {
+        var isCallingMethod = false
+
+        override fun visitElement(node: UElement): Boolean {
+            // Stop the search early when a method call has been found.
+            return isCallingMethod
+        }
+
+        override fun visitCallExpression(node: UCallExpression): Boolean {
+            if (node.kind != UastCallKind.METHOD_CALL) return false
+
+            isCallingMethod = true
+            return true
+        }
+    }
+
+    companion object {
+
+        private val EXPLANATION = """
+            Method implementations of AIDL Interfaces hosted by the `system_server` which do not
+            call any other methods should be annotated with @RequiresNoPermission. That is because
+            not calling any other methods implies that the method does not perform any permission
+            checking.
+
+            Please migrate to an @RequiresNoPermission annotation.
+        """.trimIndent()
+
+        @JvmField
+        val ISSUE_SIMPLE_REQUIRES_NO_PERMISSION = Issue.create(
+            id = "SimpleRequiresNoPermission",
+            briefDescription = "System Service APIs not calling other methods should use @RNP",
+            explanation = EXPLANATION,
+            category = Category.SECURITY,
+            priority = 5,
+            severity = Severity.ERROR,
+            implementation = Implementation(
+                SimpleRequiresNoPermissionDetector::class.java,
+                Scope.JAVA_FILE_SCOPE
+            ),
+        )
+    }
+}
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt
index 92d0829..824be93 100644
--- a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/PermissionAnnotationDetectorTest.kt
@@ -17,7 +17,6 @@
 package com.google.android.lint.aidl
 
 import com.android.tools.lint.checks.infrastructure.LintDetectorTest
-import com.android.tools.lint.checks.infrastructure.TestFile
 import com.android.tools.lint.checks.infrastructure.TestLintTask
 import com.android.tools.lint.detector.api.Detector
 import com.android.tools.lint.detector.api.Issue
@@ -64,7 +63,7 @@
                     """
                         package com.android.server;
                         public class Bar extends IBar.Stub {
-                            public void testMethod() { }
+                            public void testMethod(int parameter1, int parameter2) { }
                         }
                     """
                 )
@@ -75,8 +74,8 @@
             .expect(
                 """
                 src/frameworks/base/services/java/com/android/server/Bar.java:3: Error: The method testMethod is not permission-annotated. [MissingPermissionAnnotation]
-                    public void testMethod() { }
-                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                    public void testMethod(int parameter1, int parameter2) { }
+                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                 1 errors, 0 warnings
                 """
             )
@@ -90,7 +89,7 @@
                     """
                         package com.android.server;
                         public class Bar extends IBar.Stub {
-                            public void testMethod() { }
+                            public void testMethod(int parameter1, int parameter2) { }
                         }
                     """
                 )
@@ -132,7 +131,7 @@
                     """
                         package com.android.server;
                         public abstract class Bar extends IBar.Stub {
-                            public abstract void testMethod();
+                            public abstract void testMethod(int parameter1, int parameter2);
                         }
                     """
                 )
@@ -177,50 +176,6 @@
             .expectClean()
     }
 
-    /* Stubs */
-
-    // A service with permission annotation on the method.
-    private val interfaceIFoo: TestFile = java(
-        """
-        public interface IFoo extends android.os.IInterface {
-         public static abstract class Stub extends android.os.Binder implements IFoo {
-          }
-          @Override
-          @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
-          public void testMethod();
-          @Override
-          @android.annotation.RequiresNoPermission
-          public void testMethodNoPermission();
-          @Override
-          @android.annotation.PermissionManuallyEnforced
-          public void testMethodManual();
-        }
-        """
-    ).indented()
-
-    // A service with no permission annotation.
-    private val interfaceIBar: TestFile = java(
-        """
-        public interface IBar extends android.os.IInterface {
-         public static abstract class Stub extends android.os.Binder implements IBar {
-          }
-          public void testMethod();
-        }
-        """
-    ).indented()
-
-    // A service whose AIDL Interface is exempted.
-    private val interfaceIExempted: TestFile = java(
-        """
-        package android.accessibilityservice;
-        public interface IBrailleDisplayConnection extends android.os.IInterface {
-         public static abstract class Stub extends android.os.Binder implements IBrailleDisplayConnection {
-          }
-          public void testMethod();
-        }
-        """
-    ).indented()
-
     private val stubs = arrayOf(interfaceIFoo, interfaceIBar, interfaceIExempted)
 
     private fun createVisitedPath(filename: String) =
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetectorTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetectorTest.kt
new file mode 100644
index 0000000..a33b48c
--- /dev/null
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleRequiresNoPermissionDetectorTest.kt
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2024 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.aidl
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+
+class SimpleRequiresNoPermissionDetectorTest : LintDetectorTest() {
+    override fun getDetector(): Detector = SimpleRequiresNoPermissionDetector()
+    override fun getIssues(): List<Issue> = listOf(
+        SimpleRequiresNoPermissionDetector
+            .ISSUE_SIMPLE_REQUIRES_NO_PERMISSION
+    )
+
+    override fun lint(): TestLintTask = super.lint().allowMissingSdk()
+
+    fun testRequiresNoPermissionUsedCorrectly_shouldNotWarn() {
+        lint()
+            .files(
+                java(
+                    createVisitedPath("Foo.java"),
+                    """
+                        package com.android.server;
+                        public class Foo extends IFoo.Stub {
+                            private int memberInt;
+
+                            @Override
+                            @android.annotation.RequiresNoPermission
+                            public void testMethodNoPermission(int parameter1, int parameter2) {
+                                if (parameter1 < parameter2) {
+                                    memberInt = parameter1;
+                                } else {
+                                    memberInt = parameter2;
+                                }
+                            }
+                        }
+                    """
+                )
+                    .indented(),
+                *stubs
+            )
+            .run()
+            .expectClean()
+    }
+
+    fun testMissingRequiresNoPermission_shouldWarn() {
+        lint()
+            .files(
+                java(
+                    createVisitedPath("Bar.java"),
+                    """
+                        package com.android.server;
+                        public class Bar extends IBar.Stub {
+                            private int memberInt;
+
+                            @Override
+                            public void testMethod(int parameter1, int parameter2) {
+                                if (parameter1 < parameter2) {
+                                    memberInt = parameter1;
+                                } else {
+                                    memberInt = parameter2;
+                                }
+                            }
+                        }
+                    """
+                )
+                    .indented(),
+                *stubs
+            )
+            .run()
+            .expect(
+                """
+                src/frameworks/base/services/java/com/android/server/Bar.java:5: Error: Method testMethod doesn't perform any permission checks, meaning it should be annotated with @RequiresNoPermission. [SimpleRequiresNoPermission]
+                    @Override
+                    ^
+                1 errors, 0 warnings
+                """
+            )
+    }
+
+    fun testMethodOnlyPerformsConstructorCall_shouldWarn() {
+        lint()
+            .files(
+                java(
+                    createVisitedPath("Bar.java"),
+                    """
+                        package com.android.server;
+                        public class Bar extends IBar.Stub {
+                            private IntPair memberIntPair;
+
+                            @Override
+                            public void testMethod(int parameter1, int parameter2) {
+                                memberIntPair = new IntPair(parameter1, parameter2);
+                            }
+
+                            private static class IntPair {
+                                public int first;
+                                public int second;
+
+                                public IntPair(int first, int second) {
+                                    this.first = first;
+                                    this.second = second;
+                                }
+                            }
+                        }
+                    """
+                )
+                    .indented(),
+                *stubs
+            )
+            .run()
+            .expect(
+                """
+                src/frameworks/base/services/java/com/android/server/Bar.java:5: Error: Method testMethod doesn't perform any permission checks, meaning it should be annotated with @RequiresNoPermission. [SimpleRequiresNoPermission]
+                    @Override
+                    ^
+                1 errors, 0 warnings
+                """
+            )
+    }
+
+    fun testMissingRequiresNoPermissionInIgnoredDirectory_shouldNotWarn() {
+        lint()
+            .files(
+                java(
+                    ignoredPath,
+                    """
+                        package com.android.server;
+                        public class Bar extends IBar.Stub {
+                            @Override
+                            public void testMethod(int parameter1, int parameter2) {}
+                        }
+                    """
+                )
+                    .indented(),
+                *stubs
+            )
+            .run()
+            .expectClean()
+    }
+
+    fun testMissingRequiresNoPermissionAbstractMethod_shouldNotWarn() {
+        lint()
+            .files(
+                java(
+                    createVisitedPath("Bar.java"),
+                    """
+                        package com.android.server;
+                        public abstract class Bar extends IBar.Stub {
+                            private int memberInt;
+
+                            @Override
+                            public abstract void testMethodNoPermission(int parameter1, int parameter2);
+                        }
+                    """
+                )
+                    .indented(),
+                *stubs
+            )
+            .run()
+            .expectClean()
+    }
+
+    // If this test fails, consider the following steps:
+    //   1. Pick the first entry (interface) from `exemptAidlInterfaces`.
+    //   2. Change `interfaceIExempted` to use that interface.
+    //   3. Change this test's class to extend the interface's Stub.
+    fun testMissingRequiresNoPermissionAidlInterfaceExempted_shouldNotWarn() {
+        lint()
+            .files(
+                java(
+                    createVisitedPath("Bar.java"),
+                    """
+                        package com.android.server;
+                        public class Bar extends android.accessibilityservice.IBrailleDisplayConnection.Stub {
+                            public void testMethod(int parameter1, int parameter2) {}
+                        }
+                    """
+                )
+                    .indented(),
+                *stubs
+            )
+            .run()
+            .expectClean()
+    }
+
+    fun testMethodMakesAnotherMethodCall_shouldNotWarn() {
+        lint()
+            .files(
+                java(
+                    createVisitedPath("Bar.java"),
+                    """
+                        package com.android.server;
+                        public class Bar extends IBar.Stub {
+                            private int memberInt;
+
+                            @Override
+                            public void testMethod(int parameter1, int parameter2) {
+                                if (!hasPermission()) return;
+
+                                if (parameter1 < parameter2) {
+                                    memberInt = parameter1;
+                                } else {
+                                    memberInt = parameter2;
+                                }
+                            }
+
+                            private bool hasPermission() {
+                                // Perform a permission check.
+                                return true;
+                            }
+                        }
+                    """
+                )
+                    .indented(),
+                *stubs
+            )
+            .run()
+            .expectClean()
+    }
+
+    private val stubs = arrayOf(interfaceIFoo, interfaceIBar, interfaceIExempted)
+
+    private fun createVisitedPath(filename: String) =
+        "src/frameworks/base/services/java/com/android/server/$filename"
+
+    private val ignoredPath = "src/test/pkg/TestClass.java"
+}
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt
index 2ec8fdd..18a8f18 100644
--- a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt
@@ -85,4 +85,46 @@
         }
     }
     """.trimIndent()
-)
\ No newline at end of file
+)
+
+// A service with permission annotation on the method.
+val interfaceIFoo: TestFile = java(
+    """
+        public interface IFoo extends android.os.IInterface {
+         public static abstract class Stub extends android.os.Binder implements IFoo {
+          }
+          @Override
+          @android.annotation.EnforcePermission(android.Manifest.permission.READ_PHONE_STATE)
+          public void testMethod();
+          @Override
+          @android.annotation.RequiresNoPermission
+          public void testMethodNoPermission(int parameter1, int parameter2);
+          @Override
+          @android.annotation.PermissionManuallyEnforced
+          public void testMethodManual();
+        }
+        """
+).indented()
+
+// A service with no permission annotation.
+val interfaceIBar: TestFile = java(
+    """
+        public interface IBar extends android.os.IInterface {
+         public static abstract class Stub extends android.os.Binder implements IBar {
+          }
+          public void testMethod(int parameter1, int parameter2);
+        }
+        """
+).indented()
+
+// A service whose AIDL Interface is exempted.
+val interfaceIExempted: TestFile = java(
+    """
+        package android.accessibilityservice;
+        public interface IBrailleDisplayConnection extends android.os.IInterface {
+         public static abstract class Stub extends android.os.Binder implements IBrailleDisplayConnection {
+          }
+          public void testMethod();
+        }
+        """
+).indented()