Merge "Updating device_idle unit test owners" 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/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..1b8471d 100644
--- a/core/java/android/database/sqlite/flags.aconfig
+++ b/core/java/android/database/sqlite/flags.aconfig
@@ -9,6 +9,14 @@
}
flag {
+ 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"
+}
+
+flag {
name: "sqlite_apis_35"
is_exported: true
namespace: "system_performance"
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/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/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..80aa7d7 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -105,7 +105,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..7d0837a 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);
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
index 520ba89..0a4c488 100644
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ b/nfc/java/android/nfc/NfcOemExtension.java
@@ -82,6 +82,13 @@
private boolean mRfDiscoveryStarted = 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)}.
* Enables the controller in default mode when NFC is disabled (existing API behavior).
* works same as {@link NfcAdapter#setControllerAlwaysOn(boolean)}.
@@ -188,9 +195,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
@@ -677,9 +683,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
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/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/ravenwood/Android.bp b/ravenwood/Android.bp
index 65ea9fe..b3f78ab 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -360,6 +360,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 +619,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",
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/RavenwoodRuntimeEnvironmentController.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuntimeEnvironmentController.java
index 9002e40..28c262d 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;
@@ -52,6 +53,7 @@
import com.android.hoststubgen.hosthelper.HostTestUtils;
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;
@@ -165,6 +167,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 +188,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 +201,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 +225,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 +314,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 +354,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_runtime.cpp b/ravenwood/runtime-jni/ravenwood_runtime.cpp
index 3ff0848..5b75e98 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,30 @@
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);
+}
+
+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);
+ 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);
+}
+
// ---- Registration ----
extern void register_android_system_OsConstants(JNIEnv* env);
@@ -189,9 +214,12 @@
{ "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 */) {
+ maybeRedirectLog();
+
ALOGI("%s: JNI_OnLoad", __FILE__);
JNIEnv* env = GetJNIEnvOrDie(vm);
diff --git a/ravenwood/scripts/run-ravenwood-tests.sh b/ravenwood/scripts/run-ravenwood-tests.sh
index 5d623e0..672c685 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)$'
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 -P "$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/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/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 45885f0..c314ab0 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -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.
@@ -3632,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/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/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());
+ }
+}