diff options
105 files changed, 2047 insertions, 2602 deletions
@@ -47,3 +47,4 @@ per-file MULTIUSER_OWNERS = file:/MULTIUSER_OWNERS per-file BROADCASTS_OWNERS = file:/BROADCASTS_OWNERS per-file ADPF_OWNERS = file:/ADPF_OWNERS per-file GAME_MANAGER_OWNERS = file:/GAME_MANAGER_OWNERS +per-file SDK_OWNERS = file:/SDK_OWNERS diff --git a/SDK_OWNERS b/SDK_OWNERS new file mode 100644 index 000000000000..c9ca47aa4703 --- /dev/null +++ b/SDK_OWNERS @@ -0,0 +1,6 @@ +amhk@google.com +kimalexander@google.com +lus@google.com +michaelwr@google.com +nanaasiedu@google.com +paulduffin@google.com diff --git a/config/preloaded-classes-denylist b/config/preloaded-classes-denylist index a413bbd68f60..16f069394639 100644 --- a/config/preloaded-classes-denylist +++ b/config/preloaded-classes-denylist @@ -1,13 +1,16 @@ android.content.AsyncTaskLoader$LoadTask +android.media.MediaCodecInfo$CodecCapabilities$FeatureList android.net.ConnectivityThread$Singleton android.os.FileObserver android.os.NullVibrator +android.permission.PermissionManager +android.provider.MediaStore android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask +android.view.HdrRenderState android.widget.Magnifier +com.android.internal.jank.InteractionJankMonitor$InstanceHolder +com.android.internal.util.LatencyTracker$SLatencyTrackerHolder gov.nist.core.net.DefaultNetworkLayer -android.net.rtp.AudioGroup -android.net.rtp.AudioStream -android.net.rtp.RtpStream java.util.concurrent.ThreadLocalRandom java.util.ImmutableCollections -com.android.internal.jank.InteractionJankMonitor$InstanceHolder +sun.nio.fs.UnixChannelFactory diff --git a/core/api/current.txt b/core/api/current.txt index 6b342a541c97..6d9fe4494220 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -22920,6 +22920,65 @@ package android.media { field public static final int AC4Profile11 = 514; // 0x202 field public static final int AC4Profile21 = 1026; // 0x402 field public static final int AC4Profile22 = 1028; // 0x404 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel11Band0 = 513; // 0x201 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel11Band1 = 514; // 0x202 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel11Band2 = 516; // 0x204 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel11Band3 = 520; // 0x208 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel1Band0 = 257; // 0x101 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel1Band1 = 258; // 0x102 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel1Band2 = 260; // 0x104 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel1Band3 = 264; // 0x108 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel21Band0 = 2049; // 0x801 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel21Band1 = 2050; // 0x802 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel21Band2 = 2052; // 0x804 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel21Band3 = 2056; // 0x808 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel2Band0 = 1025; // 0x401 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel2Band1 = 1026; // 0x402 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel2Band2 = 1028; // 0x404 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel2Band3 = 1032; // 0x408 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel31Band0 = 8193; // 0x2001 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel31Band1 = 8194; // 0x2002 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel31Band2 = 8196; // 0x2004 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel31Band3 = 8200; // 0x2008 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel3Band0 = 4097; // 0x1001 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel3Band1 = 4098; // 0x1002 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel3Band2 = 4100; // 0x1004 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel3Band3 = 4104; // 0x1008 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel41Band0 = 32769; // 0x8001 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel41Band1 = 32770; // 0x8002 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel41Band2 = 32772; // 0x8004 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel41Band3 = 32776; // 0x8008 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel4Band0 = 16385; // 0x4001 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel4Band1 = 16386; // 0x4002 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel4Band2 = 16388; // 0x4004 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel4Band3 = 16392; // 0x4008 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel51Band0 = 131073; // 0x20001 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel51Band1 = 131074; // 0x20002 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel51Band2 = 131076; // 0x20004 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel51Band3 = 131080; // 0x20008 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel5Band0 = 65537; // 0x10001 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel5Band1 = 65538; // 0x10002 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel5Band2 = 65540; // 0x10004 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel5Band3 = 65544; // 0x10008 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel61Band0 = 524289; // 0x80001 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel61Band1 = 524290; // 0x80002 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel61Band2 = 524292; // 0x80004 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel61Band3 = 524296; // 0x80008 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel6Band0 = 262145; // 0x40001 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel6Band1 = 262146; // 0x40002 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel6Band2 = 262148; // 0x40004 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel6Band3 = 262152; // 0x40008 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel71Band0 = 2097153; // 0x200001 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel71Band1 = 2097154; // 0x200002 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel71Band2 = 2097156; // 0x200004 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel71Band3 = 2097160; // 0x200008 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel7Band0 = 1048577; // 0x100001 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel7Band1 = 1048578; // 0x100002 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel7Band2 = 1048580; // 0x100004 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVLevel7Band3 = 1048584; // 0x100008 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVProfile422_10 = 1; // 0x1 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVProfile422_10HDR10 = 4096; // 0x1000 + field @FlaggedApi("android.media.codec.apv_support") public static final int APVProfile422_10HDR10Plus = 8192; // 0x2000 field public static final int AV1Level2 = 1; // 0x1 field public static final int AV1Level21 = 2; // 0x2 field public static final int AV1Level22 = 4; // 0x4 @@ -23770,6 +23829,7 @@ package android.media { field public static final String MIMETYPE_TEXT_CEA_708 = "text/cea-708"; field public static final String MIMETYPE_TEXT_SUBRIP = "application/x-subrip"; field public static final String MIMETYPE_TEXT_VTT = "text/vtt"; + field @FlaggedApi("android.media.codec.apv_support") public static final String MIMETYPE_VIDEO_APV = "video/apv"; field public static final String MIMETYPE_VIDEO_AV1 = "video/av01"; field public static final String MIMETYPE_VIDEO_AVC = "video/avc"; field public static final String MIMETYPE_VIDEO_DOLBY_VISION = "video/dolby-vision"; diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 9a294fdd6fb1..0b891f6e0a71 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -102,6 +102,7 @@ package android.content { method @NonNull public android.os.UserHandle getUser(); field public static final String PAC_PROXY_SERVICE = "pac_proxy"; field public static final String TEST_NETWORK_SERVICE = "test_network"; + field @FlaggedApi("android.os.mainline_vcn_platform_api") public static final String VCN_MANAGEMENT_SERVICE = "vcn_management"; field @FlaggedApi("android.webkit.update_service_ipc_wrapper") public static final String WEBVIEW_UPDATE_SERVICE = "webviewupdate"; } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 36bdf738e402..744f019a4988 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4855,6 +4855,8 @@ public abstract class Context { * @see android.net.vcn.VcnManager * @hide */ + @FlaggedApi(android.os.Flags.FLAG_MAINLINE_VCN_PLATFORM_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final String VCN_MANAGEMENT_SERVICE = "vcn_management"; /** diff --git a/core/java/android/database/BulkCursorNative.java b/core/java/android/database/BulkCursorNative.java index 41585b3571d6..7d6e7ad857d1 100644 --- a/core/java/android/database/BulkCursorNative.java +++ b/core/java/android/database/BulkCursorNative.java @@ -215,7 +215,7 @@ final class BulkCursorProxy implements IBulkCursor { // If close() is being called from the finalizer thread, do not wait for a reply from // the remote side. final boolean fromFinalizer = - android.database.sqlite.Flags.onewayFinalizerClose() + android.database.sqlite.Flags.onewayFinalizerCloseFixed() && "FinalizerDaemon".equals(Thread.currentThread().getName()); mRemote.transact(CLOSE_TRANSACTION, data, reply, fromFinalizer ? IBinder.FLAG_ONEWAY: 0); diff --git a/core/java/android/database/sqlite/flags.aconfig b/core/java/android/database/sqlite/flags.aconfig index c597895899b6..c2cc9d18e457 100644 --- a/core/java/android/database/sqlite/flags.aconfig +++ b/core/java/android/database/sqlite/flags.aconfig @@ -2,8 +2,9 @@ package: "android.database.sqlite" container: "system" flag { - name: "oneway_finalizer_close" + name: "oneway_finalizer_close_fixed" namespace: "system_performance" + is_fixed_read_only: true description: "Make BuildCursorNative.close oneway if in the the finalizer" bug: "368221351" } diff --git a/core/java/android/hardware/location/OWNERS b/core/java/android/hardware/location/OWNERS index 747f90947b9c..340d6f2eb08c 100644 --- a/core/java/android/hardware/location/OWNERS +++ b/core/java/android/hardware/location/OWNERS @@ -9,4 +9,4 @@ wyattriley@google.com yuhany@google.com # ContextHub team -per-file *ContextHub*,*NanoApp* = file:platform/system/chre:/OWNERS +per-file Android.bp,*Hub*,*NanoApp* = file:platform/system/chre:/OWNERS diff --git a/core/java/android/hardware/usb/OWNERS b/core/java/android/hardware/usb/OWNERS index a753f9634d0d..37604bc2eb65 100644 --- a/core/java/android/hardware/usb/OWNERS +++ b/core/java/android/hardware/usb/OWNERS @@ -1,7 +1,7 @@ # Bug component: 175220 -aprasath@google.com -kumarashishg@google.com -sarup@google.com anothermark@google.com +febinthattil@google.com +aprasath@google.com badhri@google.com +kumarashishg@google.com
\ No newline at end of file diff --git a/core/java/android/net/flags.aconfig b/core/java/android/net/flags.aconfig index 48eb9680e647..f7dc7906d50d 100644 --- a/core/java/android/net/flags.aconfig +++ b/core/java/android/net/flags.aconfig @@ -5,13 +5,6 @@ container: "system" # Flags used for module APIs must be in aconfig files under each modules flag { - name: "ipsec_transform_state" - namespace: "core_networking_ipsec" - description: "The flag controls the access for getIpSecTransformState and IpSecTransformState" - bug: "308011229" -} - -flag { name: "powered_off_finding_platform" namespace: "nearby" description: "Controls whether the Powered Off Finding feature is enabled" diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 30d2dec8b4c4..3c3a4fd68b15 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -36,8 +36,6 @@ import android.util.ArraySet; import android.util.Slog; import android.view.View; -import com.android.internal.ravenwood.RavenwoodEnvironment; - import dalvik.system.VMRuntime; import java.util.ArrayList; @@ -51,10 +49,6 @@ import java.util.stream.Collectors; */ @RavenwoodKeepWholeClass public class Build { - static { - // Set up the default system properties. - RavenwoodEnvironment.ensureRavenwoodInitialized(); - } private static final String TAG = "Build"; /** Value used for when a build property is unknown. */ diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java index e80efd2a9380..60eeb2b8b0d5 100644 --- a/core/java/android/os/ParcelFileDescriptor.java +++ b/core/java/android/os/ParcelFileDescriptor.java @@ -41,7 +41,6 @@ import android.content.ContentResolver; import android.net.Uri; import android.os.MessageQueue.OnFileDescriptorEventListener; import android.ravenwood.annotation.RavenwoodKeepWholeClass; -import android.ravenwood.annotation.RavenwoodReplace; import android.ravenwood.annotation.RavenwoodThrow; import android.system.ErrnoException; import android.system.Os; @@ -51,8 +50,6 @@ import android.util.CloseGuard; import android.util.Log; import android.util.Slog; -import com.android.internal.ravenwood.RavenwoodEnvironment; - import dalvik.system.VMRuntime; import libcore.io.IoUtils; @@ -1254,15 +1251,10 @@ public class ParcelFileDescriptor implements Parcelable, Closeable { } } - @RavenwoodReplace private static boolean isAtLeastQ() { return (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q); } - private static boolean isAtLeastQ$ravenwood() { - return RavenwoodEnvironment.workaround().isTargetSdkAtLeastQ(); - } - private static int ifAtLeastQ(int value) { return isAtLeastQ() ? value : 0; } diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index cd8788db4e70..851953af1fb9 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -29,6 +29,11 @@ import android.annotation.TestApi; import android.annotation.UptimeMillisLong; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build.VERSION_CODES; +import android.ravenwood.annotation.RavenwoodKeep; +import android.ravenwood.annotation.RavenwoodKeepPartialClass; +import android.ravenwood.annotation.RavenwoodRedirect; +import android.ravenwood.annotation.RavenwoodRedirectionClass; +import android.ravenwood.annotation.RavenwoodReplace; import android.sysprop.MemoryProperties; import android.system.ErrnoException; import android.system.Os; @@ -37,8 +42,6 @@ import android.system.StructPollfd; import android.util.Pair; import android.webkit.WebViewZygote; -import com.android.internal.os.SomeArgs; -import com.android.internal.util.Preconditions; import com.android.sdksandbox.flags.Flags; import dalvik.system.VMDebug; @@ -55,6 +58,8 @@ import java.util.concurrent.TimeoutException; /** * Tools for managing OS processes. */ +@RavenwoodKeepPartialClass +@RavenwoodRedirectionClass("Process_ravenwood") public class Process { private static final String LOG_TAG = "Process"; @@ -672,7 +677,6 @@ public class Process { */ public static final ZygoteProcess ZYGOTE_PROCESS = new ZygoteProcess(); - /** * The process name set via {@link #setArgV0(String)}. */ @@ -846,47 +850,20 @@ public class Process { /** * Returns true if the current process is a 64-bit runtime. */ - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static final boolean is64Bit() { return VMRuntime.getRuntime().is64Bit(); } - private static volatile ThreadLocal<SomeArgs> sIdentity$ravenwood; - - /** @hide */ - @android.ravenwood.annotation.RavenwoodKeep - public static void init$ravenwood(final int uid, final int pid) { - sIdentity$ravenwood = ThreadLocal.withInitial(() -> { - final SomeArgs args = SomeArgs.obtain(); - args.argi1 = uid; - args.argi2 = pid; - args.argi3 = Long.hashCode(Thread.currentThread().getId()); - args.argi4 = THREAD_PRIORITY_DEFAULT; - args.arg1 = Boolean.TRUE; // backgroundOk - return args; - }); - } - - /** @hide */ - @android.ravenwood.annotation.RavenwoodKeep - public static void reset$ravenwood() { - sIdentity$ravenwood = null; - } - /** * Returns the identifier of this process, which can be used with * {@link #killProcess} and {@link #sendSignal}. */ - @android.ravenwood.annotation.RavenwoodReplace + @RavenwoodKeep public static final int myPid() { return Os.getpid(); } - /** @hide */ - public static final int myPid$ravenwood() { - return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().argi2; - } - /** * Returns the identifier of this process' parent. * @hide @@ -900,39 +877,29 @@ public class Process { * Returns the identifier of the calling thread, which be used with * {@link #setThreadPriority(int, int)}. */ - @android.ravenwood.annotation.RavenwoodReplace + @RavenwoodKeep public static final int myTid() { return Os.gettid(); } - /** @hide */ - public static final int myTid$ravenwood() { - return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().argi3; - } - /** * Returns the identifier of this process's uid. This is the kernel uid * that the process is running under, which is the identity of its * app-specific sandbox. It is different from {@link #myUserHandle} in that * a uid identifies a specific app sandbox in a specific user. */ - @android.ravenwood.annotation.RavenwoodReplace + @RavenwoodKeep public static final int myUid() { return Os.getuid(); } - /** @hide */ - public static final int myUid$ravenwood() { - return Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get().argi1; - } - /** * Returns this process's user handle. This is the * user the process is running under. It is distinct from * {@link #myUid()} in that a particular user will have multiple * distinct apps running under it each with their own uid. */ - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static UserHandle myUserHandle() { return UserHandle.of(UserHandle.getUserId(myUid())); } @@ -941,7 +908,7 @@ public class Process { * Returns whether the given uid belongs to a system core component or not. * @hide */ - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static boolean isCoreUid(int uid) { return UserHandle.isCore(uid); } @@ -952,7 +919,7 @@ public class Process { * @return Whether the uid corresponds to an application sandbox running in * a specific user. */ - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static boolean isApplicationUid(int uid) { return UserHandle.isApp(uid); } @@ -960,7 +927,7 @@ public class Process { /** * Returns whether the current process is in an isolated sandbox. */ - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static final boolean isIsolated() { return isIsolated(myUid()); } @@ -972,7 +939,7 @@ public class Process { @Deprecated @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU, publicAlternatives = "Use {@link #isIsolatedUid(int)} instead.") - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static final boolean isIsolated(int uid) { return isIsolatedUid(uid); } @@ -980,7 +947,7 @@ public class Process { /** * Returns whether the process with the given {@code uid} is an isolated sandbox. */ - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static final boolean isIsolatedUid(int uid) { uid = UserHandle.getAppId(uid); return (uid >= FIRST_ISOLATED_UID && uid <= LAST_ISOLATED_UID) @@ -992,7 +959,7 @@ public class Process { * @see android.app.sdksandbox.SdkSandboxManager */ @SuppressLint("UnflaggedApi") // promoting from @SystemApi. - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static final boolean isSdkSandboxUid(int uid) { uid = UserHandle.getAppId(uid); return (uid >= FIRST_SDK_SANDBOX_UID && uid <= LAST_SDK_SANDBOX_UID); @@ -1008,7 +975,7 @@ public class Process { * @throws IllegalArgumentException if input is not an sdk sandbox uid */ @SuppressLint("UnflaggedApi") // promoting from @SystemApi. - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static final int getAppUidForSdkSandboxUid(int uid) { if (!isSdkSandboxUid(uid)) { throw new IllegalArgumentException("Input UID is not an SDK sandbox UID"); @@ -1024,7 +991,7 @@ public class Process { */ @SystemApi(client = MODULE_LIBRARIES) @TestApi - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep // TODO(b/318651609): Deprecate once Process#getSdkSandboxUidForAppUid is rolled out to 100% public static final int toSdkSandboxUid(int uid) { return uid + (FIRST_SDK_SANDBOX_UID - FIRST_APPLICATION_UID); @@ -1040,7 +1007,7 @@ public class Process { * @throws IllegalArgumentException if input is not an app uid */ @FlaggedApi(Flags.FLAG_SDK_SANDBOX_UID_TO_APP_UID_API) - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static final int getSdkSandboxUidForAppUid(int uid) { if (!isApplicationUid(uid)) { throw new IllegalArgumentException("Input UID is not an app UID"); @@ -1051,7 +1018,7 @@ public class Process { /** * Returns whether the current process is a sdk sandbox process. */ - @android.ravenwood.annotation.RavenwoodKeep + @RavenwoodKeep public static final boolean isSdkSandbox() { return isSdkSandboxUid(myUid()); } @@ -1128,28 +1095,11 @@ public class Process { * not have permission to modify the given thread, or to use the given * priority. */ - @android.ravenwood.annotation.RavenwoodReplace + @RavenwoodRedirect public static final native void setThreadPriority(int tid, @IntRange(from = -20, to = THREAD_PRIORITY_LOWEST) int priority) throws IllegalArgumentException, SecurityException; - /** @hide */ - public static final void setThreadPriority$ravenwood(int tid, int priority) { - final SomeArgs args = - Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get(); - if (args.argi3 == tid) { - boolean backgroundOk = (args.arg1 == Boolean.TRUE); - if (priority >= THREAD_PRIORITY_BACKGROUND && !backgroundOk) { - throw new IllegalArgumentException( - "Priority " + priority + " blocked by setCanSelfBackground()"); - } - args.argi4 = priority; - } else { - throw new UnsupportedOperationException( - "Cross-thread priority management not yet available in Ravenwood"); - } - } - /** * Call with 'false' to cause future calls to {@link #setThreadPriority(int)} to * throw an exception if passed a background-level thread priority. This is only @@ -1157,16 +1107,9 @@ public class Process { * * @hide */ - @android.ravenwood.annotation.RavenwoodReplace + @RavenwoodRedirect public static final native void setCanSelfBackground(boolean backgroundOk); - /** @hide */ - public static final void setCanSelfBackground$ravenwood(boolean backgroundOk) { - final SomeArgs args = - Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get(); - args.arg1 = Boolean.valueOf(backgroundOk); - } - /** * Sets the scheduling group for a thread. * @hide @@ -1295,13 +1238,12 @@ public class Process { * * @see #setThreadPriority(int, int) */ - @android.ravenwood.annotation.RavenwoodReplace + @RavenwoodReplace public static final native void setThreadPriority( @IntRange(from = -20, to = THREAD_PRIORITY_LOWEST) int priority) throws IllegalArgumentException, SecurityException; - /** @hide */ - public static final void setThreadPriority$ravenwood(int priority) { + private static void setThreadPriority$ravenwood(int priority) { setThreadPriority(myTid(), priority); } @@ -1318,23 +1260,11 @@ public class Process { * @throws IllegalArgumentException Throws IllegalArgumentException if * <var>tid</var> does not exist. */ - @android.ravenwood.annotation.RavenwoodReplace + @RavenwoodRedirect @IntRange(from = -20, to = THREAD_PRIORITY_LOWEST) public static final native int getThreadPriority(int tid) throws IllegalArgumentException; - /** @hide */ - public static final int getThreadPriority$ravenwood(int tid) { - final SomeArgs args = - Preconditions.requireNonNullViaRavenwoodRule(sIdentity$ravenwood).get(); - if (args.argi3 == tid) { - return args.argi4; - } else { - throw new UnsupportedOperationException( - "Cross-thread priority management not yet available in Ravenwood"); - } - } - /** * Return the current scheduling policy of a thread, based on Linux. * diff --git a/core/java/android/print/OWNERS b/core/java/android/print/OWNERS index 0809de25b45c..ce79f5d0c669 100644 --- a/core/java/android/print/OWNERS +++ b/core/java/android/print/OWNERS @@ -2,3 +2,4 @@ anothermark@google.com kumarashishg@google.com +bmgordon@google.com diff --git a/core/java/android/printservice/OWNERS b/core/java/android/printservice/OWNERS index 0809de25b45c..ce79f5d0c669 100644 --- a/core/java/android/printservice/OWNERS +++ b/core/java/android/printservice/OWNERS @@ -2,3 +2,4 @@ anothermark@google.com kumarashishg@google.com +bmgordon@google.com diff --git a/core/java/android/service/contextualsearch/OWNERS b/core/java/android/service/contextualsearch/OWNERS index b7238721bc60..c435bd87be21 100644 --- a/core/java/android/service/contextualsearch/OWNERS +++ b/core/java/android/service/contextualsearch/OWNERS @@ -1,2 +1,3 @@ srazdan@google.com -hackz@google.com +hyunyoungs@google.com +awickham@google.com diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java index 8358b9a51adb..1dd9d46fdfb7 100644 --- a/core/java/android/util/Log.java +++ b/core/java/android/util/Log.java @@ -75,8 +75,7 @@ import java.net.UnknownHostException; @android.ravenwood.annotation.RavenwoodClassLoadHook( "com.android.platform.test.ravenwood.runtimehelper.ClassLoadHook.onClassLoaded") // Uncomment the following annotation to switch to the Java substitution version. -//@android.ravenwood.annotation.RavenwoodNativeSubstitutionClass( -// "com.android.platform.test.ravenwood.nativesubstitution.Log_host") +@android.ravenwood.annotation.RavenwoodRedirectionClass("Log_host") public final class Log { /** @hide */ @IntDef({ASSERT, ERROR, WARN, INFO, DEBUG, VERBOSE}) @@ -250,6 +249,7 @@ public final class Log { * tag limit of concern after this API level. */ @FastNative + @android.ravenwood.annotation.RavenwoodRedirect public static native boolean isLoggable(@Nullable String tag, @Level int level); /** @@ -425,6 +425,7 @@ public final class Log { * @hide */ @UnsupportedAppUsage + @android.ravenwood.annotation.RavenwoodRedirect public static native int println_native(int bufID, int priority, String tag, String msg); /** @@ -452,6 +453,7 @@ public final class Log { * Return the maximum payload the log daemon accepts without truncation. * @return LOGGER_ENTRY_MAX_PAYLOAD. */ + @android.ravenwood.annotation.RavenwoodRedirect private static native int logger_entry_max_payload_native(); /** diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java index 69228cafa34b..cd02130fb2f0 100644 --- a/core/java/android/view/HapticFeedbackConstants.java +++ b/core/java/android/view/HapticFeedbackConstants.java @@ -157,7 +157,7 @@ public class HapticFeedbackConstants { /** * The user is executing a swipe/drag-style gesture, such as pull-to-refresh, where the - * gesture action is “eligible” at a certain threshold of movement, and can be cancelled by + * gesture action is "eligible" at a certain threshold of movement, and can be cancelled by * moving back past the threshold. This constant indicates that the user's motion has just * passed the threshold for the action to be activated on release. * @@ -167,7 +167,7 @@ public class HapticFeedbackConstants { /** * The user is executing a swipe/drag-style gesture, such as pull-to-refresh, where the - * gesture action is “eligible” at a certain threshold of movement, and can be cancelled by + * gesture action is "eligible" at a certain threshold of movement, and can be cancelled by * moving back past the threshold. This constant indicates that the user's motion has just * re-crossed back "under" the threshold for the action to be activated, meaning the gesture is * currently in a cancelled state. diff --git a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java index 30b160ab161b..a69d2e4f4dca 100644 --- a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java +++ b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java @@ -28,19 +28,9 @@ import android.ravenwood.annotation.RavenwoodReplace; public final class RavenwoodEnvironment { public static final String TAG = "RavenwoodEnvironment"; - private static final RavenwoodEnvironment sInstance; - private static final Workaround sWorkaround; + private static RavenwoodEnvironment sInstance = new RavenwoodEnvironment(); - private RavenwoodEnvironment() { - } - - static { - sInstance = new RavenwoodEnvironment(); - sWorkaround = new Workaround(); - ensureRavenwoodInitialized(); - } - - public static RuntimeException notSupportedOnDevice() { + private static RuntimeException notSupportedOnDevice() { return new UnsupportedOperationException("This method can only be used on Ravenwood"); } @@ -52,15 +42,6 @@ public final class RavenwoodEnvironment { } /** - * Initialize the ravenwood environment if it hasn't happened already, if running on Ravenwood. - * - * No-op if called on the device side. - */ - @RavenwoodRedirect - public static void ensureRavenwoodInitialized() { - } - - /** * USE IT SPARINGLY! Returns true if it's running on Ravenwood, hostside test environment. * * <p>Using this allows code to behave differently on a real device and on Ravenwood, but @@ -91,38 +72,10 @@ public final class RavenwoodEnvironment { } /** - * See {@link Workaround}. It's only usable on Ravenwood. - */ - @RavenwoodReplace - public static Workaround workaround() { - throw notSupportedOnDevice(); - } - - private static Workaround workaround$ravenwood() { - return sWorkaround; - } - - /** * @return the "ravenwood-runtime" directory. */ @RavenwoodRedirect public String getRavenwoodRuntimePath() { throw notSupportedOnDevice(); } - - /** - * A set of APIs used to work around missing features on Ravenwood. Ideally, this class should - * be empty, and all its APIs should be able to be implemented properly. - */ - public static class Workaround { - Workaround() { - } - - /** - * @return whether the app's target SDK level is at least Q. - */ - public boolean isTargetSdkAtLeastQ() { - return true; - } - } } diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index 3a19f466f7c1..96edd63a9b12 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -23,6 +23,7 @@ import static android.media.codec.Flags.FLAG_HLG_EDITING; import static android.media.codec.Flags.FLAG_IN_PROCESS_SW_AUDIO_CODEC; import static android.media.codec.Flags.FLAG_NULL_OUTPUT_SURFACE; import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST; +import static android.media.codec.Flags.FLAG_APV_SUPPORT; import static android.media.MediaCodec.GetFlag; import android.annotation.FlaggedApi; @@ -4496,6 +4497,265 @@ public final class MediaCodecInfo { @SuppressLint("AllUpper") public static final int AC4Level4 = 0x10; + // Profiles and levels/bands for APV Codec, corresponding to the definitions in + // "Advanced Professional Video", 10.1.3 Profiles, 10.1.4 Levels and Bands + // found at https://www.ietf.org/archive/id/draft-lim-apv-02.html + + /** + * APV codec profile 422-10 as per IETF lim-apv-02, 10.1.3.1.1 + */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVProfile422_10 = 0x01; + + /** + * APV codec profile 422-10 as per IETF lim-apv-02, 10.1.3.1.1 + * with HDR10. + */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVProfile422_10HDR10 = 0x1000; + + /** + * APV codec profile 422-10 as per IETF lim-apv-02, 10.1.3.1.1 + * with HDR10Plus. + */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVProfile422_10HDR10Plus = 0x2000; + + // For APV Levels, the numerical values are constructed as follows: + // ((0x100 << (level_num - 1)) | (1 << band)) + // where: + // - "level_num" is the APV Level numbered consecutively + // (i.e., Level 1 == 1, Level 1.1 == 2, etc.) + // - "band" is the APV Band + + /** APV Codec Level 1, Band 0 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel1Band0 = 0x101; + /** APV Codec Level 1, Band 1 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel1Band1 = 0x102; + /** APV Codec Level 1, Band 2 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel1Band2 = 0x104; + /** APV Codec Level 1, Band 3 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel1Band3 = 0x108; + /** APV Codec Level 1.1, Band 0 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel11Band0 = 0x201; + /** APV Codec Level 1.1, Band 1 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel11Band1 = 0x202; + /** APV Codec Level 1.1, Band 2 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel11Band2 = 0x204; + /** APV Codec Level 1.1, Band 3 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel11Band3 = 0x208; + /** APV Codec Level 2, Band 0 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel2Band0 = 0x401; + /** APV Codec Level 2, Band 1 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel2Band1 = 0x402; + /** APV Codec Level 2, Band 2 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel2Band2 = 0x404; + /** APV Codec Level 2, Band 3 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel2Band3 = 0x408; + /** APV Codec Level 2.1, Band 0 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel21Band0 = 0x801; + /** APV Codec Level 2.1, Band 1 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel21Band1 = 0x802; + /** APV Codec Level 2.1, Band 2 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel21Band2 = 0x804; + /** APV Codec Level 2.1, Band 3 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel21Band3 = 0x808; + /** APV Codec Level 3, Band 0 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel3Band0 = 0x1001; + /** APV Codec Level 3, Band 1 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel3Band1 = 0x1002; + /** APV Codec Level 3, Band 2 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel3Band2 = 0x1004; + /** APV Codec Level 3, Band 3 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel3Band3 = 0x1008; + /** APV Codec Level 3.1, Band 0 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel31Band0 = 0x2001; + /** APV Codec Level 3.1, Band 1 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel31Band1 = 0x2002; + /** APV Codec Level 3.1, Band 2 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel31Band2 = 0x2004; + /** APV Codec Level 3.1, Band 3 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel31Band3 = 0x2008; + /** APV Codec Level 4, Band 0 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel4Band0 = 0x4001; + /** APV Codec Level 4, Band 1 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel4Band1 = 0x4002; + /** APV Codec Level 4, Band 2 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel4Band2 = 0x4004; + /** APV Codec Level 4, Band 3 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel4Band3 = 0x4008; + /** APV Codec Level 4.1, Band 0 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel41Band0 = 0x8001; + /** APV Codec Level 4.1, Band 1 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel41Band1 = 0x8002; + /** APV Codec Level 4.1, Band 2 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel41Band2 = 0x8004; + /** APV Codec Level 4.1, Band 3 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel41Band3 = 0x8008; + /** APV Codec Level 5, Band 0 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel5Band0 = 0x10001; + /** APV Codec Level 5, Band 1 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel5Band1 = 0x10002; + /** APV Codec Level 5, Band 2 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel5Band2 = 0x10004; + /** APV Codec Level 5, Band 3 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel5Band3 = 0x10008; + /** APV Codec Level 5.1, Band 0 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel51Band0 = 0x20001; + /** APV Codec Level 5.1, Band 1 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel51Band1 = 0x20002; + /** APV Codec Level 5.1, Band 2 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel51Band2 = 0x20004; + /** APV Codec Level 5.1, Band 3 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel51Band3 = 0x20008; + /** APV Codec Level 6, Band 0 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel6Band0 = 0x40001; + /** APV Codec Level 6, Band 1 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel6Band1 = 0x40002; + /** APV Codec Level 6, Band 2 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel6Band2 = 0x40004; + /** APV Codec Level 6, Band 3 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel6Band3 = 0x40008; + /** APV Codec Level 6.1, Band 0 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel61Band0 = 0x80001; + /** APV Codec Level 6.1, Band 1 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel61Band1 = 0x80002; + /** APV Codec Level 6.1, Band 2 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel61Band2 = 0x80004; + /** APV Codec Level 6.1, Band 3 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel61Band3 = 0x80008; + /** APV Codec Level 7, Band 0 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel7Band0 = 0x100001; + /** APV Codec Level 7, Band 1 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel7Band1 = 0x100002; + /** APV Codec Level 7, Band 2 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel7Band2 = 0x100004; + /** APV Codec Level 7, Band 3 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel7Band3 = 0x100008; + /** APV Codec Level 7.1, Band 0 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel71Band0 = 0x200001; + /** APV Codec Level 7.1, Band 1 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel71Band1 = 0x200002; + /** APV Codec Level 7.1, Band 2 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel71Band2 = 0x200004; + /** APV Codec Level 7.1, Band 3 as per IETF lim-apv-02, 10.1.4 */ + @SuppressLint("AllUpper") + @FlaggedApi(FLAG_APV_SUPPORT) + public static final int APVLevel71Band3 = 0x200008; + /** * The profile of the media content. Depending on the type of media this can be * one of the profile values defined in this class. diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java index cd0654ceb348..b08a86ee8f46 100644 --- a/media/java/android/media/MediaFormat.java +++ b/media/java/android/media/MediaFormat.java @@ -18,6 +18,7 @@ package android.media; import static android.media.codec.Flags.FLAG_IN_PROCESS_SW_AUDIO_CODEC; import static android.media.codec.Flags.FLAG_REGION_OF_INTEREST; +import static android.media.codec.Flags.FLAG_APV_SUPPORT; import static com.android.media.codec.flags.Flags.FLAG_CODEC_IMPORTANCE; import static com.android.media.codec.flags.Flags.FLAG_LARGE_AUDIO_FRAME; @@ -157,6 +158,8 @@ import java.util.stream.Collectors; public final class MediaFormat { public static final String MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8"; public static final String MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9"; + @FlaggedApi(FLAG_APV_SUPPORT) + public static final String MIMETYPE_VIDEO_APV = "video/apv"; public static final String MIMETYPE_VIDEO_AV1 = "video/av01"; public static final String MIMETYPE_VIDEO_AVC = "video/avc"; public static final String MIMETYPE_VIDEO_HEVC = "video/hevc"; diff --git a/media/java/android/media/audiofx/Equalizer.java b/media/java/android/media/audiofx/Equalizer.java index 7abada07181d..09863450a717 100644 --- a/media/java/android/media/audiofx/Equalizer.java +++ b/media/java/android/media/audiofx/Equalizer.java @@ -153,9 +153,8 @@ public class Equalizer extends AudioEffect { param[0] = PARAM_GET_PRESET_NAME; for (int i = 0; i < mNumPresets; i++) { param[1] = i; - checkStatus(getParameter(param, value)); - int length = 0; - while (value[length] != 0) length++; + final int length = getParameter(param, value); + checkStatus(length); try { mPresetNames[i] = new String(value, 0, length, "ISO-8859-1"); } catch (java.io.UnsupportedEncodingException e) { diff --git a/media/java/android/media/flags/editing.aconfig b/media/java/android/media/flags/editing.aconfig index 185f579df4b9..0adc4783445a 100644 --- a/media/java/android/media/flags/editing.aconfig +++ b/media/java/android/media/flags/editing.aconfig @@ -15,3 +15,10 @@ flag { description: "Enable B frames for Stagefright recorder." bug: "341121900" } + +flag { + name: "muxer_mp4_enable_apv" + namespace: "media_solutions" + description: "Enable APV support in mp4 writer." + bug: "370061501" +} diff --git a/media/java/android/mtp/OWNERS b/media/java/android/mtp/OWNERS index 6b5336e83bdc..77ed08b1f9a5 100644 --- a/media/java/android/mtp/OWNERS +++ b/media/java/android/mtp/OWNERS @@ -1,10 +1,9 @@ set noparent -aprasath@google.com anothermark@google.com -kumarashishg@google.com -sarup@google.com +febinthattil@google.com +aprasath@google.com jsharkey@android.com jameswei@google.com rmojumder@google.com - +kumarashishg@google.com diff --git a/media/tests/MtpTests/OWNERS b/media/tests/MtpTests/OWNERS index 6b5336e83bdc..bdb6cdbea332 100644 --- a/media/tests/MtpTests/OWNERS +++ b/media/tests/MtpTests/OWNERS @@ -1,10 +1,9 @@ set noparent -aprasath@google.com anothermark@google.com -kumarashishg@google.com -sarup@google.com +febinthattil@google.com +aprasath@google.com jsharkey@android.com jameswei@google.com rmojumder@google.com - +kumarashishg@google.com
\ No newline at end of file diff --git a/nfc/api/current.txt b/nfc/api/current.txt index 96b7c1339190..008120429c40 100644 --- a/nfc/api/current.txt +++ b/nfc/api/current.txt @@ -207,6 +207,7 @@ package android.nfc.cardemulation { method public boolean isDefaultServiceForCategory(android.content.ComponentName, String); method @FlaggedApi("android.nfc.enable_card_emulation_euicc") public boolean isEuiccSupported(); method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>); + method @FlaggedApi("android.nfc.nfc_event_listener") public void registerNfcEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.cardemulation.CardEmulation.NfcEventListener); method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String, boolean); method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopPatternFilterForService(@NonNull android.content.ComponentName, @NonNull String, boolean); method public boolean removeAidsForService(android.content.ComponentName, String); @@ -216,6 +217,7 @@ package android.nfc.cardemulation { method public boolean setPreferredService(android.app.Activity, android.content.ComponentName); method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setShouldDefaultToObserveModeForService(@NonNull android.content.ComponentName, boolean); method public boolean supportsAidPrefixRegistration(); + method @FlaggedApi("android.nfc.nfc_event_listener") public void unregisterNfcEventListener(@NonNull android.nfc.cardemulation.CardEmulation.NfcEventListener); method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean unsetOffHostForService(@NonNull android.content.ComponentName); method public boolean unsetPreferredService(android.app.Activity); field @Deprecated public static final String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT"; @@ -233,13 +235,16 @@ package android.nfc.cardemulation { field public static final int SELECTION_MODE_PREFER_DEFAULT = 0; // 0x0 } + @FlaggedApi("android.nfc.nfc_event_listener") public static interface CardEmulation.NfcEventListener { + method @FlaggedApi("android.nfc.nfc_event_listener") public default void onObserveModeStateChanged(boolean); + method @FlaggedApi("android.nfc.nfc_event_listener") public default void onPreferredServiceChanged(boolean); + } + public abstract class HostApduService extends android.app.Service { ctor public HostApduService(); method public final void notifyUnhandled(); method public final android.os.IBinder onBind(android.content.Intent); method public abstract void onDeactivated(int); - method @FlaggedApi("android.nfc.nfc_event_listener") public void onObserveModeStateChanged(boolean); - method @FlaggedApi("android.nfc.nfc_event_listener") public void onPreferredServiceChanged(boolean); method public abstract byte[] processCommandApdu(byte[], android.os.Bundle); method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void processPollingFrames(@NonNull java.util.List<android.nfc.cardemulation.PollingFrame>); method public final void sendResponseApdu(byte[]); diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt index 24e14e69637b..6aa8a2b73f2c 100644 --- a/nfc/api/system-current.txt +++ b/nfc/api/system-current.txt @@ -91,6 +91,7 @@ package android.nfc { method public void onDisable(@NonNull java.util.function.Consumer<java.lang.Boolean>); method public void onDisableFinished(int); method public void onDisableStarted(); + method public void onEeListenActivated(boolean); method public void onEnable(@NonNull java.util.function.Consumer<java.lang.Boolean>); method public void onEnableFinished(int); method public void onEnableStarted(); @@ -105,7 +106,7 @@ package android.nfc { method public void onRfFieldActivated(boolean); method public void onRoutingChanged(); method public void onStateUpdated(int); - method public void onTagConnected(boolean, @NonNull android.nfc.Tag); + method public void onTagConnected(boolean); method public void onTagDispatch(@NonNull java.util.function.Consumer<java.lang.Boolean>); } diff --git a/services/core/java/com/android/server/integrity/serializer/RuleSerializeException.java b/nfc/java/android/nfc/ComponentNameAndUser.aidl index 60cfc4876414..e677998a7970 100644 --- a/services/core/java/com/android/server/integrity/serializer/RuleSerializeException.java +++ b/nfc/java/android/nfc/ComponentNameAndUser.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * 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. @@ -14,19 +14,6 @@ * limitations under the License. */ -package com.android.server.integrity.serializer; +package android.nfc; -import android.annotation.NonNull; - -/** - * Thrown when rule serialization fails. - */ -public class RuleSerializeException extends Exception { - public RuleSerializeException(@NonNull String message) { - super(message); - } - - public RuleSerializeException(@NonNull String message, @NonNull Throwable cause) { - super(message, cause); - } -} +parcelable ComponentNameAndUser;
\ No newline at end of file diff --git a/nfc/java/android/nfc/ComponentNameAndUser.java b/nfc/java/android/nfc/ComponentNameAndUser.java new file mode 100644 index 000000000000..59e6c62926c9 --- /dev/null +++ b/nfc/java/android/nfc/ComponentNameAndUser.java @@ -0,0 +1,100 @@ +/* + * 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 android.nfc; + +import android.annotation.UserIdInt; +import android.content.ComponentName; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * @hide + */ +public class ComponentNameAndUser implements Parcelable { + @UserIdInt private final int mUserId; + private ComponentName mComponentName; + + public ComponentNameAndUser(@UserIdInt int userId, ComponentName componentName) { + mUserId = userId; + mComponentName = componentName; + } + + /** + * @hide + */ + public int describeContents() { + return 0; + } + + /** + * @hide + */ + public void writeToParcel(Parcel out, int flags) { + out.writeInt(mUserId); + out.writeParcelable(mComponentName, flags); + } + + public static final Parcelable.Creator<ComponentNameAndUser> CREATOR = + new Parcelable.Creator<ComponentNameAndUser>() { + public ComponentNameAndUser createFromParcel(Parcel in) { + return new ComponentNameAndUser(in); + } + + public ComponentNameAndUser[] newArray(int size) { + return new ComponentNameAndUser[size]; + } + }; + + private ComponentNameAndUser(Parcel in) { + mUserId = in.readInt(); + mComponentName = in.readParcelable(null, ComponentName.class); + } + + @UserIdInt + public int getUserId() { + return mUserId; + } + + public ComponentName getComponentName() { + return mComponentName; + } + + @Override + public String toString() { + return mComponentName + " for user id: " + mUserId; + } + + @Override + public boolean equals(Object obj) { + if (obj != null && obj instanceof ComponentNameAndUser) { + ComponentNameAndUser other = (ComponentNameAndUser) obj; + return other.getUserId() == mUserId + && Objects.equals(other.getComponentName(), mComponentName); + } + return false; + } + + @Override + public int hashCode() { + if (mComponentName == null) { + return mUserId; + } + return mComponentName.hashCode() + mUserId; + } +} diff --git a/nfc/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl index 8535e4a9cfd2..5e2e92d958a4 100644 --- a/nfc/java/android/nfc/INfcCardEmulation.aidl +++ b/nfc/java/android/nfc/INfcCardEmulation.aidl @@ -17,6 +17,8 @@ package android.nfc; import android.content.ComponentName; +import android.nfc.INfcEventListener; + import android.nfc.cardemulation.AidGroup; import android.nfc.cardemulation.ApduServiceInfo; import android.os.RemoteCallback; @@ -55,4 +57,7 @@ interface INfcCardEmulation boolean isAutoChangeEnabled(); List<String> getRoutingStatus(); void overwriteRoutingTable(int userHandle, String emptyAid, String protocol, String tech, String sc); + + void registerNfcEventListener(in INfcEventListener listener); + void unregisterNfcEventListener(in INfcEventListener listener); } diff --git a/nfc/java/android/nfc/INfcEventListener.aidl b/nfc/java/android/nfc/INfcEventListener.aidl new file mode 100644 index 000000000000..5162c26ac536 --- /dev/null +++ b/nfc/java/android/nfc/INfcEventListener.aidl @@ -0,0 +1,11 @@ +package android.nfc; + +import android.nfc.ComponentNameAndUser; + +/** + * @hide + */ +oneway interface INfcEventListener { + void onPreferredServiceChanged(in ComponentNameAndUser ComponentNameAndUser); + void onObserveModeStateChanged(boolean isEnabled); +}
\ No newline at end of file diff --git a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl index 48c7ee659266..7f1fd15fe68a 100644 --- a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl +++ b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl @@ -27,7 +27,7 @@ import java.util.List; * @hide */ interface INfcOemExtensionCallback { - void onTagConnected(boolean connected, in Tag tag); + void onTagConnected(boolean connected); void onStateUpdated(int state); void onApplyRouting(in ResultReceiver isSkipped); void onNdefRead(in ResultReceiver isSkipped); @@ -46,6 +46,7 @@ interface INfcOemExtensionCallback { void onCardEmulationActivated(boolean isActivated); void onRfFieldActivated(boolean isActivated); void onRfDiscoveryStarted(boolean isDiscoveryStarted); + void onEeListenActivated(boolean isActivated); void onGetOemAppSearchIntent(in List<String> firstPackage, in ResultReceiver intentConsumer); void onNdefMessage(in Tag tag, in NdefMessage message, in ResultReceiver hasOemExecutableContent); void onLaunchHceAppChooserActivity(in String selectedAid, in List<ApduServiceInfo> services, in ComponentName failedComponent, in String category); diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java index 520ba896f01f..1d2085c88213 100644 --- a/nfc/java/android/nfc/NfcOemExtension.java +++ b/nfc/java/android/nfc/NfcOemExtension.java @@ -80,6 +80,14 @@ public final class NfcOemExtension { private boolean mCardEmulationActivated = false; private boolean mRfFieldActivated = false; private boolean mRfDiscoveryStarted = false; + private boolean mEeListenActivated = false; + + /** + * Broadcast Action: Sent on NFC stack initialization when NFC OEM extensions are enabled. + * <p> OEM extension modules should use this intent to start their extension service </p> + * @hide + */ + public static final String ACTION_OEM_EXTENSION_INIT = "android.nfc.action.OEM_EXTENSION_INIT"; /** * Mode Type for {@link #setControllerAlwaysOnMode(int)}. @@ -188,9 +196,8 @@ public final class NfcOemExtension { * ex - if tag is connected notify cover and Nfctest app if app is in testing mode * * @param connected status of the tag true if tag is connected otherwise false - * @param tag Tag details */ - void onTagConnected(boolean connected, @NonNull Tag tag); + void onTagConnected(boolean connected); /** * Update the Nfc Adapter State @@ -320,6 +327,13 @@ public final class NfcOemExtension { void onRfDiscoveryStarted(boolean isDiscoveryStarted); /** + * Notifies the NFCEE (NFC Execution Environment) Listen has been activated. + * + * @param isActivated true, if EE Listen is ON, else EE Listen is OFF. + */ + void onEeListenActivated(boolean isActivated); + + /** * Gets the intent to find the OEM package in the OEM App market. If the consumer returns * {@code null} or a timeout occurs, the intent from the first available package will be * used instead. @@ -430,6 +444,7 @@ public final class NfcOemExtension { callback.onCardEmulationActivated(mCardEmulationActivated); callback.onRfFieldActivated(mRfFieldActivated); callback.onRfDiscoveryStarted(mRfDiscoveryStarted); + callback.onEeListenActivated(mEeListenActivated); }); } } @@ -677,9 +692,9 @@ public final class NfcOemExtension { private final class NfcOemExtensionCallback extends INfcOemExtensionCallback.Stub { @Override - public void onTagConnected(boolean connected, Tag tag) throws RemoteException { + public void onTagConnected(boolean connected) throws RemoteException { mCallbackMap.forEach((cb, ex) -> - handleVoid2ArgCallback(connected, tag, cb::onTagConnected, ex)); + handleVoidCallback(connected, cb::onTagConnected, ex)); } @Override @@ -704,6 +719,13 @@ public final class NfcOemExtension { } @Override + public void onEeListenActivated(boolean isActivated) throws RemoteException { + mEeListenActivated = isActivated; + mCallbackMap.forEach((cb, ex) -> + handleVoidCallback(isActivated, cb::onEeListenActivated, ex)); + } + + @Override public void onStateUpdated(int state) throws RemoteException { mCallbackMap.forEach((cb, ex) -> handleVoidCallback(state, cb::onStateUpdated, ex)); diff --git a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java index 5727f9915fa8..3d293f7546a5 100644 --- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java +++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java @@ -52,10 +52,12 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.TreeMap; import java.util.regex.Pattern; /** @@ -181,7 +183,8 @@ public final class ApduServiceInfo implements Parcelable { this(info, onHost, description, staticAidGroups, dynamicAidGroups, requiresUnlock, requiresScreenOn, bannerResource, uid, settingsActivityName, offHost, staticOffHost, isEnabled, - new HashMap<String, Boolean>(), new HashMap<Pattern, Boolean>()); + new HashMap<String, Boolean>(), new TreeMap<>( + Comparator.comparing(Pattern::toString))); } /** @@ -317,7 +320,8 @@ public final class ApduServiceInfo implements Parcelable { mStaticAidGroups = new HashMap<String, AidGroup>(); mDynamicAidGroups = new HashMap<String, AidGroup>(); mAutoTransact = new HashMap<String, Boolean>(); - mAutoTransactPatterns = new HashMap<Pattern, Boolean>(); + mAutoTransactPatterns = new TreeMap<Pattern, Boolean>( + Comparator.comparing(Pattern::toString)); mOnHost = onHost; final int depth = parser.getDepth(); diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java index d8f04c50b695..eb28c3b9c930 100644 --- a/nfc/java/android/nfc/cardemulation/CardEmulation.java +++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java @@ -17,6 +17,7 @@ package android.nfc.cardemulation; import android.Manifest; +import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; @@ -33,15 +34,18 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.nfc.ComponentNameAndUser; import android.nfc.Constants; import android.nfc.Flags; import android.nfc.INfcCardEmulation; +import android.nfc.INfcEventListener; import android.nfc.NfcAdapter; import android.os.Build; import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; +import android.util.ArrayMap; import android.util.Log; import java.lang.annotation.Retention; @@ -50,6 +54,8 @@ import java.util.HashMap; import java.util.HexFormat; import java.util.List; import java.util.Locale; +import java.util.Objects; +import java.util.concurrent.Executor; import java.util.regex.Pattern; /** @@ -1076,4 +1082,107 @@ public final class CardEmulation { default -> throw new IllegalStateException("Unexpected value: " + route); }; } + + /** Listener for preferred service state changes. */ + @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) + public interface NfcEventListener { + /** + * This method is called when this package gains or loses preferred Nfc service status, + * either the Default Wallet Role holder (see {@link + * android.app.role.RoleManager#ROLE_WALLET}) or the preferred service of the foreground + * activity set with {@link #setPreferredService(Activity, ComponentName)} + * + * @param isPreferred true is this service has become the preferred Nfc service, false if it + * is no longer the preferred service + */ + @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) + default void onPreferredServiceChanged(boolean isPreferred) {} + + /** + * This method is called when observe mode has been enabled or disabled. + * + * @param isEnabled true if observe mode has been enabled, false if it has been disabled + */ + @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) + default void onObserveModeStateChanged(boolean isEnabled) {} + } + + private final ArrayMap<NfcEventListener, Executor> mNfcEventListeners = new ArrayMap<>(); + + final INfcEventListener mINfcEventListener = + new INfcEventListener.Stub() { + public void onPreferredServiceChanged(ComponentNameAndUser componentNameAndUser) { + if (!android.nfc.Flags.nfcEventListener()) { + return; + } + boolean isPreferred = + componentNameAndUser != null + && componentNameAndUser.getUserId() + == mContext.getUser().getIdentifier() + && componentNameAndUser.getComponentName() != null + && Objects.equals( + mContext.getPackageName(), + componentNameAndUser.getComponentName() + .getPackageName()); + synchronized (mNfcEventListeners) { + mNfcEventListeners.forEach( + (listener, executor) -> { + executor.execute( + () -> listener.onPreferredServiceChanged(isPreferred)); + }); + } + } + + public void onObserveModeStateChanged(boolean isEnabled) { + if (!android.nfc.Flags.nfcEventListener()) { + return; + } + synchronized (mNfcEventListeners) { + mNfcEventListeners.forEach( + (listener, executor) -> { + executor.execute( + () -> listener.onObserveModeStateChanged(isEnabled)); + }); + } + } + }; + + /** + * Register a listener for NFC Events. + * + * @param executor The Executor to run the call back with + * @param listener The listener to register + */ + @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) + public void registerNfcEventListener( + @NonNull @CallbackExecutor Executor executor, @NonNull NfcEventListener listener) { + if (!android.nfc.Flags.nfcEventListener()) { + return; + } + synchronized (mNfcEventListeners) { + mNfcEventListeners.put(listener, executor); + if (mNfcEventListeners.size() == 1) { + callService(() -> sService.registerNfcEventListener(mINfcEventListener)); + } + } + } + + /** + * Unregister a preferred service listener that was previously registered with {@link + * #registerNfcEventListener(Executor, NfcEventListener)} + * + * @param listener The previously registered listener to unregister + */ + @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) + public void unregisterNfcEventListener(@NonNull NfcEventListener listener) { + if (!android.nfc.Flags.nfcEventListener()) { + return; + } + synchronized (mNfcEventListeners) { + mNfcEventListeners.remove(listener); + if (mNfcEventListeners.size() == 0) { + callService(() -> sService.unregisterNfcEventListener(mINfcEventListener)); + } + } + } } diff --git a/nfc/java/android/nfc/cardemulation/HostApduService.java b/nfc/java/android/nfc/cardemulation/HostApduService.java index cd8e19c54565..4f601f0704b4 100644 --- a/nfc/java/android/nfc/cardemulation/HostApduService.java +++ b/nfc/java/android/nfc/cardemulation/HostApduService.java @@ -239,15 +239,6 @@ public abstract class HostApduService extends Service { */ public static final int MSG_POLLING_LOOP = 4; - /** - * @hide - */ - public static final int MSG_OBSERVE_MODE_CHANGE = 5; - - /** - * @hide - */ - public static final int MSG_PREFERRED_SERVICE_CHANGED = 6; /** * @hide @@ -343,16 +334,6 @@ public abstract class HostApduService extends Service { processPollingFrames(pollingFrames); } break; - case MSG_OBSERVE_MODE_CHANGE: - if (android.nfc.Flags.nfcEventListener()) { - onObserveModeStateChanged(msg.arg1 == 1); - } - break; - case MSG_PREFERRED_SERVICE_CHANGED: - if (android.nfc.Flags.nfcEventListener()) { - onPreferredServiceChanged(msg.arg1 == 1); - } - break; default: super.handleMessage(msg); } @@ -462,25 +443,4 @@ public abstract class HostApduService extends Service { */ public abstract void onDeactivated(int reason); - - /** - * This method is called when this service is the preferred Nfc service and - * Observe mode has been enabled or disabled. - * - * @param isEnabled true if observe mode has been enabled, false if it has been disabled - */ - @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) - public void onObserveModeStateChanged(boolean isEnabled) { - - } - - /** - * This method is called when this service gains or loses preferred Nfc service status. - * - * @param isPreferred true is this service has become the preferred Nfc service, - * false if it is no longer the preferred service - */ - @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER) - public void onPreferredServiceChanged(boolean isPreferred) { - } } diff --git a/nfc/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig index 6a7e6939e773..34f020012d3c 100644 --- a/nfc/java/android/nfc/flags.aconfig +++ b/nfc/java/android/nfc/flags.aconfig @@ -165,3 +165,11 @@ flag { description: "Enabling security log for nfc state change" bug: "319934052" } + +flag { + name: "nfc_associated_role_services" + is_exported: true + namespace: "nfc" + description: "Share wallet role routing priority with associated services" + bug: "366243361" +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/OWNERS b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/OWNERS new file mode 100644 index 000000000000..a2001e66e55b --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/OWNERS @@ -0,0 +1 @@ +include /core/java/android/view/accessibility/OWNERS
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt index 349236551ecf..b2fcc434630c 100644 --- a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt +++ b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt @@ -45,7 +45,7 @@ open class DumpManager @Inject constructor() { /** See [registerCriticalDumpable]. */ fun registerCriticalDumpable(module: Dumpable) { - registerCriticalDumpable(module::class.java.canonicalName, module) + registerCriticalDumpable(module::class.java.name, module) } /** @@ -62,7 +62,7 @@ open class DumpManager @Inject constructor() { /** See [registerNormalDumpable]. */ fun registerNormalDumpable(module: Dumpable) { - registerNormalDumpable(module::class.java.canonicalName, module) + registerNormalDumpable(module::class.java.name, module) } /** @@ -104,13 +104,10 @@ open class DumpManager @Inject constructor() { dumpables[name] = DumpableEntry(module, name, priority) } - /** - * Same as the above override, but automatically uses the canonical class name as the dumpable - * name. - */ + /** Same as the above override, but automatically uses the class name as the dumpable name. */ @Synchronized fun registerDumpable(module: Dumpable) { - registerDumpable(module::class.java.canonicalName, module) + registerDumpable(module::class.java.name, module) } /** Unregisters a previously-registered dumpable. */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt index 6d5226f35e97..08881a08b511 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/dump/DumpManagerTest.kt @@ -22,6 +22,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.log.LogBuffer import com.android.systemui.log.table.TableLogBuffer import com.google.common.truth.Truth.assertThat +import java.io.PrintWriter import org.junit.Assert.assertThrows import org.junit.Before import org.junit.Test @@ -131,6 +132,21 @@ class DumpManagerTest : SysuiTestCase() { } @Test + fun registerDumpable_supportsAnonymousDumpables() { + val anonDumpable = + object : Dumpable { + override fun dump(pw: PrintWriter, args: Array<out String>) { + pw.println("AnonDumpable") + } + } + + // THEN registration with implicit names should succeed + dumpManager.registerCriticalDumpable(anonDumpable) + + // No exception thrown + } + + @Test fun getDumpables_returnsSafeCollection() { // GIVEN a variety of registered dumpables dumpManager.registerCriticalDumpable("dumpable1", dumpable1) diff --git a/packages/overlays/Android.bp b/packages/overlays/Android.bp index 5075f6322d1b..44abb9ffb34f 100644 --- a/packages/overlays/Android.bp +++ b/packages/overlays/Android.bp @@ -21,6 +21,7 @@ package { phony { name: "frameworks-base-overlays", + product_specific: true, required: [ "DisplayCutoutEmulationCornerOverlay", "DisplayCutoutEmulationDoubleOverlay", diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp index 65ea9fe3a496..4731cfbfc935 100644 --- a/ravenwood/Android.bp +++ b/ravenwood/Android.bp @@ -279,6 +279,15 @@ cc_defaults { shared_libs: [ "liblog", ], + visibility: ["//visibility:private"], +} + +cc_library_host_shared { + name: "libravenwood_initializer", + defaults: ["ravenwood_jni_defaults"], + srcs: [ + "runtime-jni/ravenwood_initializer.cpp", + ], } // We need this as a separate library because we need to overload the @@ -301,7 +310,6 @@ cc_library_host_shared { "libutils", "libcutils", ], - visibility: ["//frameworks/base"], } // For collecting the *stats.csv files in a known directory under out/host/linux-x86/testcases/. @@ -360,6 +368,239 @@ java_library { ], } +filegroup { + name: "ravenwood-data", + device_common_srcs: [ + ":system-build.prop", + ":framework-res", + ":ravenwood-empty-res", + ":framework-platform-compat-config", + ":services-platform-compat-config", + ], + device_first_srcs: [ + ":apex_icu.dat", + ], + visibility: ["//visibility:private"], +} + +// Keep in sync with build/make/target/product/generic/Android.bp +filegroup { + name: "ravenwood-fonts", + device_common_srcs: [ + ":AndroidClock.ttf", + ":CarroisGothicSC-Regular.ttf", + ":ComingSoon.ttf", + ":CutiveMono.ttf", + ":DancingScript-Regular.ttf", + ":DroidSansMono.ttf", + ":NotoColorEmoji.ttf", + ":NotoColorEmojiFlags.ttf", + ":NotoNaskhArabic-Bold.ttf", + ":NotoNaskhArabic-Regular.ttf", + ":NotoNaskhArabicUI-Bold.ttf", + ":NotoNaskhArabicUI-Regular.ttf", + ":NotoSansAdlam-VF.ttf", + ":NotoSansAhom-Regular.otf", + ":NotoSansAnatolianHieroglyphs-Regular.otf", + ":NotoSansArmenian-VF.ttf", + ":NotoSansAvestan-Regular.ttf", + ":NotoSansBalinese-Regular.ttf", + ":NotoSansBamum-Regular.ttf", + ":NotoSansBassaVah-Regular.otf", + ":NotoSansBatak-Regular.ttf", + ":NotoSansBengali-VF.ttf", + ":NotoSansBengaliUI-VF.ttf", + ":NotoSansBhaiksuki-Regular.otf", + ":NotoSansBrahmi-Regular.ttf", + ":NotoSansBuginese-Regular.ttf", + ":NotoSansBuhid-Regular.ttf", + ":NotoSansCJK-Regular.ttc", + ":NotoSansCanadianAboriginal-Regular.ttf", + ":NotoSansCarian-Regular.ttf", + ":NotoSansChakma-Regular.otf", + ":NotoSansCham-Bold.ttf", + ":NotoSansCham-Regular.ttf", + ":NotoSansCherokee-Regular.ttf", + ":NotoSansCoptic-Regular.ttf", + ":NotoSansCuneiform-Regular.ttf", + ":NotoSansCypriot-Regular.ttf", + ":NotoSansDeseret-Regular.ttf", + ":NotoSansDevanagari-VF.ttf", + ":NotoSansDevanagariUI-VF.ttf", + ":NotoSansEgyptianHieroglyphs-Regular.ttf", + ":NotoSansElbasan-Regular.otf", + ":NotoSansEthiopic-VF.ttf", + ":NotoSansGeorgian-VF.ttf", + ":NotoSansGlagolitic-Regular.ttf", + ":NotoSansGothic-Regular.ttf", + ":NotoSansGrantha-Regular.ttf", + ":NotoSansGujarati-Bold.ttf", + ":NotoSansGujarati-Regular.ttf", + ":NotoSansGujaratiUI-Bold.ttf", + ":NotoSansGujaratiUI-Regular.ttf", + ":NotoSansGunjalaGondi-Regular.otf", + ":NotoSansGurmukhi-VF.ttf", + ":NotoSansGurmukhiUI-VF.ttf", + ":NotoSansHanifiRohingya-Regular.otf", + ":NotoSansHanunoo-Regular.ttf", + ":NotoSansHatran-Regular.otf", + ":NotoSansHebrew-Bold.ttf", + ":NotoSansHebrew-Regular.ttf", + ":NotoSansImperialAramaic-Regular.ttf", + ":NotoSansInscriptionalPahlavi-Regular.ttf", + ":NotoSansInscriptionalParthian-Regular.ttf", + ":NotoSansJavanese-Regular.otf", + ":NotoSansKaithi-Regular.ttf", + ":NotoSansKannada-VF.ttf", + ":NotoSansKannadaUI-VF.ttf", + ":NotoSansKayahLi-Regular.ttf", + ":NotoSansKharoshthi-Regular.ttf", + ":NotoSansKhmer-VF.ttf", + ":NotoSansKhmerUI-Bold.ttf", + ":NotoSansKhmerUI-Regular.ttf", + ":NotoSansKhojki-Regular.otf", + ":NotoSansLao-Bold.ttf", + ":NotoSansLao-Regular.ttf", + ":NotoSansLaoUI-Bold.ttf", + ":NotoSansLaoUI-Regular.ttf", + ":NotoSansLepcha-Regular.ttf", + ":NotoSansLimbu-Regular.ttf", + ":NotoSansLinearA-Regular.otf", + ":NotoSansLinearB-Regular.ttf", + ":NotoSansLisu-Regular.ttf", + ":NotoSansLycian-Regular.ttf", + ":NotoSansLydian-Regular.ttf", + ":NotoSansMalayalam-VF.ttf", + ":NotoSansMalayalamUI-VF.ttf", + ":NotoSansMandaic-Regular.ttf", + ":NotoSansManichaean-Regular.otf", + ":NotoSansMarchen-Regular.otf", + ":NotoSansMasaramGondi-Regular.otf", + ":NotoSansMedefaidrin-VF.ttf", + ":NotoSansMeeteiMayek-Regular.ttf", + ":NotoSansMeroitic-Regular.otf", + ":NotoSansMiao-Regular.otf", + ":NotoSansModi-Regular.ttf", + ":NotoSansMongolian-Regular.ttf", + ":NotoSansMro-Regular.otf", + ":NotoSansMultani-Regular.otf", + ":NotoSansMyanmar-Bold.otf", + ":NotoSansMyanmar-Medium.otf", + ":NotoSansMyanmar-Regular.otf", + ":NotoSansMyanmarUI-Bold.otf", + ":NotoSansMyanmarUI-Medium.otf", + ":NotoSansMyanmarUI-Regular.otf", + ":NotoSansNKo-Regular.ttf", + ":NotoSansNabataean-Regular.otf", + ":NotoSansNewTaiLue-Regular.ttf", + ":NotoSansNewa-Regular.otf", + ":NotoSansOgham-Regular.ttf", + ":NotoSansOlChiki-Regular.ttf", + ":NotoSansOldItalic-Regular.ttf", + ":NotoSansOldNorthArabian-Regular.otf", + ":NotoSansOldPermic-Regular.otf", + ":NotoSansOldPersian-Regular.ttf", + ":NotoSansOldSouthArabian-Regular.ttf", + ":NotoSansOldTurkic-Regular.ttf", + ":NotoSansOriya-Bold.ttf", + ":NotoSansOriya-Regular.ttf", + ":NotoSansOriyaUI-Bold.ttf", + ":NotoSansOriyaUI-Regular.ttf", + ":NotoSansOsage-Regular.ttf", + ":NotoSansOsmanya-Regular.ttf", + ":NotoSansPahawhHmong-Regular.otf", + ":NotoSansPalmyrene-Regular.otf", + ":NotoSansPauCinHau-Regular.otf", + ":NotoSansPhagsPa-Regular.ttf", + ":NotoSansPhoenician-Regular.ttf", + ":NotoSansRejang-Regular.ttf", + ":NotoSansRunic-Regular.ttf", + ":NotoSansSamaritan-Regular.ttf", + ":NotoSansSaurashtra-Regular.ttf", + ":NotoSansSharada-Regular.otf", + ":NotoSansShavian-Regular.ttf", + ":NotoSansSinhala-VF.ttf", + ":NotoSansSinhalaUI-VF.ttf", + ":NotoSansSoraSompeng-Regular.otf", + ":NotoSansSoyombo-VF.ttf", + ":NotoSansSundanese-Regular.ttf", + ":NotoSansSylotiNagri-Regular.ttf", + ":NotoSansSymbols-Regular-Subsetted.ttf", + ":NotoSansSymbols-Regular-Subsetted2.ttf", + ":NotoSansSyriacEastern-Regular.ttf", + ":NotoSansSyriacEstrangela-Regular.ttf", + ":NotoSansSyriacWestern-Regular.ttf", + ":NotoSansTagalog-Regular.ttf", + ":NotoSansTagbanwa-Regular.ttf", + ":NotoSansTaiLe-Regular.ttf", + ":NotoSansTaiTham-Regular.ttf", + ":NotoSansTaiViet-Regular.ttf", + ":NotoSansTakri-VF.ttf", + ":NotoSansTamil-VF.ttf", + ":NotoSansTamilUI-VF.ttf", + ":NotoSansTelugu-VF.ttf", + ":NotoSansTeluguUI-VF.ttf", + ":NotoSansThaana-Bold.ttf", + ":NotoSansThaana-Regular.ttf", + ":NotoSansThai-Bold.ttf", + ":NotoSansThai-Regular.ttf", + ":NotoSansThaiUI-Bold.ttf", + ":NotoSansThaiUI-Regular.ttf", + ":NotoSansTifinagh-Regular.otf", + ":NotoSansUgaritic-Regular.ttf", + ":NotoSansVai-Regular.ttf", + ":NotoSansWancho-Regular.otf", + ":NotoSansWarangCiti-Regular.otf", + ":NotoSansYi-Regular.ttf", + ":NotoSerif-Bold.ttf", + ":NotoSerif-BoldItalic.ttf", + ":NotoSerif-Italic.ttf", + ":NotoSerif-Regular.ttf", + ":NotoSerifArmenian-VF.ttf", + ":NotoSerifBengali-VF.ttf", + ":NotoSerifCJK-Regular.ttc", + ":NotoSerifDevanagari-VF.ttf", + ":NotoSerifDogra-Regular.ttf", + ":NotoSerifEthiopic-VF.ttf", + ":NotoSerifGeorgian-VF.ttf", + ":NotoSerifGujarati-VF.ttf", + ":NotoSerifGurmukhi-VF.ttf", + ":NotoSerifHebrew-Bold.ttf", + ":NotoSerifHebrew-Regular.ttf", + ":NotoSerifHentaigana.ttf", + ":NotoSerifKannada-VF.ttf", + ":NotoSerifKhmer-Bold.otf", + ":NotoSerifKhmer-Regular.otf", + ":NotoSerifLao-Bold.ttf", + ":NotoSerifLao-Regular.ttf", + ":NotoSerifMalayalam-VF.ttf", + ":NotoSerifMyanmar-Bold.otf", + ":NotoSerifMyanmar-Regular.otf", + ":NotoSerifNyiakengPuachueHmong-VF.ttf", + ":NotoSerifSinhala-VF.ttf", + ":NotoSerifTamil-VF.ttf", + ":NotoSerifTelugu-VF.ttf", + ":NotoSerifThai-Bold.ttf", + ":NotoSerifThai-Regular.ttf", + ":NotoSerifTibetan-VF.ttf", + ":NotoSerifYezidi-VF.ttf", + ":Roboto-Regular.ttf", + ":RobotoFlex-Regular.ttf", + ":RobotoStatic-Regular.ttf", + ":SourceSansPro-Bold.ttf", + ":SourceSansPro-BoldItalic.ttf", + ":SourceSansPro-Italic.ttf", + ":SourceSansPro-Regular.ttf", + ":SourceSansPro-SemiBold.ttf", + ":SourceSansPro-SemiBoldItalic.ttf", + ], + device_first_srcs: [ + ":font_fallback.xml", + ":fonts.xml", + ], + visibility: ["//visibility:private"], +} + // JARs in "ravenwood-runtime" are set to the classpath, sorted alphabetically. // Rename some of the dependencies to make sure they're included in the intended order. @@ -386,13 +627,8 @@ java_library { android_ravenwood_libgroup { name: "ravenwood-runtime", - data: [ - ":system-build.prop", - ":framework-res", - ":ravenwood-empty-res", - ":framework-platform-compat-config", - ":services-platform-compat-config", - ], + data: [":ravenwood-data"], + fonts: [":ravenwood-fonts"], libs: [ "100-framework-minus-apex.ravenwood", "200-kxml2-android", @@ -431,6 +667,7 @@ android_ravenwood_libgroup { ], jni_libs: [ // Libraries has to be loaded in the following order + "libravenwood_initializer", "libravenwood_sysprop", "libravenwood_runtime", "libandroid_runtime", diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java index 66a6890a23b0..869d854f7b23 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodAwareTestRunner.java @@ -26,12 +26,10 @@ import android.annotation.Nullable; import android.os.Bundle; import android.platform.test.annotations.RavenwoodTestRunnerInitializing; import android.platform.test.annotations.internal.InnerRunner; -import android.platform.test.ravenwood.RavenwoodTestStats.Result; import android.util.Log; import androidx.test.platform.app.InstrumentationRegistry; -import org.junit.AssumptionViolatedException; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runner.Runner; @@ -171,10 +169,11 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase final var notifier = new RavenwoodRunNotifier(realNotifier); final var description = getDescription(); + RavenwoodTestStats.getInstance().attachToRunNotifier(notifier); + if (mRealRunner instanceof ClassSkippingTestRunner) { - mRealRunner.run(notifier); Log.i(TAG, "onClassSkipped: description=" + description); - RavenwoodTestStats.getInstance().onClassSkipped(description); + mRealRunner.run(notifier); return; } @@ -205,7 +204,6 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase if (!skipRunnerHook) { try { - RavenwoodTestStats.getInstance().onClassFinished(description); mState.exitTestClass(); } catch (Throwable th) { notifier.reportAfterTestFailure(th); @@ -295,8 +293,6 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase // method-level annotations here. if (scope == Scope.Instance && order == Order.Outer) { if (!RavenwoodEnablementChecker.shouldEnableOnRavenwood(description, true)) { - RavenwoodTestStats.getInstance().onTestFinished( - classDescription, description, Result.Skipped); return false; } } @@ -317,16 +313,6 @@ public final class RavenwoodAwareTestRunner extends RavenwoodAwareTestRunnerBase // End of a test method. mState.exitTestMethod(); - final Result result; - if (th == null) { - result = Result.Passed; - } else if (th instanceof AssumptionViolatedException) { - result = Result.Skipped; - } else { - result = Result.Failed; - } - - RavenwoodTestStats.getInstance().onTestFinished(classDescription, description, result); } // If RUN_DISABLED_TESTS is set, and the method did _not_ throw, make it an error. diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodNativeLoader.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodNativeLoader.java index d29b93c0c171..a208d6dce2ce 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodNativeLoader.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodNativeLoader.java @@ -40,7 +40,7 @@ public final class RavenwoodNativeLoader { * See frameworks/base/core/jni/platform/host/HostRuntime.cpp */ private static final Class<?>[] sLibandroidClasses = { - android.util.Log.class, +// android.util.Log.class, // Not using native log: b/377377826 android.os.Parcel.class, android.os.Binder.class, android.os.SystemProperties.class, diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java index 9002e40bba32..91778579ab28 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java @@ -40,6 +40,7 @@ import android.os.Build; import android.os.Bundle; import android.os.HandlerThread; import android.os.Looper; +import android.os.Process_ravenwood; import android.os.ServiceManager; import android.os.SystemProperties; import android.provider.DeviceConfig_host; @@ -50,8 +51,10 @@ import android.util.Log; import androidx.test.platform.app.InstrumentationRegistry; import com.android.hoststubgen.hosthelper.HostTestUtils; +import com.android.internal.annotations.GuardedBy; import com.android.internal.os.RuntimeInit; import com.android.ravenwood.RavenwoodRuntimeNative; +import com.android.ravenwood.RavenwoodRuntimeState; import com.android.ravenwood.common.RavenwoodCommonUtils; import com.android.ravenwood.common.RavenwoodRuntimeException; import com.android.ravenwood.common.SneakyThrow; @@ -84,6 +87,7 @@ public class RavenwoodRuntimeEnvironmentController { } private static final String MAIN_THREAD_NAME = "RavenwoodMain"; + private static final String LIBRAVENWOOD_INITIALIZER_NAME = "ravenwood_initializer"; private static final String RAVENWOOD_NATIVE_SYSPROP_NAME = "ravenwood_sysprop"; private static final String RAVENWOOD_NATIVE_RUNTIME_NAME = "ravenwood_runtime"; private static final String RAVENWOOD_BUILD_PROP = @@ -137,23 +141,61 @@ public class RavenwoodRuntimeEnvironmentController { return res; } + private static final Object sInitializationLock = new Object(); + + @GuardedBy("sInitializationLock") + private static boolean sInitialized = false; + + @GuardedBy("sInitializationLock") + private static Throwable sExceptionFromGlobalInit; + private static RavenwoodAwareTestRunner sRunner; private static RavenwoodSystemProperties sProps; - private static boolean sInitialized = false; /** * Initialize the global environment. */ public static void globalInitOnce() { - if (sInitialized) { - return; + synchronized (sInitializationLock) { + if (!sInitialized) { + // globalInitOnce() is called from class initializer, which cause + // this method to be called recursively, + sInitialized = true; + + // This is the first call. + try { + globalInitInner(); + } catch (Throwable th) { + Log.e(TAG, "globalInit() failed", th); + + sExceptionFromGlobalInit = th; + throw th; + } + } else { + // Subsequent calls. If the first call threw, just throw the same error, to prevent + // the test from running. + if (sExceptionFromGlobalInit != null) { + Log.e(TAG, "globalInit() failed re-throwing the same exception", + sExceptionFromGlobalInit); + + SneakyThrow.sneakyThrow(sExceptionFromGlobalInit); + } + } + } + } + + private static void globalInitInner() { + if (RAVENWOOD_VERBOSE_LOGGING) { + Log.v(TAG, "globalInit() called here...", new RuntimeException("NOT A CRASH")); } - sInitialized = true; + + // Some process-wide initialization. (maybe redirect stdout/stderr) + RavenwoodCommonUtils.loadJniLibrary(LIBRAVENWOOD_INITIALIZER_NAME); // We haven't initialized liblog yet, so directly write to System.out here. - RavenwoodCommonUtils.log(TAG, "globalInit()"); + RavenwoodCommonUtils.log(TAG, "globalInitInner()"); - // Load libravenwood_sysprop first + // Load libravenwood_sysprop before other libraries that may use SystemProperties. var libProp = RavenwoodCommonUtils.getJniLibraryPath(RAVENWOOD_NATIVE_SYSPROP_NAME); System.load(libProp); RavenwoodRuntimeNative.reloadNativeLibrary(libProp); @@ -165,6 +207,17 @@ public class RavenwoodRuntimeEnvironmentController { RavenwoodSystemProperties.initialize(RAVENWOOD_BUILD_PROP); setSystemProperties(null); + // Do this after loading RAVENWOOD_NATIVE_RUNTIME_NAME (which backs Os.setenv()), + // before loadFrameworkNativeCode() (which uses $ANDROID_LOG_TAGS). + if (RAVENWOOD_VERBOSE_LOGGING) { + RavenwoodCommonUtils.log(TAG, "Force enabling verbose logging"); + try { + Os.setenv("ANDROID_LOG_TAGS", "*:v", true); + } catch (ErrnoException e) { + throw new RuntimeException(e); + } + } + // Make sure libandroid_runtime is loaded. RavenwoodNativeLoader.loadFrameworkNativeCode(); @@ -175,15 +228,6 @@ public class RavenwoodRuntimeEnvironmentController { Objects.requireNonNull(Build.TYPE); Objects.requireNonNull(Build.VERSION.SDK); - if (RAVENWOOD_VERBOSE_LOGGING) { - RavenwoodCommonUtils.log(TAG, "Force enabling verbose logging"); - try { - Os.setenv("ANDROID_LOG_TAGS", "*:v", true); - } catch (ErrnoException e) { - // Shouldn't happen. - } - } - System.setProperty(RAVENWOOD_VERSION_JAVA_SYSPROP, "1"); // This will let AndroidJUnit4 use the original runner. System.setProperty("android.junit.runner", @@ -197,7 +241,7 @@ public class RavenwoodRuntimeEnvironmentController { */ public static void init(RavenwoodAwareTestRunner runner) { if (RAVENWOOD_VERBOSE_LOGGING) { - Log.i(TAG, "init() called here: " + runner, new RuntimeException("STACKTRACE")); + Log.v(TAG, "init() called here: " + runner, new RuntimeException("STACKTRACE")); } if (sRunner == runner) { return; @@ -221,7 +265,9 @@ public class RavenwoodRuntimeEnvironmentController { Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler); } - android.os.Process.init$ravenwood(config.mUid, config.mPid); + RavenwoodRuntimeState.sUid = config.mUid; + RavenwoodRuntimeState.sPid = config.mPid; + RavenwoodRuntimeState.sTargetSdkLevel = config.mTargetSdkLevel; sOriginalIdentityToken = Binder.clearCallingIdentity(); reinit(); setSystemProperties(config.mSystemProperties); @@ -308,7 +354,7 @@ public class RavenwoodRuntimeEnvironmentController { */ public static void reset() { if (RAVENWOOD_VERBOSE_LOGGING) { - Log.i(TAG, "reset() called here", new RuntimeException("STACKTRACE")); + Log.v(TAG, "reset() called here", new RuntimeException("STACKTRACE")); } if (sRunner == null) { throw new RavenwoodRuntimeException("Internal error: reset() already called"); @@ -348,8 +394,8 @@ public class RavenwoodRuntimeEnvironmentController { if (sOriginalIdentityToken != -1) { Binder.restoreCallingIdentity(sOriginalIdentityToken); } - android.os.Process.reset$ravenwood(); - + RavenwoodRuntimeState.reset(); + Process_ravenwood.reset(); DeviceConfig_host.reset(); try { diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodTestStats.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodTestStats.java index 016de8e45291..787058545fed 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodTestStats.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodTestStats.java @@ -18,6 +18,9 @@ package android.platform.test.ravenwood; import android.util.Log; import org.junit.runner.Description; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; +import org.junit.runner.notification.RunNotifier; import java.io.File; import java.io.IOException; @@ -27,7 +30,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; /** @@ -39,7 +42,7 @@ import java.util.Map; */ public class RavenwoodTestStats { private static final String TAG = "RavenwoodTestStats"; - private static final String HEADER = "Module,Class,ClassDesc,Passed,Failed,Skipped"; + private static final String HEADER = "Module,Class,OuterClass,Passed,Failed,Skipped"; private static RavenwoodTestStats sInstance; @@ -66,7 +69,7 @@ public class RavenwoodTestStats { private final PrintWriter mOutputWriter; private final String mTestModuleName; - public final Map<Description, Map<Description, Result>> mStats = new HashMap<>(); + public final Map<String, Map<String, Result>> mStats = new LinkedHashMap<>(); /** Ctor */ public RavenwoodTestStats() { @@ -115,75 +118,129 @@ public class RavenwoodTestStats { return cwd.getName(); } - private void addResult(Description classDescription, Description methodDescription, + private void addResult(String className, String methodName, Result result) { - mStats.compute(classDescription, (classDesc, value) -> { + mStats.compute(className, (className_, value) -> { if (value == null) { - value = new HashMap<>(); + value = new LinkedHashMap<>(); + } + // If the result is already set, don't overwrite it. + if (!value.containsKey(methodName)) { + value.put(methodName, result); } - value.put(methodDescription, result); return value; }); } /** - * Call it when a test class is skipped. - */ - public void onClassSkipped(Description classDescription) { - addResult(classDescription, Description.EMPTY, Result.Skipped); - onClassFinished(classDescription); - } - - /** * Call it when a test method is finished. */ - public void onTestFinished(Description classDescription, Description testDescription, - Result result) { - addResult(classDescription, testDescription, result); + private void onTestFinished(String className, String testName, Result result) { + addResult(className, testName, result); } /** - * Call it when a test class is finished. + * Dump all the results and clear it. */ - public void onClassFinished(Description classDescription) { - int passed = 0; - int skipped = 0; - int failed = 0; - var stats = mStats.get(classDescription); - if (stats == null) { - return; - } - for (var e : stats.values()) { - switch (e) { - case Passed: passed++; break; - case Skipped: skipped++; break; - case Failed: failed++; break; + private void dumpAllAndClear() { + for (var entry : mStats.entrySet()) { + int passed = 0; + int skipped = 0; + int failed = 0; + var className = entry.getKey(); + + for (var e : entry.getValue().values()) { + switch (e) { + case Passed: + passed++; + break; + case Skipped: + skipped++; + break; + case Failed: + failed++; + break; + } } + + mOutputWriter.printf("%s,%s,%s,%d,%d,%d\n", + mTestModuleName, className, getOuterClassName(className), + passed, failed, skipped); } + mOutputWriter.flush(); + mStats.clear(); + } - var testClass = extractTestClass(classDescription); + private static String getOuterClassName(String className) { + // Just delete the '$', because I'm not sure if the className we get here is actaully a + // valid class name that does exist. (it might have a parameter name, etc?) + int p = className.indexOf('$'); + if (p < 0) { + return className; + } + return className.substring(0, p); + } - mOutputWriter.printf("%s,%s,%s,%d,%d,%d\n", - mTestModuleName, (testClass == null ? "?" : testClass.getCanonicalName()), - classDescription, passed, failed, skipped); - mOutputWriter.flush(); + public void attachToRunNotifier(RunNotifier notifier) { + notifier.addListener(mRunListener); } - /** - * Try to extract the class from a description, which is needed because - * ParameterizedAndroidJunit4's description doesn't contain a class. - */ - private Class<?> extractTestClass(Description desc) { - if (desc.getTestClass() != null) { - return desc.getTestClass(); + private final RunListener mRunListener = new RunListener() { + @Override + public void testSuiteStarted(Description description) { + Log.d(TAG, "testSuiteStarted: " + description); } - // Look into the children. - for (var child : desc.getChildren()) { - var fromChild = extractTestClass(child); - if (fromChild != null) { - return fromChild; - } + + @Override + public void testSuiteFinished(Description description) { + Log.d(TAG, "testSuiteFinished: " + description); } - return null; - } + + @Override + public void testRunStarted(Description description) { + Log.d(TAG, "testRunStarted: " + description); + } + + @Override + public void testRunFinished(org.junit.runner.Result result) { + Log.d(TAG, "testRunFinished: " + result); + + dumpAllAndClear(); + } + + @Override + public void testStarted(Description description) { + Log.d(TAG, " testStarted: " + description); + } + + @Override + public void testFinished(Description description) { + Log.d(TAG, " testFinished: " + description); + + // Send "Passed", but if there's already another result sent for this, this won't + // override it. + onTestFinished(description.getClassName(), description.getMethodName(), Result.Passed); + } + + @Override + public void testFailure(Failure failure) { + Log.d(TAG, " testFailure: " + failure); + + var description = failure.getDescription(); + onTestFinished(description.getClassName(), description.getMethodName(), Result.Failed); + } + + @Override + public void testAssumptionFailure(Failure failure) { + Log.d(TAG, " testAssumptionFailure: " + failure); + var description = failure.getDescription(); + onTestFinished(description.getClassName(), description.getMethodName(), Result.Skipped); + } + + @Override + public void testIgnored(Description description) { + Log.d(TAG, " testIgnored: " + description); + onTestFinished(description.getClassName(), description.getMethodName(), Result.Skipped); + } + }; } diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java index 37b0abcceede..d8f2b705d539 100644 --- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java +++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodConfig.java @@ -23,6 +23,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Instrumentation; import android.content.Context; +import android.os.Build; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -67,7 +68,7 @@ public final class RavenwoodConfig { String mTargetPackageName; int mMinSdkLevel; - int mTargetSdkLevel; + int mTargetSdkLevel = Build.VERSION_CODES.CUR_DEVELOPMENT; boolean mProvideMainThread = false; diff --git a/ravenwood/runtime-helper-src/framework/android/os/Process_ravenwood.java b/ravenwood/runtime-helper-src/framework/android/os/Process_ravenwood.java new file mode 100644 index 000000000000..3c6a4d78d1d9 --- /dev/null +++ b/ravenwood/runtime-helper-src/framework/android/os/Process_ravenwood.java @@ -0,0 +1,70 @@ +/* + * 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 android.os; + +import android.util.Pair; + +public class Process_ravenwood { + + private static volatile ThreadLocal<Pair<Integer, Boolean>> sThreadPriority; + + static { + reset(); + } + + public static void reset() { + // Reset the thread local variable + sThreadPriority = ThreadLocal.withInitial( + () -> Pair.create(Process.THREAD_PRIORITY_DEFAULT, true)); + } + + /** + * Called by {@link Process#setThreadPriority(int, int)} + */ + public static void setThreadPriority(int tid, int priority) { + if (Process.myTid() == tid) { + boolean backgroundOk = sThreadPriority.get().second; + if (priority >= Process.THREAD_PRIORITY_BACKGROUND && !backgroundOk) { + throw new IllegalArgumentException( + "Priority " + priority + " blocked by setCanSelfBackground()"); + } + sThreadPriority.set(Pair.create(priority, backgroundOk)); + } else { + throw new UnsupportedOperationException( + "Cross-thread priority management not yet available in Ravenwood"); + } + } + + /** + * Called by {@link Process#setCanSelfBackground(boolean)} + */ + public static void setCanSelfBackground(boolean backgroundOk) { + int priority = sThreadPriority.get().first; + sThreadPriority.set(Pair.create(priority, backgroundOk)); + } + + /** + * Called by {@link Process#getThreadPriority(int)} + */ + public static int getThreadPriority(int tid) { + if (Process.myTid() == tid) { + return sThreadPriority.get().first; + } else { + throw new UnsupportedOperationException( + "Cross-thread priority management not yet available in Ravenwood"); + } + } +} diff --git a/ravenwood/runtime-helper-src/framework/com/android/internal/ravenwood/RavenwoodEnvironment_host.java b/ravenwood/runtime-helper-src/framework/com/android/internal/ravenwood/RavenwoodEnvironment_host.java index e12ff240c4d9..b65668b67e03 100644 --- a/ravenwood/runtime-helper-src/framework/com/android/internal/ravenwood/RavenwoodEnvironment_host.java +++ b/ravenwood/runtime-helper-src/framework/com/android/internal/ravenwood/RavenwoodEnvironment_host.java @@ -23,14 +23,6 @@ public class RavenwoodEnvironment_host { } /** - * Called from {@link RavenwoodEnvironment#ensureRavenwoodInitialized()}. - */ - public static void ensureRavenwoodInitialized() { - // Initialization is now done by RavenwoodAwareTestRunner. - // Should we remove it? - } - - /** * Called from {@link RavenwoodEnvironment#getRavenwoodRuntimePath()}. */ public static String getRavenwoodRuntimePath(RavenwoodEnvironment env) { diff --git a/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java b/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java index c94ef31a5e5e..02981713674d 100644 --- a/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java +++ b/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java @@ -16,6 +16,7 @@ package android.system; import com.android.ravenwood.RavenwoodRuntimeNative; +import com.android.ravenwood.RavenwoodRuntimeState; import com.android.ravenwood.common.JvmWorkaround; import java.io.FileDescriptor; @@ -97,4 +98,16 @@ public final class Os { public static void setenv(String name, String value, boolean overwrite) throws ErrnoException { RavenwoodRuntimeNative.setenv(name, value, overwrite); } + + public static int getpid() { + return RavenwoodRuntimeState.sPid; + } + + public static int getuid() { + return RavenwoodRuntimeState.sUid; + } + + public static int gettid() { + return RavenwoodRuntimeNative.gettid(); + } } diff --git a/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java index f13189f6f8be..7b940b423b69 100644 --- a/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java +++ b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeNative.java @@ -58,6 +58,8 @@ public class RavenwoodRuntimeNative { public static native void clearSystemProperties(); + public static native int gettid(); + public static long lseek(FileDescriptor fd, long offset, int whence) throws ErrnoException { return nLseek(JvmWorkaround.getInstance().getFdInt(fd), offset, whence); } diff --git a/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeState.java b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeState.java new file mode 100644 index 000000000000..175e020d61d6 --- /dev/null +++ b/ravenwood/runtime-helper-src/libcore-fake/com/android/ravenwood/RavenwoodRuntimeState.java @@ -0,0 +1,35 @@ +/* + * 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.android.ravenwood; + +public class RavenwoodRuntimeState { + // This must match VMRuntime.SDK_VERSION_CUR_DEVELOPMENT. + public static final int CUR_DEVELOPMENT = 10000; + + public static volatile int sUid; + public static volatile int sPid; + public static volatile int sTargetSdkLevel; + + static { + reset(); + } + + public static void reset() { + sUid = -1; + sPid = -1; + sTargetSdkLevel = CUR_DEVELOPMENT; + } +} diff --git a/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java b/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java index ba89f71dde8a..eaadac6a8b92 100644 --- a/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java +++ b/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java @@ -19,6 +19,7 @@ package dalvik.system; // The original is here: // $ANDROID_BUILD_TOP/libcore/libart/src/main/java/dalvik/system/VMRuntime.java +import com.android.ravenwood.RavenwoodRuntimeState; import com.android.ravenwood.common.JvmWorkaround; import java.lang.reflect.Array; @@ -52,4 +53,8 @@ public class VMRuntime { public long addressOf(Object obj) { return JvmWorkaround.getInstance().addressOf(obj); } + + public int getTargetSdkVersion() { + return RavenwoodRuntimeState.sTargetSdkLevel; + } } diff --git a/ravenwood/runtime-jni/ravenwood_initializer.cpp b/ravenwood/runtime-jni/ravenwood_initializer.cpp new file mode 100644 index 000000000000..89fb7c3c3510 --- /dev/null +++ b/ravenwood/runtime-jni/ravenwood_initializer.cpp @@ -0,0 +1,50 @@ +/* + * 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. + */ + + /* + * This file is compiled into a single SO file, which we load at the very first. + * We can do process-wide initialization here. + */ + +#include <fcntl.h> +#include <unistd.h> + +#include "jni_helper.h" + +static void maybeRedirectLog() { + auto ravenwoodLogOut = getenv("RAVENWOOD_LOG_OUT"); + if (ravenwoodLogOut == NULL) { + return; + } + ALOGI("RAVENWOOD_LOG_OUT set. Redirecting output to %s", ravenwoodLogOut); + + // Redirect stdin / stdout to /dev/tty. + int ttyFd = open(ravenwoodLogOut, O_WRONLY | O_APPEND); + if (ttyFd == -1) { + ALOGW("$RAVENWOOD_LOG_OUT is set to %s, but failed to open: %s ", ravenwoodLogOut, + strerror(errno)); + return; + } + dup2(ttyFd, 1); + dup2(ttyFd, 2); +} + +extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { + ALOGI("%s: JNI_OnLoad", __FILE__); + + maybeRedirectLog(); + return JNI_VERSION_1_4; +} diff --git a/ravenwood/runtime-jni/ravenwood_runtime.cpp b/ravenwood/runtime-jni/ravenwood_runtime.cpp index 3ff08483c956..c1993f691686 100644 --- a/ravenwood/runtime-jni/ravenwood_runtime.cpp +++ b/ravenwood/runtime-jni/ravenwood_runtime.cpp @@ -17,6 +17,7 @@ #include <fcntl.h> #include <string.h> #include <sys/stat.h> +#include <sys/syscall.h> #include <unistd.h> #include <utils/misc.h> @@ -173,6 +174,12 @@ static void Linux_setenv(JNIEnv* env, jobject, jstring javaName, jstring javaVal throwIfMinusOne(env, "setenv", setenv(name.c_str(), value.c_str(), overwrite ? 1 : 0)); } + +static jint Linux_gettid(JNIEnv* env, jobject) { + // gettid(2() was added in glibc 2.30 but Android uses an older version in prebuilt. + return syscall(__NR_gettid); +} + // ---- Registration ---- extern void register_android_system_OsConstants(JNIEnv* env); @@ -189,6 +196,7 @@ static const JNINativeMethod sMethods[] = { "stat", "(Ljava/lang/String;)Landroid/system/StructStat;", (void*)Linux_stat }, { "nOpen", "(Ljava/lang/String;II)I", (void*)Linux_open }, { "setenv", "(Ljava/lang/String;Ljava/lang/String;Z)V", (void*)Linux_setenv }, + { "gettid", "()I", (void*)Linux_gettid }, }; extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { diff --git a/ravenwood/scripts/run-ravenwood-tests.sh b/ravenwood/scripts/run-ravenwood-tests.sh index 5d623e0b6c36..1910100a7f5d 100755 --- a/ravenwood/scripts/run-ravenwood-tests.sh +++ b/ravenwood/scripts/run-ravenwood-tests.sh @@ -18,12 +18,38 @@ # Options: # # -s: "Smoke" test -- skip slow tests (SysUI, ICU) +# +# -x PCRE: Specify exclusion filter in PCRE +# Example: -x '^(Cts|hoststub)' # Exclude CTS and hoststubgen tests. +# +# -f PCRE: Specify inclusion filter in PCRE + + +# Regex to identify slow tests, in PCRE +SLOW_TEST_RE='^(SystemUiRavenTests|CtsIcuTestCasesRavenwood|CarSystemUIRavenTests)$' smoke=0 -while getopts "s" opt; do +include_re="" +exclude_re="" +smoke_exclude_re="" +dry_run="" +while getopts "sx:f:d" opt; do case "$opt" in s) - smoke=1 + # Remove slow tests. + smoke_exclude_re="$SLOW_TEST_RE" + ;; + x) + # Take a PCRE from the arg, and use it as an exclusion filter. + exclude_re="$OPTARG" + ;; + f) + # Take a PCRE from the arg, and use it as an inclusion filter. + include_re="$OPTARG" + ;; + d) + # Dry run + dry_run="echo" ;; '?') exit 1 @@ -35,21 +61,46 @@ shift $(($OPTIND - 1)) all_tests=(hoststubgentest tiny-framework-dump-test hoststubgen-invoke-test ravenwood-stats-checker) all_tests+=( $(${0%/*}/list-ravenwood-tests.sh) ) -# Regex to identify slow tests, in PCRE -slow_tests_re='^(SystemUiRavenTests|CtsIcuTestCasesRavenwood)$' - -if (( $smoke )) ; then - # Remove the slow tests. - all_tests=( $( - for t in "${all_tests[@]}"; do - echo $t | grep -vP "$slow_tests_re" - done - ) ) -fi +filter() { + local re="$1" + local grep_arg="$2" + if [[ "$re" == "" ]] ; then + cat # No filtering + else + grep $grep_arg -iP "$re" + fi +} -run() { - echo "Running: $*" - "${@}" +filter_in() { + filter "$1" } -run ${ATEST:-atest} "${all_tests[@]}" +filter_out() { + filter "$1" -v +} + + +# Remove the slow tests. +targets=( $( + for t in "${all_tests[@]}"; do + echo $t | filter_in "$include_re" | filter_out "$smoke_exclude_re" | filter_out "$exclude_re" + done +) ) + +# Show the target tests + +echo "Target tests:" +for t in "${targets[@]}"; do + echo " $t" +done + +# Calculate the removed tests. + +diff="$(diff <(echo "${all_tests[@]}" | tr ' ' '\n') <(echo "${targets[@]}" | tr ' ' '\n') )" + +if [[ "$diff" != "" ]]; then + echo "Excluded tests:" + echo "$diff" +fi + +$dry_run ${ATEST:-atest} "${targets[@]}" diff --git a/ravenwood/tests/bivalenttest/Android.bp b/ravenwood/tests/bivalenttest/Android.bp index ce0033d02910..4895a1a6d1a2 100644 --- a/ravenwood/tests/bivalenttest/Android.bp +++ b/ravenwood/tests/bivalenttest/Android.bp @@ -43,9 +43,12 @@ java_defaults { // To make sure it won't cause VerifyError (b/324063814) "platformprotosnano", + + "com.android.internal.os.flags-aconfig-java", ], srcs: [ "test/**/*.java", + "test/**/*.kt", ], jni_libs: [ "libravenwoodbivalenttest_jni", @@ -58,10 +61,12 @@ java_defaults { // TODO(b/371215487): migrate bivalenttest.ravenizer tests to another architecture exclude_srcs: [ "test/**/ravenizer/*.java", + "test/**/ravenizer/*.kt", ], static_libs: [ "junit", "truth", + "flag-junit", "ravenwood-junit", ], test_suites: [ diff --git a/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/aconfig/RavenwoodAconfigFlagTest.kt b/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/aconfig/RavenwoodAconfigFlagTest.kt new file mode 100644 index 000000000000..fd6d6fb66465 --- /dev/null +++ b/ravenwood/tests/bivalenttest/test/com/android/ravenwoodtest/bivalenttest/aconfig/RavenwoodAconfigFlagTest.kt @@ -0,0 +1,102 @@ +/* + * 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.android.ravenwoodtest.bivalenttest.aconfig + +import android.platform.test.annotations.EnableFlags +import android.platform.test.annotations.RequiresFlagsDisabled +import android.platform.test.annotations.RequiresFlagsEnabled +import android.platform.test.flag.junit.DeviceFlagsValueProvider +import android.platform.test.flag.junit.SetFlagsRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.internal.os.Flags +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Assert.fail +import org.junit.Ignore +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + + +@RunWith(AndroidJUnit4::class) +class RavenwoodAconfigSimpleReadTests { + @Test + fun testFalseFlags() { + assertFalse(Flags.ravenwoodFlagRo1()) + assertFalse(Flags.ravenwoodFlagRw1()) + } + + @Test + @Ignore // TODO: Enable this test after rolling out the "2" flags. + fun testTrueFlags() { + assertTrue(Flags.ravenwoodFlagRo2()) + assertTrue(Flags.ravenwoodFlagRw2()) + } +} + +@RunWith(AndroidJUnit4::class) +class RavenwoodAconfigCheckFlagsRuleTests { + @Rule + @JvmField + val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + + @Test + @RequiresFlagsEnabled(Flags.FLAG_RAVENWOOD_FLAG_RO_1) + fun testRequireFlagsEnabledRo() { + fail("This test shouldn't be executed") + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_RAVENWOOD_FLAG_RW_1) + fun testRequireFlagsEnabledRw() { + fail("This test shouldn't be executed") + } + + @Test + @RequiresFlagsDisabled(Flags.FLAG_RAVENWOOD_FLAG_RO_2) + @Ignore // TODO: Enable this test after rolling out the "2" flags. + fun testRequireFlagsDisabledRo() { + fail("This test shouldn't be executed") + } + + @Test + @RequiresFlagsDisabled(Flags.FLAG_RAVENWOOD_FLAG_RW_2) + @Ignore // TODO: Enable this test after rolling out the "2" flags. + fun testRequireFlagsDisabledRw() { + fail("This test shouldn't be executed") + } +} + +@RunWith(AndroidJUnit4::class) +class RavenwoodAconfigSetFlagsRuleWithDefaultTests { + @Rule + @JvmField + val setFlagsRule = SetFlagsRule() + + @Test + @EnableFlags(Flags.FLAG_RAVENWOOD_FLAG_RO_1) + fun testSetRoFlag() { + assertTrue(Flags.ravenwoodFlagRo1()) + assertFalse(Flags.ravenwoodFlagRw1()) + } + + @Test + @EnableFlags(Flags.FLAG_RAVENWOOD_FLAG_RW_1) + fun testSetRwFlag() { + assertFalse(Flags.ravenwoodFlagRo1()) + assertTrue(Flags.ravenwoodFlagRw1()) + } +} diff --git a/ravenwood/tests/runtime-test/Android.bp b/ravenwood/tests/runtime-test/Android.bp index 410292001670..0c0df1f993aa 100644 --- a/ravenwood/tests/runtime-test/Android.bp +++ b/ravenwood/tests/runtime-test/Android.bp @@ -10,6 +10,9 @@ package { android_ravenwood_test { name: "RavenwoodRuntimeTest", + libs: [ + "ravenwood-helper-runtime", + ], static_libs: [ "androidx.annotation_annotation", "androidx.test.ext.junit", diff --git a/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/IdentityTest.java b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/IdentityTest.java new file mode 100644 index 000000000000..8e04b698c9d9 --- /dev/null +++ b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/IdentityTest.java @@ -0,0 +1,66 @@ +/* + * 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.android.ravenwoodtest.runtimetest; + +import static android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE; +import static android.os.Process.FIRST_APPLICATION_UID; + +import static org.junit.Assert.assertEquals; + +import android.os.Binder; +import android.os.Build; +import android.os.Process; +import android.platform.test.ravenwood.RavenwoodConfig; +import android.system.Os; + +import com.android.ravenwood.RavenwoodRuntimeState; + +import dalvik.system.VMRuntime; + +import org.junit.Test; + +public class IdentityTest { + + @RavenwoodConfig.Config + public static final RavenwoodConfig sConfig = + new RavenwoodConfig.Builder() + .setTargetSdkLevel(UPSIDE_DOWN_CAKE) + .setProcessApp() + .build(); + + @Test + public void testUid() { + assertEquals(FIRST_APPLICATION_UID, RavenwoodRuntimeState.sUid); + assertEquals(FIRST_APPLICATION_UID, Os.getuid()); + assertEquals(FIRST_APPLICATION_UID, Process.myUid()); + assertEquals(FIRST_APPLICATION_UID, Binder.getCallingUid()); + } + + @Test + public void testPid() { + int pid = RavenwoodRuntimeState.sPid; + assertEquals(pid, Os.getpid()); + assertEquals(pid, Process.myPid()); + assertEquals(pid, Binder.getCallingPid()); + } + + @Test + public void testTargetSdkLevel() { + assertEquals(Build.VERSION_CODES.CUR_DEVELOPMENT, RavenwoodRuntimeState.CUR_DEVELOPMENT); + assertEquals(UPSIDE_DOWN_CAKE, RavenwoodRuntimeState.sTargetSdkLevel); + assertEquals(UPSIDE_DOWN_CAKE, VMRuntime.getRuntime().getTargetSdkVersion()); + } +} diff --git a/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/OsTest.java b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/OsTest.java index c2230c739ccf..c55506a0a10a 100644 --- a/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/OsTest.java +++ b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/OsTest.java @@ -24,6 +24,8 @@ import static android.system.OsConstants.S_ISREG; import static android.system.OsConstants.S_ISSOCK; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; import static java.nio.file.LinkOption.NOFOLLOW_LINKS; @@ -51,10 +53,12 @@ import java.nio.file.attribute.PosixFileAttributes; import java.nio.file.attribute.PosixFilePermission; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) public class OsTest { + public interface ConsumerWithThrow<T> { void accept(T var1) throws Exception; } @@ -165,6 +169,35 @@ public class OsTest { }); } + private static class TestThread extends Thread { + + final CountDownLatch mLatch = new CountDownLatch(1); + int mTid; + + TestThread() { + setDaemon(true); + } + + @Override + public void run() { + mTid = Os.gettid(); + mLatch.countDown(); + } + } + + @Test + public void testGetTid() throws InterruptedException { + var t1 = new TestThread(); + var t2 = new TestThread(); + t1.start(); + t2.start(); + // Wait for thread execution + assertTrue(t1.mLatch.await(1, TimeUnit.SECONDS)); + assertTrue(t2.mLatch.await(1, TimeUnit.SECONDS)); + // Make sure the tid is unique per-thread + assertNotEquals(t1.mTid, t2.mTid); + } + // Verify StructStat values from libcore against native JVM PosixFileAttributes private static void assertAttributesEqual(PosixFileAttributes attr, StructStat stat) { assertEquals(attr.lastModifiedTime(), convertTimespecToFileTime(stat.st_mtim)); diff --git a/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/ProcessTest.java b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/ProcessTest.java new file mode 100644 index 000000000000..d25b5c19f351 --- /dev/null +++ b/ravenwood/tests/runtime-test/test/com/android/ravenwoodtest/runtimetest/ProcessTest.java @@ -0,0 +1,54 @@ +/* + * 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.android.ravenwoodtest.runtimetest; + +import static android.os.Process.THREAD_PRIORITY_BACKGROUND; +import static android.os.Process.THREAD_PRIORITY_DEFAULT; +import static android.os.Process.THREAD_PRIORITY_FOREGROUND; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import android.os.Process; +import android.system.Os; + +import org.junit.Test; + +public class ProcessTest { + + @Test + public void testGetUidPidTid() { + assertEquals(Os.getuid(), Process.myUid()); + assertEquals(Os.getpid(), Process.myPid()); + assertEquals(Os.gettid(), Process.myTid()); + } + + @Test + public void testThreadPriority() { + assertThrows(UnsupportedOperationException.class, + () -> Process.getThreadPriority(Process.myTid() + 1)); + assertThrows(UnsupportedOperationException.class, + () -> Process.setThreadPriority(Process.myTid() + 1, THREAD_PRIORITY_DEFAULT)); + assertEquals(THREAD_PRIORITY_DEFAULT, Process.getThreadPriority(Process.myTid())); + Process.setThreadPriority(THREAD_PRIORITY_FOREGROUND); + assertEquals(THREAD_PRIORITY_FOREGROUND, Process.getThreadPriority(Process.myTid())); + Process.setCanSelfBackground(false); + Process.setThreadPriority(THREAD_PRIORITY_DEFAULT); + assertEquals(THREAD_PRIORITY_DEFAULT, Process.getThreadPriority(Process.myTid())); + assertThrows(IllegalArgumentException.class, + () -> Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND)); + } +} diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt index a02082d12934..f47aaba8ef22 100644 --- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt +++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt @@ -327,6 +327,10 @@ fun ClassNode.isSynthetic(): Boolean { return (this.access and Opcodes.ACC_SYNTHETIC) != 0 } +fun ClassNode.isAbstract(): Boolean { + return (this.access and Opcodes.ACC_ABSTRACT) != 0 +} + fun MethodNode.isSynthetic(): Boolean { return (this.access and Opcodes.ACC_SYNTHETIC) != 0 } diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt index 32dcbe546f3c..a0e5599c0a7c 100644 --- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt +++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt @@ -46,7 +46,7 @@ class RavenizerOptions( var enableValidation: SetOnce<Boolean> = SetOnce(true), /** Whether the validation failure is fatal or not. */ - var fatalValidation: SetOnce<Boolean> = SetOnce(false), + var fatalValidation: SetOnce<Boolean> = SetOnce(true), /** Whether to remove mockito and dexmaker classes. */ var stripMockito: SetOnce<Boolean> = SetOnce(false), diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Validator.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Validator.kt index 27092d28ae5e..8ec0932d89dd 100644 --- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Validator.kt +++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/Validator.kt @@ -16,10 +16,12 @@ package com.android.platform.test.ravenwood.ravenizer import com.android.hoststubgen.asm.ClassNodes +import com.android.hoststubgen.asm.isAbstract import com.android.hoststubgen.asm.startsWithAny import com.android.hoststubgen.asm.toHumanReadableClassName import com.android.hoststubgen.log import org.objectweb.asm.tree.ClassNode +import java.util.regex.Pattern fun validateClasses(classes: ClassNodes): Boolean { var allOk = true @@ -41,25 +43,35 @@ fun checkClass(cn: ClassNode, classes: ClassNodes): Boolean { } var allOk = true + log.i("Checking ${cn.name.toHumanReadableClassName()}") + // See if there's any class that extends a legacy base class. // But ignore the base classes in android.test. - if (!cn.name.startsWithAny("android/test/")) { - allOk = checkSuperClass(cn, cn, classes) && allOk + if (!cn.isAbstract() && !cn.name.startsWith("android/test/") + && !isAllowListedLegacyTest(cn) + ) { + allOk = checkSuperClassForJunit3(cn, cn, classes) && allOk } return allOk } -fun checkSuperClass(targetClass: ClassNode, currentClass: ClassNode, classes: ClassNodes): Boolean { +fun checkSuperClassForJunit3( + targetClass: ClassNode, + currentClass: ClassNode, + classes: ClassNodes, +): Boolean { if (currentClass.superName == null || currentClass.superName == "java/lang/Object") { return true // No parent class } + // Make sure the class doesn't extend a junit3 TestCase class. if (currentClass.superName.isLegacyTestBaseClass()) { log.e("Error: Class ${targetClass.name.toHumanReadableClassName()} extends" - + " a legacy test class ${currentClass.superName.toHumanReadableClassName()}.") + + " a legacy test class ${currentClass.superName.toHumanReadableClassName()}" + + ", which is not supported on Ravenwood. Please migrate to Junit4 syntax.") return false } classes.findClass(currentClass.superName)?.let { - return checkSuperClass(targetClass, it, classes) + return checkSuperClassForJunit3(targetClass, it, classes) } // Super class not found. // log.w("Class ${currentClass.superName} not found.") @@ -73,9 +85,64 @@ fun String.isLegacyTestBaseClass(): Boolean { return this.startsWithAny( "junit/framework/TestCase", - // In case the test doesn't statically include JUnit, we need + // In case the test doesn't statically include JUnit, we need the following. "android/test/AndroidTestCase", "android/test/InstrumentationTestCase", "android/test/InstrumentationTestSuite", ) } + +private val allowListedLegacyTests = setOf( +// List of existing test classes that use the JUnit3 syntax. We exempt them for now, but +// will reject any more of them. +// +// Note, we want internal class names, but for convenience, we use '.'s and '%'s here +// and replace them later. (a '$' would be parsed as a string template.) + *""" +android.util.proto.cts.DebuggingTest +android.util.proto.cts.EncodedBufferTest +android.util.proto.cts.ProtoOutputStreamBoolTest +android.util.proto.cts.ProtoOutputStreamBytesTest +android.util.proto.cts.ProtoOutputStreamDoubleTest +android.util.proto.cts.ProtoOutputStreamEnumTest +android.util.proto.cts.ProtoOutputStreamFixed32Test +android.util.proto.cts.ProtoOutputStreamFixed64Test +android.util.proto.cts.ProtoOutputStreamFloatTest +android.util.proto.cts.ProtoOutputStreamInt32Test +android.util.proto.cts.ProtoOutputStreamInt64Test +android.util.proto.cts.ProtoOutputStreamObjectTest +android.util.proto.cts.ProtoOutputStreamSFixed32Test +android.util.proto.cts.ProtoOutputStreamSFixed64Test +android.util.proto.cts.ProtoOutputStreamSInt32Test +android.util.proto.cts.ProtoOutputStreamSInt64Test +android.util.proto.cts.ProtoOutputStreamStringTest +android.util.proto.cts.ProtoOutputStreamSwitchedWriteTest +android.util.proto.cts.ProtoOutputStreamTagTest +android.util.proto.cts.ProtoOutputStreamUInt32Test +android.util.proto.cts.ProtoOutputStreamUInt64Test + +android.os.cts.BadParcelableExceptionTest +android.os.cts.DeadObjectExceptionTest +android.os.cts.ParcelFormatExceptionTest +android.os.cts.PatternMatcherTest +android.os.cts.RemoteExceptionTest + +android.os.storage.StorageManagerBaseTest +android.os.storage.StorageManagerIntegrationTest +android.util.LogTest%PerformanceTest + +com.android.server.power.stats.BatteryStatsCounterTest +com.android.server.power.stats.BatteryStatsDualTimerTest +com.android.server.power.stats.BatteryStatsDurationTimerTest +com.android.server.power.stats.BatteryStatsSamplingTimerTest +com.android.server.power.stats.BatteryStatsStopwatchTimerTest +com.android.server.power.stats.BatteryStatsTimeBaseTest +com.android.server.power.stats.BatteryStatsTimerTest + + """.trim().replace('%', '$').replace('.', '/') + .split(Pattern.compile("""\s+""")).toTypedArray() +) + +private fun isAllowListedLegacyTest(targetClass: ClassNode): Boolean { + return allowListedLegacyTests.contains(targetClass.name) +}
\ No newline at end of file diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java index 2e9a4dcb45aa..a10039f9bf6c 100644 --- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java +++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java @@ -462,7 +462,9 @@ public final class AutoFillUI { @Override public void onShown() { - mCallback.onShown(UI_TYPE_DIALOG, response.getDatasets().size()); + if (mCallback != null) { + mCallback.onShown(UI_TYPE_DIALOG, response.getDatasets().size()); + } } @Override @@ -511,7 +513,9 @@ public final class AutoFillUI { @Override public void startIntentSender(IntentSender intentSender) { - mCallback.startIntentSenderAndFinishSession(intentSender); + if (mCallback != null) { + mCallback.startIntentSenderAndFinishSession(intentSender); + } } private void log(int type) { diff --git a/services/core/java/com/android/server/SerialService.java b/services/core/java/com/android/server/SerialService.java index 82c2038d8011..71885fdc9c81 100644 --- a/services/core/java/com/android/server/SerialService.java +++ b/services/core/java/com/android/server/SerialService.java @@ -18,22 +18,30 @@ package com.android.server; import android.annotation.EnforcePermission; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.hardware.ISerialManager; import android.hardware.SerialManagerInternal; import android.os.ParcelFileDescriptor; import android.os.PermissionEnforcer; +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; +import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; import java.io.File; +import java.io.FileDescriptor; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.function.Supplier; @android.ravenwood.annotation.RavenwoodKeepWholeClass public class SerialService extends ISerialManager.Stub { + private static final String TAG = "SerialService"; + private final Context mContext; @GuardedBy("mSerialPorts") @@ -50,7 +58,7 @@ public class SerialService extends ISerialManager.Stub { final String[] serialPorts = getSerialPorts(context); for (String serialPort : serialPorts) { mSerialPorts.put(serialPort, () -> { - return native_open(serialPort); + return tryOpen(serialPort); }); } } @@ -135,5 +143,14 @@ public class SerialService extends ISerialManager.Stub { } }; - private native ParcelFileDescriptor native_open(String path); + private static @Nullable ParcelFileDescriptor tryOpen(String path) { + try { + FileDescriptor fd = Os.open(path, OsConstants.O_RDWR | OsConstants.O_NOCTTY, 0); + return new ParcelFileDescriptor(fd); + } catch (ErrnoException e) { + Slog.e(TAG, "Could not open: " + path, e); + // We return null to preserve API semantics from earlier implementation variants. + return null; + } + } } diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java index dc7749cb02ef..06e6c8b1ec53 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -525,6 +525,9 @@ public class VcnManagementService extends IVcnManagementService.Stub { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); + if (action == null) { + return; + } switch (action) { case Intent.ACTION_PACKAGE_ADDED: // Fallthrough diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index d11abf85c7d2..4a4a1b4de0f0 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5239,6 +5239,11 @@ public class ActivityManagerService extends IActivityManager.Stub mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action == null) { + return; + } + String[] pkgs = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES); if (pkgs != null) { for (String pkg : pkgs) { diff --git a/services/core/java/com/android/server/appbinding/AppBindingService.java b/services/core/java/com/android/server/appbinding/AppBindingService.java index 5db6dc7ccc15..6ccb3ee8bcc9 100644 --- a/services/core/java/com/android/server/appbinding/AppBindingService.java +++ b/services/core/java/com/android/server/appbinding/AppBindingService.java @@ -235,6 +235,9 @@ public class AppBindingService extends Binder { } final String action = intent.getAction(); + if (action == null) { + return; + } if (Intent.ACTION_USER_REMOVED.equals(action)) { onUserRemoved(userId); diff --git a/services/core/java/com/android/server/audio/LoudnessCodecHelper.java b/services/core/java/com/android/server/audio/LoudnessCodecHelper.java index 01f770b1e89f..9fa5da47aae7 100644 --- a/services/core/java/com/android/server/audio/LoudnessCodecHelper.java +++ b/services/core/java/com/android/server/audio/LoudnessCodecHelper.java @@ -133,6 +133,9 @@ public class LoudnessCodecHelper { private static final EventLogger sLogger = new EventLogger( AudioService.LOG_NB_EVENTS_LOUDNESS_CODEC, "Loudness updates"); + private final Object mDispatcherLock = new Object(); + + @GuardedBy("mDispatcherLock") private final LoudnessRemoteCallbackList mLoudnessUpdateDispatchers = new LoudnessRemoteCallbackList(this); @@ -339,12 +342,16 @@ public class LoudnessCodecHelper { } void registerLoudnessCodecUpdatesDispatcher(ILoudnessCodecUpdatesDispatcher dispatcher) { - mLoudnessUpdateDispatchers.register(dispatcher, Binder.getCallingPid()); + synchronized (mDispatcherLock) { + mLoudnessUpdateDispatchers.register(dispatcher, Binder.getCallingPid()); + } } void unregisterLoudnessCodecUpdatesDispatcher( ILoudnessCodecUpdatesDispatcher dispatcher) { - mLoudnessUpdateDispatchers.unregister(dispatcher); + synchronized (mDispatcherLock) { + mLoudnessUpdateDispatchers.unregister(dispatcher); + } } void startLoudnessCodecUpdates(int sessionId) { @@ -640,17 +647,20 @@ public class LoudnessCodecHelper { Log.d(TAG, "dispatchNewLoudnessParameters: sessionId " + sessionId + " bundle: " + bundle); } - final int nbDispatchers = mLoudnessUpdateDispatchers.beginBroadcast(); - for (int i = 0; i < nbDispatchers; ++i) { - try { - mLoudnessUpdateDispatchers.getBroadcastItem(i) - .dispatchLoudnessCodecParameterChange(sessionId, bundle); - } catch (RemoteException e) { - Log.e(TAG, "Error dispatching for sessionId " + sessionId + " bundle: " + bundle, - e); + synchronized (mDispatcherLock) { + final int nbDispatchers = mLoudnessUpdateDispatchers.beginBroadcast(); + for (int i = 0; i < nbDispatchers; ++i) { + try { + mLoudnessUpdateDispatchers.getBroadcastItem(i) + .dispatchLoudnessCodecParameterChange(sessionId, bundle); + } catch (RemoteException e) { + Log.e(TAG, + "Error dispatching for sessionId " + sessionId + " bundle: " + bundle, + e); + } } + mLoudnessUpdateDispatchers.finishBroadcast(); } - mLoudnessUpdateDispatchers.finishBroadcast(); } @GuardedBy("mLock") diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java index 97c32b986d38..49934126ab8c 100644 --- a/services/core/java/com/android/server/input/KeyboardLayoutManager.java +++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java @@ -255,17 +255,6 @@ class KeyboardLayoutManager implements InputManager.InputDeviceListener { } } - private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) { - // Different languages are never compatible - if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) { - return false; - } - // If both the system and the keyboard layout have a country specifier, they must be equal. - return TextUtils.isEmpty(systemLocale.getCountry()) - || TextUtils.isEmpty(keyboardLocale.getCountry()) - || systemLocale.getCountry().equals(keyboardLocale.getCountry()); - } - @MainThread private void updateKeyboardLayouts() { // Scan all input devices state for keyboard layouts that have been uninstalled. @@ -953,21 +942,33 @@ class KeyboardLayoutManager implements InputManager.InputDeviceListener { return; } + List<String> layoutNames = new ArrayList<>(); + for (String layoutDesc : config.getConfiguredLayouts()) { + KeyboardLayout kl = getKeyboardLayout(layoutDesc); + if (kl == null) { + // b/349033234: Weird state with stale keyboard layout configured. + // Possibly due to race condition between KCM providing package being removed and + // corresponding layouts being removed from Datastore and cache. + // {@see updateKeyboardLayouts()} + // + // Ideally notification will be correctly shown after the keyboard layouts are + // configured again with the new package state. + return; + } + layoutNames.add(kl.getLabel()); + } showKeyboardLayoutNotification( r.getString( R.string.keyboard_layout_notification_selected_title, inputDevice.getName()), - createConfiguredNotificationText(mContext, config.getConfiguredLayouts()), + createConfiguredNotificationText(mContext, layoutNames), inputDevice); } @MainThread private String createConfiguredNotificationText(@NonNull Context context, - @NonNull Set<String> selectedLayouts) { + @NonNull List<String> layoutNames) { final Resources r = context.getResources(); - List<String> layoutNames = new ArrayList<>(); - selectedLayouts.forEach( - (layoutDesc) -> layoutNames.add(getKeyboardLayout(layoutDesc).getLabel())); Collections.sort(layoutNames); switch (layoutNames.size()) { case 1: diff --git a/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java b/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java deleted file mode 100644 index e831e40e70d1..000000000000 --- a/services/core/java/com/android/server/integrity/parser/RuleMetadataParser.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2019 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.android.server.integrity.parser; - -import android.annotation.Nullable; -import android.util.Xml; - -import com.android.modules.utils.TypedXmlPullParser; -import com.android.server.integrity.model.RuleMetadata; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.IOException; -import java.io.InputStream; - -/** Helper class for parsing rule metadata. */ -public class RuleMetadataParser { - - public static final String RULE_PROVIDER_TAG = "P"; - public static final String VERSION_TAG = "V"; - - /** Parse the rule metadata from an input stream. */ - @Nullable - public static RuleMetadata parse(InputStream inputStream) - throws XmlPullParserException, IOException { - - String ruleProvider = ""; - String version = ""; - - TypedXmlPullParser xmlPullParser = Xml.resolvePullParser(inputStream); - - int eventType; - while ((eventType = xmlPullParser.next()) != XmlPullParser.END_DOCUMENT) { - if (eventType == XmlPullParser.START_TAG) { - String tag = xmlPullParser.getName(); - switch (tag) { - case RULE_PROVIDER_TAG: - ruleProvider = xmlPullParser.nextText(); - break; - case VERSION_TAG: - version = xmlPullParser.nextText(); - break; - default: - throw new IllegalStateException("Unknown tag in metadata: " + tag); - } - } - } - - return new RuleMetadata(ruleProvider, version); - } -} diff --git a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java deleted file mode 100644 index 8ba5870aef0f..000000000000 --- a/services/core/java/com/android/server/integrity/serializer/RuleBinarySerializer.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright (C) 2019 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.android.server.integrity.serializer; - -import static com.android.server.integrity.model.ComponentBitSize.ATOMIC_FORMULA_START; -import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_END; -import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_START; -import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS; -import static com.android.server.integrity.model.ComponentBitSize.DEFAULT_FORMAT_VERSION; -import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS; -import static com.android.server.integrity.model.ComponentBitSize.FORMAT_VERSION_BITS; -import static com.android.server.integrity.model.ComponentBitSize.INSTALLER_ALLOWED_BY_MANIFEST_START; -import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS; -import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS; -import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS; -import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS; -import static com.android.server.integrity.model.IndexingFileConstants.END_INDEXING_KEY; -import static com.android.server.integrity.model.IndexingFileConstants.INDEXING_BLOCK_SIZE; -import static com.android.server.integrity.model.IndexingFileConstants.START_INDEXING_KEY; -import static com.android.server.integrity.serializer.RuleIndexingDetails.APP_CERTIFICATE_INDEXED; -import static com.android.server.integrity.serializer.RuleIndexingDetails.NOT_INDEXED; -import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAGE_NAME_INDEXED; - -import android.content.integrity.AtomicFormula; -import android.content.integrity.CompoundFormula; -import android.content.integrity.InstallerAllowedByManifestFormula; -import android.content.integrity.IntegrityFormula; -import android.content.integrity.IntegrityUtils; -import android.content.integrity.Rule; - -import com.android.internal.util.Preconditions; -import com.android.server.integrity.model.BitOutputStream; -import com.android.server.integrity.model.ByteTrackedOutputStream; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.charset.StandardCharsets; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -/** A helper class to serialize rules from the {@link Rule} model to Binary representation. */ -public class RuleBinarySerializer implements RuleSerializer { - static final int TOTAL_RULE_SIZE_LIMIT = 200000; - static final int INDEXED_RULE_SIZE_LIMIT = 100000; - static final int NONINDEXED_RULE_SIZE_LIMIT = 1000; - - // Get the byte representation for a list of rules. - @Override - public byte[] serialize(List<Rule> rules, Optional<Integer> formatVersion) - throws RuleSerializeException { - try { - ByteArrayOutputStream rulesOutputStream = new ByteArrayOutputStream(); - serialize(rules, formatVersion, rulesOutputStream, new ByteArrayOutputStream()); - return rulesOutputStream.toByteArray(); - } catch (Exception e) { - throw new RuleSerializeException(e.getMessage(), e); - } - } - - // Get the byte representation for a list of rules, and write them to an output stream. - @Override - public void serialize( - List<Rule> rules, - Optional<Integer> formatVersion, - OutputStream rulesFileOutputStream, - OutputStream indexingFileOutputStream) - throws RuleSerializeException { - try { - if (rules == null) { - throw new IllegalArgumentException("Null rules cannot be serialized."); - } - - if (rules.size() > TOTAL_RULE_SIZE_LIMIT) { - throw new IllegalArgumentException("Too many rules provided: " + rules.size()); - } - - // Determine the indexing groups and the order of the rules within each indexed group. - Map<Integer, Map<String, List<Rule>>> indexedRules = - RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets(rules); - - // Validate the rule blocks are not larger than expected limits. - verifySize(indexedRules.get(PACKAGE_NAME_INDEXED), INDEXED_RULE_SIZE_LIMIT); - verifySize(indexedRules.get(APP_CERTIFICATE_INDEXED), INDEXED_RULE_SIZE_LIMIT); - verifySize(indexedRules.get(NOT_INDEXED), NONINDEXED_RULE_SIZE_LIMIT); - - // Serialize the rules. - ByteTrackedOutputStream ruleFileByteTrackedOutputStream = - new ByteTrackedOutputStream(rulesFileOutputStream); - serializeRuleFileMetadata(formatVersion, ruleFileByteTrackedOutputStream); - LinkedHashMap<String, Integer> packageNameIndexes = - serializeRuleList( - indexedRules.get(PACKAGE_NAME_INDEXED), - ruleFileByteTrackedOutputStream); - LinkedHashMap<String, Integer> appCertificateIndexes = - serializeRuleList( - indexedRules.get(APP_CERTIFICATE_INDEXED), - ruleFileByteTrackedOutputStream); - LinkedHashMap<String, Integer> unindexedRulesIndexes = - serializeRuleList( - indexedRules.get(NOT_INDEXED), ruleFileByteTrackedOutputStream); - - // Serialize their indexes. - BitOutputStream indexingBitOutputStream = new BitOutputStream(indexingFileOutputStream); - serializeIndexGroup(packageNameIndexes, indexingBitOutputStream, /* isIndexed= */ true); - serializeIndexGroup( - appCertificateIndexes, indexingBitOutputStream, /* isIndexed= */ true); - serializeIndexGroup( - unindexedRulesIndexes, indexingBitOutputStream, /* isIndexed= */ false); - indexingBitOutputStream.flush(); - } catch (Exception e) { - throw new RuleSerializeException(e.getMessage(), e); - } - } - - private void verifySize(Map<String, List<Rule>> ruleListMap, int ruleSizeLimit) { - int totalRuleCount = - ruleListMap.values().stream() - .map(list -> list.size()) - .collect(Collectors.summingInt(Integer::intValue)); - if (totalRuleCount > ruleSizeLimit) { - throw new IllegalArgumentException( - "Too many rules provided in the indexing group. Provided " - + totalRuleCount - + " limit " - + ruleSizeLimit); - } - } - - private void serializeRuleFileMetadata( - Optional<Integer> formatVersion, ByteTrackedOutputStream outputStream) - throws IOException { - int formatVersionValue = formatVersion.orElse(DEFAULT_FORMAT_VERSION); - - BitOutputStream bitOutputStream = new BitOutputStream(outputStream); - bitOutputStream.setNext(FORMAT_VERSION_BITS, formatVersionValue); - bitOutputStream.flush(); - } - - private LinkedHashMap<String, Integer> serializeRuleList( - Map<String, List<Rule>> rulesMap, ByteTrackedOutputStream outputStream) - throws IOException { - Preconditions.checkArgument( - rulesMap != null, "serializeRuleList should never be called with null rule list."); - - BitOutputStream bitOutputStream = new BitOutputStream(outputStream); - LinkedHashMap<String, Integer> indexMapping = new LinkedHashMap(); - indexMapping.put(START_INDEXING_KEY, outputStream.getWrittenBytesCount()); - - List<String> sortedKeys = rulesMap.keySet().stream().sorted().collect(Collectors.toList()); - int indexTracker = 0; - for (String key : sortedKeys) { - if (indexTracker >= INDEXING_BLOCK_SIZE) { - indexMapping.put(key, outputStream.getWrittenBytesCount()); - indexTracker = 0; - } - - for (Rule rule : rulesMap.get(key)) { - serializeRule(rule, bitOutputStream); - bitOutputStream.flush(); - indexTracker++; - } - } - indexMapping.put(END_INDEXING_KEY, outputStream.getWrittenBytesCount()); - - return indexMapping; - } - - private void serializeRule(Rule rule, BitOutputStream bitOutputStream) throws IOException { - if (rule == null) { - throw new IllegalArgumentException("Null rule can not be serialized"); - } - - // Start with a '1' bit to mark the start of a rule. - bitOutputStream.setNext(); - - serializeFormula(rule.getFormula(), bitOutputStream); - bitOutputStream.setNext(EFFECT_BITS, rule.getEffect()); - - // End with a '1' bit to mark the end of a rule. - bitOutputStream.setNext(); - } - - private void serializeFormula(IntegrityFormula formula, BitOutputStream bitOutputStream) - throws IOException { - if (formula instanceof AtomicFormula) { - serializeAtomicFormula((AtomicFormula) formula, bitOutputStream); - } else if (formula instanceof CompoundFormula) { - serializeCompoundFormula((CompoundFormula) formula, bitOutputStream); - } else if (formula instanceof InstallerAllowedByManifestFormula) { - bitOutputStream.setNext(SEPARATOR_BITS, INSTALLER_ALLOWED_BY_MANIFEST_START); - } else { - throw new IllegalArgumentException( - String.format("Invalid formula type: %s", formula.getClass())); - } - } - - private void serializeCompoundFormula( - CompoundFormula compoundFormula, BitOutputStream bitOutputStream) throws IOException { - if (compoundFormula == null) { - throw new IllegalArgumentException("Null compound formula can not be serialized"); - } - - bitOutputStream.setNext(SEPARATOR_BITS, COMPOUND_FORMULA_START); - bitOutputStream.setNext(CONNECTOR_BITS, compoundFormula.getConnector()); - for (IntegrityFormula formula : compoundFormula.getFormulas()) { - serializeFormula(formula, bitOutputStream); - } - bitOutputStream.setNext(SEPARATOR_BITS, COMPOUND_FORMULA_END); - } - - private void serializeAtomicFormula( - AtomicFormula atomicFormula, BitOutputStream bitOutputStream) throws IOException { - if (atomicFormula == null) { - throw new IllegalArgumentException("Null atomic formula can not be serialized"); - } - - bitOutputStream.setNext(SEPARATOR_BITS, ATOMIC_FORMULA_START); - bitOutputStream.setNext(KEY_BITS, atomicFormula.getKey()); - if (atomicFormula.getTag() == AtomicFormula.STRING_ATOMIC_FORMULA_TAG) { - AtomicFormula.StringAtomicFormula stringAtomicFormula = - (AtomicFormula.StringAtomicFormula) atomicFormula; - bitOutputStream.setNext(OPERATOR_BITS, AtomicFormula.EQ); - serializeStringValue( - stringAtomicFormula.getValue(), - stringAtomicFormula.getIsHashedValue(), - bitOutputStream); - } else if (atomicFormula.getTag() == AtomicFormula.LONG_ATOMIC_FORMULA_TAG) { - AtomicFormula.LongAtomicFormula longAtomicFormula = - (AtomicFormula.LongAtomicFormula) atomicFormula; - bitOutputStream.setNext(OPERATOR_BITS, longAtomicFormula.getOperator()); - // TODO(b/147880712): Temporary hack until we support long values in bitOutputStream - long value = longAtomicFormula.getValue(); - serializeIntValue((int) (value >>> 32), bitOutputStream); - serializeIntValue((int) value, bitOutputStream); - } else if (atomicFormula.getTag() == AtomicFormula.BOOLEAN_ATOMIC_FORMULA_TAG) { - AtomicFormula.BooleanAtomicFormula booleanAtomicFormula = - (AtomicFormula.BooleanAtomicFormula) atomicFormula; - bitOutputStream.setNext(OPERATOR_BITS, AtomicFormula.EQ); - serializeBooleanValue(booleanAtomicFormula.getValue(), bitOutputStream); - } else { - throw new IllegalArgumentException( - String.format("Invalid atomic formula type: %s", atomicFormula.getClass())); - } - } - - private void serializeIndexGroup( - LinkedHashMap<String, Integer> indexes, - BitOutputStream bitOutputStream, - boolean isIndexed) - throws IOException { - // Output the starting location of this indexing group. - serializeStringValue(START_INDEXING_KEY, /* isHashedValue= */ false, bitOutputStream); - serializeIntValue(indexes.get(START_INDEXING_KEY), bitOutputStream); - - // If the group is indexed, output the locations of the indexes. - if (isIndexed) { - for (Map.Entry<String, Integer> entry : indexes.entrySet()) { - if (!entry.getKey().equals(START_INDEXING_KEY) - && !entry.getKey().equals(END_INDEXING_KEY)) { - serializeStringValue( - entry.getKey(), /* isHashedValue= */ false, bitOutputStream); - serializeIntValue(entry.getValue(), bitOutputStream); - } - } - } - - // Output the end location of this indexing group. - serializeStringValue(END_INDEXING_KEY, /*isHashedValue= */ false, bitOutputStream); - serializeIntValue(indexes.get(END_INDEXING_KEY), bitOutputStream); - } - - private void serializeStringValue( - String value, boolean isHashedValue, BitOutputStream bitOutputStream) - throws IOException { - if (value == null) { - throw new IllegalArgumentException("String value can not be null."); - } - byte[] valueBytes = getBytesForString(value, isHashedValue); - - bitOutputStream.setNext(isHashedValue); - bitOutputStream.setNext(VALUE_SIZE_BITS, valueBytes.length); - for (byte valueByte : valueBytes) { - bitOutputStream.setNext(/* numOfBits= */ 8, valueByte); - } - } - - private void serializeIntValue(int value, BitOutputStream bitOutputStream) throws IOException { - bitOutputStream.setNext(/* numOfBits= */ 32, value); - } - - private void serializeBooleanValue(boolean value, BitOutputStream bitOutputStream) - throws IOException { - bitOutputStream.setNext(value); - } - - // Get the byte array for a value. - // If the value is not hashed, use its byte array form directly. - // If the value is hashed, get the raw form decoding of the value. All hashed values are - // hex-encoded. Serialized values are in raw form. - private static byte[] getBytesForString(String value, boolean isHashedValue) { - if (!isHashedValue) { - return value.getBytes(StandardCharsets.UTF_8); - } - return IntegrityUtils.getBytesFromHexDigest(value); - } -} diff --git a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetails.java b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetails.java deleted file mode 100644 index 2cbd4ede5214..000000000000 --- a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetails.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2019 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.android.server.integrity.serializer; - -import android.annotation.IntDef; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** Holds the indexing type and indexing key of a given formula. */ -class RuleIndexingDetails { - - static final int NOT_INDEXED = 0; - static final int PACKAGE_NAME_INDEXED = 1; - static final int APP_CERTIFICATE_INDEXED = 2; - - static final String DEFAULT_RULE_KEY = "N/A"; - - /** Represents which indexed file the rule should be located. */ - @IntDef( - value = { - NOT_INDEXED, - PACKAGE_NAME_INDEXED, - APP_CERTIFICATE_INDEXED - }) - @Retention(RetentionPolicy.SOURCE) - public @interface IndexType { - } - - private @IndexType int mIndexType; - private String mRuleKey; - - /** Constructor without a ruleKey for {@code NOT_INDEXED}. */ - RuleIndexingDetails(@IndexType int indexType) { - this.mIndexType = indexType; - this.mRuleKey = DEFAULT_RULE_KEY; - } - - /** Constructor with a ruleKey for indexed rules. */ - RuleIndexingDetails(@IndexType int indexType, String ruleKey) { - this.mIndexType = indexType; - this.mRuleKey = ruleKey; - } - - /** Returns the indexing type for the rule. */ - @IndexType - public int getIndexType() { - return mIndexType; - } - - /** Returns the identified rule key. */ - public String getRuleKey() { - return mRuleKey; - } -} diff --git a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java b/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java deleted file mode 100644 index e7235591fb9b..000000000000 --- a/services/core/java/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifier.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2019 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.android.server.integrity.serializer; - -import static com.android.server.integrity.serializer.RuleIndexingDetails.APP_CERTIFICATE_INDEXED; -import static com.android.server.integrity.serializer.RuleIndexingDetails.NOT_INDEXED; -import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAGE_NAME_INDEXED; - -import android.content.integrity.AtomicFormula; -import android.content.integrity.CompoundFormula; -import android.content.integrity.IntegrityFormula; -import android.content.integrity.Rule; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -/** A helper class for identifying the indexing type and key of a given rule. */ -class RuleIndexingDetailsIdentifier { - - /** - * Splits a given rule list into three indexing categories. Each rule category is returned as a - * TreeMap that is sorted by their indexing keys -- where keys correspond to package name for - * PACKAGE_NAME_INDEXED rules, app certificate for APP_CERTIFICATE_INDEXED rules and N/A for - * NOT_INDEXED rules. - */ - public static Map<Integer, Map<String, List<Rule>>> splitRulesIntoIndexBuckets( - List<Rule> rules) { - if (rules == null) { - throw new IllegalArgumentException( - "Index buckets cannot be created for null rule list."); - } - - Map<Integer, Map<String, List<Rule>>> typeOrganizedRuleMap = new HashMap(); - typeOrganizedRuleMap.put(NOT_INDEXED, new HashMap()); - typeOrganizedRuleMap.put(PACKAGE_NAME_INDEXED, new HashMap<>()); - typeOrganizedRuleMap.put(APP_CERTIFICATE_INDEXED, new HashMap<>()); - - // Split the rules into the appropriate indexed pattern. The Tree Maps help us to keep the - // entries sorted by their index key. - for (Rule rule : rules) { - RuleIndexingDetails indexingDetails; - try { - indexingDetails = getIndexingDetails(rule.getFormula()); - } catch (Exception e) { - throw new IllegalArgumentException( - String.format("Malformed rule identified. [%s]", rule.toString())); - } - - int ruleIndexType = indexingDetails.getIndexType(); - String ruleKey = indexingDetails.getRuleKey(); - - if (!typeOrganizedRuleMap.get(ruleIndexType).containsKey(ruleKey)) { - typeOrganizedRuleMap.get(ruleIndexType).put(ruleKey, new ArrayList()); - } - - typeOrganizedRuleMap.get(ruleIndexType).get(ruleKey).add(rule); - } - - return typeOrganizedRuleMap; - } - - private static RuleIndexingDetails getIndexingDetails(IntegrityFormula formula) { - switch (formula.getTag()) { - case IntegrityFormula.COMPOUND_FORMULA_TAG: - return getIndexingDetailsForCompoundFormula((CompoundFormula) formula); - case IntegrityFormula.STRING_ATOMIC_FORMULA_TAG: - return getIndexingDetailsForStringAtomicFormula( - (AtomicFormula.StringAtomicFormula) formula); - case IntegrityFormula.LONG_ATOMIC_FORMULA_TAG: - case IntegrityFormula.INSTALLER_ALLOWED_BY_MANIFEST_FORMULA_TAG: - case IntegrityFormula.BOOLEAN_ATOMIC_FORMULA_TAG: - // Package name and app certificate related formulas are string atomic formulas. - return new RuleIndexingDetails(NOT_INDEXED); - default: - throw new IllegalArgumentException( - String.format("Invalid formula tag type: %s", formula.getTag())); - } - } - - private static RuleIndexingDetails getIndexingDetailsForCompoundFormula( - CompoundFormula compoundFormula) { - int connector = compoundFormula.getConnector(); - List<IntegrityFormula> formulas = compoundFormula.getFormulas(); - - switch (connector) { - case CompoundFormula.AND: - case CompoundFormula.OR: - // If there is a package name related atomic rule, return package name indexed. - Optional<RuleIndexingDetails> packageNameRule = - formulas.stream() - .map(formula -> getIndexingDetails(formula)) - .filter(ruleIndexingDetails -> ruleIndexingDetails.getIndexType() - == PACKAGE_NAME_INDEXED) - .findAny(); - if (packageNameRule.isPresent()) { - return packageNameRule.get(); - } - - // If there is an app certificate related atomic rule but no package name related - // atomic rule, return app certificate indexed. - Optional<RuleIndexingDetails> appCertificateRule = - formulas.stream() - .map(formula -> getIndexingDetails(formula)) - .filter(ruleIndexingDetails -> ruleIndexingDetails.getIndexType() - == APP_CERTIFICATE_INDEXED) - .findAny(); - if (appCertificateRule.isPresent()) { - return appCertificateRule.get(); - } - - // Do not index when there is not package name or app certificate indexing. - return new RuleIndexingDetails(NOT_INDEXED); - default: - // Having a NOT operator in the indexing messes up the indexing; e.g., deny - // installation if app certificate is NOT X (should not be indexed with app cert - // X). We will not keep these rules indexed. - // Also any other type of unknown operators will not be indexed. - return new RuleIndexingDetails(NOT_INDEXED); - } - } - - private static RuleIndexingDetails getIndexingDetailsForStringAtomicFormula( - AtomicFormula.StringAtomicFormula atomicFormula) { - switch (atomicFormula.getKey()) { - case AtomicFormula.PACKAGE_NAME: - return new RuleIndexingDetails(PACKAGE_NAME_INDEXED, atomicFormula.getValue()); - case AtomicFormula.APP_CERTIFICATE: - return new RuleIndexingDetails(APP_CERTIFICATE_INDEXED, atomicFormula.getValue()); - default: - return new RuleIndexingDetails(NOT_INDEXED); - } - } -} - diff --git a/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java deleted file mode 100644 index 022b4b8cb7eb..000000000000 --- a/services/core/java/com/android/server/integrity/serializer/RuleMetadataSerializer.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2019 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.android.server.integrity.serializer; - -import static com.android.server.integrity.parser.RuleMetadataParser.RULE_PROVIDER_TAG; -import static com.android.server.integrity.parser.RuleMetadataParser.VERSION_TAG; - -import android.util.Xml; - -import com.android.modules.utils.TypedXmlSerializer; -import com.android.server.integrity.model.RuleMetadata; - -import org.xmlpull.v1.XmlSerializer; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.charset.StandardCharsets; - -/** Helper class for writing rule metadata. */ -public class RuleMetadataSerializer { - /** Serialize the rule metadata to an output stream. */ - public static void serialize(RuleMetadata ruleMetadata, OutputStream outputStream) - throws IOException { - TypedXmlSerializer xmlSerializer = Xml.resolveSerializer(outputStream); - - serializeTaggedValue(xmlSerializer, RULE_PROVIDER_TAG, ruleMetadata.getRuleProvider()); - serializeTaggedValue(xmlSerializer, VERSION_TAG, ruleMetadata.getVersion()); - - xmlSerializer.endDocument(); - } - - private static void serializeTaggedValue(TypedXmlSerializer xmlSerializer, String tag, - String value) throws IOException { - xmlSerializer.startTag(/* namespace= */ null, tag); - xmlSerializer.text(value); - xmlSerializer.endTag(/* namespace= */ null, tag); - } -} diff --git a/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java b/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java deleted file mode 100644 index 2941856915a8..000000000000 --- a/services/core/java/com/android/server/integrity/serializer/RuleSerializer.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2019 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.android.server.integrity.serializer; - -import android.content.integrity.Rule; - -import java.io.OutputStream; -import java.util.List; -import java.util.Optional; - -/** A helper class to serialize rules from the {@link Rule} model. */ -public interface RuleSerializer { - - /** Serialize rules to an output stream */ - void serialize( - List<Rule> rules, - Optional<Integer> formatVersion, - OutputStream ruleFileOutputStream, - OutputStream indexingFileOutputStream) - throws RuleSerializeException; - - /** Serialize rules to a ByteArray. */ - byte[] serialize(List<Rule> rules, Optional<Integer> formatVersion) - throws RuleSerializeException; -} diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 8798a64ec479..c314ab06fbad 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -253,10 +253,10 @@ public class LockSettingsService extends ILockSettings.Stub { private static final String MIGRATED_FRP2 = "migrated_frp2"; private static final String MIGRATED_KEYSTORE_NS = "migrated_keystore_namespace"; - private static final String MIGRATED_SP_CE_ONLY = "migrated_all_users_to_sp_and_bound_ce"; private static final String MIGRATED_SP_FULL = "migrated_all_users_to_sp_and_bound_keys"; private static final String MIGRATED_WEAVER_DISABLED_ON_UNSECURED_USERS = "migrated_weaver_disabled_on_unsecured_users"; + // Note: some other migrated_* strings used to be used and may exist in the database already. // Duration that LockSettingsService will store the gatekeeper password for. This allows // multiple biometric enrollments without prompting the user to enter their password via @@ -347,6 +347,8 @@ public class LockSettingsService extends ILockSettings.Stub { private final StorageManagerInternal mStorageManagerInternal; + private final Object mGcWorkToken = new Object(); + // This class manages life cycle events for encrypted users on File Based Encryption (FBE) // devices. The most basic of these is to show/hide notifications about missing features until // the user unlocks the account and credential-encrypted storage is available. @@ -1219,21 +1221,16 @@ public class LockSettingsService extends ILockSettings.Stub { Slog.i(TAG, "Synthetic password is already not protected by Weaver"); } } else if (sp == null) { - Slogf.wtf(TAG, "Failed to unwrap synthetic password for unsecured user %d", userId); - return; + throw new IllegalStateException( + "Failed to unwrap synthetic password for unsecured user " + userId); } // Call setCeStorageProtection(), to re-encrypt the CE key with the SP if it's currently - // encrypted by an empty secret. Skip this if it was definitely already done as part of the - // upgrade to Android 14, since while setCeStorageProtection() is idempotent it does log - // some error messages when called again. Do not skip this if - // config_disableWeaverOnUnsecuredUsers=true, since in that case we'd like to recover from - // the case where an earlier upgrade to Android 14 incorrectly skipped this step. - if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null - || isWeaverDisabledOnUnsecuredUsers()) { - Slogf.i(TAG, "Encrypting CE key of user %d with synthetic password", userId); - setCeStorageProtection(userId, sp); - } + // encrypted by an empty secret. If the CE key is already encrypted by the SP, then this is + // a no-op except for some log messages. + Slogf.i(TAG, "Encrypting CE key of user %d with synthetic password", userId); + setCeStorageProtection(userId, sp); + Slogf.i(TAG, "Initializing Keystore super keys for user %d", userId); initKeystoreSuperKeys(userId, sp, /* allowExisting= */ true); } @@ -3637,11 +3634,19 @@ public class LockSettingsService extends ILockSettings.Stub { * release references to the argument. */ private void scheduleGc() { + // Cancel any existing GC request first, so that GC requests don't pile up if lockscreen + // credential operations are happening very quickly, e.g. as sometimes happens during tests. + // + // This delays the already-requested GC, but that is fine in practice where lockscreen + // operations don't happen very quickly. And the precise time that the sanitization happens + // isn't very important; doing it within a minute can be fine, for example. + mHandler.removeCallbacksAndMessages(mGcWorkToken); + mHandler.postDelayed(() -> { System.gc(); System.runFinalization(); System.gc(); - }, 2000); + }, mGcWorkToken, 2000); } private class DeviceProvisionedObserver extends ContentObserver { diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java index 89555a9f1de4..c8a87994ee16 100644 --- a/services/core/java/com/android/server/media/MediaSession2Record.java +++ b/services/core/java/com/android/server/media/MediaSession2Record.java @@ -161,6 +161,11 @@ public class MediaSession2Record extends MediaSessionRecordImpl { } @Override + public void onGlobalPrioritySessionActiveChanged(boolean isGlobalPrioritySessionActive) { + // NA as MediaSession2 doesn't support UserEngagementStates for FGS. + } + + @Override public boolean sendMediaButton(String packageName, int pid, int uid, boolean asSystemService, KeyEvent ke, int sequenceId, ResultReceiver cb) { // TODO(jaewan): Implement. diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 0a9109b3e98c..0d779af22c2d 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -234,51 +234,49 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde private final Runnable mUserEngagementTimeoutExpirationRunnable = () -> { synchronized (mLock) { - updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ true); + updateUserEngagedStateIfNeededLocked( + /* isTimeoutExpired= */ true, + /* isGlobalPrioritySessionActive= */ false); } }; @GuardedBy("mLock") private @UserEngagementState int mUserEngagementState = USER_DISENGAGED; - @IntDef({USER_PERMANENTLY_ENGAGED, USER_TEMPORARY_ENGAGED, USER_DISENGAGED}) + @IntDef({USER_PERMANENTLY_ENGAGED, USER_TEMPORARILY_ENGAGED, USER_DISENGAGED}) @Retention(RetentionPolicy.SOURCE) private @interface UserEngagementState {} /** - * Indicates that the session is active and in one of the user engaged states. + * Indicates that the session is {@linkplain MediaSession#isActive() active} and in one of the + * {@linkplain PlaybackState#isActive() active states}. * * @see #updateUserEngagedStateIfNeededLocked(boolean) */ private static final int USER_PERMANENTLY_ENGAGED = 0; /** - * Indicates that the session is active and in {@link PlaybackState#STATE_PAUSED} state. + * Indicates that the session is {@linkplain MediaSession#isActive() active} and has recently + * switched to one of the {@linkplain PlaybackState#isActive() inactive states}. * * @see #updateUserEngagedStateIfNeededLocked(boolean) */ - private static final int USER_TEMPORARY_ENGAGED = 1; + private static final int USER_TEMPORARILY_ENGAGED = 1; /** - * Indicates that the session is either not active or in one of the user disengaged states + * Indicates that the session is either not {@linkplain MediaSession#isActive() active} or in + * one of the {@linkplain PlaybackState#isActive() inactive states}. * * @see #updateUserEngagedStateIfNeededLocked(boolean) */ private static final int USER_DISENGAGED = 2; /** - * Indicates the duration of the temporary engaged states, in milliseconds. + * Indicates the duration of the temporary engaged state, in milliseconds. * - * <p>Some {@link MediaSession} states like {@link PlaybackState#STATE_PAUSED} are temporarily - * engaged, meaning the corresponding session is only considered in an engaged state for the - * duration of this timeout, and only if coming from an engaged state. - * - * <p>For example, if a session is transitioning from a user-engaged state {@link - * PlaybackState#STATE_PLAYING} to a temporary user-engaged state {@link - * PlaybackState#STATE_PAUSED}, then the session will be considered in a user-engaged state for - * the duration of this timeout, starting at the transition instant. However, a temporary - * user-engaged state is not considered user-engaged when transitioning from a non-user engaged - * state {@link PlaybackState#STATE_STOPPED}. + * <p>When switching to an {@linkplain PlaybackState#isActive() inactive state}, the user is + * treated as temporarily engaged, meaning the corresponding session is only considered in an + * engaged state for the duration of this timeout, and only if coming from an engaged state. */ private static final int TEMP_USER_ENGAGED_TIMEOUT_MS = 600000; @@ -604,7 +602,8 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde mSessionCb.mCb.asBinder().unlinkToDeath(this, 0); mDestroyed = true; mPlaybackState = null; - updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ true); + updateUserEngagedStateIfNeededLocked( + /* isTimeoutExpired= */ true, /* isGlobalPrioritySessionActive= */ false); mHandler.post(MessageHandler.MSG_DESTROYED); } } @@ -621,6 +620,24 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde mHandler.post(mUserEngagementTimeoutExpirationRunnable); } + @Override + public void onGlobalPrioritySessionActiveChanged(boolean isGlobalPrioritySessionActive) { + mHandler.post( + () -> { + synchronized (mLock) { + if (isGlobalPrioritySessionActive) { + mHandler.removeCallbacks(mUserEngagementTimeoutExpirationRunnable); + } else { + if (mUserEngagementState == USER_TEMPORARILY_ENGAGED) { + mHandler.postDelayed( + mUserEngagementTimeoutExpirationRunnable, + TEMP_USER_ENGAGED_TIMEOUT_MS); + } + } + } + }); + } + /** * Sends media button. * @@ -1111,21 +1128,20 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde } @GuardedBy("mLock") - private void updateUserEngagedStateIfNeededLocked(boolean isTimeoutExpired) { + private void updateUserEngagedStateIfNeededLocked( + boolean isTimeoutExpired, boolean isGlobalPrioritySessionActive) { if (!Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange()) { return; } int oldUserEngagedState = mUserEngagementState; int newUserEngagedState; - if (!isActive() || mPlaybackState == null || mDestroyed) { + if (!isActive() || mPlaybackState == null) { newUserEngagedState = USER_DISENGAGED; - } else if (isActive() && mPlaybackState.isActive()) { + } else if (mPlaybackState.isActive()) { newUserEngagedState = USER_PERMANENTLY_ENGAGED; - } else if (mPlaybackState.getState() == PlaybackState.STATE_PAUSED) { - newUserEngagedState = - oldUserEngagedState == USER_PERMANENTLY_ENGAGED || !isTimeoutExpired - ? USER_TEMPORARY_ENGAGED - : USER_DISENGAGED; + } else if (oldUserEngagedState == USER_PERMANENTLY_ENGAGED + || (oldUserEngagedState == USER_TEMPORARILY_ENGAGED && !isTimeoutExpired)) { + newUserEngagedState = USER_TEMPORARILY_ENGAGED; } else { newUserEngagedState = USER_DISENGAGED; } @@ -1134,7 +1150,7 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde } mUserEngagementState = newUserEngagedState; - if (newUserEngagedState == USER_TEMPORARY_ENGAGED) { + if (newUserEngagedState == USER_TEMPORARILY_ENGAGED && !isGlobalPrioritySessionActive) { mHandler.postDelayed( mUserEngagementTimeoutExpirationRunnable, TEMP_USER_ENGAGED_TIMEOUT_MS); } else { @@ -1189,9 +1205,11 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde .logFgsApiEnd(ActivityManager.FOREGROUND_SERVICE_API_TYPE_MEDIA_PLAYBACK, callingUid, callingPid); } + boolean isGlobalPrioritySessionActive = mService.isGlobalPrioritySessionActive(); synchronized (mLock) { mIsActive = active; - updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ false); + updateUserEngagedStateIfNeededLocked( + /* isTimeoutExpired= */ false, isGlobalPrioritySessionActive); } long token = Binder.clearCallingIdentity(); try { @@ -1348,9 +1366,11 @@ public class MediaSessionRecord extends MediaSessionRecordImpl implements IBinde boolean shouldUpdatePriority = ALWAYS_PRIORITY_STATES.contains(newState) || (!TRANSITION_PRIORITY_STATES.contains(oldState) && TRANSITION_PRIORITY_STATES.contains(newState)); + boolean isGlobalPrioritySessionActive = mService.isGlobalPrioritySessionActive(); synchronized (mLock) { mPlaybackState = state; - updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ false); + updateUserEngagedStateIfNeededLocked( + /* isTimeoutExpired= */ false, isGlobalPrioritySessionActive); } final long token = Binder.clearCallingIdentity(); try { diff --git a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java index 15f90d4fdd0e..6c3b1234935a 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java +++ b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java @@ -206,6 +206,10 @@ public abstract class MediaSessionRecordImpl { */ public abstract void expireTempEngaged(); + /** Notifies record that the global priority session active state changed. */ + public abstract void onGlobalPrioritySessionActiveChanged( + boolean isGlobalPrioritySessionActive); + @Override public final boolean equals(Object o) { if (this == o) return true; diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index 1ebc856af2d8..2b29fbd9c5b5 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -362,6 +362,7 @@ public class MediaSessionService extends SystemService implements Monitor { + record.isActive()); } user.pushAddressedPlayerChangedLocked(); + mHandler.post(this::notifyGlobalPrioritySessionActiveChanged); } else { if (!user.mPriorityStack.contains(record)) { Log.w(TAG, "Unknown session updated. Ignoring."); @@ -394,11 +395,16 @@ public class MediaSessionService extends SystemService implements Monitor { // Currently only media1 can become global priority session. void setGlobalPrioritySession(MediaSessionRecord record) { + boolean globalPrioritySessionActiveChanged = false; synchronized (mLock) { FullUserRecord user = getFullUserRecordLocked(record.getUserId()); if (mGlobalPrioritySession != record) { Log.d(TAG, "Global priority session is changed from " + mGlobalPrioritySession + " to " + record); + globalPrioritySessionActiveChanged = + (mGlobalPrioritySession == null && record.isActive()) + || (mGlobalPrioritySession != null + && mGlobalPrioritySession.isActive() != record.isActive()); mGlobalPrioritySession = record; if (user != null && user.mPriorityStack.contains(record)) { // Handle the global priority session separately. @@ -409,6 +415,30 @@ public class MediaSessionService extends SystemService implements Monitor { } } } + if (globalPrioritySessionActiveChanged) { + mHandler.post(this::notifyGlobalPrioritySessionActiveChanged); + } + } + + /** Returns whether the global priority session is active. */ + boolean isGlobalPrioritySessionActive() { + synchronized (mLock) { + return isGlobalPriorityActiveLocked(); + } + } + + private void notifyGlobalPrioritySessionActiveChanged() { + if (!Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange()) { + return; + } + synchronized (mLock) { + boolean isGlobalPriorityActive = isGlobalPriorityActiveLocked(); + for (Set<MediaSessionRecordImpl> records : mUserEngagedSessionsForFgs.values()) { + for (MediaSessionRecordImpl record : records) { + record.onGlobalPrioritySessionActiveChanged(isGlobalPriorityActive); + } + } + } } private List<MediaSessionRecord> getActiveSessionsLocked(int userId) { @@ -646,8 +676,11 @@ public class MediaSessionService extends SystemService implements Monitor { if (mGlobalPrioritySession == session) { mGlobalPrioritySession = null; - if (session.isActive() && user != null) { - user.pushAddressedPlayerChangedLocked(); + if (session.isActive()) { + if (user != null) { + user.pushAddressedPlayerChangedLocked(); + } + mHandler.post(this::notifyGlobalPrioritySessionActiveChanged); } } else { if (user != null) { diff --git a/services/core/java/com/android/server/vcn/VcnContext.java b/services/core/java/com/android/server/vcn/VcnContext.java index a492a72933d7..6ce868540070 100644 --- a/services/core/java/com/android/server/vcn/VcnContext.java +++ b/services/core/java/com/android/server/vcn/VcnContext.java @@ -18,7 +18,6 @@ package com.android.server.vcn; import android.annotation.NonNull; import android.content.Context; -import android.net.IpSecTransformState; import android.net.vcn.FeatureFlags; import android.net.vcn.FeatureFlagsImpl; import android.os.Looper; @@ -70,19 +69,6 @@ public class VcnContext { return mIsInTestMode; } - public boolean isFlagIpSecTransformStateEnabled() { - // TODO: b/328844044: Ideally this code should gate the behavior by checking the - // android.net.platform.flags.ipsec_transform_state flag but that flag is not accessible - // right now. We should either update the code when the flag is accessible or remove the - // legacy behavior after VIC SDK finalization - try { - new IpSecTransformState.Builder(); - return true; - } catch (Exception e) { - return false; - } - } - @NonNull public FeatureFlags getFeatureFlags() { return mFeatureFlags; diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 189b6089186e..2d3bc84debff 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -1912,8 +1912,7 @@ public class VcnGatewayConnection extends StateMachine { // Transforms do not need to be persisted; the IkeSession will keep them alive mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform); - if (direction == IpSecManager.DIRECTION_IN - && mVcnContext.isFlagIpSecTransformStateEnabled()) { + if (direction == IpSecManager.DIRECTION_IN) { mUnderlyingNetworkController.updateInboundTransform(mUnderlying, transform); } diff --git a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java index 6f1e15b5033f..16ab51e8d604 100644 --- a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java +++ b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java @@ -148,12 +148,6 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor { Objects.requireNonNull(deps, "Missing deps"); - if (!vcnContext.isFlagIpSecTransformStateEnabled()) { - // Caller error - logWtf("ipsecTransformState flag disabled"); - throw new IllegalAccessException("ipsecTransformState flag disabled"); - } - mHandler = new Handler(getVcnContext().getLooper()); mPowerManager = getVcnContext().getContext().getSystemService(PowerManager.class); diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java index 0b9b677df16a..3eeeece5da46 100644 --- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java +++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkController.java @@ -204,10 +204,8 @@ public class UnderlyingNetworkController { List<NetworkCallback> oldCellCallbacks = new ArrayList<>(mCellBringupCallbacks); mCellBringupCallbacks.clear(); - if (mVcnContext.isFlagIpSecTransformStateEnabled()) { - for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) { - evaluator.close(); - } + for (UnderlyingNetworkEvaluator evaluator : mUnderlyingNetworkRecords.values()) { + evaluator.close(); } mUnderlyingNetworkRecords.clear(); @@ -429,10 +427,7 @@ public class UnderlyingNetworkController { if (oldSnapshot .getAllSubIdsInGroup(mSubscriptionGroup) .equals(newSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))) { - - if (mVcnContext.isFlagIpSecTransformStateEnabled()) { - reevaluateNetworks(); - } + reevaluateNetworks(); return; } registerOrUpdateNetworkRequests(); @@ -445,11 +440,6 @@ public class UnderlyingNetworkController { */ public void updateInboundTransform( @NonNull UnderlyingNetworkRecord currentNetwork, @NonNull IpSecTransform transform) { - if (!mVcnContext.isFlagIpSecTransformStateEnabled()) { - logWtf("#updateInboundTransform: unexpected call; flags missing"); - return; - } - Objects.requireNonNull(currentNetwork, "currentNetwork is null"); Objects.requireNonNull(transform, "transform is null"); @@ -572,10 +562,7 @@ public class UnderlyingNetworkController { @Override public void onLost(@NonNull Network network) { - if (mVcnContext.isFlagIpSecTransformStateEnabled()) { - mUnderlyingNetworkRecords.get(network).close(); - } - + mUnderlyingNetworkRecords.get(network).close(); mUnderlyingNetworkRecords.remove(network); reevaluateNetworks(); @@ -648,11 +635,6 @@ public class UnderlyingNetworkController { class NetworkEvaluatorCallbackImpl implements NetworkEvaluatorCallback { @Override public void onEvaluationResultChanged() { - if (!mVcnContext.isFlagIpSecTransformStateEnabled()) { - logWtf("#onEvaluationResultChanged: unexpected call; flags missing"); - return; - } - mVcnContext.ensureRunningOnLooperThread(); reevaluateNetworks(); } diff --git a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java index 448a7ebfffd8..08be11e29689 100644 --- a/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java +++ b/services/core/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluator.java @@ -102,17 +102,15 @@ public class UnderlyingNetworkEvaluator { updatePriorityClass( underlyingNetworkTemplates, subscriptionGroup, lastSnapshot, carrierConfig); - if (isIpSecPacketLossDetectorEnabled()) { - try { - mMetricMonitors.add( - mDependencies.newIpSecPacketLossDetector( - mVcnContext, - mNetworkRecordBuilder.getNetwork(), - carrierConfig, - new MetricMonitorCallbackImpl())); - } catch (IllegalAccessException e) { - // No action. Do not add anything to mMetricMonitors - } + try { + mMetricMonitors.add( + mDependencies.newIpSecPacketLossDetector( + mVcnContext, + mNetworkRecordBuilder.getNetwork(), + carrierConfig, + new MetricMonitorCallbackImpl())); + } catch (IllegalAccessException e) { + // No action. Do not add anything to mMetricMonitors } } @@ -188,22 +186,12 @@ public class UnderlyingNetworkEvaluator { } } - private boolean isIpSecPacketLossDetectorEnabled() { - return isIpSecPacketLossDetectorEnabled(mVcnContext); - } - - private static boolean isIpSecPacketLossDetectorEnabled(VcnContext vcnContext) { - return vcnContext.isFlagIpSecTransformStateEnabled(); - } - /** Get the comparator for UnderlyingNetworkEvaluator */ public static Comparator<UnderlyingNetworkEvaluator> getComparator(VcnContext vcnContext) { return (left, right) -> { - if (isIpSecPacketLossDetectorEnabled(vcnContext)) { - if (left.mIsPenalized != right.mIsPenalized) { - // A penalized network should have lower priority which means a larger index - return left.mIsPenalized ? 1 : -1; - } + if (left.mIsPenalized != right.mIsPenalized) { + // A penalized network should have lower priority which means a larger index + return left.mIsPenalized ? 1 : -1; } final int leftIndex = left.mPriorityClass; diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java index 043470f62850..9ee42b17c2a4 100644 --- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java +++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java @@ -84,8 +84,13 @@ public class WebViewUpdateService extends SystemService { mWebViewUpdatedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action == null) { + return; + } + int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); - switch (intent.getAction()) { + switch (action) { case Intent.ACTION_PACKAGE_REMOVED: // When a package is replaced we will receive two intents, one // representing the removal of the old package and one representing the diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index e6d81324efa1..d2a128b74732 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -938,7 +938,6 @@ class ActivityStarter { mLastStartReason = request.reason; mLastStartActivityTimeMs = System.currentTimeMillis(); - final ActivityRecord previousStart = mLastStartActivityRecord; final IApplicationThread caller = request.caller; Intent intent = request.intent; NeededUriGrants intentGrants = request.intentGrants; diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 7a710dc51004..662f916d8a69 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -55,7 +55,6 @@ cc_library_static { "com_android_server_powerstats_PowerStatsService.cpp", "com_android_server_power_stats_CpuPowerStatsCollector.cpp", "com_android_server_hint_HintManagerService.cpp", - "com_android_server_SerialService.cpp", "com_android_server_soundtrigger_middleware_AudioSessionProviderImpl.cpp", "com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker.cpp", "com_android_server_stats_pull_StatsPullAtomService.cpp", diff --git a/services/core/jni/com_android_server_SerialService.cpp b/services/core/jni/com_android_server_SerialService.cpp deleted file mode 100644 index 6600c981b68d..000000000000 --- a/services/core/jni/com_android_server_SerialService.cpp +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2011 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. - */ - -#define LOG_TAG "SerialServiceJNI" -#include "utils/Log.h" - -#include "jni.h" -#include <nativehelper/JNIPlatformHelp.h> -#include "android_runtime/AndroidRuntime.h" - -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -namespace android -{ - -static struct parcel_file_descriptor_offsets_t -{ - jclass mClass; - jmethodID mConstructor; -} gParcelFileDescriptorOffsets; - -static jobject android_server_SerialService_open(JNIEnv *env, jobject /* thiz */, jstring path) -{ - const char *pathStr = env->GetStringUTFChars(path, NULL); - - int fd = open(pathStr, O_RDWR | O_NOCTTY); - if (fd < 0) { - ALOGE("could not open %s", pathStr); - env->ReleaseStringUTFChars(path, pathStr); - return NULL; - } - env->ReleaseStringUTFChars(path, pathStr); - - jobject fileDescriptor = jniCreateFileDescriptor(env, fd); - if (fileDescriptor == NULL) { - close(fd); - return NULL; - } - return env->NewObject(gParcelFileDescriptorOffsets.mClass, - gParcelFileDescriptorOffsets.mConstructor, fileDescriptor); -} - - -static const JNINativeMethod method_table[] = { - { "native_open", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;", - (void*)android_server_SerialService_open }, -}; - -int register_android_server_SerialService(JNIEnv *env) -{ - jclass clazz = env->FindClass("com/android/server/SerialService"); - if (clazz == NULL) { - ALOGE("Can't find com/android/server/SerialService"); - return -1; - } - - clazz = env->FindClass("android/os/ParcelFileDescriptor"); - LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor"); - gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz); - gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V"); - LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL, - "Unable to find constructor for android.os.ParcelFileDescriptor"); - - return jniRegisterNativeMethods(env, "com/android/server/SerialService", - method_table, NELEM(method_table)); -} - -}; diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index 6464081d615a..f9633e2e0b23 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -33,7 +33,6 @@ int register_android_server_PowerStatsService(JNIEnv* env); int register_android_server_power_stats_CpuPowerStatsCollector(JNIEnv* env); int register_android_server_HintManagerService(JNIEnv* env); int register_android_server_storage_AppFuse(JNIEnv* env); -int register_android_server_SerialService(JNIEnv* env); int register_android_server_SystemServer(JNIEnv* env); int register_android_server_UsbAlsaJackDetector(JNIEnv* env); int register_android_server_UsbAlsaMidiDevice(JNIEnv* env); @@ -93,7 +92,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_PowerStatsService(env); register_android_server_power_stats_CpuPowerStatsCollector(env); register_android_server_HintManagerService(env); - register_android_server_SerialService(env); register_android_server_InputManager(env); register_android_server_LightsService(env); register_android_server_UsbDeviceManager(env); diff --git a/services/tests/mockingservicestests/src/com/android/server/OWNERS b/services/tests/mockingservicestests/src/com/android/server/OWNERS index dc5cb8d6bdf5..0c9f70ca96b5 100644 --- a/services/tests/mockingservicestests/src/com/android/server/OWNERS +++ b/services/tests/mockingservicestests/src/com/android/server/OWNERS @@ -1,6 +1,6 @@ per-file *Alarm* = file:/apex/jobscheduler/OWNERS per-file *AppStateTracker* = file:/apex/jobscheduler/OWNERS -per-file *DeviceIdleController* = file:/apex/jobscheduler/OWNERS +per-file *DeviceIdleController* = file:/apex/jobscheduler/DEVICE_IDLE_OWNERS per-file SensitiveContentProtectionManagerService* = file:/core/java/android/permission/OWNERS per-file RescuePartyTest.java = file:/packages/CrashRecovery/OWNERS per-file *Storage* = file:/core/java/android/os/storage/OWNERS diff --git a/services/tests/mockingservicestests/src/com/android/server/am/OWNERS b/services/tests/mockingservicestests/src/com/android/server/am/OWNERS index 4fac647c4ceb..809b7bbfd3a0 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/OWNERS +++ b/services/tests/mockingservicestests/src/com/android/server/am/OWNERS @@ -2,3 +2,4 @@ include /services/core/java/com/android/server/am/OWNERS per-file ApplicationStartInfoTest.java = yforta@google.com, carmenjackson@google.com, jji@google.com per-file CachedAppOptimizerTest.java = file:/PERFORMANCE_OWNERS +per-file BaseBroadcastQueueTest.java = file:/BROADCASTS_OWNERS diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java deleted file mode 100644 index 9ed2e88bd6a2..000000000000 --- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleBinarySerializerTest.java +++ /dev/null @@ -1,914 +0,0 @@ -/* - * Copyright (C) 2019 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.android.server.integrity.serializer; - -import static com.android.server.integrity.model.ComponentBitSize.ATOMIC_FORMULA_START; -import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_END; -import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMULA_START; -import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS; -import static com.android.server.integrity.model.ComponentBitSize.DEFAULT_FORMAT_VERSION; -import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS; -import static com.android.server.integrity.model.ComponentBitSize.FORMAT_VERSION_BITS; -import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS; -import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS; -import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS; -import static com.android.server.integrity.model.ComponentBitSize.VALUE_SIZE_BITS; -import static com.android.server.integrity.model.IndexingFileConstants.END_INDEXING_KEY; -import static com.android.server.integrity.model.IndexingFileConstants.INDEXING_BLOCK_SIZE; -import static com.android.server.integrity.model.IndexingFileConstants.START_INDEXING_KEY; -import static com.android.server.integrity.serializer.RuleBinarySerializer.INDEXED_RULE_SIZE_LIMIT; -import static com.android.server.integrity.serializer.RuleBinarySerializer.NONINDEXED_RULE_SIZE_LIMIT; -import static com.android.server.integrity.utils.TestUtils.getBits; -import static com.android.server.integrity.utils.TestUtils.getBytes; -import static com.android.server.integrity.utils.TestUtils.getValueBits; -import static com.android.server.testutils.TestUtils.assertExpectException; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.integrity.AppInstallMetadata; -import android.content.integrity.AtomicFormula; -import android.content.integrity.CompoundFormula; -import android.content.integrity.IntegrityFormula; -import android.content.integrity.IntegrityUtils; -import android.content.integrity.Rule; - -import androidx.annotation.NonNull; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -import java.io.ByteArrayOutputStream; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -@RunWith(JUnit4.class) -public class RuleBinarySerializerTest { - - private static final String SAMPLE_INSTALLER_NAME = "com.test.installer"; - private static final String SAMPLE_INSTALLER_CERT = "installer_cert"; - - private static final String COMPOUND_FORMULA_START_BITS = - getBits(COMPOUND_FORMULA_START, SEPARATOR_BITS); - private static final String COMPOUND_FORMULA_END_BITS = - getBits(COMPOUND_FORMULA_END, SEPARATOR_BITS); - private static final String ATOMIC_FORMULA_START_BITS = - getBits(ATOMIC_FORMULA_START, SEPARATOR_BITS); - - private static final String NOT = getBits(CompoundFormula.NOT, CONNECTOR_BITS); - private static final String AND = getBits(CompoundFormula.AND, CONNECTOR_BITS); - private static final String OR = getBits(CompoundFormula.OR, CONNECTOR_BITS); - - private static final String PACKAGE_NAME = getBits(AtomicFormula.PACKAGE_NAME, KEY_BITS); - private static final String APP_CERTIFICATE = getBits(AtomicFormula.APP_CERTIFICATE, KEY_BITS); - private static final String INSTALLER_NAME = getBits(AtomicFormula.INSTALLER_NAME, KEY_BITS); - private static final String INSTALLER_CERTIFICATE = - getBits(AtomicFormula.INSTALLER_CERTIFICATE, KEY_BITS); - private static final String VERSION_CODE = getBits(AtomicFormula.VERSION_CODE, KEY_BITS); - private static final String PRE_INSTALLED = getBits(AtomicFormula.PRE_INSTALLED, KEY_BITS); - - private static final String EQ = getBits(AtomicFormula.EQ, OPERATOR_BITS); - - private static final String IS_NOT_HASHED = "0"; - private static final String IS_HASHED = "1"; - - private static final String DENY = getBits(Rule.DENY, EFFECT_BITS); - - private static final String START_BIT = "1"; - private static final String END_BIT = "1"; - - private static final byte[] DEFAULT_FORMAT_VERSION_BYTES = - getBytes(getBits(DEFAULT_FORMAT_VERSION, FORMAT_VERSION_BITS)); - - private static final String SERIALIZED_START_INDEXING_KEY = - IS_NOT_HASHED - + getBits(START_INDEXING_KEY.length(), VALUE_SIZE_BITS) - + getValueBits(START_INDEXING_KEY); - private static final String SERIALIZED_END_INDEXING_KEY = - IS_NOT_HASHED - + getBits(END_INDEXING_KEY.length(), VALUE_SIZE_BITS) - + getValueBits(END_INDEXING_KEY); - - @Test - public void testBinaryString_serializeNullRules() { - RuleSerializer binarySerializer = new RuleBinarySerializer(); - - assertExpectException( - RuleSerializeException.class, - /* expectedExceptionMessageRegex= */ "Null rules cannot be serialized.", - () -> binarySerializer.serialize(null, /* formatVersion= */ Optional.empty())); - } - - @Test - public void testBinaryString_emptyRules() throws Exception { - ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream(); - ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream(); - RuleSerializer binarySerializer = new RuleBinarySerializer(); - - binarySerializer.serialize( - Collections.emptyList(), - /* formatVersion= */ Optional.empty(), - ruleOutputStream, - indexingOutputStream); - - ByteArrayOutputStream expectedRuleOutputStream = new ByteArrayOutputStream(); - expectedRuleOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES); - assertThat(ruleOutputStream.toByteArray()) - .isEqualTo(expectedRuleOutputStream.toByteArray()); - - ByteArrayOutputStream expectedIndexingOutputStream = new ByteArrayOutputStream(); - String serializedIndexingBytes = - SERIALIZED_START_INDEXING_KEY - + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ 32) - + SERIALIZED_END_INDEXING_KEY - + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ 32); - byte[] expectedIndexingBytes = - getBytes( - serializedIndexingBytes - + serializedIndexingBytes - + serializedIndexingBytes); - expectedIndexingOutputStream.write(expectedIndexingBytes); - assertThat(indexingOutputStream.toByteArray()) - .isEqualTo(expectedIndexingOutputStream.toByteArray()); - } - - @Test - public void testBinaryStream_serializeValidCompoundFormula() throws Exception { - String packageName = "com.test.app"; - Rule rule = - new Rule( - new CompoundFormula( - CompoundFormula.NOT, - Collections.singletonList( - new AtomicFormula.StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, - packageName, - /* isHashedValue= */ false))), - Rule.DENY); - - ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream(); - ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream(); - RuleSerializer binarySerializer = new RuleBinarySerializer(); - binarySerializer.serialize( - Collections.singletonList(rule), - /* formatVersion= */ Optional.empty(), - ruleOutputStream, - indexingOutputStream); - - String expectedBits = - START_BIT - + COMPOUND_FORMULA_START_BITS - + NOT - + ATOMIC_FORMULA_START_BITS - + PACKAGE_NAME - + EQ - + IS_NOT_HASHED - + getBits(packageName.length(), VALUE_SIZE_BITS) - + getValueBits(packageName) - + COMPOUND_FORMULA_END_BITS - + DENY - + END_BIT; - ByteArrayOutputStream expectedRuleOutputStream = new ByteArrayOutputStream(); - expectedRuleOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES); - expectedRuleOutputStream.write(getBytes(expectedBits)); - assertThat(ruleOutputStream.toByteArray()) - .isEqualTo(expectedRuleOutputStream.toByteArray()); - - ByteArrayOutputStream expectedIndexingOutputStream = new ByteArrayOutputStream(); - String expectedIndexingBitsForIndexed = - SERIALIZED_START_INDEXING_KEY - + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ 32) - + SERIALIZED_END_INDEXING_KEY - + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ 32); - String expectedIndexingBitsForUnindexed = - SERIALIZED_START_INDEXING_KEY - + getBits(DEFAULT_FORMAT_VERSION_BYTES.length, /* numOfBits= */ 32) - + SERIALIZED_END_INDEXING_KEY - + getBits( - DEFAULT_FORMAT_VERSION_BYTES.length + getBytes(expectedBits).length, - /* numOfBits= */ 32); - expectedIndexingOutputStream.write( - getBytes( - expectedIndexingBitsForIndexed - + expectedIndexingBitsForIndexed - + expectedIndexingBitsForUnindexed)); - - assertThat(indexingOutputStream.toByteArray()) - .isEqualTo(expectedIndexingOutputStream.toByteArray()); - } - - @Test - public void testBinaryString_serializeValidCompoundFormula_notConnector() throws Exception { - String packageName = "com.test.app"; - Rule rule = - new Rule( - new CompoundFormula( - CompoundFormula.NOT, - Collections.singletonList( - new AtomicFormula.StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, - packageName, - /* isHashedValue= */ false))), - Rule.DENY); - RuleSerializer binarySerializer = new RuleBinarySerializer(); - String expectedBits = - START_BIT - + COMPOUND_FORMULA_START_BITS - + NOT - + ATOMIC_FORMULA_START_BITS - + PACKAGE_NAME - + EQ - + IS_NOT_HASHED - + getBits(packageName.length(), VALUE_SIZE_BITS) - + getValueBits(packageName) - + COMPOUND_FORMULA_END_BITS - + DENY - + END_BIT; - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES); - byteArrayOutputStream.write(getBytes(expectedBits)); - byte[] expectedRules = byteArrayOutputStream.toByteArray(); - - byte[] actualRules = - binarySerializer.serialize( - Collections.singletonList(rule), /* formatVersion= */ Optional.empty()); - - assertThat(actualRules).isEqualTo(expectedRules); - } - - @Test - public void testBinaryString_serializeValidCompoundFormula_andConnector() throws Exception { - String packageName = "com.test.app"; - String appCertificate = "test_cert"; - Rule rule = - new Rule( - new CompoundFormula( - CompoundFormula.AND, - Arrays.asList( - new AtomicFormula.StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, - packageName, - /* isHashedValue= */ false), - new AtomicFormula.StringAtomicFormula( - AtomicFormula.APP_CERTIFICATE, - appCertificate, - /* isHashedValue= */ false))), - Rule.DENY); - RuleSerializer binarySerializer = new RuleBinarySerializer(); - String expectedBits = - START_BIT - + COMPOUND_FORMULA_START_BITS - + AND - + ATOMIC_FORMULA_START_BITS - + PACKAGE_NAME - + EQ - + IS_NOT_HASHED - + getBits(packageName.length(), VALUE_SIZE_BITS) - + getValueBits(packageName) - + ATOMIC_FORMULA_START_BITS - + APP_CERTIFICATE - + EQ - + IS_NOT_HASHED - + getBits(appCertificate.length(), VALUE_SIZE_BITS) - + getValueBits(appCertificate) - + COMPOUND_FORMULA_END_BITS - + DENY - + END_BIT; - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES); - byteArrayOutputStream.write(getBytes(expectedBits)); - byte[] expectedRules = byteArrayOutputStream.toByteArray(); - - byte[] actualRules = - binarySerializer.serialize( - Collections.singletonList(rule), /* formatVersion= */ Optional.empty()); - - assertThat(actualRules).isEqualTo(expectedRules); - } - - @Test - public void testBinaryString_serializeValidCompoundFormula_orConnector() throws Exception { - String packageName = "com.test.app"; - String appCertificate = "test_cert"; - Rule rule = - new Rule( - new CompoundFormula( - CompoundFormula.OR, - Arrays.asList( - new AtomicFormula.StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, - packageName, - /* isHashedValue= */ false), - new AtomicFormula.StringAtomicFormula( - AtomicFormula.APP_CERTIFICATE, - appCertificate, - /* isHashedValue= */ false))), - Rule.DENY); - RuleSerializer binarySerializer = new RuleBinarySerializer(); - String expectedBits = - START_BIT - + COMPOUND_FORMULA_START_BITS - + OR - + ATOMIC_FORMULA_START_BITS - + PACKAGE_NAME - + EQ - + IS_NOT_HASHED - + getBits(packageName.length(), VALUE_SIZE_BITS) - + getValueBits(packageName) - + ATOMIC_FORMULA_START_BITS - + APP_CERTIFICATE - + EQ - + IS_NOT_HASHED - + getBits(appCertificate.length(), VALUE_SIZE_BITS) - + getValueBits(appCertificate) - + COMPOUND_FORMULA_END_BITS - + DENY - + END_BIT; - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES); - byteArrayOutputStream.write(getBytes(expectedBits)); - byte[] expectedRules = byteArrayOutputStream.toByteArray(); - - byte[] actualRules = - binarySerializer.serialize( - Collections.singletonList(rule), /* formatVersion= */ Optional.empty()); - - assertThat(actualRules).isEqualTo(expectedRules); - } - - @Test - public void testBinaryString_serializeValidAtomicFormula_stringValue() throws Exception { - String packageName = "com.test.app"; - Rule rule = - new Rule( - new AtomicFormula.StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, - packageName, - /* isHashedValue= */ false), - Rule.DENY); - RuleSerializer binarySerializer = new RuleBinarySerializer(); - String expectedBits = - START_BIT - + ATOMIC_FORMULA_START_BITS - + PACKAGE_NAME - + EQ - + IS_NOT_HASHED - + getBits(packageName.length(), VALUE_SIZE_BITS) - + getValueBits(packageName) - + DENY - + END_BIT; - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES); - byteArrayOutputStream.write(getBytes(expectedBits)); - byte[] expectedRules = byteArrayOutputStream.toByteArray(); - - byte[] actualRules = - binarySerializer.serialize( - Collections.singletonList(rule), /* formatVersion= */ Optional.empty()); - - assertThat(actualRules).isEqualTo(expectedRules); - } - - @Test - public void testBinaryString_serializeValidAtomicFormula_hashedValue() throws Exception { - String appCertificate = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; - Rule rule = - new Rule( - new AtomicFormula.StringAtomicFormula( - AtomicFormula.APP_CERTIFICATE, - IntegrityUtils.getHexDigest( - appCertificate.getBytes(StandardCharsets.UTF_8)), - /* isHashedValue= */ true), - Rule.DENY); - RuleSerializer binarySerializer = new RuleBinarySerializer(); - String expectedBits = - START_BIT - + ATOMIC_FORMULA_START_BITS - + APP_CERTIFICATE - + EQ - + IS_HASHED - + getBits(appCertificate.length(), VALUE_SIZE_BITS) - + getValueBits(appCertificate) - + DENY - + END_BIT; - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES); - byteArrayOutputStream.write(getBytes(expectedBits)); - byte[] expectedRules = byteArrayOutputStream.toByteArray(); - - byte[] actualRules = - binarySerializer.serialize( - Collections.singletonList(rule), /* formatVersion= */ Optional.empty()); - - assertThat(actualRules).isEqualTo(expectedRules); - } - - @Test - public void testBinaryString_serializeValidAtomicFormula_integerValue() throws Exception { - long versionCode = 1; - Rule rule = - new Rule( - new AtomicFormula.LongAtomicFormula( - AtomicFormula.VERSION_CODE, AtomicFormula.EQ, versionCode), - Rule.DENY); - RuleSerializer binarySerializer = new RuleBinarySerializer(); - String expectedBits = - START_BIT - + ATOMIC_FORMULA_START_BITS - + VERSION_CODE - + EQ - + getBits(versionCode, /* numOfBits= */ 64) - + DENY - + END_BIT; - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES); - byteArrayOutputStream.write(getBytes(expectedBits)); - byte[] expectedRules = byteArrayOutputStream.toByteArray(); - - byte[] actualRules = - binarySerializer.serialize( - Collections.singletonList(rule), /* formatVersion= */ Optional.empty()); - - assertThat(actualRules).isEqualTo(expectedRules); - } - - @Test - public void testBinaryString_serializeValidAtomicFormula_booleanValue() throws Exception { - String preInstalled = "1"; - Rule rule = - new Rule( - new AtomicFormula.BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true), - Rule.DENY); - RuleSerializer binarySerializer = new RuleBinarySerializer(); - String expectedBits = - START_BIT - + ATOMIC_FORMULA_START_BITS - + PRE_INSTALLED - + EQ - + preInstalled - + DENY - + END_BIT; - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - byteArrayOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES); - byteArrayOutputStream.write(getBytes(expectedBits)); - byte[] expectedRules = byteArrayOutputStream.toByteArray(); - - byte[] actualRules = - binarySerializer.serialize( - Collections.singletonList(rule), /* formatVersion= */ Optional.empty()); - - assertThat(actualRules).isEqualTo(expectedRules); - } - - @Test - public void testBinaryString_serializeInvalidFormulaType() throws Exception { - IntegrityFormula invalidFormula = getInvalidFormula(); - Rule rule = new Rule(invalidFormula, Rule.DENY); - RuleSerializer binarySerializer = new RuleBinarySerializer(); - - assertExpectException( - RuleSerializeException.class, - /* expectedExceptionMessageRegex= */ "Malformed rule identified.", - () -> - binarySerializer.serialize( - Collections.singletonList(rule), - /* formatVersion= */ Optional.empty())); - } - - @Test - public void testBinaryString_serializeFormatVersion() throws Exception { - int formatVersion = 1; - RuleSerializer binarySerializer = new RuleBinarySerializer(); - String expectedBits = getBits(formatVersion, FORMAT_VERSION_BITS); - byte[] expectedRules = getBytes(expectedBits); - - byte[] actualRules = - binarySerializer.serialize( - Collections.emptyList(), /* formatVersion= */ Optional.of(formatVersion)); - - assertThat(actualRules).isEqualTo(expectedRules); - } - - @Test - public void testBinaryString_verifyManyRulesAreIndexedCorrectly() throws Exception { - int ruleCount = 225; - String packagePrefix = "package.name."; - String appCertificatePrefix = "app.cert."; - String installerNamePrefix = "installer."; - - // Create the rule set with 225 package name based rules, 225 app certificate indexed rules, - // and 225 non-indexed rules.. - List<Rule> ruleList = new ArrayList(); - for (int count = 0; count < ruleCount; count++) { - ruleList.add( - getRuleWithPackageNameAndSampleInstallerName( - String.format("%s%04d", packagePrefix, count))); - } - for (int count = 0; count < ruleCount; count++) { - ruleList.add( - getRuleWithAppCertificateAndSampleInstallerName( - String.format("%s%04d", appCertificatePrefix, count))); - } - for (int count = 0; count < ruleCount; count++) { - ruleList.add( - getNonIndexedRuleWithInstallerName( - String.format("%s%04d", installerNamePrefix, count))); - } - - // Serialize the rules. - ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream(); - ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream(); - RuleSerializer binarySerializer = new RuleBinarySerializer(); - binarySerializer.serialize( - ruleList, - /* formatVersion= */ Optional.empty(), - ruleOutputStream, - indexingOutputStream); - - // Verify the rules file and index files. - ByteArrayOutputStream expectedOrderedRuleOutputStream = new ByteArrayOutputStream(); - ByteArrayOutputStream expectedIndexingOutputStream = new ByteArrayOutputStream(); - - expectedOrderedRuleOutputStream.write(DEFAULT_FORMAT_VERSION_BYTES); - int totalBytesWritten = DEFAULT_FORMAT_VERSION_BYTES.length; - - String expectedIndexingBytesForPackageNameIndexed = - SERIALIZED_START_INDEXING_KEY + getBits(totalBytesWritten, /* numOfBits= */ 32); - for (int count = 0; count < ruleCount; count++) { - String packageName = String.format("%s%04d", packagePrefix, count); - if (count > 0 && count % INDEXING_BLOCK_SIZE == 0) { - expectedIndexingBytesForPackageNameIndexed += - IS_NOT_HASHED - + getBits(packageName.length(), VALUE_SIZE_BITS) - + getValueBits(packageName) - + getBits(totalBytesWritten, /* numOfBits= */ 32); - } - - byte[] bytesForPackage = - getBytes( - getSerializedCompoundRuleWithPackageNameAndSampleInstallerName( - packageName)); - expectedOrderedRuleOutputStream.write(bytesForPackage); - totalBytesWritten += bytesForPackage.length; - } - expectedIndexingBytesForPackageNameIndexed += - SERIALIZED_END_INDEXING_KEY + getBits(totalBytesWritten, /* numOfBits= */ 32); - - String expectedIndexingBytesForAppCertificateIndexed = - SERIALIZED_START_INDEXING_KEY + getBits(totalBytesWritten, /* numOfBits= */ 32); - for (int count = 0; count < ruleCount; count++) { - String appCertificate = String.format("%s%04d", appCertificatePrefix, count); - if (count > 0 && count % INDEXING_BLOCK_SIZE == 0) { - expectedIndexingBytesForAppCertificateIndexed += - IS_NOT_HASHED - + getBits(appCertificate.length(), VALUE_SIZE_BITS) - + getValueBits(appCertificate) - + getBits(totalBytesWritten, /* numOfBits= */ 32); - } - - byte[] bytesForPackage = - getBytes( - getSerializedCompoundRuleWithCertificateNameAndSampleInstallerName( - appCertificate)); - expectedOrderedRuleOutputStream.write(bytesForPackage); - totalBytesWritten += bytesForPackage.length; - } - expectedIndexingBytesForAppCertificateIndexed += - SERIALIZED_END_INDEXING_KEY + getBits(totalBytesWritten, /* numOfBits= */ 32); - - String expectedIndexingBytesForUnindexed = - SERIALIZED_START_INDEXING_KEY + getBits(totalBytesWritten, /* numOfBits= */ 32); - for (int count = 0; count < ruleCount; count++) { - byte[] bytesForPackage = - getBytes( - getSerializedCompoundRuleWithInstallerNameAndInstallerCert( - String.format("%s%04d", installerNamePrefix, count))); - expectedOrderedRuleOutputStream.write(bytesForPackage); - totalBytesWritten += bytesForPackage.length; - } - expectedIndexingBytesForUnindexed += - SERIALIZED_END_INDEXING_KEY + getBits(totalBytesWritten, /* numOfBits= */ 32); - expectedIndexingOutputStream.write( - getBytes( - expectedIndexingBytesForPackageNameIndexed - + expectedIndexingBytesForAppCertificateIndexed - + expectedIndexingBytesForUnindexed)); - - assertThat(ruleOutputStream.toByteArray()) - .isEqualTo(expectedOrderedRuleOutputStream.toByteArray()); - assertThat(indexingOutputStream.toByteArray()) - .isEqualTo(expectedIndexingOutputStream.toByteArray()); - } - - @Test - public void testBinaryString_totalRuleSizeLimitReached() { - int ruleCount = INDEXED_RULE_SIZE_LIMIT - 1; - String packagePrefix = "package.name."; - String appCertificatePrefix = "app.cert."; - String installerNamePrefix = "installer."; - - // Create the rule set with more rules than the system can handle in total. - List<Rule> ruleList = new ArrayList(); - for (int count = 0; count < ruleCount; count++) { - ruleList.add( - getRuleWithPackageNameAndSampleInstallerName( - String.format("%s%04d", packagePrefix, count))); - } - for (int count = 0; count < ruleCount; count++) { - ruleList.add( - getRuleWithAppCertificateAndSampleInstallerName( - String.format("%s%04d", appCertificatePrefix, count))); - } - for (int count = 0; count < NONINDEXED_RULE_SIZE_LIMIT - 1; count++) { - ruleList.add( - getNonIndexedRuleWithInstallerName( - String.format("%s%04d", installerNamePrefix, count))); - } - - // Serialize the rules. - ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream(); - ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream(); - RuleSerializer binarySerializer = new RuleBinarySerializer(); - - assertExpectException( - RuleSerializeException.class, - "Too many rules provided", - () -> - binarySerializer.serialize( - ruleList, - /* formatVersion= */ Optional.empty(), - ruleOutputStream, - indexingOutputStream)); - } - - @Test - public void testBinaryString_tooManyPackageNameIndexedRules() { - String packagePrefix = "package.name."; - - // Create a rule set with too many package name indexed rules. - List<Rule> ruleList = new ArrayList(); - for (int count = 0; count < INDEXED_RULE_SIZE_LIMIT + 1; count++) { - ruleList.add( - getRuleWithPackageNameAndSampleInstallerName( - String.format("%s%04d", packagePrefix, count))); - } - - // Serialize the rules. - ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream(); - ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream(); - RuleSerializer binarySerializer = new RuleBinarySerializer(); - - assertExpectException( - RuleSerializeException.class, - "Too many rules provided in the indexing group.", - () -> - binarySerializer.serialize( - ruleList, - /* formatVersion= */ Optional.empty(), - ruleOutputStream, - indexingOutputStream)); - } - - @Test - public void testBinaryString_tooManyAppCertificateIndexedRules() { - String appCertificatePrefix = "app.cert."; - - // Create a rule set with too many app certificate indexed rules. - List<Rule> ruleList = new ArrayList(); - for (int count = 0; count < INDEXED_RULE_SIZE_LIMIT + 1; count++) { - ruleList.add( - getRuleWithAppCertificateAndSampleInstallerName( - String.format("%s%04d", appCertificatePrefix, count))); - } - - // Serialize the rules. - ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream(); - ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream(); - RuleSerializer binarySerializer = new RuleBinarySerializer(); - - assertExpectException( - RuleSerializeException.class, - "Too many rules provided in the indexing group.", - () -> - binarySerializer.serialize( - ruleList, - /* formatVersion= */ Optional.empty(), - ruleOutputStream, - indexingOutputStream)); - } - - @Test - public void testBinaryString_tooManyNonIndexedRules() { - String installerNamePrefix = "installer."; - - // Create a rule set with too many unindexed rules. - List<Rule> ruleList = new ArrayList(); - for (int count = 0; count < NONINDEXED_RULE_SIZE_LIMIT + 1; count++) { - ruleList.add( - getNonIndexedRuleWithInstallerName( - String.format("%s%04d", installerNamePrefix, count))); - } - - // Serialize the rules. - ByteArrayOutputStream ruleOutputStream = new ByteArrayOutputStream(); - ByteArrayOutputStream indexingOutputStream = new ByteArrayOutputStream(); - RuleSerializer binarySerializer = new RuleBinarySerializer(); - - assertExpectException( - RuleSerializeException.class, - "Too many rules provided in the indexing group.", - () -> - binarySerializer.serialize( - ruleList, - /* formatVersion= */ Optional.empty(), - ruleOutputStream, - indexingOutputStream)); - } - - private Rule getRuleWithPackageNameAndSampleInstallerName(String packageName) { - return new Rule( - new CompoundFormula( - CompoundFormula.AND, - Arrays.asList( - new AtomicFormula.StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, - packageName, - /* isHashedValue= */ false), - new AtomicFormula.StringAtomicFormula( - AtomicFormula.INSTALLER_NAME, - SAMPLE_INSTALLER_NAME, - /* isHashedValue= */ false))), - Rule.DENY); - } - - private String getSerializedCompoundRuleWithPackageNameAndSampleInstallerName( - String packageName) { - return START_BIT - + COMPOUND_FORMULA_START_BITS - + AND - + ATOMIC_FORMULA_START_BITS - + PACKAGE_NAME - + EQ - + IS_NOT_HASHED - + getBits(packageName.length(), VALUE_SIZE_BITS) - + getValueBits(packageName) - + ATOMIC_FORMULA_START_BITS - + INSTALLER_NAME - + EQ - + IS_NOT_HASHED - + getBits(SAMPLE_INSTALLER_NAME.length(), VALUE_SIZE_BITS) - + getValueBits(SAMPLE_INSTALLER_NAME) - + COMPOUND_FORMULA_END_BITS - + DENY - + END_BIT; - } - - private Rule getRuleWithAppCertificateAndSampleInstallerName(String certificate) { - return new Rule( - new CompoundFormula( - CompoundFormula.AND, - Arrays.asList( - new AtomicFormula.StringAtomicFormula( - AtomicFormula.APP_CERTIFICATE, - certificate, - /* isHashedValue= */ false), - new AtomicFormula.StringAtomicFormula( - AtomicFormula.INSTALLER_NAME, - SAMPLE_INSTALLER_NAME, - /* isHashedValue= */ false))), - Rule.DENY); - } - - private String getSerializedCompoundRuleWithCertificateNameAndSampleInstallerName( - String appCertificate) { - return START_BIT - + COMPOUND_FORMULA_START_BITS - + AND - + ATOMIC_FORMULA_START_BITS - + APP_CERTIFICATE - + EQ - + IS_NOT_HASHED - + getBits(appCertificate.length(), VALUE_SIZE_BITS) - + getValueBits(appCertificate) - + ATOMIC_FORMULA_START_BITS - + INSTALLER_NAME - + EQ - + IS_NOT_HASHED - + getBits(SAMPLE_INSTALLER_NAME.length(), VALUE_SIZE_BITS) - + getValueBits(SAMPLE_INSTALLER_NAME) - + COMPOUND_FORMULA_END_BITS - + DENY - + END_BIT; - } - - private Rule getNonIndexedRuleWithInstallerName(String installerName) { - return new Rule( - new CompoundFormula( - CompoundFormula.AND, - Arrays.asList( - new AtomicFormula.StringAtomicFormula( - AtomicFormula.INSTALLER_NAME, - installerName, - /* isHashedValue= */ false), - new AtomicFormula.StringAtomicFormula( - AtomicFormula.INSTALLER_CERTIFICATE, - SAMPLE_INSTALLER_CERT, - /* isHashedValue= */ false))), - Rule.DENY); - } - - private String getSerializedCompoundRuleWithInstallerNameAndInstallerCert( - String installerName) { - return START_BIT - + COMPOUND_FORMULA_START_BITS - + AND - + ATOMIC_FORMULA_START_BITS - + INSTALLER_NAME - + EQ - + IS_NOT_HASHED - + getBits(installerName.length(), VALUE_SIZE_BITS) - + getValueBits(installerName) - + ATOMIC_FORMULA_START_BITS - + INSTALLER_CERTIFICATE - + EQ - + IS_NOT_HASHED - + getBits(SAMPLE_INSTALLER_CERT.length(), VALUE_SIZE_BITS) - + getValueBits(SAMPLE_INSTALLER_CERT) - + COMPOUND_FORMULA_END_BITS - + DENY - + END_BIT; - } - - private static IntegrityFormula getInvalidFormula() { - return new AtomicFormula(0) { - @Override - public int getTag() { - return 0; - } - - @Override - public boolean matches(AppInstallMetadata appInstallMetadata) { - return false; - } - - @Override - public boolean isAppCertificateFormula() { - return false; - } - - @Override - public boolean isAppCertificateLineageFormula() { - return false; - } - - @Override - public boolean isInstallerFormula() { - return false; - } - - @Override - public int hashCode() { - return super.hashCode(); - } - - @Override - public boolean equals(Object obj) { - return super.equals(obj); - } - - @NonNull - @Override - protected Object clone() throws CloneNotSupportedException { - return super.clone(); - } - - @Override - public String toString() { - return super.toString(); - } - - @Override - protected void finalize() throws Throwable { - super.finalize(); - } - }; - } -} diff --git a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java b/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java deleted file mode 100644 index 6dccdf51af02..000000000000 --- a/services/tests/servicestests/src/com/android/server/integrity/serializer/RuleIndexingDetailsIdentifierTest.java +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright (C) 2019 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.android.server.integrity.serializer; - -import static com.android.server.integrity.serializer.RuleIndexingDetails.APP_CERTIFICATE_INDEXED; -import static com.android.server.integrity.serializer.RuleIndexingDetails.NOT_INDEXED; -import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAGE_NAME_INDEXED; -import static com.android.server.integrity.serializer.RuleIndexingDetailsIdentifier.splitRulesIntoIndexBuckets; -import static com.android.server.testutils.TestUtils.assertExpectException; - -import static com.google.common.truth.Truth.assertThat; - -import android.content.integrity.AppInstallMetadata; -import android.content.integrity.AtomicFormula; -import android.content.integrity.CompoundFormula; -import android.content.integrity.IntegrityFormula; -import android.content.integrity.Rule; - -import androidx.annotation.NonNull; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -/** Unit tests for {@link RuleIndexingDetailsIdentifier}. */ -@RunWith(JUnit4.class) -public class RuleIndexingDetailsIdentifierTest { - - private static final String SAMPLE_APP_CERTIFICATE = "testcert"; - private static final String SAMPLE_INSTALLER_NAME = "com.test.installer"; - private static final String SAMPLE_INSTALLER_CERTIFICATE = "installercert"; - private static final String SAMPLE_PACKAGE_NAME = "com.test.package"; - - private static final AtomicFormula ATOMIC_FORMULA_WITH_PACKAGE_NAME = - new AtomicFormula.StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, - SAMPLE_PACKAGE_NAME, - /* isHashedValue= */ false); - private static final AtomicFormula ATOMIC_FORMULA_WITH_APP_CERTIFICATE = - new AtomicFormula.StringAtomicFormula( - AtomicFormula.APP_CERTIFICATE, - SAMPLE_APP_CERTIFICATE, - /* isHashedValue= */ false); - private static final AtomicFormula ATOMIC_FORMULA_WITH_INSTALLER_NAME = - new AtomicFormula.StringAtomicFormula( - AtomicFormula.INSTALLER_NAME, - SAMPLE_INSTALLER_NAME, - /* isHashedValue= */ false); - private static final AtomicFormula ATOMIC_FORMULA_WITH_INSTALLER_CERTIFICATE = - new AtomicFormula.StringAtomicFormula( - AtomicFormula.INSTALLER_CERTIFICATE, - SAMPLE_INSTALLER_CERTIFICATE, - /* isHashedValue= */ false); - private static final AtomicFormula ATOMIC_FORMULA_WITH_VERSION_CODE = - new AtomicFormula.LongAtomicFormula(AtomicFormula.VERSION_CODE, - AtomicFormula.EQ, 12); - private static final AtomicFormula ATOMIC_FORMULA_WITH_ISPREINSTALLED = - new AtomicFormula.BooleanAtomicFormula( - AtomicFormula.PRE_INSTALLED, /* booleanValue= */ - true); - - - private static final Rule RULE_WITH_PACKAGE_NAME = - new Rule( - new CompoundFormula( - CompoundFormula.AND, - Arrays.asList( - ATOMIC_FORMULA_WITH_PACKAGE_NAME, - ATOMIC_FORMULA_WITH_INSTALLER_NAME)), - Rule.DENY); - private static final Rule RULE_WITH_APP_CERTIFICATE = - new Rule( - new CompoundFormula( - CompoundFormula.AND, - Arrays.asList( - ATOMIC_FORMULA_WITH_APP_CERTIFICATE, - ATOMIC_FORMULA_WITH_INSTALLER_NAME)), - Rule.DENY); - private static final Rule RULE_WITH_INSTALLER_RESTRICTIONS = - new Rule( - new CompoundFormula( - CompoundFormula.AND, - Arrays.asList( - ATOMIC_FORMULA_WITH_INSTALLER_NAME, - ATOMIC_FORMULA_WITH_INSTALLER_CERTIFICATE)), - Rule.DENY); - - private static final Rule RULE_WITH_NONSTRING_RESTRICTIONS = - new Rule( - new CompoundFormula( - CompoundFormula.AND, - Arrays.asList( - ATOMIC_FORMULA_WITH_VERSION_CODE, - ATOMIC_FORMULA_WITH_ISPREINSTALLED)), - Rule.DENY); - public static final int INVALID_FORMULA_TAG = -1; - - @Test - public void getIndexType_nullRule() { - List<Rule> ruleList = null; - - assertExpectException( - IllegalArgumentException.class, - /* expectedExceptionMessageRegex= */ - "Index buckets cannot be created for null rule list.", - () -> splitRulesIntoIndexBuckets(ruleList)); - } - - @Test - public void getIndexType_invalidFormula() { - List<Rule> ruleList = new ArrayList(); - ruleList.add(new Rule(getInvalidFormula(), Rule.DENY)); - - assertExpectException( - IllegalArgumentException.class, - /* expectedExceptionMessageRegex= */ "Malformed rule identified.", - () -> splitRulesIntoIndexBuckets(ruleList)); - } - - @Test - public void getIndexType_ruleContainingPackageNameFormula() { - List<Rule> ruleList = new ArrayList(); - ruleList.add(RULE_WITH_PACKAGE_NAME); - - Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); - - // Verify the resulting map content. - assertThat(result.keySet()) - .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); - assertThat(result.get(NOT_INDEXED)).isEmpty(); - assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty(); - assertThat(result.get(PACKAGE_NAME_INDEXED).keySet()).containsExactly(SAMPLE_PACKAGE_NAME); - assertThat(result.get(PACKAGE_NAME_INDEXED).get(SAMPLE_PACKAGE_NAME)) - .containsExactly(RULE_WITH_PACKAGE_NAME); - } - - @Test - public void getIndexType_ruleContainingAppCertificateFormula() { - List<Rule> ruleList = new ArrayList(); - ruleList.add(RULE_WITH_APP_CERTIFICATE); - - Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); - - assertThat(result.keySet()) - .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); - assertThat(result.get(NOT_INDEXED)).isEmpty(); - assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty(); - assertThat(result.get(APP_CERTIFICATE_INDEXED).keySet()) - .containsExactly(SAMPLE_APP_CERTIFICATE); - assertThat(result.get(APP_CERTIFICATE_INDEXED).get(SAMPLE_APP_CERTIFICATE)) - .containsExactly(RULE_WITH_APP_CERTIFICATE); - } - - @Test - public void getIndexType_ruleWithUnindexedCompoundFormula() { - List<Rule> ruleList = new ArrayList(); - ruleList.add(RULE_WITH_INSTALLER_RESTRICTIONS); - - Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); - - assertThat(result.keySet()) - .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); - assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty(); - assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty(); - assertThat(result.get(NOT_INDEXED).get("N/A")) - .containsExactly(RULE_WITH_INSTALLER_RESTRICTIONS); - } - - @Test - public void getIndexType_ruleContainingCompoundFormulaWithIntAndBoolean() { - List<Rule> ruleList = new ArrayList(); - ruleList.add(RULE_WITH_NONSTRING_RESTRICTIONS); - - Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); - - assertThat(result.keySet()) - .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); - assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty(); - assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty(); - assertThat(result.get(NOT_INDEXED).get("N/A")) - .containsExactly(RULE_WITH_NONSTRING_RESTRICTIONS); - } - - @Test - public void getIndexType_negatedRuleContainingPackageNameFormula() { - Rule negatedRule = - new Rule( - new CompoundFormula( - CompoundFormula.NOT, - Arrays.asList( - new CompoundFormula( - CompoundFormula.AND, - Arrays.asList( - ATOMIC_FORMULA_WITH_PACKAGE_NAME, - ATOMIC_FORMULA_WITH_APP_CERTIFICATE)))), - Rule.DENY); - List<Rule> ruleList = new ArrayList(); - ruleList.add(negatedRule); - - Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); - - assertThat(result.keySet()) - .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); - assertThat(result.get(PACKAGE_NAME_INDEXED)).isEmpty(); - assertThat(result.get(APP_CERTIFICATE_INDEXED)).isEmpty(); - assertThat(result.get(NOT_INDEXED).get("N/A")).containsExactly(negatedRule); - } - - @Test - public void getIndexType_allRulesTogetherSplitCorrectly() { - Rule packageNameRuleA = getRuleWithPackageName("aaa"); - Rule packageNameRuleB = getRuleWithPackageName("bbb"); - Rule packageNameRuleC = getRuleWithPackageName("ccc"); - Rule certificateRule1 = getRuleWithAppCertificate("cert1"); - Rule certificateRule2 = getRuleWithAppCertificate("cert2"); - Rule certificateRule3 = getRuleWithAppCertificate("cert3"); - - List<Rule> ruleList = new ArrayList(); - ruleList.add(packageNameRuleB); - ruleList.add(packageNameRuleC); - ruleList.add(packageNameRuleA); - ruleList.add(certificateRule3); - ruleList.add(certificateRule2); - ruleList.add(certificateRule1); - ruleList.add(RULE_WITH_INSTALLER_RESTRICTIONS); - ruleList.add(RULE_WITH_NONSTRING_RESTRICTIONS); - - Map<Integer, Map<String, List<Rule>>> result = splitRulesIntoIndexBuckets(ruleList); - - assertThat(result.keySet()) - .containsExactly(NOT_INDEXED, PACKAGE_NAME_INDEXED, APP_CERTIFICATE_INDEXED); - - // We check asserts this way to ensure ordering based on package name. - assertThat(result.get(PACKAGE_NAME_INDEXED).keySet()).containsExactly("aaa", "bbb", "ccc"); - - // We check asserts this way to ensure ordering based on app certificate. - assertThat(result.get(APP_CERTIFICATE_INDEXED).keySet()).containsExactly("cert1", "cert2", - "cert3"); - - assertThat(result.get(NOT_INDEXED).get("N/A")) - .containsExactly(RULE_WITH_INSTALLER_RESTRICTIONS, - RULE_WITH_NONSTRING_RESTRICTIONS); - } - - private Rule getRuleWithPackageName(String packageName) { - return new Rule( - new CompoundFormula( - CompoundFormula.AND, - Arrays.asList( - new AtomicFormula.StringAtomicFormula( - AtomicFormula.PACKAGE_NAME, - packageName, - /* isHashedValue= */ false), - ATOMIC_FORMULA_WITH_INSTALLER_NAME)), - Rule.DENY); - } - - private Rule getRuleWithAppCertificate(String certificate) { - return new Rule( - new CompoundFormula( - CompoundFormula.AND, - Arrays.asList( - new AtomicFormula.StringAtomicFormula( - AtomicFormula.APP_CERTIFICATE, - certificate, - /* isHashedValue= */ false), - ATOMIC_FORMULA_WITH_INSTALLER_NAME)), - Rule.DENY); - } - - private IntegrityFormula getInvalidFormula() { - return new AtomicFormula(0) { - @Override - public int getTag() { - return INVALID_FORMULA_TAG; - } - - @Override - public boolean matches(AppInstallMetadata appInstallMetadata) { - return false; - } - - @Override - public boolean isAppCertificateFormula() { - return false; - } - - @Override - public boolean isAppCertificateLineageFormula() { - return false; - } - - @Override - public boolean isInstallerFormula() { - return false; - } - - @Override - public int hashCode() { - return super.hashCode(); - } - - @Override - public boolean equals(Object obj) { - return super.equals(obj); - } - - @NonNull - @Override - protected Object clone() throws CloneNotSupportedException { - return super.clone(); - } - - @Override - public String toString() { - return super.toString(); - } - - @Override - protected void finalize() throws Throwable { - super.finalize(); - } - }; - } -} diff --git a/services/usb/OWNERS b/services/usb/OWNERS index d35dbb56437b..2dff392d4e34 100644 --- a/services/usb/OWNERS +++ b/services/usb/OWNERS @@ -1,9 +1,9 @@ -aprasath@google.com -kumarashishg@google.com -sarup@google.com anothermark@google.com +febinthattil@google.com +aprasath@google.com badhri@google.com elaurent@google.com albertccwang@google.com jameswei@google.com -howardyen@google.com
\ No newline at end of file +howardyen@google.com +kumarashishg@google.com
\ No newline at end of file diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java index e045f100e549..4c7b25aaa7c3 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java @@ -223,7 +223,6 @@ public class VcnGatewayConnectionTestBase { doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider(); doReturn(mFeatureFlags).when(mVcnContext).getFeatureFlags(); doReturn(true).when(mVcnContext).isFlagSafeModeTimeoutConfigEnabled(); - doReturn(true).when(mVcnContext).isFlagIpSecTransformStateEnabled(); doReturn(mUnderlyingNetworkController) .when(mDeps) diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java index bc7ff47d9a01..441b78035703 100644 --- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java +++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java @@ -20,7 +20,6 @@ import static com.android.server.vcn.VcnTestUtils.setupSystemService; import static com.android.server.vcn.routeselection.UnderlyingNetworkControllerTest.getLinkPropertiesWithName; import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -127,8 +126,6 @@ public abstract class NetworkEvaluationTestBase { false /* isInTestMode */)); doNothing().when(mVcnContext).ensureRunningOnLooperThread(); - doReturn(true).when(mVcnContext).isFlagIpSecTransformStateEnabled(); - setupSystemService( mContext, mConnectivityManager, diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java index 6f31d8db070f..e540932d0e1f 100644 --- a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java +++ b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkControllerTest.java @@ -226,7 +226,6 @@ public class UnderlyingNetworkControllerTest { private void resetVcnContext(VcnContext vcnContext) { reset(vcnContext); doNothing().when(vcnContext).ensureRunningOnLooperThread(); - doReturn(true).when(vcnContext).isFlagIpSecTransformStateEnabled(); } // Package private for use in NetworkPriorityClassifierTest diff --git a/tools/systemfeatures/Android.bp b/tools/systemfeatures/Android.bp index 590f7190881a..e6d0a3d4149f 100644 --- a/tools/systemfeatures/Android.bp +++ b/tools/systemfeatures/Android.bp @@ -58,6 +58,7 @@ java_test_host { "junit", "objenesis", "mockito", + "systemfeatures-gen-lib", "truth", ], } diff --git a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt index 196b5e7c02ab..1abe77fd3ceb 100644 --- a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt +++ b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt @@ -71,7 +71,7 @@ object SystemFeaturesGenerator { println("Usage: SystemFeaturesGenerator <outputClassName> [options]") println(" Options:") println(" --readonly=true|false Whether to encode features as build-time constants") - println(" --feature=\$NAME:\$VER A feature+version pair, where \$VER can be:") + println(" --feature=\$NAME:\$VER A feature+version pair, where \$VER can be:") println(" * blank/empty == undefined (variable API)") println(" * valid int == enabled (constant API)") println(" * UNAVAILABLE == disabled (constant API)") @@ -89,6 +89,17 @@ object SystemFeaturesGenerator { /** Main entrypoint for build-time system feature codegen. */ @JvmStatic fun main(args: Array<String>) { + generate(args, System.out) + } + + /** + * Simple API entrypoint for build-time system feature codegen. + * + * Note: Typically this would be implemented in terms of a proper Builder-type input argument, + * but it's primarily used for testing as opposed to direct production usage. + */ + @JvmStatic + fun generate(args: Array<String>, output: Appendable) { if (args.size < 1) { usage() return @@ -155,7 +166,7 @@ object SystemFeaturesGenerator { .addFileComment("This file is auto-generated. DO NOT MODIFY.\n") .addFileComment("Args: ${args.joinToString(" \\\n ")}") .build() - .writeTo(System.out) + .writeTo(output) } /* @@ -171,12 +182,27 @@ object SystemFeaturesGenerator { return when (featureArgs.getOrNull(1)) { null, "" -> FeatureInfo(name, null, readonly = false) "UNAVAILABLE" -> FeatureInfo(name, null, readonly = true) - else -> FeatureInfo(name, featureArgs[1].toIntOrNull(), readonly = true) + else -> { + val featureVersion = + featureArgs[1].toIntOrNull() + ?: throw IllegalArgumentException( + "Invalid feature version input for $name: ${featureArgs[1]}" + ) + FeatureInfo(name, featureArgs[1].toInt(), readonly = true) + } } } private fun parseFeatureName(name: String): String = - if (name.startsWith("FEATURE_")) name else "FEATURE_$name" + when { + name.startsWith("android") -> + throw IllegalArgumentException( + "Invalid feature name input: \"android\"-namespaced features must be " + + "provided as PackageManager.FEATURE_* suffixes, not raw feature strings." + ) + name.startsWith("FEATURE_") -> name + else -> "FEATURE_$name" + } /* * Adds per-feature query methods to the class with the form: diff --git a/tools/systemfeatures/tests/src/SystemFeaturesGeneratorApiTest.java b/tools/systemfeatures/tests/src/SystemFeaturesGeneratorApiTest.java new file mode 100644 index 000000000000..f8c585d60ef7 --- /dev/null +++ b/tools/systemfeatures/tests/src/SystemFeaturesGeneratorApiTest.java @@ -0,0 +1,81 @@ +/* + * 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.android.systemfeatures; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.io.IOException; + +// Note: This is a very simple argument test to validate certain behaviors for +// invalid arguments. Correctness and validity is largely exercised by +// SystemFeaturesGeneratorTest. +@RunWith(JUnit4.class) +public class SystemFeaturesGeneratorApiTest { + + @Rule public final MockitoRule mockito = MockitoJUnit.rule(); + + @Mock private Appendable mOut; + + @Test + public void testEmpty() throws IOException { + final String[] args = new String[] {}; + // This should just print the commandline and return. + SystemFeaturesGenerator.generate(args, mOut); + verify(mOut, never()).append(any()); + } + + @Test + public void testBasic() throws IOException { + final String[] args = new String[] { + "com.foo.Features", + "--feature=TELEVISION:0", + }; + SystemFeaturesGenerator.generate(args, mOut); + verify(mOut, atLeastOnce()).append(any()); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidFeatureVersion() throws IOException { + final String[] args = new String[] { + "com.foo.Features", + "--feature=TELEVISION:blarg", + }; + SystemFeaturesGenerator.generate(args, mOut); + verify(mOut, never()).append(any()); + } + + @Test(expected = IllegalArgumentException.class) + public void testInvalidFeatureNameFromAndroidNamespace() throws IOException { + final String[] args = new String[] { + "com.foo.Features", + "--feature=android.hardware.doesntexist:0", + }; + SystemFeaturesGenerator.generate(args, mOut); + verify(mOut, never()).append(any()); + } +} |