diff options
25 files changed, 633 insertions, 112 deletions
diff --git a/cmds/uiautomator/library/Android.bp b/cmds/uiautomator/library/Android.bp index 966bf13adfe4..5c5b220d20e9 100644 --- a/cmds/uiautomator/library/Android.bp +++ b/cmds/uiautomator/library/Android.bp @@ -28,9 +28,9 @@ droidstubs { "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 @@ droiddoc { ":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 2d8db84bbbde..9881a90ff003 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -33192,6 +33192,7 @@ package android.os { } 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 @@ package android.os { 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 @@ package android.os { 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 6f11d3ae661c..af93c964a8ba 100644 --- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java @@ -35,7 +35,6 @@ import android.os.PersistableBundle; 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 @@ public final class VcnGatewayConnectionConfig { @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 a97563724e50..e1d1b3c65c99 100644 --- a/core/java/android/net/vcn/VcnUnderlyingNetworkSpecifier.java +++ b/core/java/android/net/vcn/VcnUnderlyingNetworkSpecifier.java @@ -24,7 +24,6 @@ import android.os.Parcelable; 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 @@ public final class VcnUnderlyingNetworkSpecifier extends NetworkSpecifier implem @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 c22f46cdc2b5..80546cd6770f 100644 --- a/core/java/android/os/BinderProxy.java +++ b/core/java/android/os/BinderProxy.java @@ -650,13 +650,13 @@ public final class BinderProxy implements IBinder { * 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 @@ public final class BinderProxy implements IBinder { /** * 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 @@ public final class BinderProxy implements IBinder { } 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 8185e8e542e1..a997f4c86704 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 interface IBinder { */ 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 @@ public interface IBinder { * @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 @@ public interface IBinder { * * <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 11b1b08b787d..b5c278ad69a0 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -169,6 +169,14 @@ flag { } 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 17c4ee96c68a..387180600953 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -288,7 +288,6 @@ cc_library_shared_for_libandroid_runtime { "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 921b77d61f4d..ef50a95b6287 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -1747,9 +1747,9 @@ static const JNINativeMethod gBinderProxyMethods[] = { {"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 @@ static int int_register_android_os_BinderProxy(JNIEnv* env) "(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 77e8a404a0ff..fe54aa8d87f0 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 @@ import java.util.concurrent.TimeUnit; 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 ee2e7e06081e..195a18a5f521 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.AtomicInteger; 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 @@ public class BinderFrozenStateChangeNotificationTest { @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 class BinderFrozenStateChangeNotificationTest { 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 class BinderFrozenStateChangeNotificationTest { 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 @@ public class BinderFrozenStateChangeNotificationTest { } } - 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 d12cba00f0dc..d0070678d4fa 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 @@ public class BinderDeathDispatcherTest { } @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 cfca48084d97..d264058737e5 100644 --- a/libs/hwui/hwui/DrawTextFunctor.h +++ b/libs/hwui/hwui/DrawTextFunctor.h @@ -62,6 +62,7 @@ static void simplifyPaint(int color, Paint* paint) { } 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 bc8a7afd94e9..9603c0a9f7c7 100644 --- a/nfc/api/system-current.txt +++ b/nfc/api/system-current.txt @@ -60,8 +60,13 @@ package android.nfc { 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 e2ec95215d1a..246efc7ca557 100644 --- a/nfc/java/android/nfc/INfcAdapter.aidl +++ b/nfc/java/android/nfc/INfcAdapter.aidl @@ -73,7 +73,7 @@ interface INfcAdapter 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 f47879385070..de85f1eeabe3 100644 --- a/nfc/java/android/nfc/NfcAdapter.java +++ b/nfc/java/android/nfc/NfcAdapter.java @@ -559,6 +559,18 @@ public final class NfcAdapter { @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 @@ public final class NfcAdapter { * 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 @@ public final class NfcAdapter { 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 d51b704a7e7f..45038d41e237 100644 --- a/nfc/java/android/nfc/NfcOemExtension.java +++ b/nfc/java/android/nfc/NfcOemExtension.java @@ -70,6 +70,58 @@ public final class NfcOemExtension { 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 @@ public final class NfcOemExtension { 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 103449b6b0f7..ee8ce17cecd4 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.spy; 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 @@ public class MenuViewTest extends SysuiTestCase { 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 @@ public class MenuViewTest extends SysuiTestCase { @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 158d444bcff2..1e25f1cf1d5e 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 @@ class LockSettingsStorage { 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 96a25dac21e3..1e82b8999834 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 @@ public class TelephonySubscriptionTracker extends BroadcastReceiver { 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 290e7be9f6c4..94674348df08 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.android.tools.lint.detector.api.CURRENT_API 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 @@ class AndroidGlobalIssueRegistry : IssueRegistry() { 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 000000000000..1a13c0280ec6 --- /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 92d0829911bf..824be9309dbc 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 @@ class PermissionAnnotationDetectorTest : LintDetectorTest() { """ package com.android.server; public class Bar extends IBar.Stub { - public void testMethod() { } + public void testMethod(int parameter1, int parameter2) { } } """ ) @@ -75,8 +74,8 @@ class PermissionAnnotationDetectorTest : LintDetectorTest() { .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 @@ class PermissionAnnotationDetectorTest : LintDetectorTest() { """ package com.android.server; public class Bar extends IBar.Stub { - public void testMethod() { } + public void testMethod(int parameter1, int parameter2) { } } """ ) @@ -132,7 +131,7 @@ class PermissionAnnotationDetectorTest : LintDetectorTest() { """ 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 @@ class PermissionAnnotationDetectorTest : LintDetectorTest() { .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 000000000000..a33b48c7eaa0 --- /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 2ec8fddbb4e9..18a8f186b624 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 @@ val manifestStub: TestFile = java( } } """.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() |