Merge "Dedupe build rules for non-updatable sdk libs" into main
diff --git a/Android.bp b/Android.bp
index ed56fd8..e8f6264 100644
--- a/Android.bp
+++ b/Android.bp
@@ -620,6 +620,7 @@
name: "android-non-updatable-stub-sources",
srcs: [
":framework-mime-sources", // mimemap builds separately but has no separate droidstubs.
+ ":framework-minus-apex-aconfig-srcjars",
":framework-non-updatable-sources",
":opt-telephony-srcs",
":opt-net-voip-srcs",
diff --git a/BAL_OWNERS b/BAL_OWNERS
new file mode 100644
index 0000000..d56a1d4
--- /dev/null
+++ b/BAL_OWNERS
@@ -0,0 +1,5 @@
+brufino@google.com
+achim@google.com
+topjohnwu@google.com
+lus@google.com
+
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index d566552..5688b96 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -29,9 +29,6 @@
droidstubs {
name: "api-stubs-docs-non-updatable",
- srcs: [
- ":framework-minus-apex-aconfig-srcjars",
- ],
defaults: [
"android-non-updatable-stubs-defaults",
"module-classpath-stubs-defaults",
@@ -91,9 +88,6 @@
droidstubs {
name: "system-api-stubs-docs-non-updatable",
- srcs: [
- ":framework-minus-apex-aconfig-srcjars",
- ],
defaults: [
"android-non-updatable-stubs-defaults",
"module-classpath-stubs-defaults",
@@ -134,9 +128,6 @@
droidstubs {
name: "test-api-stubs-docs-non-updatable",
- srcs: [
- ":framework-minus-apex-aconfig-srcjars",
- ],
defaults: [
"android-non-updatable-stubs-defaults",
"module-classpath-stubs-defaults",
@@ -184,9 +175,6 @@
droidstubs {
name: "module-lib-api-stubs-docs-non-updatable",
- srcs: [
- ":framework-minus-apex-aconfig-srcjars",
- ],
defaults: [
"android-non-updatable-stubs-defaults",
"module-classpath-stubs-defaults",
diff --git a/core/api/current.txt b/core/api/current.txt
index fd4da0d..7cf7e19 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -28951,6 +28951,7 @@
method @NonNull public long[] getRetryIntervalsMillis();
method @NonNull public java.util.List<android.net.vcn.VcnUnderlyingNetworkTemplate> getVcnUnderlyingNetworkPriorities();
method public boolean hasGatewayOption(int);
+ method @FlaggedApi("android.net.vcn.safe_mode_config") public boolean isSafeModeEnabled();
field public static final int VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY = 0; // 0x0
}
@@ -28959,6 +28960,7 @@
method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addExposedCapability(int);
method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addGatewayOption(int);
method @NonNull public android.net.vcn.VcnGatewayConnectionConfig build();
+ method @FlaggedApi("android.net.vcn.safe_mode_config") @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder enableSafeMode(boolean);
method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeExposedCapability(int);
method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeGatewayOption(int);
method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder setMaxMtu(@IntRange(from=0x500) int);
@@ -32662,7 +32664,7 @@
field public static final int S_V2 = 32; // 0x20
field public static final int TIRAMISU = 33; // 0x21
field public static final int UPSIDE_DOWN_CAKE = 34; // 0x22
- field public static final int VANILLA_ICE_CREAM = 10000; // 0x2710
+ field @FlaggedApi("android.os.android_os_build_vanilla_ice_cream") public static final int VANILLA_ICE_CREAM = 10000; // 0x2710
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 7cfa1e3..1a22e9b 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -14,7 +14,7 @@
@UiContext public class Activity extends android.view.ContextThemeWrapper implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback android.view.LayoutInflater.Factory2 android.view.View.OnCreateContextMenuListener android.view.Window.Callback {
method public final boolean addDumpable(@NonNull android.util.Dumpable);
- method public final boolean isResumed();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public final boolean isResumed();
}
public class ActivityManager {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index b6c9678..c1b70cb0 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -10244,6 +10244,7 @@
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
method @FlaggedApi("android.nfc.enable_nfc_reader_option") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableReaderOption(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public int getAdapterState();
method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.Map<java.lang.String,java.lang.Boolean> getTagIntentAppPreferenceForUser(int);
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported();
@@ -10254,6 +10255,7 @@
method @FlaggedApi("android.nfc.enable_nfc_mainline") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setReaderMode(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setTagIntentAppPreferenceForUser(int, @NonNull String, boolean);
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnListener(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
+ field @FlaggedApi("android.nfc.enable_nfc_mainline") public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC = "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC";
field public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1; // 0xffffffff
field public static final int TAG_INTENT_APP_PREF_RESULT_SUCCESS = 0; // 0x0
field public static final int TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE = -2; // 0xfffffffe
@@ -10315,6 +10317,10 @@
field @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.ApduServiceInfo> CREATOR;
}
+ public final class CardEmulation {
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<android.nfc.cardemulation.ApduServiceInfo> getServices(@NonNull String, int);
+ }
+
@FlaggedApi("android.nfc.enable_nfc_mainline") public final class NfcFServiceInfo implements android.os.Parcelable {
ctor @FlaggedApi("android.nfc.enable_nfc_mainline") public NfcFServiceInfo(@NonNull android.content.pm.PackageManager, @NonNull android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method @FlaggedApi("android.nfc.enable_nfc_mainline") public int describeContents();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 2590869..06c139f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -31,6 +31,7 @@
import android.annotation.CallbackExecutor;
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
+import android.annotation.FlaggedApi;
import android.annotation.IdRes;
import android.annotation.IntDef;
import android.annotation.LayoutRes;
@@ -79,6 +80,7 @@
import android.media.AudioManager;
import android.media.session.MediaController;
import android.net.Uri;
+import android.nfc.Flags;
import android.os.BadParcelableException;
import android.os.Build;
import android.os.Bundle;
@@ -8915,6 +8917,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public final boolean isResumed() {
return mResumed;
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index a40fb15..779a8db 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -16,10 +16,12 @@
package android.net.vcn;
import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
+import static android.net.vcn.Flags.FLAG_SAFE_MODE_CONFIG;
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
import static com.android.internal.annotations.VisibleForTesting.Visibility;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -235,6 +237,9 @@
"mMinUdpPort4500NatTimeoutSeconds";
private final int mMinUdpPort4500NatTimeoutSeconds;
+ private static final String IS_SAFE_MODE_DISABLED_KEY = "mIsSafeModeDisabled";
+ private final boolean mIsSafeModeDisabled;
+
private static final String GATEWAY_OPTIONS_KEY = "mGatewayOptions";
@NonNull private final Set<Integer> mGatewayOptions;
@@ -247,6 +252,7 @@
@NonNull long[] retryIntervalsMs,
@IntRange(from = MIN_MTU_V6) int maxMtu,
@NonNull int minUdpPort4500NatTimeoutSeconds,
+ boolean isSafeModeDisabled,
@NonNull Set<Integer> gatewayOptions) {
mGatewayConnectionName = gatewayConnectionName;
mTunnelConnectionParams = tunnelConnectionParams;
@@ -255,6 +261,7 @@
mMaxMtu = maxMtu;
mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds;
mGatewayOptions = Collections.unmodifiableSet(new ArraySet(gatewayOptions));
+ mIsSafeModeDisabled = isSafeModeDisabled;
mUnderlyingNetworkTemplates = new ArrayList<>(underlyingNetworkTemplates);
if (mUnderlyingNetworkTemplates.isEmpty()) {
@@ -317,6 +324,7 @@
in.getInt(
MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY,
MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET);
+ mIsSafeModeDisabled = in.getBoolean(IS_SAFE_MODE_DISABLED_KEY);
validate();
}
@@ -483,6 +491,16 @@
}
/**
+ * Check whether safe mode is enabled
+ *
+ * @see Builder#enableSafeMode(boolean)
+ */
+ @FlaggedApi(FLAG_SAFE_MODE_CONFIG)
+ public boolean isSafeModeEnabled() {
+ return !mIsSafeModeDisabled;
+ }
+
+ /**
* Checks if the given VCN gateway option is enabled.
*
* @param option the option to check.
@@ -528,6 +546,7 @@
result.putLongArray(RETRY_INTERVAL_MS_KEY, mRetryIntervalsMs);
result.putInt(MAX_MTU_KEY, mMaxMtu);
result.putInt(MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS_KEY, mMinUdpPort4500NatTimeoutSeconds);
+ result.putBoolean(IS_SAFE_MODE_DISABLED_KEY, mIsSafeModeDisabled);
return result;
}
@@ -542,6 +561,7 @@
Arrays.hashCode(mRetryIntervalsMs),
mMaxMtu,
mMinUdpPort4500NatTimeoutSeconds,
+ mIsSafeModeDisabled,
mGatewayOptions);
}
@@ -559,6 +579,7 @@
&& Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs)
&& mMaxMtu == rhs.mMaxMtu
&& mMinUdpPort4500NatTimeoutSeconds == rhs.mMinUdpPort4500NatTimeoutSeconds
+ && mIsSafeModeDisabled == rhs.mIsSafeModeDisabled
&& mGatewayOptions.equals(rhs.mGatewayOptions);
}
@@ -577,6 +598,7 @@
@NonNull private long[] mRetryIntervalsMs = DEFAULT_RETRY_INTERVALS_MS;
private int mMaxMtu = DEFAULT_MAX_MTU;
private int mMinUdpPort4500NatTimeoutSeconds = MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET;
+ private boolean mIsSafeModeDisabled = false;
@NonNull private final Set<Integer> mGatewayOptions = new ArraySet<>();
@@ -789,6 +811,27 @@
}
/**
+ * Enable/disable safe mode
+ *
+ * <p>If a VCN fails to provide connectivity within a system-provided timeout, it will enter
+ * safe mode. In safe mode, the VCN Network will be torn down and the system will restore
+ * connectivity by allowing underlying cellular networks to be used as default. At the same
+ * time, VCN will continue to retry until it succeeds.
+ *
+ * <p>When safe mode is disabled and VCN connection fails to provide connectivity, end users
+ * might not have connectivity, and may not have access to carrier-owned underlying
+ * networks.
+ *
+ * @param enabled whether safe mode should be enabled. Defaults to {@code true}
+ */
+ @FlaggedApi(FLAG_SAFE_MODE_CONFIG)
+ @NonNull
+ public Builder enableSafeMode(boolean enabled) {
+ mIsSafeModeDisabled = !enabled;
+ return this;
+ }
+
+ /**
* Builds and validates the VcnGatewayConnectionConfig.
*
* @return an immutable VcnGatewayConnectionConfig instance
@@ -803,6 +846,7 @@
mRetryIntervalsMs,
mMaxMtu,
mMinUdpPort4500NatTimeoutSeconds,
+ mIsSafeModeDisabled,
mGatewayOptions);
}
}
diff --git a/core/java/android/nfc/INfcCardEmulation.aidl b/core/java/android/nfc/INfcCardEmulation.aidl
index 53843fe..c7b3b2c 100644
--- a/core/java/android/nfc/INfcCardEmulation.aidl
+++ b/core/java/android/nfc/INfcCardEmulation.aidl
@@ -40,5 +40,6 @@
boolean unsetPreferredService();
boolean supportsAidPrefixRegistration();
ApduServiceInfo getPreferredPaymentService(int userHandle);
+ boolean setServiceEnabledForCategoryOther(int userHandle, in ComponentName app, boolean status);
boolean isDefaultPaymentRegistered();
}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 4a7bd3f..c897595 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -378,6 +378,8 @@
* <p>An external NFC field detected when device locked and SecureNfc enabled.
* @hide
*/
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC =
"android.nfc.action.REQUIRE_UNLOCK_FOR_NFC";
@@ -944,7 +946,8 @@
*
* @hide
*/
- @UnsupportedAppUsage
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
public int getAdapterState() {
try {
return sService.getState();
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 665b753..9cf8c4d 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -127,6 +127,11 @@
private final String mSettingsActivityName;
/**
+ * State of the service for CATEGORY_OTHER selection
+ */
+ private boolean mOtherServiceSelectionState;
+
+ /**
* @hide
*/
public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
@@ -134,8 +139,21 @@
boolean requiresUnlock, int bannerResource, int uid,
String settingsActivityName, String offHost, String staticOffHost) {
this(info, onHost, description, staticAidGroups, dynamicAidGroups,
+ requiresUnlock, bannerResource, uid, settingsActivityName,
+ offHost, staticOffHost, false);
+ }
+
+ /**
+ * @hide
+ */
+ public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
+ List<AidGroup> staticAidGroups, List<AidGroup> dynamicAidGroups,
+ boolean requiresUnlock, int bannerResource, int uid,
+ String settingsActivityName, String offHost, String staticOffHost,
+ boolean isSelected) {
+ this(info, onHost, description, staticAidGroups, dynamicAidGroups,
requiresUnlock, onHost ? true : false, bannerResource, uid,
- settingsActivityName, offHost, staticOffHost);
+ settingsActivityName, offHost, staticOffHost, isSelected);
}
/**
@@ -144,7 +162,7 @@
public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
List<AidGroup> staticAidGroups, List<AidGroup> dynamicAidGroups,
boolean requiresUnlock, boolean requiresScreenOn, int bannerResource, int uid,
- String settingsActivityName, String offHost, String staticOffHost) {
+ String settingsActivityName, String offHost, String staticOffHost, boolean isSelected) {
this.mService = info;
this.mDescription = description;
this.mStaticAidGroups = new HashMap<String, AidGroup>();
@@ -163,6 +181,8 @@
this.mBannerResourceId = bannerResource;
this.mUid = uid;
this.mSettingsActivityName = settingsActivityName;
+ this.mOtherServiceSelectionState = isSelected;
+
}
/**
@@ -351,6 +371,9 @@
}
// Set uid
mUid = si.applicationInfo.uid;
+
+ mOtherServiceSelectionState = false; // support other category
+
}
/**
@@ -720,43 +743,47 @@
dest.writeInt(mBannerResourceId);
dest.writeInt(mUid);
dest.writeString(mSettingsActivityName);
+
+ dest.writeInt(mOtherServiceSelectionState ? 1 : 0);
};
@FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
public static final @NonNull Parcelable.Creator<ApduServiceInfo> CREATOR =
new Parcelable.Creator<ApduServiceInfo>() {
- @Override
- public ApduServiceInfo createFromParcel(Parcel source) {
- ResolveInfo info = ResolveInfo.CREATOR.createFromParcel(source);
- String description = source.readString();
- boolean onHost = source.readInt() != 0;
- String offHostName = source.readString();
- String staticOffHostName = source.readString();
- ArrayList<AidGroup> staticAidGroups = new ArrayList<AidGroup>();
- int numStaticGroups = source.readInt();
- if (numStaticGroups > 0) {
- source.readTypedList(staticAidGroups, AidGroup.CREATOR);
- }
- ArrayList<AidGroup> dynamicAidGroups = new ArrayList<AidGroup>();
- int numDynamicGroups = source.readInt();
- if (numDynamicGroups > 0) {
- source.readTypedList(dynamicAidGroups, AidGroup.CREATOR);
- }
- boolean requiresUnlock = source.readInt() != 0;
- boolean requiresScreenOn = source.readInt() != 0;
- int bannerResource = source.readInt();
- int uid = source.readInt();
- String settingsActivityName = source.readString();
- return new ApduServiceInfo(info, onHost, description, staticAidGroups,
- dynamicAidGroups, requiresUnlock, requiresScreenOn, bannerResource, uid,
- settingsActivityName, offHostName, staticOffHostName);
- }
+ @Override
+ public ApduServiceInfo createFromParcel(Parcel source) {
+ ResolveInfo info = ResolveInfo.CREATOR.createFromParcel(source);
+ String description = source.readString();
+ boolean onHost = source.readInt() != 0;
+ String offHostName = source.readString();
+ String staticOffHostName = source.readString();
+ ArrayList<AidGroup> staticAidGroups = new ArrayList<AidGroup>();
+ int numStaticGroups = source.readInt();
+ if (numStaticGroups > 0) {
+ source.readTypedList(staticAidGroups, AidGroup.CREATOR);
+ }
+ ArrayList<AidGroup> dynamicAidGroups = new ArrayList<AidGroup>();
+ int numDynamicGroups = source.readInt();
+ if (numDynamicGroups > 0) {
+ source.readTypedList(dynamicAidGroups, AidGroup.CREATOR);
+ }
+ boolean requiresUnlock = source.readInt() != 0;
+ boolean requiresScreenOn = source.readInt() != 0;
+ int bannerResource = source.readInt();
+ int uid = source.readInt();
+ String settingsActivityName = source.readString();
+ boolean isSelected = source.readInt() != 0;
+ return new ApduServiceInfo(info, onHost, description, staticAidGroups,
+ dynamicAidGroups, requiresUnlock, requiresScreenOn, bannerResource, uid,
+ settingsActivityName, offHostName, staticOffHostName,
+ isSelected);
+ }
- @Override
- public ApduServiceInfo[] newArray(int size) {
- return new ApduServiceInfo[size];
- }
- };
+ @Override
+ public ApduServiceInfo[] newArray(int size) {
+ return new ApduServiceInfo[size];
+ }
+ };
/**
* Dump contents for debugging.
@@ -779,14 +806,16 @@
}
pw.println(" Static AID groups:");
for (AidGroup group : mStaticAidGroups.values()) {
- pw.println(" Category: " + group.getCategory());
+ pw.println(" Category: " + group.getCategory()
+ + "(selected: " + mOtherServiceSelectionState + ")");
for (String aid : group.getAids()) {
pw.println(" AID: " + aid);
}
}
pw.println(" Dynamic AID groups:");
for (AidGroup group : mDynamicAidGroups.values()) {
- pw.println(" Category: " + group.getCategory());
+ pw.println(" Category: " + group.getCategory()
+ + "(selected: " + mOtherServiceSelectionState + ")");
for (String aid : group.getAids()) {
pw.println(" AID: " + aid);
}
@@ -796,6 +825,22 @@
pw.println(" Requires Device ScreenOn: " + mRequiresDeviceScreenOn);
}
+
+ /**
+ * @hide
+ */
+ public void setOtherServiceState(boolean selected) {
+ mOtherServiceSelectionState = selected;
+ }
+
+
+ /**
+ * @hide
+ */
+ public boolean isSelectedOtherService() {
+ return mOtherServiceSelectionState;
+ }
+
/**
* Dump debugging info as ApduServiceInfoProto.
*
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index 32c2a1b..d048b59 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -16,17 +16,21 @@
package android.nfc.cardemulation;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
+import android.annotation.UserIdInt;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.nfc.Constants;
+import android.nfc.Flags;
import android.nfc.INfcCardEmulation;
import android.nfc.NfcAdapter;
import android.os.RemoteException;
@@ -877,9 +881,16 @@
}
/**
+ * Retrieves list of services registered of the provided category for the provided user.
+ *
+ * @param category Category string, one of {@link #CATEGORY_PAYMENT} or {@link #CATEGORY_OTHER}
+ * @param userId the user handle of the user whose information is being requested.
* @hide
*/
- public List<ApduServiceInfo> getServices(String category, int userId) {
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
+ @NonNull
+ public List<ApduServiceInfo> getServices(@NonNull String category, @UserIdInt int userId) {
try {
return sService.getServices(userId, category);
} catch (RemoteException e) {
@@ -936,6 +947,39 @@
return true;
}
+ /**
+ * Allows to set or unset preferred service (category other) to avoid AID Collision.
+ *
+ * @param service The ComponentName of the service
+ * @param status true to enable, false to disable
+ * @return set service for the category and true if service is already set return false.
+ *
+ * @hide
+ */
+ public boolean setServiceEnabledForCategoryOther(ComponentName service, boolean status) {
+ if (service == null) {
+ throw new NullPointerException("activity or service or category is null");
+ }
+ int userId = mContext.getUser().getIdentifier();
+
+ try {
+ return sService.setServiceEnabledForCategoryOther(userId, service, status);
+ } catch (RemoteException e) {
+ // Try one more time
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return false;
+ }
+ try {
+ return sService.setServiceEnabledForCategoryOther(userId, service, status);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach CardEmulationService.");
+ return false;
+ }
+ }
+ }
+
void recoverService() {
NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
sService = adapter.getCardEmulationService();
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 6a4ec9b..25fba60 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -21,6 +21,7 @@
import android.Manifest.permission;
import android.annotation.FlaggedApi;
import android.annotation.RequiresPermission;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
@@ -236,6 +237,7 @@
OsProtoEnums.CHARGING_POLICY_ADAPTIVE_LONGLIFE; // = 4
/** @hide */
+ @SuppressLint("UnflaggedApi") // TestApi without associated feature.
@TestApi
public static final int BATTERY_PLUGGED_ANY =
BATTERY_PLUGGED_AC | BATTERY_PLUGGED_USB | BATTERY_PLUGGED_WIRELESS
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 509c3b8..a9b7257 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -17,6 +17,7 @@
package android.os;
import android.Manifest;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -1227,6 +1228,7 @@
/**
* Vanilla Ice Cream.
*/
+ @FlaggedApi(Flags.FLAG_ANDROID_OS_BUILD_VANILLA_ICE_CREAM)
public static final int VANILLA_ICE_CREAM = CUR_DEVELOPMENT;
}
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index 77229c4..4031153 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -1,6 +1,13 @@
package: "android.os"
flag {
+ name: "android_os_build_vanilla_ice_cream"
+ namespace: "build"
+ description: "Feature flag for adding the VANILLA_ICE_CREAM constant."
+ bug: "264658905"
+}
+
+flag {
name: "state_of_health_public"
namespace: "system_sw_battery"
description: "Feature flag for making state_of_health a public api."
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 965277c..1c5f4f0 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -868,6 +868,11 @@
args.mPkgDataInfoList, args.mAllowlistedDataInfoList,
args.mBindMountAppDataDirs, args.mBindMountAppStorageDirs);
+ // While `specializeAppProcess` sets the thread name on the process's main thread, this
+ // is distinct from the app process name which appears in stack traces, as the latter is
+ // sourced from the argument buffer of the Process class. Set the app process name here.
+ Zygote.setAppProcessName(args, TAG);
+
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return ZygoteInit.zygoteInit(args.mTargetSdkVersion,
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 993e4e7..5fe086d 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -296,7 +296,6 @@
} else {
// child; result is a Runnable.
zygoteServer.setForkChild();
- Zygote.setAppProcessName(parsedArgs, TAG); // ??? Necessary?
return result;
}
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 8d11672..a3e0016 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1105,10 +1105,9 @@
@UnsupportedAppUsage
public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
- if (isSpecialUserId(userId)) {
- // For secure password storage (that is required for special users such as FRP), the
- // underlying storage also enforces the deadline. Since we cannot store settings
- // for special users, don't.
+ if (userId == USER_FRP) {
+ // For secure password storage (that is required for FRP), the underlying storage also
+ // enforces the deadline. Since we cannot store settings for the FRP user, don't.
return deadline;
}
mLockoutDeadlines.put(userId, deadline);
diff --git a/core/tests/coretests/src/android/app/OWNERS b/core/tests/coretests/src/android/app/OWNERS
index 64f5e6c..5636f9b 100644
--- a/core/tests/coretests/src/android/app/OWNERS
+++ b/core/tests/coretests/src/android/app/OWNERS
@@ -10,3 +10,7 @@
# KeyguardManagerTest
per-file KeyguardManagerTest.java = file:/services/core/java/com/android/server/locksettings/OWNERS
+
+# Files related to background activity launches
+per-file Background*Start* = file:/BAL_OWNERS
+
diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp
index fe3132e..ceab164 100644
--- a/native/android/system_fonts.cpp
+++ b/native/android/system_fonts.cpp
@@ -21,23 +21,21 @@
#include <android/font.h>
#include <android/font_matcher.h>
#include <android/system_fonts.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <hwui/MinikinSkia.h>
+#include <libxml/parser.h>
+#include <log/log.h>
+#include <minikin/FontCollection.h>
+#include <minikin/LocaleList.h>
+#include <minikin/SystemFonts.h>
+#include <sys/stat.h>
+#include <unistd.h>
#include <memory>
#include <string>
#include <vector>
-#include <errno.h>
-#include <fcntl.h>
-#include <libxml/tree.h>
-#include <log/log.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <hwui/MinikinSkia.h>
-#include <minikin/FontCollection.h>
-#include <minikin/LocaleList.h>
-#include <minikin/SystemFonts.h>
-
struct XmlCharDeleter {
void operator()(xmlChar* b) { xmlFree(b); }
};
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 2e45da3..d56448d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -1174,7 +1174,7 @@
synchronized (mInternal.mOomAdjuster.mCachedAppOptimizer.mFreezerLock) {
app.mOptRecord.setFreezeSticky(isSticky);
mInternal.mOomAdjuster.mCachedAppOptimizer.unfreezeAppInternalLSP(app, 0,
- false);
+ true);
}
}
}
diff --git a/services/core/java/com/android/server/net/NetworkManagementService.java b/services/core/java/com/android/server/net/NetworkManagementService.java
index a5a934f..550ad5d 100644
--- a/services/core/java/com/android/server/net/NetworkManagementService.java
+++ b/services/core/java/com/android/server/net/NetworkManagementService.java
@@ -74,6 +74,7 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.util.HexDump;
import com.android.modules.utils.build.SdkLevel;
+import com.android.net.flags.Flags;
import com.android.net.module.util.NetdUtils;
import com.android.net.module.util.PermissionUtils;
import com.android.server.FgThread;
@@ -1059,17 +1060,25 @@
Log.w(TAG, "setDataSaverMode(): already " + mDataSaverMode);
return true;
}
- Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "bandwidthEnableDataSaver");
+ Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setDataSaverModeEnabled");
try {
- final boolean changed = mNetdService.bandwidthEnableDataSaver(enable);
- if (changed) {
+ if (Flags.setDataSaverViaCm()) {
+ // setDataSaverEnabled throws if it fails to set data saver.
+ mContext.getSystemService(ConnectivityManager.class)
+ .setDataSaverEnabled(enable);
mDataSaverMode = enable;
+ return true;
} else {
- Log.w(TAG, "setDataSaverMode(" + enable + "): netd command silently failed");
+ final boolean changed = mNetdService.bandwidthEnableDataSaver(enable);
+ if (changed) {
+ mDataSaverMode = enable;
+ } else {
+ Log.e(TAG, "setDataSaverMode(" + enable + "): failed to set iptables");
+ }
+ return changed;
}
- return changed;
- } catch (RemoteException e) {
- Log.w(TAG, "setDataSaverMode(" + enable + "): netd command failed", e);
+ } catch (RemoteException | IllegalStateException e) {
+ Log.e(TAG, "setDataSaverMode(" + enable + "): failed with exception", e);
return false;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 6a2ddc8..ea082cf 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -159,6 +159,9 @@
if (pkgSetting.getPkg().isCoreApp()) {
throw new IllegalStateException("Found a core app that's not important");
}
+ // Use REASON_FIRST_BOOT to query "pm.dexopt.first-boot" for the compiler filter, but
+ // the reason itself won't make it into the actual compiler reason because it will be
+ // overridden in otapreopt.cpp.
mDexoptCommands.addAll(generatePackageDexopts(pkgSetting.getPkg(), pkgSetting,
PackageManagerService.REASON_FIRST_BOOT));
}
diff --git a/services/core/java/com/android/server/vcn/VcnContext.java b/services/core/java/com/android/server/vcn/VcnContext.java
index d958222..9213d96 100644
--- a/services/core/java/com/android/server/vcn/VcnContext.java
+++ b/services/core/java/com/android/server/vcn/VcnContext.java
@@ -18,6 +18,8 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.net.vcn.FeatureFlags;
+import android.net.vcn.FeatureFlagsImpl;
import android.os.Looper;
import java.util.Objects;
@@ -31,6 +33,7 @@
@NonNull private final Context mContext;
@NonNull private final Looper mLooper;
@NonNull private final VcnNetworkProvider mVcnNetworkProvider;
+ @NonNull private final FeatureFlags mFeatureFlags;
private final boolean mIsInTestMode;
public VcnContext(
@@ -42,6 +45,9 @@
mLooper = Objects.requireNonNull(looper, "Missing looper");
mVcnNetworkProvider = Objects.requireNonNull(vcnNetworkProvider, "Missing networkProvider");
mIsInTestMode = isInTestMode;
+
+ // Auto-generated class
+ mFeatureFlags = new FeatureFlagsImpl();
}
@NonNull
@@ -63,6 +69,11 @@
return mIsInTestMode;
}
+ @NonNull
+ public FeatureFlags getFeatureFlags() {
+ return mFeatureFlags;
+ }
+
/**
* Verifies that the caller is running on the VcnContext Thread.
*
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index d480ddb..54c97dd 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -1222,6 +1222,14 @@
@VisibleForTesting(visibility = Visibility.PRIVATE)
void setSafeModeAlarm() {
+ final boolean isFlagSafeModeConfigEnabled = mVcnContext.getFeatureFlags().safeModeConfig();
+ logVdbg("isFlagSafeModeConfigEnabled " + isFlagSafeModeConfigEnabled);
+
+ if (isFlagSafeModeConfigEnabled && !mConnectionConfig.isSafeModeEnabled()) {
+ logVdbg("setSafeModeAlarm: safe mode disabled");
+ return;
+ }
+
logVdbg("Setting safe mode alarm; mCurrentToken: " + mCurrentToken);
// Only schedule a NEW alarm if none is already set.
diff --git a/services/core/java/com/android/server/wm/OWNERS b/services/core/java/com/android/server/wm/OWNERS
index f8c39d0..cd70447 100644
--- a/services/core/java/com/android/server/wm/OWNERS
+++ b/services/core/java/com/android/server/wm/OWNERS
@@ -18,5 +18,8 @@
yunfanc@google.com
wilsonshih@google.com
-per-file BackgroundActivityStartController.java = set noparent
-per-file BackgroundActivityStartController.java = brufino@google.com, topjohnwu@google.com, achim@google.com, ogunwale@google.com, louischang@google.com, lus@google.com
+# Files related to background activity launches
+per-file Background*Start* = set noparent
+per-file Background*Start* = file:/BAL_OWNERS
+per-file Background*Start* = ogunwale@google.com, louischang@google.com
+
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 3063d46..46ca445 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -6510,11 +6510,11 @@
mActivityType = ACTIVITY_TYPE_STANDARD;
}
- if (mActivityType != ACTIVITY_TYPE_STANDARD
+ if (!DisplayContent.alwaysCreateRootTask(tda.getWindowingMode(), mActivityType)
&& mActivityType != ACTIVITY_TYPE_UNDEFINED) {
- // For now there can be only one root task of a particular non-standard activity
- // type on a display. So, get that ignoring whatever windowing mode it is
- // currently in.
+ // Only Recents or Standard activity types are allowed to have more than one
+ // root task on a display, this is independent of whatever windowing mode it
+ // is currently in.
Task rootTask = tda.getRootTask(WINDOWING_MODE_UNDEFINED, mActivityType);
if (rootTask != null) {
throw new IllegalArgumentException("Root task=" + rootTask + " of activityType="
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
index af144cf..2cdfbff 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkManagementServiceTest.java
@@ -57,6 +57,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.app.IBatteryStats;
+import com.android.net.flags.Flags;
import org.junit.After;
import org.junit.Before;
@@ -263,7 +264,11 @@
verify(mCm).addUidToMeteredNetworkDenyList(TEST_UID);
mNMService.setDataSaverModeEnabled(true);
- verify(mNetdService).bandwidthEnableDataSaver(true);
+ if (Flags.setDataSaverViaCm()) {
+ verify(mCm).setDataSaverEnabled(true);
+ } else {
+ verify(mNetdService).bandwidthEnableDataSaver(true);
+ }
mNMService.setUidOnMeteredNetworkDenylist(TEST_UID, false);
assertTrue("Should be true since data saver is on and the uid is not allowlisted",
@@ -279,7 +284,11 @@
mNMService.setUidOnMeteredNetworkAllowlist(TEST_UID, false);
verify(mCm).removeUidFromMeteredNetworkAllowList(TEST_UID);
mNMService.setDataSaverModeEnabled(false);
- verify(mNetdService).bandwidthEnableDataSaver(false);
+ if (Flags.setDataSaverViaCm()) {
+ verify(mCm).setDataSaverEnabled(false);
+ } else {
+ verify(mNetdService).bandwidthEnableDataSaver(false);
+ }
assertFalse("Network should not be restricted when data saver is off",
mNMService.isNetworkRestricted(TEST_UID));
}
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index a1a39ff..cb37821 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -117,6 +117,16 @@
return buildTestConfig(UNDERLYING_NETWORK_TEMPLATES);
}
+ // Public for use in VcnGatewayConnectionTest
+ public static VcnGatewayConnectionConfig.Builder newTestBuilderMinimal() {
+ final VcnGatewayConnectionConfig.Builder builder = newBuilder();
+ for (int caps : EXPOSED_CAPS) {
+ builder.addExposedCapability(caps);
+ }
+
+ return builder;
+ }
+
private static VcnGatewayConnectionConfig.Builder newBuilder() {
// Append a unique identifier to the name prefix to guarantee that all created
// VcnGatewayConnectionConfigs have a unique name (required by VcnConfig).
@@ -125,6 +135,17 @@
TUNNEL_CONNECTION_PARAMS);
}
+ private static VcnGatewayConnectionConfig.Builder newBuilderMinimal() {
+ final VcnGatewayConnectionConfig.Builder builder =
+ new VcnGatewayConnectionConfig.Builder(
+ "newBuilderMinimal", TUNNEL_CONNECTION_PARAMS);
+ for (int caps : EXPOSED_CAPS) {
+ builder.addExposedCapability(caps);
+ }
+
+ return builder;
+ }
+
private static VcnGatewayConnectionConfig buildTestConfigWithExposedCapsAndOptions(
VcnGatewayConnectionConfig.Builder builder,
Set<Integer> gatewayOptions,
@@ -273,6 +294,7 @@
assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis());
assertEquals(MAX_MTU, config.getMaxMtu());
+ assertTrue(config.isSafeModeEnabled());
assertFalse(
config.hasGatewayOption(
@@ -290,6 +312,13 @@
}
@Test
+ public void testBuilderAndGettersSafeModeDisabled() {
+ final VcnGatewayConnectionConfig config = newBuilderMinimal().enableSafeMode(false).build();
+
+ assertFalse(config.isSafeModeEnabled());
+ }
+
+ @Test
public void testPersistableBundle() {
final VcnGatewayConnectionConfig config = buildTestConfig();
@@ -305,6 +334,13 @@
}
@Test
+ public void testPersistableBundleSafeModeDisabled() {
+ final VcnGatewayConnectionConfig config = newBuilderMinimal().enableSafeMode(false).build();
+
+ assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle()));
+ }
+
+ @Test
public void testParsePersistableBundleWithoutVcnUnderlyingNetworkTemplates() {
PersistableBundle configBundle = buildTestConfig().toPersistableBundle();
configBundle.putPersistableBundle(UNDERLYING_NETWORK_TEMPLATES_KEY, null);
@@ -411,4 +447,18 @@
assertEquals(config, configEqual);
assertNotEquals(config, configNotEqual);
}
+
+ @Test
+ public void testSafeModeEnableDisableEquality() throws Exception {
+ final VcnGatewayConnectionConfig config = newBuilderMinimal().build();
+ final VcnGatewayConnectionConfig configEqual = newBuilderMinimal().build();
+
+ assertEquals(config.isSafeModeEnabled(), configEqual.isSafeModeEnabled());
+
+ final VcnGatewayConnectionConfig configNotEqual =
+ newBuilderMinimal().enableSafeMode(false).build();
+
+ assertEquals(config, configEqual);
+ assertNotEquals(config, configNotEqual);
+ }
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 302af52..bf73198 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -75,6 +75,9 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionCallback;
+import com.android.server.vcn.VcnGatewayConnection.VcnChildSessionConfiguration;
+import com.android.server.vcn.VcnGatewayConnection.VcnIkeSession;
+import com.android.server.vcn.VcnGatewayConnection.VcnNetworkAgent;
import com.android.server.vcn.routeselection.UnderlyingNetworkRecord;
import com.android.server.vcn.util.MtuUtils;
@@ -651,6 +654,74 @@
verifySafeModeStateAndCallbackFired(2 /* invocationCount */, true /* isInSafeMode */);
}
+ private void verifySetSafeModeAlarm(
+ boolean safeModeEnabledByCaller,
+ boolean safeModeConfigFlagEnabled,
+ boolean expectingSafeModeEnabled)
+ throws Exception {
+ final VcnGatewayConnectionConfig config =
+ VcnGatewayConnectionConfigTest.newTestBuilderMinimal()
+ .enableSafeMode(safeModeEnabledByCaller)
+ .build();
+ final VcnGatewayConnection.Dependencies deps =
+ mock(VcnGatewayConnection.Dependencies.class);
+ setUpWakeupMessage(
+ mSafeModeTimeoutAlarm, VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM, deps);
+ doReturn(safeModeConfigFlagEnabled).when(mFeatureFlags).safeModeConfig();
+
+ final VcnGatewayConnection connection =
+ new VcnGatewayConnection(
+ mVcnContext,
+ TEST_SUB_GRP,
+ TEST_SUBSCRIPTION_SNAPSHOT,
+ config,
+ mGatewayStatusCallback,
+ true /* isMobileDataEnabled */,
+ deps);
+
+ connection.setSafeModeAlarm();
+
+ final int expectedCallCnt = expectingSafeModeEnabled ? 1 : 0;
+ verify(deps, times(expectedCallCnt))
+ .newWakeupMessage(
+ eq(mVcnContext),
+ any(),
+ eq(VcnGatewayConnection.SAFEMODE_TIMEOUT_ALARM),
+ any());
+ }
+
+ @Test
+ public void testSafeModeEnabled_configFlagEnabled() throws Exception {
+ verifySetSafeModeAlarm(
+ true /* safeModeEnabledByCaller */,
+ true /* safeModeConfigFlagEnabled */,
+ true /* expectingSafeModeEnabled */);
+ }
+
+ @Test
+ public void testSafeModeEnabled_configFlagDisabled() throws Exception {
+ verifySetSafeModeAlarm(
+ true /* safeModeEnabledByCaller */,
+ false /* safeModeConfigFlagEnabled */,
+ true /* expectingSafeModeEnabled */);
+ }
+
+ @Test
+ public void testSafeModeDisabled_configFlagEnabled() throws Exception {
+ verifySetSafeModeAlarm(
+ false /* safeModeEnabledByCaller */,
+ true /* safeModeConfigFlagEnabled */,
+ false /* expectingSafeModeEnabled */);
+ }
+
+ @Test
+ public void testSafeModeDisabled_configFlagDisabled() throws Exception {
+ verifySetSafeModeAlarm(
+ false /* safeModeEnabledByCaller */,
+ false /* safeModeConfigFlagEnabled */,
+ true /* expectingSafeModeEnabled */);
+ }
+
private Consumer<VcnNetworkAgent> setupNetworkAndGetUnwantedCallback() {
triggerChildOpened();
mTestLooper.dispatchAll();
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index 5efbf59..edced87 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -53,6 +53,7 @@
import android.net.ipsec.ike.IkeSessionCallback;
import android.net.ipsec.ike.IkeSessionConfiguration;
import android.net.ipsec.ike.IkeSessionConnectionInfo;
+import android.net.vcn.FeatureFlags;
import android.net.vcn.VcnGatewayConnectionConfig;
import android.net.vcn.VcnGatewayConnectionConfigTest;
import android.os.ParcelUuid;
@@ -165,6 +166,7 @@
@NonNull protected final Context mContext;
@NonNull protected final TestLooper mTestLooper;
@NonNull protected final VcnNetworkProvider mVcnNetworkProvider;
+ @NonNull protected final FeatureFlags mFeatureFlags;
@NonNull protected final VcnContext mVcnContext;
@NonNull protected final VcnGatewayConnectionConfig mConfig;
@NonNull protected final VcnGatewayStatusCallback mGatewayStatusCallback;
@@ -190,6 +192,7 @@
mContext = mock(Context.class);
mTestLooper = new TestLooper();
mVcnNetworkProvider = mock(VcnNetworkProvider.class);
+ mFeatureFlags = mock(FeatureFlags.class);
mVcnContext = mock(VcnContext.class);
mConfig = VcnGatewayConnectionConfigTest.buildTestConfig();
mGatewayStatusCallback = mock(VcnGatewayStatusCallback.class);
@@ -222,6 +225,7 @@
doReturn(mContext).when(mVcnContext).getContext();
doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
+ doReturn(mFeatureFlags).when(mVcnContext).getFeatureFlags();
doReturn(mUnderlyingNetworkController)
.when(mDeps)
@@ -241,8 +245,15 @@
doReturn(ELAPSED_REAL_TIME).when(mDeps).getElapsedRealTime();
}
+ protected void setUpWakeupMessage(
+ @NonNull WakeupMessage msg,
+ @NonNull String cmdName,
+ VcnGatewayConnection.Dependencies deps) {
+ doReturn(msg).when(deps).newWakeupMessage(eq(mVcnContext), any(), eq(cmdName), any());
+ }
+
private void setUpWakeupMessage(@NonNull WakeupMessage msg, @NonNull String cmdName) {
- doReturn(msg).when(mDeps).newWakeupMessage(eq(mVcnContext), any(), eq(cmdName), any());
+ setUpWakeupMessage(msg, cmdName, mDeps);
}
@Before