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()