Merge "Create empty VCN libraries" into main
diff --git a/OWNERS b/OWNERS
index eb2bfcf..d0a634e 100644
--- a/OWNERS
+++ b/OWNERS
@@ -47,3 +47,4 @@
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 0000000..c9ca47a
--- /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 a413bbd..16f0693 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 6b342a5..6d9fe44 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -22920,6 +22920,65 @@
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 @@
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 9a294fd..0b891f6 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -102,6 +102,7 @@
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 36bdf73..744f019 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4855,6 +4855,8 @@
* @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 41585b3..7d6e7ad 100644
--- a/core/java/android/database/BulkCursorNative.java
+++ b/core/java/android/database/BulkCursorNative.java
@@ -215,7 +215,7 @@
// 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 c597895..c2cc9d1 100644
--- a/core/java/android/database/sqlite/flags.aconfig
+++ b/core/java/android/database/sqlite/flags.aconfig
@@ -2,8 +2,9 @@
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 747f909..340d6f2 100644
--- a/core/java/android/hardware/location/OWNERS
+++ b/core/java/android/hardware/location/OWNERS
@@ -9,4 +9,4 @@
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 a753f96..37604bc 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 48eb968..f7dc790 100644
--- a/core/java/android/net/flags.aconfig
+++ b/core/java/android/net/flags.aconfig
@@ -5,13 +5,6 @@
# 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 30d2dec..3c3a4fd 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -36,8 +36,6 @@
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 @@
*/
@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 e80efd2..60eeb2b 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -41,7 +41,6 @@
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.Log;
import android.util.Slog;
-import com.android.internal.ravenwood.RavenwoodEnvironment;
-
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
@@ -1254,15 +1251,10 @@
}
}
- @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 cd8788d..851953a 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -29,6 +29,11 @@
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.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 @@
/**
* Tools for managing OS processes.
*/
+@RavenwoodKeepPartialClass
+@RavenwoodRedirectionClass("Process_ravenwood")
public class Process {
private static final String LOG_TAG = "Process";
@@ -672,7 +677,6 @@
*/
public static final ZygoteProcess ZYGOTE_PROCESS = new ZygoteProcess();
-
/**
* The process name set via {@link #setArgV0(String)}.
*/
@@ -846,47 +850,20 @@
/**
* 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 @@
* 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 @@
* 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 @@
* @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 @@
/**
* 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 @@
@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 @@
/**
* 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 @@
* @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 @@
* @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 @@
*/
@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 @@
* @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 @@
/**
* 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 @@
* 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 @@
*
* @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 @@
*
* @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 @@
* @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 0809de2..ce79f5d 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 0809de2..ce79f5d 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 b723872..c435bd8 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 8358b9a..1dd9d46 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -75,8 +75,7 @@
@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 @@
* 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 @@
* @hide
*/
@UnsupportedAppUsage
+ @android.ravenwood.annotation.RavenwoodRedirect
public static native int println_native(int bufID, int priority, String tag, String msg);
/**
@@ -452,6 +453,7 @@
* 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 69228ca..cd02130 100644
--- a/core/java/android/view/HapticFeedbackConstants.java
+++ b/core/java/android/view/HapticFeedbackConstants.java
@@ -157,7 +157,7 @@
/**
* 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 @@
/**
* 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 30b160a..a69d2e4 100644
--- a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
+++ b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java
@@ -28,19 +28,9 @@
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 @@
}
/**
- * 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 @@
}
/**
- * 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 3a19f46..96edd63 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_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 @@
@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 cd0654c..b08a86e 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -18,6 +18,7 @@
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 @@
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 7abada0..0986345 100644
--- a/media/java/android/media/audiofx/Equalizer.java
+++ b/media/java/android/media/audiofx/Equalizer.java
@@ -153,9 +153,8 @@
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 185f579..0adc478 100644
--- a/media/java/android/media/flags/editing.aconfig
+++ b/media/java/android/media/flags/editing.aconfig
@@ -15,3 +15,10 @@
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 6b5336e..77ed08b 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 6b5336e..bdb6cdb 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 96b7c13..00812042 100644
--- a/nfc/api/current.txt
+++ b/nfc/api/current.txt
@@ -207,6 +207,7 @@
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 @@
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 @@
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 24e14e6..6aa8a2b 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -91,6 +91,7 @@
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 @@
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/nfc/java/android/nfc/ComponentNameAndUser.aidl b/nfc/java/android/nfc/ComponentNameAndUser.aidl
new file mode 100644
index 0000000..e677998
--- /dev/null
+++ b/nfc/java/android/nfc/ComponentNameAndUser.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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;
+
+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 0000000..59e6c62
--- /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 8535e4a..5e2e92d 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 @@
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 0000000..5162c26
--- /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 48c7ee6..7f1fd15 100644
--- a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
+++ b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
@@ -27,7 +27,7 @@
* @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 @@
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 520ba89..1d2085c 100644
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -80,6 +80,14 @@
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 @@
* 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 @@
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 @@
callback.onCardEmulationActivated(mCardEmulationActivated);
callback.onRfFieldActivated(mRfFieldActivated);
callback.onRfDiscoveryStarted(mRfDiscoveryStarted);
+ callback.onEeListenActivated(mEeListenActivated);
});
}
}
@@ -677,9 +692,9 @@
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 @@
}
@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 5727f99..3d293f7 100644
--- a/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -52,10 +52,12 @@
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 @@
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 @@
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 d8f04c5..eb28c3b 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.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.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 @@
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 cd8e19c..4f601f0 100644
--- a/nfc/java/android/nfc/cardemulation/HostApduService.java
+++ b/nfc/java/android/nfc/cardemulation/HostApduService.java
@@ -239,15 +239,6 @@
*/
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 @@
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 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 6a7e693..34f0200 100644
--- a/nfc/java/android/nfc/flags.aconfig
+++ b/nfc/java/android/nfc/flags.aconfig
@@ -165,3 +165,11 @@
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 0000000..a2001e6
--- /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 3492365..b2fcc43 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 @@
/** See [registerCriticalDumpable]. */
fun registerCriticalDumpable(module: Dumpable) {
- registerCriticalDumpable(module::class.java.canonicalName, module)
+ registerCriticalDumpable(module::class.java.name, module)
}
/**
@@ -62,7 +62,7 @@
/** See [registerNormalDumpable]. */
fun registerNormalDumpable(module: Dumpable) {
- registerNormalDumpable(module::class.java.canonicalName, module)
+ registerNormalDumpable(module::class.java.name, module)
}
/**
@@ -104,13 +104,10 @@
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 6d5226f..08881a0 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.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 @@
}
@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 5075f63..44abb9f 100644
--- a/packages/overlays/Android.bp
+++ b/packages/overlays/Android.bp
@@ -21,6 +21,7 @@
phony {
name: "frameworks-base-overlays",
+ product_specific: true,
required: [
"DisplayCutoutEmulationCornerOverlay",
"DisplayCutoutEmulationDoubleOverlay",
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 65ea9fe..4731cfb 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -279,6 +279,15 @@
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 @@
"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 @@
],
}
+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 @@
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 @@
],
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 66a6890..869d854 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.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 @@
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 @@
if (!skipRunnerHook) {
try {
- RavenwoodTestStats.getInstance().onClassFinished(description);
mState.exitTestClass();
} catch (Throwable th) {
notifier.reportAfterTestFailure(th);
@@ -295,8 +293,6 @@
// 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 @@
// 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 d29b93c..a208d6d 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 @@
* 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 9002e40..9177857 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.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 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 @@
}
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 @@
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);
+ }
+ }
}
- sInitialized = true;
+ }
+
+ private static void globalInitInner() {
+ if (RAVENWOOD_VERBOSE_LOGGING) {
+ Log.v(TAG, "globalInit() called here...", new RuntimeException("NOT A CRASH"));
+ }
+
+ // 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 @@
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 @@
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 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 @@
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 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 @@
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 016de8e..7870585 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 @@
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.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 @@
*/
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 @@
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 @@
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<>();
}
- value.put(methodDescription, result);
+ // If the result is already set, don't overwrite it.
+ if (!value.containsKey(methodName)) {
+ value.put(methodName, 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);
}
-
- var testClass = extractTestClass(classDescription);
-
- mOutputWriter.printf("%s,%s,%s,%d,%d,%d\n",
- mTestModuleName, (testClass == null ? "?" : testClass.getCanonicalName()),
- classDescription, passed, failed, skipped);
mOutputWriter.flush();
+ mStats.clear();
}
- /**
- * 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 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;
}
- // Look into the children.
- for (var child : desc.getChildren()) {
- var fromChild = extractTestClass(child);
- if (fromChild != null) {
- return fromChild;
- }
- }
- return null;
+ return className.substring(0, p);
}
+
+ public void attachToRunNotifier(RunNotifier notifier) {
+ notifier.addListener(mRunListener);
+ }
+
+ private final RunListener mRunListener = new RunListener() {
+ @Override
+ public void testSuiteStarted(Description description) {
+ Log.d(TAG, "testSuiteStarted: " + description);
+ }
+
+ @Override
+ public void testSuiteFinished(Description description) {
+ Log.d(TAG, "testSuiteFinished: " + description);
+ }
+
+ @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 37b0abc..d8f2b70 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.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 @@
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 0000000..3c6a4d7
--- /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 e12ff24..b65668b 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 @@
}
/**
- * 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 c94ef31..0298171 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 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 f13189f..7b940b4 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 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 0000000..175e020
--- /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 ba89f71..eaadac6 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 @@
// 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 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 0000000..89fb7c3
--- /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 3ff0848..c1993f6 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 @@
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 @@
{ "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 5d623e0..1910100 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 @@
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
-
-run() {
- echo "Running: $*"
- "${@}"
+filter() {
+ local re="$1"
+ local grep_arg="$2"
+ if [[ "$re" == "" ]] ; then
+ cat # No filtering
+ else
+ grep $grep_arg -iP "$re"
+ fi
}
-run ${ATEST:-atest} "${all_tests[@]}"
+filter_in() {
+ filter "$1"
+}
+
+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 ce0033d..4895a1a 100644
--- a/ravenwood/tests/bivalenttest/Android.bp
+++ b/ravenwood/tests/bivalenttest/Android.bp
@@ -43,9 +43,12 @@
// 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 @@
// 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 0000000..fd6d6fb
--- /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 4102920..0c0df1f 100644
--- a/ravenwood/tests/runtime-test/Android.bp
+++ b/ravenwood/tests/runtime-test/Android.bp
@@ -10,6 +10,9 @@
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 0000000..8e04b69
--- /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 c2230c7..c55506a 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_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.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 @@
});
}
+ 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 0000000..d25b5c1
--- /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 a02082d..f47aaba 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 @@
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 32dcbe5..a0e5599 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 @@
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 27092d2..8ec0932 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 @@
}
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 @@
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 2e9a4dc..a10039f 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 @@
@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 @@
@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 82c2038..71885fd 100644
--- a/services/core/java/com/android/server/SerialService.java
+++ b/services/core/java/com/android/server/SerialService.java
@@ -18,22 +18,30 @@
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 @@
final String[] serialPorts = getSerialPorts(context);
for (String serialPort : serialPorts) {
mSerialPorts.put(serialPort, () -> {
- return native_open(serialPort);
+ return tryOpen(serialPort);
});
}
}
@@ -135,5 +143,14 @@
}
};
- 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 dc7749c..06e6c8b 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -525,6 +525,9 @@
@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 d11abf8..4a4a1b4 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 @@
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 5db6dc7..6ccb3ee 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 @@
}
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 01f770b..9fa5da4 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 @@
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 @@
}
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 @@
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 97c32b9..4993412 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 @@
}
}
- 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 @@
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 e831e40..0000000
--- 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 8ba5870..0000000
--- 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 2cbd4ede..0000000
--- 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 e723559..0000000
--- 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 022b4b8..0000000
--- 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/RuleSerializeException.java b/services/core/java/com/android/server/integrity/serializer/RuleSerializeException.java
deleted file mode 100644
index 60cfc48..0000000
--- a/services/core/java/com/android/server/integrity/serializer/RuleSerializeException.java
+++ /dev/null
@@ -1,32 +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.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);
- }
-}
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 2941856..0000000
--- 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 8798a64..c314ab0 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 @@
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 @@
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 @@
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 @@
* 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 89555a9..c8a8799 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 @@
}
@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 0a9109b..0d779af 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 @@
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 @@
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 @@
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 @@
}
@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 @@
}
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 @@
.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 @@
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 15f90d4..6c3b123 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 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 1ebc856..2b29fbd 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 @@
+ 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 @@
// 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 @@
}
}
}
+ 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 @@
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 a492a72..6ce8685 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 @@
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 @@
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 189b608..2d3bc84 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 @@
// 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 6f1e15b..16ab51e 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 @@
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 0b9b677..3eeeece 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 @@
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 @@
if (oldSnapshot
.getAllSubIdsInGroup(mSubscriptionGroup)
.equals(newSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))) {
-
- if (mVcnContext.isFlagIpSecTransformStateEnabled()) {
- reevaluateNetworks();
- }
+ reevaluateNetworks();
return;
}
registerOrUpdateNetworkRequests();
@@ -445,11 +440,6 @@
*/
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 @@
@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 @@
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 448a7eb..08be11e 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 @@
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 @@
}
}
- 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 043470f..9ee42b1 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 @@
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 e6d8132..d2a128b 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 @@
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 7a710dc..662f916 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -55,7 +55,6 @@
"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 6600c98..0000000
--- 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 6464081..f9633e2 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -33,7 +33,6 @@
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 @@
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 dc5cb8d6..0c9f70c 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 4fac647..809b7bb 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 @@
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 9ed2e88..0000000
--- 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 6dccdf5..0000000
--- 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 d35dbb56..2dff392 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 e045f10..4c7b25a 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 @@
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 bc7ff47..441b780 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.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 @@
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 6f31d8d..e540932 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 @@
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 590f719..e6d0a3d 100644
--- a/tools/systemfeatures/Android.bp
+++ b/tools/systemfeatures/Android.bp
@@ -58,6 +58,7 @@
"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 196b5e7..1abe77f 100644
--- a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
+++ b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
@@ -71,7 +71,7 @@
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 @@
/** 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 @@
.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 @@
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 0000000..f8c585d
--- /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());
+ }
+}