diff options
50 files changed, 1189 insertions, 395 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index d90b9d405fc3..8fbcfb3ef055 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -19599,6 +19599,10 @@ package android.media { field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_BIT_WIDTH; field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_CHANNEL_MASK; field @NonNull public static final android.media.AudioMetadata.Key<java.lang.String> KEY_MIME; + field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_PRESENTATION_CONTENT_CLASSIFIER; + field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_PRESENTATION_ID; + field @NonNull public static final android.media.AudioMetadata.Key<java.lang.String> KEY_PRESENTATION_LANGUAGE; + field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_PROGRAM_ID; field @NonNull public static final android.media.AudioMetadata.Key<java.lang.Integer> KEY_SAMPLE_RATE; } @@ -19652,6 +19656,15 @@ package android.media { method public boolean hasAudioDescription(); method public boolean hasDialogueEnhancement(); method public boolean hasSpokenSubtitles(); + field public static final int CONTENT_COMMENTARY = 5; // 0x5 + field public static final int CONTENT_DIALOG = 4; // 0x4 + field public static final int CONTENT_EMERGENCY = 6; // 0x6 + field public static final int CONTENT_HEARING_IMPAIRED = 3; // 0x3 + field public static final int CONTENT_MAIN = 0; // 0x0 + field public static final int CONTENT_MUSIC_AND_EFFECTS = 1; // 0x1 + field public static final int CONTENT_UNKNOWN = -1; // 0xffffffff + field public static final int CONTENT_VISUALLY_IMPAIRED = 2; // 0x2 + field public static final int CONTENT_VOICEOVER = 7; // 0x7 field public static final int MASTERED_FOR_3D = 3; // 0x3 field public static final int MASTERED_FOR_HEADPHONE = 4; // 0x4 field public static final int MASTERED_FOR_STEREO = 1; // 0x1 @@ -39635,6 +39648,7 @@ package android.telephony { field public static final int ACTIVATION_REJECT_GGSN = 30; // 0x1e field public static final int ACTIVATION_REJECT_UNSPECIFIED = 31; // 0x1f field public static final int ACTIVE_PDP_CONTEXT_MAX_NUMBER_REACHED = 65; // 0x41 + field public static final int ALL_MATCHING_RULES_FAILED = 2254; // 0x8ce field public static final int APN_DISABLED = 2045; // 0x7fd field public static final int APN_DISALLOWED_ON_ROAMING = 2059; // 0x80b field public static final int APN_MISMATCH = 2054; // 0x806 @@ -39784,6 +39798,7 @@ package android.telephony { field public static final int LTE_NAS_SERVICE_REQUEST_FAILED = 2117; // 0x845 field public static final int LTE_THROTTLING_NOT_REQUIRED = 2127; // 0x84f field public static final int MAC_FAILURE = 2183; // 0x887 + field public static final int MATCH_ALL_RULE_NOT_ALLOWED = 2253; // 0x8cd field public static final int MAXIMIUM_NSAPIS_EXCEEDED = 2157; // 0x86d field public static final int MAXINUM_SIZE_OF_L2_MESSAGE_EXCEEDED = 2166; // 0x876 field public static final int MAX_ACCESS_PROBE = 2079; // 0x81f diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 24adb7d61978..3529858a0c95 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -8,6 +8,14 @@ package android.app { } +package android.app.usage { + + public class NetworkStatsManager { + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyNetworkStatus(@NonNull java.util.List<android.net.Network>, @NonNull java.util.List<android.net.NetworkStateSnapshot>, @Nullable String, @NonNull java.util.List<android.net.UnderlyingNetworkInfo>); + } + +} + package android.net { public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 801b08e76231..35ce520e28a8 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -1493,11 +1493,18 @@ package android.bluetooth { field public static final int ACCESS_REJECTED = 2; // 0x2 field public static final int ACCESS_UNKNOWN = 0; // 0x0 field public static final String ACTION_SILENCE_MODE_CHANGED = "android.bluetooth.device.action.SILENCE_MODE_CHANGED"; + field public static final String DEVICE_TYPE_DEFAULT = "Default"; + field public static final String DEVICE_TYPE_UNTETHERED_HEADSET = "Untethered Headset"; + field public static final String DEVICE_TYPE_WATCH = "Watch"; field public static final int METADATA_COMPANION_APP = 4; // 0x4 + field public static final int METADATA_DEVICE_TYPE = 17; // 0x11 field public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; // 0x10 field public static final int METADATA_HARDWARE_VERSION = 3; // 0x3 field public static final int METADATA_IS_UNTETHERED_HEADSET = 6; // 0x6 + field public static final int METADATA_MAIN_BATTERY = 18; // 0x12 + field public static final int METADATA_MAIN_CHARGING = 19; // 0x13 field public static final int METADATA_MAIN_ICON = 5; // 0x5 + field public static final int METADATA_MAIN_LOW_BATTERY_THRESHOLD = 20; // 0x14 field public static final int METADATA_MANUFACTURER_NAME = 0; // 0x0 field public static final int METADATA_MAX_LENGTH = 2048; // 0x800 field public static final int METADATA_MODEL_NAME = 1; // 0x1 @@ -1505,12 +1512,15 @@ package android.bluetooth { field public static final int METADATA_UNTETHERED_CASE_BATTERY = 12; // 0xc field public static final int METADATA_UNTETHERED_CASE_CHARGING = 15; // 0xf field public static final int METADATA_UNTETHERED_CASE_ICON = 9; // 0x9 + field public static final int METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD = 23; // 0x17 field public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10; // 0xa field public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13; // 0xd field public static final int METADATA_UNTETHERED_LEFT_ICON = 7; // 0x7 + field public static final int METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD = 21; // 0x15 field public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11; // 0xb field public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14; // 0xe field public static final int METADATA_UNTETHERED_RIGHT_ICON = 8; // 0x8 + field public static final int METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD = 22; // 0x16 } public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile { @@ -10429,6 +10439,7 @@ package android.telephony.data { method public long getRetryDurationMillis(); method @Nullable public android.telephony.data.SliceInfo getSliceInfo(); method @Deprecated public int getSuggestedRetryTime(); + method @NonNull public java.util.List<android.telephony.data.TrafficDescriptor> getTrafficDescriptors(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataCallResponse> CREATOR; field public static final int HANDOVER_FAILURE_MODE_DO_FALLBACK = 1; // 0x1 @@ -10464,6 +10475,7 @@ package android.telephony.data { method @NonNull public android.telephony.data.DataCallResponse.Builder setRetryDurationMillis(long); method @NonNull public android.telephony.data.DataCallResponse.Builder setSliceInfo(@Nullable android.telephony.data.SliceInfo); method @Deprecated @NonNull public android.telephony.data.DataCallResponse.Builder setSuggestedRetryTime(int); + method @NonNull public android.telephony.data.DataCallResponse.Builder setTrafficDescriptors(@NonNull java.util.List<android.telephony.data.TrafficDescriptor>); } public final class DataProfile implements android.os.Parcelable { @@ -10535,7 +10547,7 @@ package android.telephony.data { method public void setDataProfile(@NonNull java.util.List<android.telephony.data.DataProfile>, boolean, @NonNull android.telephony.data.DataServiceCallback); method public void setInitialAttachApn(@NonNull android.telephony.data.DataProfile, boolean, @NonNull android.telephony.data.DataServiceCallback); method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @NonNull android.telephony.data.DataServiceCallback); - method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @IntRange(from=0, to=15) int, @Nullable android.telephony.data.SliceInfo, @NonNull android.telephony.data.DataServiceCallback); + method public void setupDataCall(int, @NonNull android.telephony.data.DataProfile, boolean, boolean, int, @Nullable android.net.LinkProperties, @IntRange(from=0, to=15) int, @Nullable android.telephony.data.SliceInfo, @Nullable android.telephony.data.TrafficDescriptor, boolean, @NonNull android.telephony.data.DataServiceCallback); method public void startHandover(int, @NonNull android.telephony.data.DataServiceCallback); } @@ -10637,6 +10649,15 @@ package android.telephony.data { method @NonNull public android.telephony.data.ThrottleStatus.Builder setTransportType(int); } + public final class TrafficDescriptor implements android.os.Parcelable { + ctor public TrafficDescriptor(@Nullable String, @Nullable String); + method public int describeContents(); + method @Nullable public String getDnn(); + method @Nullable public String getOsAppId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.TrafficDescriptor> CREATOR; + } + } package android.telephony.euicc { diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS index 1ff64dbe6d2e..e0e9b62d3809 100644 --- a/core/java/android/app/OWNERS +++ b/core/java/android/app/OWNERS @@ -73,6 +73,7 @@ per-file ClientTransactionHandler.java = file:/services/core/java/com/android/se per-file Fragment.java = file:/services/core/java/com/android/server/wm/OWNERS per-file *Task* = file:/services/core/java/com/android/server/wm/OWNERS per-file Window* = file:/services/core/java/com/android/server/wm/OWNERS +per-file ConfigurationController.java = file:/services/core/java/com/android/server/wm/OWNERS # TODO(b/174932174): determine the ownership of KeyguardManager.java diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 1d5dc1d5df1c..098d8b6c6058 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -16,6 +16,8 @@ package android.app.usage; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -28,8 +30,11 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.DataUsageRequest; import android.net.INetworkStatsService; +import android.net.Network; import android.net.NetworkStack; +import android.net.NetworkStateSnapshot; import android.net.NetworkTemplate; +import android.net.UnderlyingNetworkInfo; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; import android.os.Binder; @@ -48,6 +53,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.NetworkIdentityUtils; +import java.util.List; import java.util.Objects; /** @@ -633,6 +639,50 @@ public class NetworkStatsManager { return template; } + /** + * Notify {@code NetworkStatsService} about network status changed. + * + * Notifies NetworkStatsService of network state changes for data usage accounting purposes. + * + * To avoid races that attribute data usage to wrong network, such as new network with + * the same interface after SIM hot-swap, this function will not return until + * {@code NetworkStatsService} finishes its work of retrieving traffic statistics from + * all data sources. + * + * @param defaultNetworks the list of all networks that could be used by network traffic that + * does not explicitly select a network. + * @param networkStateSnapshots a list of {@link NetworkStateSnapshot}s, one for + * each network that is currently connected. + * @param activeIface the active (i.e., connected) default network interface for the calling + * uid. Used to determine on which network future calls to + * {@link android.net.TrafficStats#incrementOperationCount} applies to. + * @param underlyingNetworkInfos the list of underlying network information for all + * currently-connected VPNs. + * + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) + public void notifyNetworkStatus( + @NonNull List<Network> defaultNetworks, + @NonNull List<NetworkStateSnapshot> networkStateSnapshots, + @Nullable String activeIface, + @NonNull List<UnderlyingNetworkInfo> underlyingNetworkInfos) { + try { + Objects.requireNonNull(defaultNetworks); + Objects.requireNonNull(networkStateSnapshots); + Objects.requireNonNull(underlyingNetworkInfos); + // TODO: Change internal namings after the name is decided. + mService.forceUpdateIfaces(defaultNetworks.toArray(new Network[0]), + networkStateSnapshots.toArray(new NetworkStateSnapshot[0]), activeIface, + underlyingNetworkInfos.toArray(new UnderlyingNetworkInfo[0])); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + private static class CallbackHandler extends Handler { private final int mNetworkType; private final String mSubscriberId; diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 0f864a81c144..89030bcf12e0 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -354,6 +354,35 @@ public final class BluetoothDevice implements Parcelable { public static final String ACTION_SDP_RECORD = "android.bluetooth.device.action.SDP_RECORD"; + /** @hide */ + @IntDef(prefix = "METADATA_", value = { + METADATA_MANUFACTURER_NAME, + METADATA_MODEL_NAME, + METADATA_SOFTWARE_VERSION, + METADATA_HARDWARE_VERSION, + METADATA_COMPANION_APP, + METADATA_MAIN_ICON, + METADATA_IS_UNTETHERED_HEADSET, + METADATA_UNTETHERED_LEFT_ICON, + METADATA_UNTETHERED_RIGHT_ICON, + METADATA_UNTETHERED_CASE_ICON, + METADATA_UNTETHERED_LEFT_BATTERY, + METADATA_UNTETHERED_RIGHT_BATTERY, + METADATA_UNTETHERED_CASE_BATTERY, + METADATA_UNTETHERED_LEFT_CHARGING, + METADATA_UNTETHERED_RIGHT_CHARGING, + METADATA_UNTETHERED_CASE_CHARGING, + METADATA_ENHANCED_SETTINGS_UI_URI, + METADATA_DEVICE_TYPE, + METADATA_MAIN_BATTERY, + METADATA_MAIN_CHARGING, + METADATA_MAIN_LOW_BATTERY_THRESHOLD, + METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD, + METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD, + METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD}) + @Retention(RetentionPolicy.SOURCE) + public @interface MetadataKey{} + /** * Maximum length of a metadata entry, this is to avoid exploding Bluetooth * disk usage @@ -503,6 +532,89 @@ public final class BluetoothDevice implements Parcelable { public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; /** + * Type of the Bluetooth device, must be within the list of + * BluetoothDevice.DEVICE_TYPE_* + * Data type should be {@String} as {@link Byte} array. + * @hide + */ + @SystemApi + public static final int METADATA_DEVICE_TYPE = 17; + + /** + * Battery level of the Bluetooth device, use when the Bluetooth device + * does not support HFP battery indicator. + * Data type should be {@String} as {@link Byte} array. + * @hide + */ + @SystemApi + public static final int METADATA_MAIN_BATTERY = 18; + + /** + * Whether the device is charging. + * Data type should be {@String} as {@link Byte} array. + * @hide + */ + @SystemApi + public static final int METADATA_MAIN_CHARGING = 19; + + /** + * The battery threshold of the Bluetooth device to show low battery icon. + * Data type should be {@String} as {@link Byte} array. + * @hide + */ + @SystemApi + public static final int METADATA_MAIN_LOW_BATTERY_THRESHOLD = 20; + + /** + * The battery threshold of the left headset to show low battery icon. + * Data type should be {@String} as {@link Byte} array. + * @hide + */ + @SystemApi + public static final int METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD = 21; + + /** + * The battery threshold of the right headset to show low battery icon. + * Data type should be {@String} as {@link Byte} array. + * @hide + */ + @SystemApi + public static final int METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD = 22; + + /** + * The battery threshold of the case to show low battery icon. + * Data type should be {@String} as {@link Byte} array. + * @hide + */ + @SystemApi + public static final int METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD = 23; + + /** + * Device type which is used in METADATA_DEVICE_TYPE + * Indicates this Bluetooth device is a standard Bluetooth accessory or + * not listed in METADATA_DEVICE_TYPE_*. + * @hide + */ + @SystemApi + public static final String DEVICE_TYPE_DEFAULT = "Default"; + + /** + * Device type which is used in METADATA_DEVICE_TYPE + * Indicates this Bluetooth device is a watch. + * @hide + */ + @SystemApi + public static final String DEVICE_TYPE_WATCH = "Watch"; + + /** + * Device type which is used in METADATA_DEVICE_TYPE + * Indicates this Bluetooth device is an untethered headset. + * @hide + */ + @SystemApi + public static final String DEVICE_TYPE_UNTETHERED_HEADSET = "Untethered Headset"; + + /** * Broadcast Action: This intent is used to broadcast the {@link UUID} * wrapped as a {@link android.os.ParcelUuid} of the remote device after it * has been fetched. This intent is sent only when the UUIDs of the remote @@ -2258,7 +2370,7 @@ public final class BluetoothDevice implements Parcelable { */ @SystemApi @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - public boolean setMetadata(int key, @NonNull byte[] value) { + public boolean setMetadata(@MetadataKey int key, @NonNull byte[] value) { final IBluetooth service = sService; if (service == null) { Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata"); @@ -2286,7 +2398,7 @@ public final class BluetoothDevice implements Parcelable { @SystemApi @Nullable @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) - public byte[] getMetadata(int key) { + public byte[] getMetadata(@MetadataKey int key) { final IBluetooth service = sService; if (service == null) { Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata"); @@ -2299,4 +2411,14 @@ public final class BluetoothDevice implements Parcelable { return null; } } + + /** + * Get the maxinum metadata key ID. + * + * @return the last supported metadata key + * @hide + */ + public static @MetadataKey int getMaxMetadataKey() { + return METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD; + } } diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java b/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java index e3a130c4b436..4e64dbed7017 100644 --- a/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java +++ b/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java @@ -22,7 +22,7 @@ import android.os.Parcelable; /** * The {@link PeriodicAdvertisingParameters} provide a way to adjust periodic * advertising preferences for each Bluetooth LE advertising set. Use {@link - * AdvertisingSetParameters.Builder} to create an instance of this class. + * PeriodicAdvertisingParameters.Builder} to create an instance of this class. */ public final class PeriodicAdvertisingParameters implements Parcelable { diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java index ffc78f3fd942..bb4480ec61d2 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java +++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java @@ -98,6 +98,8 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { public static ForInternedStringValueMap sForInternedStringValueMap = Parcelling.Cache.getOrCreate(ForInternedStringValueMap.class); public static ForStringSet sForStringSet = Parcelling.Cache.getOrCreate(ForStringSet.class); + public static ForInternedStringSet sForInternedStringSet = + Parcelling.Cache.getOrCreate(ForInternedStringSet.class); protected static ParsedIntentInfo.StringPairListParceler sForIntentInfoPairs = Parcelling.Cache.getOrCreate(ParsedIntentInfo.StringPairListParceler.class); @@ -1033,6 +1035,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { dest.writeBoolean(this.forceQueryable); dest.writeParcelableList(this.queriesIntents, flags); sForInternedStringList.parcel(this.queriesPackages, dest, flags); + sForInternedStringSet.parcel(this.queriesProviders, dest, flags); dest.writeString(this.appComponentFactory); dest.writeString(this.backupAgentName); dest.writeInt(this.banner); @@ -1197,6 +1200,7 @@ public class ParsingPackageImpl implements ParsingPackage, Parcelable { this.forceQueryable = in.readBoolean(); this.queriesIntents = in.createTypedArrayList(Intent.CREATOR); this.queriesPackages = sForInternedStringList.unparcel(in); + this.queriesProviders = sForInternedStringSet.unparcel(in); this.appComponentFactory = in.readString(); this.backupAgentName = in.readString(); this.banner = in.readInt(); diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 8f1e2defd215..268002f1dd52 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -232,11 +232,10 @@ public final class IpSecAlgorithm implements Parcelable { ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, SDK_VERSION_ZERO); ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, SDK_VERSION_ZERO); - // STOPSHIP: b/170424293 Use Build.VERSION_CODES.S when it is defined - ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.R + 1); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.R + 1); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.R + 1); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.R + 1); + ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.S); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.S); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.S); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.S); } private static final Set<String> ENABLED_ALGOS = diff --git a/core/java/android/net/OemNetworkPreferences.java b/core/java/android/net/OemNetworkPreferences.java index b4034556f66e..48bd29769f83 100644 --- a/core/java/android/net/OemNetworkPreferences.java +++ b/core/java/android/net/OemNetworkPreferences.java @@ -29,7 +29,15 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; -/** @hide */ +/** + * Network preferences to set the default active network on a per-application basis as per a given + * {@link OemNetworkPreference}. An example of this would be to set an application's network + * preference to {@link #OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK} which would have the default + * network for that application set to an unmetered network first if available and if not, it then + * set that application's default network to an OEM managed network if available. + * + * @hide + */ @SystemApi public final class OemNetworkPreferences implements Parcelable { /** @@ -64,6 +72,10 @@ public final class OemNetworkPreferences implements Parcelable { @NonNull private final Bundle mNetworkMappings; + /** + * Return the currently built application package name to {@link OemNetworkPreference} mappings. + * @return the current network preferences map. + */ @NonNull public Map<String, Integer> getNetworkPreferences() { return convertToUnmodifiableMap(mNetworkMappings); @@ -105,6 +117,11 @@ public final class OemNetworkPreferences implements Parcelable { mNetworkMappings = new Bundle(); } + /** + * Constructor to populate the builder's values with an already built + * {@link OemNetworkPreferences}. + * @param preferences the {@link OemNetworkPreferences} to populate with. + */ public Builder(@NonNull final OemNetworkPreferences preferences) { Objects.requireNonNull(preferences); mNetworkMappings = (Bundle) preferences.mNetworkMappings.clone(); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index cfb18ad24faf..6d3b58c7db20 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -15099,30 +15099,6 @@ public final class Settings { /** * Performs a strict and comprehensive check of whether a calling package is allowed to - * change the state of network, as the condition differs for pre-M, M+, and - * privileged/preinstalled apps. The caller is expected to have either the - * CHANGE_NETWORK_STATE or the WRITE_SETTINGS permission declared. Either of these - * permissions allow changing network state; WRITE_SETTINGS is a runtime permission and - * can be revoked, but (except in M, excluding M MRs), CHANGE_NETWORK_STATE is a normal - * permission and cannot be revoked. See http://b/23597341 - * - * Note: if the check succeeds because the application holds WRITE_SETTINGS, the operation - * of this app will be updated to the current time. - * @hide - */ - public static boolean checkAndNoteChangeNetworkStateOperation(Context context, int uid, - String callingPackage, boolean throwException) { - if (context.checkCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE) - == PackageManager.PERMISSION_GRANTED) { - return true; - } - return isCallingPackageAllowedToPerformAppOpsProtectedOperation(context, uid, - callingPackage, throwException, AppOpsManager.OP_WRITE_SETTINGS, - PM_CHANGE_NETWORK_STATE, true); - } - - /** - * Performs a strict and comprehensive check of whether a calling package is allowed to * draw on top of other apps, as the conditions differs for pre-M, M+, and * privileged/preinstalled apps. If the provided uid does not match the callingPackage, * a negative result will be returned. diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index c9062d8a50bc..bcfb06b15ab8 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -304,15 +304,14 @@ static std::array<UsapTableEntry, USAP_POOL_SIZE_MAX_LIMIT> gUsapTable; static FileDescriptorTable* gOpenFdTable = nullptr; // Must match values in com.android.internal.os.Zygote. -// Note that there are gaps in the constants: -// This is to further keep the values consistent with IVold.aidl +// The values should be consistent with IVold.aidl enum MountExternalKind { MOUNT_EXTERNAL_NONE = 0, MOUNT_EXTERNAL_DEFAULT = 1, - MOUNT_EXTERNAL_INSTALLER = 5, - MOUNT_EXTERNAL_PASS_THROUGH = 7, - MOUNT_EXTERNAL_ANDROID_WRITABLE = 8, - MOUNT_EXTERNAL_COUNT = 9 + MOUNT_EXTERNAL_INSTALLER = 2, + MOUNT_EXTERNAL_PASS_THROUGH = 3, + MOUNT_EXTERNAL_ANDROID_WRITABLE = 4, + MOUNT_EXTERNAL_COUNT = 5 }; // Must match values in com.android.internal.os.Zygote. diff --git a/core/tests/coretests/src/android/app/usage/OWNERS b/core/tests/coretests/src/android/app/usage/OWNERS new file mode 100644 index 000000000000..1271fa799808 --- /dev/null +++ b/core/tests/coretests/src/android/app/usage/OWNERS @@ -0,0 +1,2 @@ +# Bug component: 532296 +include /services/usage/OWNERS diff --git a/media/java/android/media/AudioMetadata.java b/media/java/android/media/AudioMetadata.java index ff9fd4187272..ca175b4853a6 100644 --- a/media/java/android/media/AudioMetadata.java +++ b/media/java/android/media/AudioMetadata.java @@ -195,6 +195,61 @@ public final class AudioMetadata { @NonNull public static final Key<Integer> KEY_AUDIO_ENCODING = createKey("audio-encoding", Integer.class); + + /** + * A key representing the audio presentation id being decoded by a next generation + * audio decoder. + * + * An Integer value representing presentation id. + * + * @see AudioPresentation#getPresentationId() + */ + @NonNull public static final Key<Integer> KEY_PRESENTATION_ID = + createKey("presentation-id", Integer.class); + + /** + * A key representing the audio program id being decoded by a next generation + * audio decoder. + * + * An Integer value representing program id. + * + * @see AudioPresentation#getProgramId() + */ + @NonNull public static final Key<Integer> KEY_PROGRAM_ID = + createKey("program-id", Integer.class); + + + /** + * A key representing the audio presentation content classifier being rendered + * by a next generation audio decoder. + * + * An Integer value representing presentation content classifier. + * + * @see AudioPresentation.ContentClassifier + * One of {@link AudioPresentation#CONTENT_UNKNOWN}, + * {@link AudioPresentation#CONTENT_MAIN}, + * {@link AudioPresentation#CONTENT_MUSIC_AND_EFFECTS}, + * {@link AudioPresentation#CONTENT_VISUALLY_IMPAIRED}, + * {@link AudioPresentation#CONTENT_HEARING_IMPAIRED}, + * {@link AudioPresentation#CONTENT_DIALOG}, + * {@link AudioPresentation#CONTENT_COMMENTARY}, + * {@link AudioPresentation#CONTENT_EMERGENCY}, + * {@link AudioPresentation#CONTENT_VOICEOVER}. + */ + @NonNull public static final Key<Integer> KEY_PRESENTATION_CONTENT_CLASSIFIER = + createKey("presentation-content-classifier", Integer.class); + + /** + * A key representing the audio presentation language being rendered by a next + * generation audio decoder. + * + * A String value representing ISO 639-2 (three letter code). + * + * @see AudioPresentation#getLocale() + */ + @NonNull public static final Key<String> KEY_PRESENTATION_LANGUAGE = + createKey("presentation-language", String.class); + private Format() {} // delete constructor } diff --git a/media/java/android/media/AudioPresentation.java b/media/java/android/media/AudioPresentation.java index 894fbba6c983..47358be3e926 100644 --- a/media/java/android/media/AudioPresentation.java +++ b/media/java/android/media/AudioPresentation.java @@ -57,6 +57,64 @@ public final class AudioPresentation { /** @hide */ @IntDef( value = { + CONTENT_UNKNOWN, + CONTENT_MAIN, + CONTENT_MUSIC_AND_EFFECTS, + CONTENT_VISUALLY_IMPAIRED, + CONTENT_HEARING_IMPAIRED, + CONTENT_DIALOG, + CONTENT_COMMENTARY, + CONTENT_EMERGENCY, + CONTENT_VOICEOVER, + }) + + /** + * The ContentClassifier int definitions represent the AudioPresentation content + * classifier (as per TS 103 190-1 v1.2.1 4.3.3.8.1) + */ + @Retention(RetentionPolicy.SOURCE) + public @interface ContentClassifier {} + + /** + * Audio presentation classifier: Unknown. + */ + public static final int CONTENT_UNKNOWN = -1; + /** + * Audio presentation classifier: Complete main. + */ + public static final int CONTENT_MAIN = 0; + /** + * Audio presentation content classifier: Music and effects. + */ + public static final int CONTENT_MUSIC_AND_EFFECTS = 1; + /** + * Audio presentation content classifier: Visually impaired. + */ + public static final int CONTENT_VISUALLY_IMPAIRED = 2; + /** + * Audio presentation content classifier: Hearing impaired. + */ + public static final int CONTENT_HEARING_IMPAIRED = 3; + /** + * Audio presentation content classifier: Dialog. + */ + public static final int CONTENT_DIALOG = 4; + /** + * Audio presentation content classifier: Commentary. + */ + public static final int CONTENT_COMMENTARY = 5; + /** + * Audio presentation content classifier: Emergency. + */ + public static final int CONTENT_EMERGENCY = 6; + /** + * Audio presentation content classifier: Voice over. + */ + public static final int CONTENT_VOICEOVER = 7; + + /** @hide */ + @IntDef( + value = { MASTERING_NOT_INDICATED, MASTERED_FOR_STEREO, MASTERED_FOR_SURROUND, diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt index 4bfcda38260a..a8f1a4d2a7f8 100644 --- a/packages/Connectivity/framework/api/current.txt +++ b/packages/Connectivity/framework/api/current.txt @@ -302,6 +302,7 @@ package android.net { field public static final int NET_CAPABILITY_CBS = 5; // 0x5 field public static final int NET_CAPABILITY_DUN = 2; // 0x2 field public static final int NET_CAPABILITY_EIMS = 10; // 0xa + field public static final int NET_CAPABILITY_ENTERPRISE = 29; // 0x1d field public static final int NET_CAPABILITY_FOREGROUND = 19; // 0x13 field public static final int NET_CAPABILITY_FOTA = 3; // 0x3 field public static final int NET_CAPABILITY_IA = 7; // 0x7 diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java index 6273f4bb577b..66e7da43cb66 100644 --- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java +++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java @@ -2245,31 +2245,6 @@ public class ConnectivityManager { } } - /* TODO: These permissions checks don't belong in client-side code. Move them to - * services.jar, possibly in com.android.server.net. */ - - /** {@hide} */ - public static final void enforceChangePermission(Context context, - String callingPkg, String callingAttributionTag) { - int uid = Binder.getCallingUid(); - checkAndNoteChangeNetworkStateOperation(context, uid, callingPkg, - callingAttributionTag, true /* throwException */); - } - - /** - * Check if the package is a allowed to change the network state. This also accounts that such - * an access happened. - * - * @return {@code true} iff the package is allowed to change the network state. - */ - // TODO: Remove method and replace with direct call once R code is pushed to AOSP - private static boolean checkAndNoteChangeNetworkStateOperation(@NonNull Context context, - int uid, @NonNull String callingPackage, @Nullable String callingAttributionTag, - boolean throwException) { - return Settings.checkAndNoteChangeNetworkStateOperation(context, uid, callingPackage, - throwException); - } - /** * Check if the package is a allowed to write settings. This also accounts that such an access * happened. diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java index 26d14cbfaa95..cd76f409b093 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java +++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java @@ -205,6 +205,7 @@ public final class NetworkCapabilities implements Parcelable { NET_CAPABILITY_OEM_PRIVATE, NET_CAPABILITY_VEHICLE_INTERNAL, NET_CAPABILITY_NOT_VCN_MANAGED, + NET_CAPABILITY_ENTERPRISE, }) public @interface NetCapability { } @@ -415,8 +416,17 @@ public final class NetworkCapabilities implements Parcelable { @SystemApi public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; + /** + * Indicates that this network is intended for enterprise use. + * <p> + * 5G URSP rules may indicate that all data should use a connection dedicated for enterprise + * use. If the enterprise capability is requested, all enterprise traffic will be routed over + * the connection with this capability. + */ + public static final int NET_CAPABILITY_ENTERPRISE = 29; + private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; - private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_VCN_MANAGED; + private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_ENTERPRISE; /** * Network capabilities that are expected to be mutable, i.e., can change while a particular @@ -474,7 +484,8 @@ public final class NetworkCapabilities implements Parcelable { | (1 << NET_CAPABILITY_MCX) | (1 << NET_CAPABILITY_RCS) | (1 << NET_CAPABILITY_VEHICLE_INTERNAL) - | (1 << NET_CAPABILITY_XCAP); + | (1 << NET_CAPABILITY_XCAP) + | (1 << NET_CAPABILITY_ENTERPRISE); /** * Capabilities that force network to be restricted. @@ -2028,8 +2039,9 @@ public final class NetworkCapabilities implements Parcelable { case NET_CAPABILITY_PARTIAL_CONNECTIVITY: return "PARTIAL_CONNECTIVITY"; case NET_CAPABILITY_TEMPORARILY_NOT_METERED: return "TEMPORARILY_NOT_METERED"; case NET_CAPABILITY_OEM_PRIVATE: return "OEM_PRIVATE"; - case NET_CAPABILITY_VEHICLE_INTERNAL: return "NET_CAPABILITY_VEHICLE_INTERNAL"; + case NET_CAPABILITY_VEHICLE_INTERNAL: return "VEHICLE_INTERNAL"; case NET_CAPABILITY_NOT_VCN_MANAGED: return "NOT_VCN_MANAGED"; + case NET_CAPABILITY_ENTERPRISE: return "ENTERPRISE"; default: return Integer.toString(capability); } } diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java index 7f19662c6961..c1dca5df1b2f 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java @@ -394,16 +394,20 @@ public class DynamicSystemInstallationService extends Service } private void executeNotifyIfInUseCommand() { - int status = getStatus(); - - if (status == STATUS_IN_USE) { - startForeground(NOTIFICATION_ID, - buildNotification(STATUS_IN_USE, CAUSE_NOT_SPECIFIED)); - } else if (status == STATUS_READY) { - startForeground(NOTIFICATION_ID, - buildNotification(STATUS_READY, CAUSE_NOT_SPECIFIED)); - } else { - stopSelf(); + switch (getStatus()) { + case STATUS_IN_USE: + startForeground(NOTIFICATION_ID, + buildNotification(STATUS_IN_USE, CAUSE_NOT_SPECIFIED)); + break; + case STATUS_READY: + startForeground(NOTIFICATION_ID, + buildNotification(STATUS_READY, CAUSE_NOT_SPECIFIED)); + break; + case STATUS_IN_PROGRESS: + break; + case STATUS_NOT_STARTED: + default: + stopSelf(); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java index 3cbf2685af26..ad459a4c3b93 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -23,6 +23,7 @@ import android.graphics.drawable.Drawable; import android.location.LocationManager; import android.media.AudioManager; import android.net.ConnectivityManager; +import android.net.TetheringManager; import android.os.BatteryManager; import android.os.SystemProperties; import android.os.UserHandle; @@ -86,10 +87,10 @@ public class Utils { * Return string resource that best describes combination of tethering * options available on this device. */ - public static int getTetheringLabel(ConnectivityManager cm) { - String[] usbRegexs = cm.getTetherableUsbRegexs(); - String[] wifiRegexs = cm.getTetherableWifiRegexs(); - String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs(); + public static int getTetheringLabel(TetheringManager tm) { + String[] usbRegexs = tm.getTetherableUsbRegexs(); + String[] wifiRegexs = tm.getTetherableWifiRegexs(); + String[] bluetoothRegexs = tm.getTetherableBluetoothRegexs(); boolean usbAvailable = usbRegexs.length != 0; boolean wifiAvailable = wifiRegexs.length != 0; diff --git a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java index dad82ee61e08..02326ea85ff6 100644 --- a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java +++ b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java @@ -26,7 +26,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.drawable.Drawable; -import android.net.ConnectivityManager; +import android.net.TetheringManager; import android.net.TrafficStats; import android.os.Process; import android.os.RemoteException; @@ -123,9 +123,8 @@ public class UidDetailProvider { detail.icon = pm.getDefaultActivityIcon(); return detail; case TrafficStats.UID_TETHERING: - final ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService( - Context.CONNECTIVITY_SERVICE); - detail.label = res.getString(Utils.getTetheringLabel(cm)); + final TetheringManager tm = mContext.getSystemService(TetheringManager.class); + detail.label = res.getString(Utils.getTetheringLabel(tm)); detail.icon = pm.getDefaultActivityIcon(); return detail; case Process.OTA_UPDATE_UID: diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 82d606579e4d..986e2acf6029 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -142,10 +142,13 @@ import android.net.UnderlyingNetworkInfo; import android.net.Uri; import android.net.VpnManager; import android.net.VpnTransportInfo; -import android.net.metrics.INetdEventListener; import android.net.metrics.IpConnectivityLog; import android.net.metrics.NetworkEvent; import android.net.netlink.InetDiagMessage; +import android.net.resolv.aidl.DnsHealthEventParcel; +import android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener; +import android.net.resolv.aidl.Nat64PrefixEventParcel; +import android.net.resolv.aidl.PrivateDnsValidationEventParcel; import android.net.shared.PrivateDnsConfig; import android.net.util.MultinetworkPolicyTracker; import android.net.util.NetdService; @@ -1400,7 +1403,7 @@ public class ConnectivityService extends IConnectivityManager.Stub return null; } - private NetworkState getUnfilteredActiveNetworkState(int uid) { + private NetworkAgentInfo getNetworkAgentInfoForUid(int uid) { NetworkAgentInfo nai = getDefaultNetworkForUid(uid); final Network[] networks = getVpnUnderlyingNetworks(uid); @@ -1416,12 +1419,7 @@ public class ConnectivityService extends IConnectivityManager.Stub nai = null; } } - - if (nai != null) { - return nai.getNetworkState(); - } else { - return NetworkState.EMPTY; - } + return nai; } /** @@ -1474,24 +1472,28 @@ public class ConnectivityService extends IConnectivityManager.Stub "%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId())); } - private void filterNetworkInfo(@NonNull NetworkInfo networkInfo, - @NonNull NetworkCapabilities nc, int uid, boolean ignoreBlocked) { - if (isNetworkWithCapabilitiesBlocked(nc, uid, ignoreBlocked)) { - networkInfo.setDetailedState(DetailedState.BLOCKED, null, null); - } - networkInfo.setDetailedState( - getLegacyLockdownState(networkInfo.getDetailedState()), - "" /* reason */, null /* extraInfo */); - } - /** - * Apply any relevant filters to {@link NetworkState} for the given UID. For + * Apply any relevant filters to the specified {@link NetworkInfo} for the given UID. For * example, this may mark the network as {@link DetailedState#BLOCKED} based * on {@link #isNetworkWithCapabilitiesBlocked}. */ - private void filterNetworkStateForUid(NetworkState state, int uid, boolean ignoreBlocked) { - if (state == null || state.networkInfo == null || state.linkProperties == null) return; - filterNetworkInfo(state.networkInfo, state.networkCapabilities, uid, ignoreBlocked); + @NonNull + private NetworkInfo filterNetworkInfo(@NonNull NetworkInfo networkInfo, int type, + @NonNull NetworkCapabilities nc, int uid, boolean ignoreBlocked) { + NetworkInfo filtered = new NetworkInfo(networkInfo); + filtered.setType(type); + final DetailedState state = isNetworkWithCapabilitiesBlocked(nc, uid, ignoreBlocked) + ? DetailedState.BLOCKED + : filtered.getDetailedState(); + filtered.setDetailedState(getLegacyLockdownState(state), + "" /* reason */, null /* extraInfo */); + return filtered; + } + + private NetworkInfo getFilteredNetworkInfo(NetworkAgentInfo nai, int uid, + boolean ignoreBlocked) { + return filterNetworkInfo(nai.networkInfo, nai.networkInfo.getType(), + nai.networkCapabilities, uid, ignoreBlocked); } /** @@ -1505,10 +1507,11 @@ public class ConnectivityService extends IConnectivityManager.Stub public NetworkInfo getActiveNetworkInfo() { enforceAccessPermission(); final int uid = mDeps.getCallingUid(); - final NetworkState state = getUnfilteredActiveNetworkState(uid); - filterNetworkStateForUid(state, uid, false); - maybeLogBlockedNetworkInfo(state.networkInfo, uid); - return state.networkInfo; + final NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid); + if (nai == null) return null; + final NetworkInfo networkInfo = getFilteredNetworkInfo(nai, uid, false); + maybeLogBlockedNetworkInfo(networkInfo, uid); + return networkInfo; } @Override @@ -1543,30 +1546,37 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) { PermissionUtils.enforceNetworkStackPermission(mContext); - final NetworkState state = getUnfilteredActiveNetworkState(uid); - filterNetworkStateForUid(state, uid, ignoreBlocked); - return state.networkInfo; + final NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid); + if (nai == null) return null; + return getFilteredNetworkInfo(nai, uid, ignoreBlocked); + } + + /** Returns a NetworkInfo object for a network that doesn't exist. */ + private NetworkInfo makeFakeNetworkInfo(int networkType, int uid) { + final NetworkInfo info = new NetworkInfo(networkType, 0 /* subtype */, + getNetworkTypeName(networkType), "" /* subtypeName */); + info.setIsAvailable(true); + // For compatibility with legacy code, return BLOCKED instead of DISCONNECTED when + // background data is restricted. + final NetworkCapabilities nc = new NetworkCapabilities(); // Metered. + final DetailedState state = isNetworkWithCapabilitiesBlocked(nc, uid, false) + ? DetailedState.BLOCKED + : DetailedState.DISCONNECTED; + info.setDetailedState(getLegacyLockdownState(state), + "" /* reason */, null /* extraInfo */); + return info; } - private NetworkInfo getFilteredNetworkInfo(int networkType, int uid) { + private NetworkInfo getFilteredNetworkInfoForType(int networkType, int uid) { if (!mLegacyTypeTracker.isTypeSupported(networkType)) { return null; } final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType); - final NetworkInfo info; - final NetworkCapabilities nc; - if (nai != null) { - info = new NetworkInfo(nai.networkInfo); - info.setType(networkType); - nc = nai.networkCapabilities; - } else { - info = new NetworkInfo(networkType, 0, getNetworkTypeName(networkType), ""); - info.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null); - info.setIsAvailable(true); - nc = new NetworkCapabilities(); + if (nai == null) { + return makeFakeNetworkInfo(networkType, uid); } - filterNetworkInfo(info, nc, uid, false); - return info; + return filterNetworkInfo(nai.networkInfo, networkType, nai.networkCapabilities, uid, + false); } @Override @@ -1576,27 +1586,23 @@ public class ConnectivityService extends IConnectivityManager.Stub if (getVpnUnderlyingNetworks(uid) != null) { // A VPN is active, so we may need to return one of its underlying networks. This // information is not available in LegacyTypeTracker, so we have to get it from - // getUnfilteredActiveNetworkState. - final NetworkState state = getUnfilteredActiveNetworkState(uid); - if (state.networkInfo != null && state.networkInfo.getType() == networkType) { - filterNetworkStateForUid(state, uid, false); - return state.networkInfo; + // getNetworkAgentInfoForUid. + final NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid); + if (nai == null) return null; + final NetworkInfo networkInfo = getFilteredNetworkInfo(nai, uid, false); + if (networkInfo.getType() == networkType) { + return networkInfo; } } - return getFilteredNetworkInfo(networkType, uid); + return getFilteredNetworkInfoForType(networkType, uid); } @Override public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignoreBlocked) { enforceAccessPermission(); final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); - if (nai != null) { - final NetworkState state = nai.getNetworkState(); - filterNetworkStateForUid(state, uid, ignoreBlocked); - return state.networkInfo; - } else { - return null; - } + if (nai == null) return null; + return getFilteredNetworkInfo(nai, uid, ignoreBlocked); } @Override @@ -1624,10 +1630,10 @@ public class ConnectivityService extends IConnectivityManager.Stub return null; } final int uid = mDeps.getCallingUid(); - if (!isNetworkWithCapabilitiesBlocked(nai.networkCapabilities, uid, false)) { - return nai.network; + if (isNetworkWithCapabilitiesBlocked(nai.networkCapabilities, uid, false)) { + return null; } - return null; + return nai.network; } @Override @@ -1716,9 +1722,9 @@ public class ConnectivityService extends IConnectivityManager.Stub public LinkProperties getActiveLinkProperties() { enforceAccessPermission(); final int uid = mDeps.getCallingUid(); - NetworkState state = getUnfilteredActiveNetworkState(uid); - if (state.linkProperties == null) return null; - return linkPropertiesRestrictedForCallerPermissions(state.linkProperties, + NetworkAgentInfo nai = getNetworkAgentInfoForUid(uid); + if (nai == null) return null; + return linkPropertiesRestrictedForCallerPermissions(nai.linkProperties, Binder.getCallingPid(), uid); } @@ -2037,25 +2043,24 @@ public class ConnectivityService extends IConnectivityManager.Stub return true; } - private class NetdEventCallback extends INetdEventListener.Stub { + class DnsResolverUnsolicitedEventCallback extends + IDnsResolverUnsolicitedEventListener.Stub { @Override - public void onPrivateDnsValidationEvent(int netId, String ipAddress, - String hostname, boolean validated) { + public void onPrivateDnsValidationEvent(final PrivateDnsValidationEventParcel event) { try { mHandler.sendMessage(mHandler.obtainMessage( EVENT_PRIVATE_DNS_VALIDATION_UPDATE, - new PrivateDnsValidationUpdate(netId, - InetAddresses.parseNumericAddress(ipAddress), - hostname, validated))); + new PrivateDnsValidationUpdate(event.netId, + InetAddresses.parseNumericAddress(event.ipAddress), + event.hostname, event.validation))); } catch (IllegalArgumentException e) { loge("Error parsing ip address in validation event"); } } @Override - public void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs, - String hostname, String[] ipAddresses, int ipAddressesCount, int uid) { - NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId); + public void onDnsHealthEvent(final DnsHealthEventParcel event) { + NetworkAgentInfo nai = getNetworkAgentInfoForNetId(event.netId); // Netd event only allow registrants from system. Each NetworkMonitor thread is under // the caller thread of registerNetworkAgent. Thus, it's not allowed to register netd // event callback for certain nai. e.g. cellular. Register here to pass to @@ -2064,34 +2069,18 @@ public class ConnectivityService extends IConnectivityManager.Stub // callback from each caller type. Need to re-factor NetdEventListenerService to allow // multiple NetworkMonitor registrants. if (nai != null && nai.satisfies(mDefaultRequest.mRequests.get(0))) { - nai.networkMonitor().notifyDnsResponse(returnCode); + nai.networkMonitor().notifyDnsResponse(event.healthResult); } } @Override - public void onNat64PrefixEvent(int netId, boolean added, - String prefixString, int prefixLength) { - mHandler.post(() -> handleNat64PrefixEvent(netId, added, prefixString, prefixLength)); - } - - @Override - public void onConnectEvent(int netId, int error, int latencyMs, String ipAddr, int port, - int uid) { - } - - @Override - public void onWakeupEvent(String prefix, int uid, int ethertype, int ipNextHeader, - byte[] dstHw, String srcIp, String dstIp, int srcPort, int dstPort, - long timestampNs) { + public void onNat64PrefixEvent(final Nat64PrefixEventParcel event) { + mHandler.post(() -> handleNat64PrefixEvent(event.netId, event.prefixOperation, + event.prefixAddress, event.prefixLength)); } @Override - public void onTcpSocketStatsEvent(int[] networkIds, int[] sentPackets, int[] lostPackets, - int[] rttsUs, int[] sentAckDiffsMs) { - } - - @Override - public int getInterfaceVersion() throws RemoteException { + public int getInterfaceVersion() { return this.VERSION; } @@ -2099,16 +2088,17 @@ public class ConnectivityService extends IConnectivityManager.Stub public String getInterfaceHash() { return this.HASH; } - }; + } @VisibleForTesting - protected final INetdEventListener mNetdEventCallback = new NetdEventCallback(); + protected final DnsResolverUnsolicitedEventCallback mResolverUnsolEventCallback = + new DnsResolverUnsolicitedEventCallback(); - private void registerNetdEventCallback() { + private void registerDnsResolverUnsolicitedEventListener() { try { - mDnsResolver.registerEventListener(mNetdEventCallback); + mDnsResolver.registerUnsolicitedEventListener(mResolverUnsolEventCallback); } catch (Exception e) { - loge("Error registering DnsResolver callback: " + e); + loge("Error registering DnsResolver unsolicited event callback: " + e); } } @@ -2198,8 +2188,45 @@ public class ConnectivityService extends IConnectivityManager.Stub "ConnectivityService"); } + /** + * Performs a strict and comprehensive check of whether a calling package is allowed to + * change the state of network, as the condition differs for pre-M, M+, and + * privileged/preinstalled apps. The caller is expected to have either the + * CHANGE_NETWORK_STATE or the WRITE_SETTINGS permission declared. Either of these + * permissions allow changing network state; WRITE_SETTINGS is a runtime permission and + * can be revoked, but (except in M, excluding M MRs), CHANGE_NETWORK_STATE is a normal + * permission and cannot be revoked. See http://b/23597341 + * + * Note: if the check succeeds because the application holds WRITE_SETTINGS, the operation + * of this app will be updated to the current time. + */ private void enforceChangePermission(String callingPkg, String callingAttributionTag) { - ConnectivityManager.enforceChangePermission(mContext, callingPkg, callingAttributionTag); + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE) + == PackageManager.PERMISSION_GRANTED) { + return; + } + + if (callingPkg == null) { + throw new SecurityException("Calling package name is null."); + } + + final AppOpsManager appOpsMgr = mContext.getSystemService(AppOpsManager.class); + final int uid = mDeps.getCallingUid(); + final int mode = appOpsMgr.noteOpNoThrow(AppOpsManager.OPSTR_WRITE_SETTINGS, uid, + callingPkg, callingAttributionTag, null /* message */); + + if (mode == AppOpsManager.MODE_ALLOWED) { + return; + } + + if ((mode == AppOpsManager.MODE_DEFAULT) && (mContext.checkCallingOrSelfPermission( + android.Manifest.permission.WRITE_SETTINGS) == PackageManager.PERMISSION_GRANTED)) { + return; + } + + throw new SecurityException(callingPkg + " was not granted either of these permissions:" + + android.Manifest.permission.CHANGE_NETWORK_STATE + "," + + android.Manifest.permission.WRITE_SETTINGS + "."); } private void enforceSettingsPermission() { @@ -2402,7 +2429,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // to ensure the tracking will be initialized correctly. mPermissionMonitor.startMonitoring(); mProxyTracker.loadGlobalProxy(); - registerNetdEventCallback(); + registerDnsResolverUnsolicitedEventListener(); synchronized (this) { mSystemReady = true; @@ -3043,9 +3070,6 @@ public class ConnectivityService extends IConnectivityManager.Stub log(nai.toShortString() + " validation " + (valid ? "passed" : "failed") + logMsg); } if (valid != nai.lastValidated) { - if (wasDefault) { - mMetricsLog.logDefaultNetworkValidity(valid); - } final int oldScore = nai.getCurrentScore(); nai.lastValidated = valid; nai.everValidated |= valid; @@ -3333,21 +3357,21 @@ public class ConnectivityService extends IConnectivityManager.Stub handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties)); } - private void handleNat64PrefixEvent(int netId, boolean added, String prefixString, + private void handleNat64PrefixEvent(int netId, int operation, String prefixAddress, int prefixLength) { NetworkAgentInfo nai = mNetworkForNetId.get(netId); if (nai == null) return; - log(String.format("NAT64 prefix %s on netId %d: %s/%d", - (added ? "added" : "removed"), netId, prefixString, prefixLength)); + log(String.format("NAT64 prefix changed on netId %d: operation=%d, %s/%d", + netId, operation, prefixAddress, prefixLength)); IpPrefix prefix = null; - if (added) { + if (operation == IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED) { try { - prefix = new IpPrefix(InetAddresses.parseNumericAddress(prefixString), + prefix = new IpPrefix(InetAddresses.parseNumericAddress(prefixAddress), prefixLength); } catch (IllegalArgumentException e) { - loge("Invalid NAT64 prefix " + prefixString + "/" + prefixLength); + loge("Invalid NAT64 prefix " + prefixAddress + "/" + prefixLength); return; } } @@ -3466,14 +3490,6 @@ public class ConnectivityService extends IConnectivityManager.Stub final boolean wasDefault = isDefaultNetwork(nai); if (wasDefault) { mDefaultInetConditionPublished = 0; - // Log default network disconnection before required book-keeping. - // Let rematchAllNetworksAndRequests() below record a new default network event - // if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence - // whose timestamps tell how long it takes to recover a default network. - long now = SystemClock.elapsedRealtime(); - mMetricsLog.logDefaultNetworkEvent(null, 0, false, - null /* lp */, null /* nc */, nai.network, nai.getCurrentScore(), - nai.linkProperties, nai.networkCapabilities); } notifyIfacesChangedForNetworkStats(); // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied @@ -7109,27 +7125,6 @@ public class ConnectivityService extends IConnectivityManager.Stub updateTcpBufferSizes(null != newDefaultNetwork ? newDefaultNetwork.linkProperties.getTcpBufferSizes() : null); notifyIfacesChangedForNetworkStats(); - - // Log 0 -> X and Y -> X default network transitions, where X is the new default. - final Network network = (newDefaultNetwork != null) ? newDefaultNetwork.network : null; - final int score = (newDefaultNetwork != null) ? newDefaultNetwork.getCurrentScore() : 0; - final boolean validated = newDefaultNetwork != null && newDefaultNetwork.lastValidated; - final LinkProperties lp = (newDefaultNetwork != null) - ? newDefaultNetwork.linkProperties : null; - final NetworkCapabilities nc = (newDefaultNetwork != null) - ? newDefaultNetwork.networkCapabilities : null; - - final Network prevNetwork = (oldDefaultNetwork != null) - ? oldDefaultNetwork.network : null; - final int prevScore = (oldDefaultNetwork != null) - ? oldDefaultNetwork.getCurrentScore() : 0; - final LinkProperties prevLp = (oldDefaultNetwork != null) - ? oldDefaultNetwork.linkProperties : null; - final NetworkCapabilities prevNc = (oldDefaultNetwork != null) - ? oldDefaultNetwork.networkCapabilities : null; - - mMetricsLog.logDefaultNetworkEvent(network, score, validated, lp, nc, - prevNetwork, prevScore, prevLp, prevNc); } private void makeDefaultForApps(@NonNull final NetworkRequestInfo nri, diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java index 43d9ade67a11..4f6b5301e56f 100644 --- a/services/core/java/com/android/server/connectivity/DnsManager.java +++ b/services/core/java/com/android/server/connectivity/DnsManager.java @@ -19,6 +19,8 @@ package com.android.server.connectivity; import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE_FALLBACK; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; +import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE; +import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS; import static android.provider.Settings.Global.DNS_RESOLVER_MAX_SAMPLES; import static android.provider.Settings.Global.DNS_RESOLVER_MIN_SAMPLES; import static android.provider.Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS; @@ -147,17 +149,18 @@ public class DnsManager { } public static class PrivateDnsValidationUpdate { - final public int netId; - final public InetAddress ipAddress; - final public String hostname; - final public boolean validated; + public final int netId; + public final InetAddress ipAddress; + public final String hostname; + // Refer to IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_*. + public final int validationResult; public PrivateDnsValidationUpdate(int netId, InetAddress ipAddress, - String hostname, boolean validated) { + String hostname, int validationResult) { this.netId = netId; this.ipAddress = ipAddress; this.hostname = hostname; - this.validated = validated; + this.validationResult = validationResult; } } @@ -216,10 +219,13 @@ public class DnsManager { if (!mValidationMap.containsKey(p)) { return; } - if (update.validated) { + if (update.validationResult == VALIDATION_RESULT_SUCCESS) { mValidationMap.put(p, ValidationStatus.SUCCEEDED); - } else { + } else if (update.validationResult == VALIDATION_RESULT_FAILURE) { mValidationMap.put(p, ValidationStatus.FAILED); + } else { + Log.e(TAG, "Unknown private dns validation operation=" + + update.validationResult); } } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 3a5e10ed951a..ebf1fe9d7cd0 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -379,6 +379,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { case MSG_UPDATE_IFACES: { // If no cached states, ignore. if (mLastNetworkStateSnapshots == null) break; + // TODO (b/181642673): Protect mDefaultNetworks from concurrent accessing. updateIfaces(mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface); break; } @@ -1266,7 +1267,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * they are combined under a single {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") - private void updateIfacesLocked(@Nullable Network[] defaultNetworks, + private void updateIfacesLocked(@NonNull Network[] defaultNetworks, @NonNull NetworkStateSnapshot[] snapshots) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -1282,10 +1283,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Rebuild active interfaces based on connected networks mActiveIfaces.clear(); mActiveUidIfaces.clear(); - if (defaultNetworks != null) { - // Caller is ConnectivityService. Update the list of default networks. - mDefaultNetworks = defaultNetworks; - } + // Update the list of default networks. + mDefaultNetworks = defaultNetworks; mLastNetworkStateSnapshots = snapshots; diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java index b6ddd93af3b8..b2db9f5af07e 100644 --- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -65,7 +65,7 @@ public class UnderlyingNetworkTracker { @NonNull private final NetworkCallback mRouteSelectionCallback = new RouteSelectionCallback(); @NonNull private TelephonySubscriptionSnapshot mLastSnapshot; - private boolean mIsRunning = true; + private boolean mIsQuitting = false; @Nullable private UnderlyingNetworkRecord mCurrentRecord; @Nullable private UnderlyingNetworkRecord.Builder mRecordInProgress; @@ -151,7 +151,7 @@ public class UnderlyingNetworkTracker { mVcnContext.ensureRunningOnLooperThread(); // Don't bother re-filing NetworkRequests if this Tracker has been torn down. - if (!mIsRunning) { + if (mIsQuitting) { return; } @@ -205,7 +205,7 @@ public class UnderlyingNetworkTracker { } mCellBringupCallbacks.clear(); - mIsRunning = false; + mIsQuitting = true; } /** Returns whether the currently selected Network matches the given network. */ diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java index 6ad30b544257..9d39c67d27fb 100644 --- a/services/core/java/com/android/server/vcn/Vcn.java +++ b/services/core/java/com/android/server/vcn/Vcn.java @@ -16,6 +16,8 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; + import static com.android.server.VcnManagementService.VDBG; import android.annotation.NonNull; @@ -84,6 +86,13 @@ public class Vcn extends Handler { */ private static final int MSG_EVENT_SUBSCRIPTIONS_CHANGED = MSG_EVENT_BASE + 2; + /** + * A GatewayConnection owned by this VCN quit. + * + * @param obj VcnGatewayConnectionConfig + */ + private static final int MSG_EVENT_GATEWAY_CONNECTION_QUIT = MSG_EVENT_BASE + 3; + /** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */ private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE; @@ -208,6 +217,9 @@ public class Vcn extends Handler { case MSG_EVENT_SUBSCRIPTIONS_CHANGED: handleSubscriptionsChanged((TelephonySubscriptionSnapshot) msg.obj); break; + case MSG_EVENT_GATEWAY_CONNECTION_QUIT: + handleGatewayConnectionQuit((VcnGatewayConnectionConfig) msg.obj); + break; case MSG_CMD_TEARDOWN: handleTeardown(); break; @@ -263,7 +275,7 @@ public class Vcn extends Handler { // If preexisting VcnGatewayConnection(s) satisfy request, return for (VcnGatewayConnectionConfig gatewayConnectionConfig : mVcnGatewayConnections.keySet()) { - if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { + if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { if (VDBG) { Slog.v( getLogTag(), @@ -278,7 +290,7 @@ public class Vcn extends Handler { // up for (VcnGatewayConnectionConfig gatewayConnectionConfig : mConfig.getGatewayConnectionConfigs()) { - if (requestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { + if (isRequestSatisfiedByGatewayConnectionConfig(request, gatewayConnectionConfig)) { Slog.v( getLogTag(), "Bringing up new VcnGatewayConnection for request " + request.requestId); @@ -289,12 +301,21 @@ public class Vcn extends Handler { mSubscriptionGroup, mLastSnapshot, gatewayConnectionConfig, - new VcnGatewayStatusCallbackImpl()); + new VcnGatewayStatusCallbackImpl(gatewayConnectionConfig)); mVcnGatewayConnections.put(gatewayConnectionConfig, vcnGatewayConnection); } } } + private void handleGatewayConnectionQuit(VcnGatewayConnectionConfig config) { + Slog.v(getLogTag(), "VcnGatewayConnection quit: " + config); + mVcnGatewayConnections.remove(config); + + // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied + // start a new GatewayConnection) + mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); + } + private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) { mLastSnapshot = snapshot; @@ -305,9 +326,10 @@ public class Vcn extends Handler { } } - private boolean requestSatisfiedByGatewayConnectionConfig( + private boolean isRequestSatisfiedByGatewayConnectionConfig( @NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) { final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(); + builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); for (int cap : config.getAllExposedCapabilities()) { builder.addCapability(cap); } @@ -339,9 +361,23 @@ public class Vcn extends Handler { @VcnErrorCode int errorCode, @Nullable String exceptionClass, @Nullable String exceptionMessage); + + /** Called by a VcnGatewayConnection to indicate that it has fully torn down. */ + void onQuit(); } private class VcnGatewayStatusCallbackImpl implements VcnGatewayStatusCallback { + public final VcnGatewayConnectionConfig mGatewayConnectionConfig; + + VcnGatewayStatusCallbackImpl(VcnGatewayConnectionConfig gatewayConnectionConfig) { + mGatewayConnectionConfig = gatewayConnectionConfig; + } + + @Override + public void onQuit() { + sendMessage(obtainMessage(MSG_EVENT_GATEWAY_CONNECTION_QUIT, mGatewayConnectionConfig)); + } + @Override public void onEnteredSafeMode() { sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE)); diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 06748a3aa2d1..6bc9978a0731 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -168,6 +168,8 @@ public class VcnGatewayConnection extends StateMachine { private static final String DISCONNECT_REASON_INTERNAL_ERROR = "Uncaught exception: "; private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST = "Underlying Network lost"; + private static final String DISCONNECT_REASON_NETWORK_AGENT_UNWANTED = + "NetworkAgent was unwanted"; private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel"; private static final int TOKEN_ALL = Integer.MIN_VALUE; @@ -379,13 +381,16 @@ public class VcnGatewayConnection extends StateMachine { /** The reason why the disconnect was requested. */ @NonNull public final String reason; - EventDisconnectRequestedInfo(@NonNull String reason) { + public final boolean shouldQuit; + + EventDisconnectRequestedInfo(@NonNull String reason, boolean shouldQuit) { this.reason = Objects.requireNonNull(reason); + this.shouldQuit = shouldQuit; } @Override public int hashCode() { - return Objects.hash(reason); + return Objects.hash(reason, shouldQuit); } @Override @@ -395,7 +400,7 @@ public class VcnGatewayConnection extends StateMachine { } final EventDisconnectRequestedInfo rhs = (EventDisconnectRequestedInfo) other; - return reason.equals(rhs.reason); + return reason.equals(rhs.reason) && shouldQuit == rhs.shouldQuit; } } @@ -488,8 +493,14 @@ public class VcnGatewayConnection extends StateMachine { */ @NonNull private final VcnWakeLock mWakeLock; - /** Running state of this VcnGatewayConnection. */ - private boolean mIsRunning = true; + /** + * Whether the VcnGatewayConnection is in the process of irreversibly quitting. + * + * <p>This variable is false for the lifecycle of the VcnGatewayConnection, until a command to + * teardown has been received. This may be flipped due to events such as the Network becoming + * unwanted, the owning VCN entering safe mode, or an irrecoverable internal failure. + */ + private boolean mIsQuitting = false; /** * The token used by the primary/current/active session. @@ -622,10 +633,8 @@ public class VcnGatewayConnection extends StateMachine { * <p>Once torn down, this VcnTunnel CANNOT be started again. */ public void teardownAsynchronously() { - sendMessageAndAcquireWakeLock( - EVENT_DISCONNECT_REQUESTED, - TOKEN_ALL, - new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN)); + sendDisconnectRequestedAndAcquireWakelock( + DISCONNECT_REASON_TEARDOWN, true /* shouldQuit */); // TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this // is also called asynchronously when a NetworkAgent becomes unwanted @@ -646,6 +655,8 @@ public class VcnGatewayConnection extends StateMachine { cancelSafeModeAlarm(); mUnderlyingNetworkTracker.teardown(); + + mGatewayStatusCallback.onQuit(); } /** @@ -693,7 +704,7 @@ public class VcnGatewayConnection extends StateMachine { private void acquireWakeLock() { mVcnContext.ensureRunningOnLooperThread(); - if (mIsRunning) { + if (!mIsQuitting) { mWakeLock.acquire(); } } @@ -892,7 +903,7 @@ public class VcnGatewayConnection extends StateMachine { TOKEN_ALL, 0 /* arg2 */, new EventDisconnectRequestedInfo( - DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); + DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */)); mDisconnectRequestAlarm = createScheduledAlarm( DISCONNECT_REQUEST_ALARM, @@ -909,7 +920,8 @@ public class VcnGatewayConnection extends StateMachine { // Cancel any existing disconnect due to previous loss of underlying network removeEqualMessages( EVENT_DISCONNECT_REQUESTED, - new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); + new EventDisconnectRequestedInfo( + DISCONNECT_REASON_UNDERLYING_NETWORK_LOST, false /* shouldQuit */)); } private void setRetryTimeoutAlarm(long delay) { @@ -1041,11 +1053,8 @@ public class VcnGatewayConnection extends StateMachine { enterState(); } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); - sendMessageAndAcquireWakeLock( - EVENT_DISCONNECT_REQUESTED, - TOKEN_ALL, - new EventDisconnectRequestedInfo( - DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); + sendDisconnectRequestedAndAcquireWakelock( + DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */); } } @@ -1083,11 +1092,8 @@ public class VcnGatewayConnection extends StateMachine { processStateMsg(msg); } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); - sendMessageAndAcquireWakeLock( - EVENT_DISCONNECT_REQUESTED, - TOKEN_ALL, - new EventDisconnectRequestedInfo( - DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); + sendDisconnectRequestedAndAcquireWakelock( + DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */); } // Attempt to release the WakeLock - only possible if the Handler queue is empty @@ -1104,11 +1110,8 @@ public class VcnGatewayConnection extends StateMachine { exitState(); } catch (Exception e) { Slog.wtf(TAG, "Uncaught exception", e); - sendMessageAndAcquireWakeLock( - EVENT_DISCONNECT_REQUESTED, - TOKEN_ALL, - new EventDisconnectRequestedInfo( - DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); + sendDisconnectRequestedAndAcquireWakelock( + DISCONNECT_REASON_INTERNAL_ERROR + e.toString(), true /* shouldQuit */); } } @@ -1141,11 +1144,11 @@ public class VcnGatewayConnection extends StateMachine { } } - protected void handleDisconnectRequested(String msg) { + protected void handleDisconnectRequested(EventDisconnectRequestedInfo info) { // TODO(b/180526152): notify VcnStatusCallback for Network loss - Slog.v(TAG, "Tearing down. Cause: " + msg); - mIsRunning = false; + Slog.v(TAG, "Tearing down. Cause: " + info.reason); + mIsQuitting = info.shouldQuit; teardownNetwork(); @@ -1177,7 +1180,7 @@ public class VcnGatewayConnection extends StateMachine { private class DisconnectedState extends BaseState { @Override protected void enterState() { - if (!mIsRunning) { + if (mIsQuitting) { quitNow(); // Ignore all queued events; cleanup is complete. } @@ -1200,9 +1203,11 @@ public class VcnGatewayConnection extends StateMachine { } break; case EVENT_DISCONNECT_REQUESTED: - mIsRunning = false; + if (((EventDisconnectRequestedInfo) msg.obj).shouldQuit) { + mIsQuitting = true; - quitNow(); + quitNow(); + } break; default: logUnhandledMessage(msg); @@ -1284,10 +1289,11 @@ public class VcnGatewayConnection extends StateMachine { break; case EVENT_DISCONNECT_REQUESTED: + EventDisconnectRequestedInfo info = ((EventDisconnectRequestedInfo) msg.obj); + mIsQuitting = info.shouldQuit; teardownNetwork(); - String reason = ((EventDisconnectRequestedInfo) msg.obj).reason; - if (reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) { + if (info.reason.equals(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)) { // TODO(b/180526152): notify VcnStatusCallback for Network loss // Will trigger EVENT_SESSION_CLOSED immediately. @@ -1300,7 +1306,7 @@ public class VcnGatewayConnection extends StateMachine { case EVENT_SESSION_CLOSED: mIkeSession = null; - if (mIsRunning && mUnderlying != null) { + if (!mIsQuitting && mUnderlying != null) { transitionTo(mSkipRetryTimeout ? mConnectingState : mRetryTimeoutState); } else { teardownNetwork(); @@ -1391,7 +1397,7 @@ public class VcnGatewayConnection extends StateMachine { transitionTo(mConnectedState); break; case EVENT_DISCONNECT_REQUESTED: - handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); + handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj); break; case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: mGatewayStatusCallback.onEnteredSafeMode(); @@ -1438,6 +1444,7 @@ public class VcnGatewayConnection extends StateMachine { mVcnContext.getVcnNetworkProvider()) { @Override public void unwanted() { + Slog.d(TAG, "NetworkAgent was unwanted"); teardownAsynchronously(); } @@ -1471,7 +1478,7 @@ public class VcnGatewayConnection extends StateMachine { @NonNull IpSecTransform transform, int direction) { try { - // TODO(b/180163196): Set underlying network of tunnel interface + tunnelIface.setUnderlyingNetwork(underlyingNetwork); // Transforms do not need to be persisted; the IkeSession will keep them alive mIpSecManager.applyTunnelModeTransform(tunnelIface, direction, transform); @@ -1577,7 +1584,7 @@ public class VcnGatewayConnection extends StateMachine { setupInterfaceAndNetworkAgent(mCurrentToken, mTunnelIface, mChildConfig); break; case EVENT_DISCONNECT_REQUESTED: - handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); + handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj); break; case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: mGatewayStatusCallback.onEnteredSafeMode(); @@ -1682,7 +1689,7 @@ public class VcnGatewayConnection extends StateMachine { transitionTo(mConnectingState); break; case EVENT_DISCONNECT_REQUESTED: - handleDisconnectRequested(((EventDisconnectRequestedInfo) msg.obj).reason); + handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj); break; case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED: mGatewayStatusCallback.onEnteredSafeMode(); @@ -1905,13 +1912,13 @@ public class VcnGatewayConnection extends StateMachine { } @VisibleForTesting(visibility = Visibility.PRIVATE) - boolean isRunning() { - return mIsRunning; + boolean isQuitting() { + return mIsQuitting; } @VisibleForTesting(visibility = Visibility.PRIVATE) - void setIsRunning(boolean isRunning) { - mIsRunning = isRunning; + void setIsQuitting(boolean isQuitting) { + mIsQuitting = isQuitting; } @VisibleForTesting(visibility = Visibility.PRIVATE) @@ -1924,6 +1931,14 @@ public class VcnGatewayConnection extends StateMachine { mIkeSession = session; } + @VisibleForTesting(visibility = Visibility.PRIVATE) + void sendDisconnectRequestedAndAcquireWakelock(String reason, boolean shouldQuit) { + sendMessageAndAcquireWakeLock( + EVENT_DISCONNECT_REQUESTED, + TOKEN_ALL, + new EventDisconnectRequestedInfo(reason, shouldQuit)); + } + private IkeSessionParams buildIkeParams() { // TODO: Implement this once IkeSessionParams is persisted return null; diff --git a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java index bfeec011a2c9..a90969599159 100644 --- a/services/core/java/com/android/server/vcn/VcnNetworkProvider.java +++ b/services/core/java/com/android/server/vcn/VcnNetworkProvider.java @@ -67,9 +67,7 @@ public class VcnNetworkProvider extends NetworkProvider { mListeners.add(listener); // Send listener all cached requests - for (NetworkRequestEntry entry : mRequests.values()) { - notifyListenerForEvent(listener, entry); - } + resendAllRequests(listener); } /** Unregisters the specified listener from receiving future NetworkRequests. */ @@ -78,6 +76,14 @@ public class VcnNetworkProvider extends NetworkProvider { mListeners.remove(listener); } + /** Sends all cached NetworkRequest(s) to the specified listener. */ + @VisibleForTesting(visibility = Visibility.PACKAGE) + public void resendAllRequests(@NonNull NetworkRequestListener listener) { + for (NetworkRequestEntry entry : mRequests.values()) { + notifyListenerForEvent(listener, entry); + } + } + private void notifyListenerForEvent( @NonNull NetworkRequestListener listener, @NonNull NetworkRequestEntry entry) { listener.onNetworkRequested(entry.mRequest, entry.mScore, entry.mProviderId); diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java index 0d878b401bee..a262939c0ef9 100644 --- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java +++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java @@ -102,7 +102,7 @@ public final class ProfcollectForwardingService extends SystemService { return false; } try { - return !mIProfcollect.GetSupportedProvider().isEmpty(); + return !mIProfcollect.get_supported_provider().isEmpty(); } catch (RemoteException e) { Log.e(LOG_TAG, e.getMessage()); return false; @@ -191,7 +191,7 @@ public final class ProfcollectForwardingService extends SystemService { } try { - sSelfService.mIProfcollect.ProcessProfile(); + sSelfService.mIProfcollect.process(false); } catch (RemoteException e) { Log.e(LOG_TAG, e.getMessage()); } @@ -234,7 +234,7 @@ public final class ProfcollectForwardingService extends SystemService { if (DEBUG) { Log.d(LOG_TAG, "Tracing on app launch event: " + packageName); } - mIProfcollect.TraceOnce("applaunch"); + mIProfcollect.trace_once("applaunch"); } catch (RemoteException e) { Log.e(LOG_TAG, e.getMessage()); } @@ -296,7 +296,7 @@ public final class ProfcollectForwardingService extends SystemService { } try { - mIProfcollect.CreateProfileReport(); + mIProfcollect.report(); } catch (RemoteException e) { Log.e(LOG_TAG, e.getMessage()); } diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java index 99f2e5ee0755..4a53a8023792 100644 --- a/telephony/java/android/telephony/Annotation.java +++ b/telephony/java/android/telephony/Annotation.java @@ -111,6 +111,7 @@ public class Annotation { public @interface NetworkType { } + // TODO(b/180542000): remove and replace references with @ApnSetting.ApnType @IntDef(flag = true, prefix = {"TYPE_"}, value = { ApnSetting.TYPE_DEFAULT, ApnSetting.TYPE_MMS, @@ -124,6 +125,7 @@ public class Annotation { ApnSetting.TYPE_EMERGENCY, ApnSetting.TYPE_MCX, ApnSetting.TYPE_XCAP, + // ApnSetting.TYPE_ENTERPRISE }) @Retention(RetentionPolicy.SOURCE) public @interface ApnType { diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 18846c456027..b82c78bcf2dd 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -4710,7 +4710,7 @@ public class CarrierConfigManager { sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_ORIGINATOR_STRING_ARRAY, new String[0]); sDefaults.putStringArray(KEY_APN_PRIORITY_STRING_ARRAY, new String[] { - "default:0", "mms:2", "supl:2", "dun:2", "hipri:3", "fota:2", + "default:0", "enterprise:1", "mms:2", "supl:2", "dun:2", "hipri:3", "fota:2", "ims:2", "cbs:2", "ia:2", "emergency:2", "mcx:3", "xcap:3" }); sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]); diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java index 99a77ae5d133..c8ed82cd2a3f 100644 --- a/telephony/java/android/telephony/DataFailCause.java +++ b/telephony/java/android/telephony/DataFailCause.java @@ -917,6 +917,10 @@ public final class DataFailCause { public static final int HANDOFF_PREFERENCE_CHANGED = 0x8CB; /** Data call fail due to the slice not being allowed for the data call. */ public static final int SLICE_REJECTED = 0x8CC; + /** No matching rule available for the request, and match-all rule is not allowed for it. */ + public static final int MATCH_ALL_RULE_NOT_ALLOWED = 0x8CD; + /** If connection failed for all matching URSP rules. */ + public static final int ALL_MATCHING_RULES_FAILED = 0x8CE; //IKE error notifications message as specified in 3GPP TS 24.302 (Section 8.1.2.2). diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index d58fa912dce2..b503733f8de9 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -28,8 +28,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.provider.Telephony; import android.provider.Telephony.Carriers; -import android.telephony.Annotation; -import android.telephony.Annotation.ApnType; import android.telephony.Annotation.NetworkType; import android.telephony.ServiceState; import android.telephony.TelephonyManager; @@ -116,6 +114,31 @@ public class ApnSetting implements Parcelable { public static final int TYPE_MCX = ApnTypes.MCX; /** APN type for XCAP. */ public static final int TYPE_XCAP = ApnTypes.XCAP; + /** + * APN type for ENTERPRISE. + * @hide + */ + public static final int TYPE_ENTERPRISE = TYPE_XCAP << 1; + + /** @hide */ + @IntDef(flag = true, prefix = {"TYPE_"}, value = { + TYPE_DEFAULT, + TYPE_MMS, + TYPE_SUPL, + TYPE_DUN, + TYPE_HIPRI, + TYPE_FOTA, + TYPE_IMS, + TYPE_CBS, + TYPE_IA, + TYPE_EMERGENCY, + TYPE_MCX, + TYPE_XCAP, + TYPE_ENTERPRISE, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ApnType { + } // Possible values for authentication types. /** No authentication type. */ @@ -151,6 +174,7 @@ public class ApnSetting implements Parcelable { TYPE_MMS_STRING, TYPE_SUPL_STRING, TYPE_XCAP_STRING, + TYPE_ENTERPRISE_STRING, }, prefix = "TYPE_", suffix = "_STRING") @Retention(RetentionPolicy.SOURCE) public @interface ApnTypeString {} @@ -291,6 +315,12 @@ public class ApnSetting implements Parcelable { @SystemApi public static final String TYPE_XCAP_STRING = "xcap"; + /** + * APN type for ENTERPRISE traffic. + * @hide + */ + public static final String TYPE_ENTERPRISE_STRING = "enterprise"; + /** @hide */ @IntDef(prefix = { "AUTH_TYPE_" }, value = { @@ -370,6 +400,7 @@ public class ApnSetting implements Parcelable { APN_TYPE_STRING_MAP.put(TYPE_EMERGENCY_STRING, TYPE_EMERGENCY); APN_TYPE_STRING_MAP.put(TYPE_MCX_STRING, TYPE_MCX); APN_TYPE_STRING_MAP.put(TYPE_XCAP_STRING, TYPE_XCAP); + APN_TYPE_STRING_MAP.put(TYPE_ENTERPRISE_STRING, TYPE_ENTERPRISE); APN_TYPE_INT_MAP = new ArrayMap<>(); APN_TYPE_INT_MAP.put(TYPE_DEFAULT, TYPE_DEFAULT_STRING); @@ -384,6 +415,7 @@ public class ApnSetting implements Parcelable { APN_TYPE_INT_MAP.put(TYPE_EMERGENCY, TYPE_EMERGENCY_STRING); APN_TYPE_INT_MAP.put(TYPE_MCX, TYPE_MCX_STRING); APN_TYPE_INT_MAP.put(TYPE_XCAP, TYPE_XCAP_STRING); + APN_TYPE_INT_MAP.put(TYPE_ENTERPRISE, TYPE_ENTERPRISE_STRING); PROTOCOL_STRING_MAP = new ArrayMap<>(); PROTOCOL_STRING_MAP.put("IP", PROTOCOL_IP); @@ -1490,7 +1522,7 @@ public class ApnSetting implements Parcelable { * @hide */ @SystemApi - public static @NonNull @ApnTypeString String getApnTypeString(@Annotation.ApnType int apnType) { + public static @NonNull @ApnTypeString String getApnTypeString(@ApnType int apnType) { if (apnType == TYPE_ALL) { return "*"; } @@ -1503,7 +1535,7 @@ public class ApnSetting implements Parcelable { * when provided with an invalid int for compatibility purposes. * @hide */ - public static @NonNull String getApnTypeStringInternal(@Annotation.ApnType int apnType) { + public static @NonNull String getApnTypeStringInternal(@ApnType int apnType) { String result = getApnTypeString(apnType); return TextUtils.isEmpty(result) ? "Unknown" : result; } @@ -1517,7 +1549,7 @@ public class ApnSetting implements Parcelable { * @hide */ @SystemApi - public static @Annotation.ApnType int getApnTypeInt(@NonNull @ApnTypeString String apnType) { + public static @ApnType int getApnTypeInt(@NonNull @ApnTypeString String apnType) { return APN_TYPE_STRING_MAP.getOrDefault(apnType.toLowerCase(), 0); } @@ -2162,7 +2194,7 @@ public class ApnSetting implements Parcelable { public ApnSetting build() { if ((mApnTypeBitmask & (TYPE_DEFAULT | TYPE_MMS | TYPE_SUPL | TYPE_DUN | TYPE_HIPRI | TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX - | TYPE_XCAP)) == 0 + | TYPE_XCAP | TYPE_ENTERPRISE)) == 0 || TextUtils.isEmpty(mApnName) || TextUtils.isEmpty(mEntryName)) { return null; } diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java index 1edacd9429f1..a5e5ab01810f 100644 --- a/telephony/java/android/telephony/data/DataCallResponse.java +++ b/telephony/java/android/telephony/data/DataCallResponse.java @@ -138,6 +138,7 @@ public final class DataCallResponse implements Parcelable { private final Qos mDefaultQos; private final List<QosBearerSession> mQosBearerSessions; private final SliceInfo mSliceInfo; + private final List<TrafficDescriptor> mTrafficDescriptors; /** * @param cause Data call fail cause. {@link DataFailCause#NONE} indicates no error. @@ -189,6 +190,7 @@ public final class DataCallResponse implements Parcelable { mDefaultQos = null; mQosBearerSessions = new ArrayList<>(); mSliceInfo = null; + mTrafficDescriptors = new ArrayList<>(); } private DataCallResponse(@DataFailureCause int cause, long suggestedRetryTime, int id, @@ -198,7 +200,7 @@ public final class DataCallResponse implements Parcelable { @Nullable List<InetAddress> pcscfAddresses, int mtu, int mtuV4, int mtuV6, @HandoverFailureMode int handoverFailureMode, int pduSessionId, @Nullable Qos defaultQos, @Nullable List<QosBearerSession> qosBearerSessions, - @Nullable SliceInfo sliceInfo) { + @Nullable SliceInfo sliceInfo, @Nullable List<TrafficDescriptor> trafficDescriptors) { mCause = cause; mSuggestedRetryTime = suggestedRetryTime; mId = id; @@ -219,8 +221,11 @@ public final class DataCallResponse implements Parcelable { mHandoverFailureMode = handoverFailureMode; mPduSessionId = pduSessionId; mDefaultQos = defaultQos; - mQosBearerSessions = qosBearerSessions; + mQosBearerSessions = (qosBearerSessions == null) + ? new ArrayList<>() : new ArrayList<>(qosBearerSessions); mSliceInfo = sliceInfo; + mTrafficDescriptors = (trafficDescriptors == null) + ? new ArrayList<>() : new ArrayList<>(trafficDescriptors); } /** @hide */ @@ -249,6 +254,8 @@ public final class DataCallResponse implements Parcelable { mQosBearerSessions = new ArrayList<>(); source.readList(mQosBearerSessions, QosBearerSession.class.getClassLoader()); mSliceInfo = source.readParcelable(SliceInfo.class.getClassLoader()); + mTrafficDescriptors = new ArrayList<>(); + source.readList(mTrafficDescriptors, TrafficDescriptor.class.getClassLoader()); } /** @@ -380,7 +387,6 @@ public final class DataCallResponse implements Parcelable { * * @hide */ - @Nullable public Qos getDefaultQos() { return mDefaultQos; @@ -405,6 +411,14 @@ public final class DataCallResponse implements Parcelable { return mSliceInfo; } + /** + * @return The traffic descriptors related to this data connection. + */ + @NonNull + public List<TrafficDescriptor> getTrafficDescriptors() { + return mTrafficDescriptors; + } + @NonNull @Override public String toString() { @@ -428,6 +442,7 @@ public final class DataCallResponse implements Parcelable { .append(" defaultQos=").append(mDefaultQos) .append(" qosBearerSessions=").append(mQosBearerSessions) .append(" sliceInfo=").append(mSliceInfo) + .append(" trafficDescriptors=").append(mTrafficDescriptors) .append("}"); return sb.toString(); } @@ -442,15 +457,22 @@ public final class DataCallResponse implements Parcelable { DataCallResponse other = (DataCallResponse) o; - final boolean isQosSame = (mDefaultQos == null || other.mDefaultQos == null) ? - mDefaultQos == other.mDefaultQos : - mDefaultQos.equals(other.mDefaultQos); + final boolean isQosSame = (mDefaultQos == null || other.mDefaultQos == null) + ? mDefaultQos == other.mDefaultQos + : mDefaultQos.equals(other.mDefaultQos); - final boolean isQosBearerSessionsSame = (mQosBearerSessions == null || mQosBearerSessions == null) ? - mQosBearerSessions == other.mQosBearerSessions : - mQosBearerSessions.size() == other.mQosBearerSessions.size() + final boolean isQosBearerSessionsSame = + (mQosBearerSessions == null || other.mQosBearerSessions == null) + ? mQosBearerSessions == other.mQosBearerSessions + : mQosBearerSessions.size() == other.mQosBearerSessions.size() && mQosBearerSessions.containsAll(other.mQosBearerSessions); + final boolean isTrafficDescriptorsSame = + (mTrafficDescriptors == null || other.mTrafficDescriptors == null) + ? mTrafficDescriptors == other.mTrafficDescriptors + : mTrafficDescriptors.size() == other.mTrafficDescriptors.size() + && mTrafficDescriptors.containsAll(other.mTrafficDescriptors); + return mCause == other.mCause && mSuggestedRetryTime == other.mSuggestedRetryTime && mId == other.mId @@ -472,7 +494,8 @@ public final class DataCallResponse implements Parcelable { && mPduSessionId == other.mPduSessionId && isQosSame && isQosBearerSessionsSame - && Objects.equals(mSliceInfo, other.mSliceInfo); + && Objects.equals(mSliceInfo, other.mSliceInfo) + && isTrafficDescriptorsSame; } @Override @@ -480,7 +503,7 @@ public final class DataCallResponse implements Parcelable { return Objects.hash(mCause, mSuggestedRetryTime, mId, mLinkStatus, mProtocolType, mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses, mPcscfAddresses, mMtu, mMtuV4, mMtuV6, mHandoverFailureMode, mPduSessionId, mDefaultQos, - mQosBearerSessions, mSliceInfo); + mQosBearerSessions, mSliceInfo, mTrafficDescriptors); } @Override @@ -512,6 +535,7 @@ public final class DataCallResponse implements Parcelable { } dest.writeList(mQosBearerSessions); dest.writeParcelable(mSliceInfo, flags); + dest.writeList(mTrafficDescriptors); } public static final @android.annotation.NonNull Parcelable.Creator<DataCallResponse> CREATOR = @@ -597,6 +621,8 @@ public final class DataCallResponse implements Parcelable { private SliceInfo mSliceInfo; + private List<TrafficDescriptor> mTrafficDescriptors = new ArrayList<>(); + /** * Default constructor for Builder. */ @@ -836,6 +862,24 @@ public final class DataCallResponse implements Parcelable { } /** + * The traffic descriptors for this data connection, as defined in 3GPP TS 24.526 + * Section 5.2. They are used for URSP traffic matching as described in 3GPP TS 24.526 + * Section 4.2.2. They includes an optional DNN, which, if present, must be used for traffic + * matching; it does not specify the end point to be used for the data call. The end point + * is specified by {@link DataProfile}, which must be used as the end point if one is not + * specified through URSP rules. + * + * @param trafficDescriptors the traffic descriptors for the data call. + * + * @return The same instance of the builder. + */ + public @NonNull Builder setTrafficDescriptors( + @NonNull List<TrafficDescriptor> trafficDescriptors) { + mTrafficDescriptors = trafficDescriptors; + return this; + } + + /** * Build the DataCallResponse. * * @return the DataCallResponse object. @@ -844,7 +888,7 @@ public final class DataCallResponse implements Parcelable { return new DataCallResponse(mCause, mSuggestedRetryTime, mId, mLinkStatus, mProtocolType, mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses, mPcscfAddresses, mMtu, mMtuV4, mMtuV6, mHandoverFailureMode, mPduSessionId, - mDefaultQos, mQosBearerSessions, mSliceInfo); + mDefaultQos, mQosBearerSessions, mSliceInfo, mTrafficDescriptors); } } } diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java index 03c2ef9d9baa..74d26947abd0 100644 --- a/telephony/java/android/telephony/data/DataService.java +++ b/telephony/java/android/telephony/data/DataService.java @@ -200,6 +200,17 @@ public abstract class DataService extends Service { * handover is occurring from EPDG to 5G. If the slice passed is rejected, then * {@link DataCallResponse#getCause()} is * {@link android.telephony.DataFailCause#SLICE_REJECTED}. + * @param trafficDescriptor {@link TrafficDescriptor} for which data connection needs to be + * established. It is used for URSP traffic matching as described in 3GPP TS 24.526 + * Section 4.2.2. It includes an optional DNN which, if present, must be used for + * traffic matching; it does not specify the end point to be used for the data call. + * @param matchAllRuleAllowed Indicates if using default match-all URSP rule for this + * request is allowed. If false, this request must not use the match-all URSP rule + * and if a non-match-all rule is not found (or if URSP rules are not available) then + * {@link DataCallResponse#getCause()} is + * {@link android.telephony.DataFailCause#MATCH_ALL_RULE_NOT_ALLOWED}. This is needed + * as some requests need to have a hard failure if the intention cannot be met, + * for example, a zero-rating slice. * @param callback The result callback for this request. */ public void setupDataCall(int accessNetworkType, @NonNull DataProfile dataProfile, @@ -207,6 +218,7 @@ public abstract class DataService extends Service { @SetupDataReason int reason, @Nullable LinkProperties linkProperties, @IntRange(from = 0, to = 15) int pduSessionId, @Nullable SliceInfo sliceInfo, + @Nullable TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed, @NonNull DataServiceCallback callback) { /* Call the old version since the new version isn't supported */ setupDataCall(accessNetworkType, dataProfile, isRoaming, allowRoaming, reason, @@ -399,10 +411,13 @@ public abstract class DataService extends Service { public final LinkProperties linkProperties; public final int pduSessionId; public final SliceInfo sliceInfo; + public final TrafficDescriptor trafficDescriptor; + public final boolean matchAllRuleAllowed; public final IDataServiceCallback callback; SetupDataCallRequest(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, - boolean allowRoaming, int reason, LinkProperties linkProperties, - int pduSessionId, SliceInfo sliceInfo, IDataServiceCallback callback) { + boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId, + SliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, + boolean matchAllRuleAllowed, IDataServiceCallback callback) { this.accessNetworkType = accessNetworkType; this.dataProfile = dataProfile; this.isRoaming = isRoaming; @@ -411,6 +426,8 @@ public abstract class DataService extends Service { this.reason = reason; this.pduSessionId = pduSessionId; this.sliceInfo = sliceInfo; + this.trafficDescriptor = trafficDescriptor; + this.matchAllRuleAllowed = matchAllRuleAllowed; this.callback = callback; } } @@ -521,7 +538,8 @@ public abstract class DataService extends Service { setupDataCallRequest.dataProfile, setupDataCallRequest.isRoaming, setupDataCallRequest.allowRoaming, setupDataCallRequest.reason, setupDataCallRequest.linkProperties, setupDataCallRequest.pduSessionId, - setupDataCallRequest.sliceInfo, + setupDataCallRequest.sliceInfo, setupDataCallRequest.trafficDescriptor, + setupDataCallRequest.matchAllRuleAllowed, (setupDataCallRequest.callback != null) ? new DataServiceCallback(setupDataCallRequest.callback) : null); @@ -686,11 +704,12 @@ public abstract class DataService extends Service { public void setupDataCall(int slotIndex, int accessNetworkType, DataProfile dataProfile, boolean isRoaming, boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId, SliceInfo sliceInfo, + TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed, IDataServiceCallback callback) { mHandler.obtainMessage(DATA_SERVICE_REQUEST_SETUP_DATA_CALL, slotIndex, 0, new SetupDataCallRequest(accessNetworkType, dataProfile, isRoaming, allowRoaming, reason, linkProperties, pduSessionId, sliceInfo, - callback)) + trafficDescriptor, matchAllRuleAllowed, callback)) .sendToTarget(); } diff --git a/telephony/java/android/telephony/data/IDataService.aidl b/telephony/java/android/telephony/data/IDataService.aidl index e0b9a1a9bb5a..81f5fd3b69a9 100644 --- a/telephony/java/android/telephony/data/IDataService.aidl +++ b/telephony/java/android/telephony/data/IDataService.aidl @@ -20,6 +20,7 @@ import android.net.LinkProperties; import android.telephony.data.DataProfile; import android.telephony.data.IDataServiceCallback; import android.telephony.data.SliceInfo; +import android.telephony.data.TrafficDescriptor; /** * {@hide} @@ -30,7 +31,9 @@ oneway interface IDataService void removeDataServiceProvider(int slotId); void setupDataCall(int slotId, int accessNetwork, in DataProfile dataProfile, boolean isRoaming, boolean allowRoaming, int reason, in LinkProperties linkProperties, - int pduSessionId, in SliceInfo sliceInfo, IDataServiceCallback callback); + int pduSessionId, in SliceInfo sliceInfo, + in TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed, + IDataServiceCallback callback); void deactivateDataCall(int slotId, int cid, int reason, IDataServiceCallback callback); void setInitialAttachApn(int slotId, in DataProfile dataProfile, boolean isRoaming, IDataServiceCallback callback); diff --git a/telephony/java/android/telephony/data/TrafficDescriptor.aidl b/telephony/java/android/telephony/data/TrafficDescriptor.aidl new file mode 100644 index 000000000000..a9c7604a91b6 --- /dev/null +++ b/telephony/java/android/telephony/data/TrafficDescriptor.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2021 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. + */ + +/** @hide */ +package android.telephony.data; + +parcelable TrafficDescriptor; diff --git a/telephony/java/android/telephony/data/TrafficDescriptor.java b/telephony/java/android/telephony/data/TrafficDescriptor.java new file mode 100644 index 000000000000..480379d641b6 --- /dev/null +++ b/telephony/java/android/telephony/data/TrafficDescriptor.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2021 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.telephony.data; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * A traffic descriptor, as defined in 3GPP TS 24.526 Section 5.2. It is used for URSP traffic + * matching as described in 3GPP TS 24.526 Section 4.2.2. It includes an optional DNN, which, + * if present, must be used for traffic matching; it does not specify the end point to be used for + * the data call. + * @hide + */ +@SystemApi +public final class TrafficDescriptor implements Parcelable { + private final String mDnn; + private final String mOsAppId; + + private TrafficDescriptor(@NonNull Parcel in) { + mDnn = in.readString(); + mOsAppId = in.readString(); + } + + /** + * Create a traffic descriptor, as defined in 3GPP TS 24.526 Section 5.2 + * @param dnn optional DNN, which must be used for traffic matching, if present + * @param osAppId OsId + osAppId of the traffic descriptor + */ + public TrafficDescriptor(@Nullable String dnn, @Nullable String osAppId) { + mDnn = dnn; + mOsAppId = osAppId; + } + + /** + * DNN stands for Data Network Name and represents an APN as defined in 3GPP TS 23.003. + * @return the DNN of this traffic descriptor. + */ + public @Nullable String getDnn() { + return mDnn; + } + + /** + * OsAppId represents the OsId + OsAppId as defined in 3GPP TS 24.526 Section 5.2. + * @return the OS App ID of this traffic descriptor. + */ + public @Nullable String getOsAppId() { + return mOsAppId; + } + + @Override + public int describeContents() { + return 0; + } + + @NonNull @Override + public String toString() { + return "TrafficDescriptor={mDnn=" + mDnn + ", mOsAppId=" + mOsAppId + "}"; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(mDnn); + dest.writeString(mOsAppId); + } + + public static final @NonNull Parcelable.Creator<TrafficDescriptor> CREATOR = + new Parcelable.Creator<TrafficDescriptor>() { + @Override + public @NonNull TrafficDescriptor createFromParcel(@NonNull Parcel source) { + return new TrafficDescriptor(source); + } + + @Override + public @NonNull TrafficDescriptor[] newArray(int size) { + return new TrafficDescriptor[size]; + } + }; + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TrafficDescriptor that = (TrafficDescriptor) o; + return Objects.equals(mDnn, that.mDnn) && Objects.equals(mOsAppId, that.mOsAppId); + } + + @Override + public int hashCode() { + return Objects.hash(mDnn, mOsAppId); + } +} diff --git a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java index 5f8e93d02a00..8ad40ed1032c 100644 --- a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java @@ -57,10 +57,10 @@ public class ImsEcbmImplBase { } else if (listener != null && mListener == null) { mListener = listener; } else { - // Fail fast here instead of silently overwriting the listener to another - // listener due to another connection connecting. - throw new IllegalStateException("ImsEcbmImplBase: Listener already set by " - + "another connection."); + // Warn that the listener is being replaced while active + Log.w(TAG, "setListener is being called when there is already an active " + + "listener"); + mListener = listener; } } } diff --git a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java index 8e961acc7b36..ec1c7b3a92a8 100644 --- a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java @@ -62,10 +62,10 @@ public class ImsMultiEndpointImplBase { } else if (listener != null && mListener == null) { mListener = listener; } else { - // Fail fast here instead of silently overwriting the listener to another - // listener due to another connection connecting. - throw new IllegalStateException("ImsMultiEndpointImplBase: Listener already" - + " set by another connection."); + // Warn that the listener is being replaced while active + Log.w(TAG, "setListener is being called when there is already an active " + + "listener"); + mListener = listener; } } } diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java index 83b89aa8e814..eb3e8ed5a8e4 100644 --- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java @@ -224,11 +224,10 @@ public class ImsUtImplBase { } else if (listener != null && mUtListener == null) { mUtListener = new ImsUtListener(listener); } else { - // This is a limitation of the current API surface, there can only be one - // listener connected. Fail fast instead of silently overwriting the other - // listener. - throw new IllegalStateException("ImsUtImplBase#setListener: listener already " - + "set by another connected interface!"); + // Warn that the listener is being replaced while active + Log.w(TAG, "setListener is being called when there is already an active " + + "listener"); + mUtListener = new ImsUtListener(listener); } } diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java index 151187c5071f..3a99f0e010c6 100644 --- a/telephony/java/com/android/internal/telephony/PhoneConstants.java +++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java @@ -126,6 +126,7 @@ public class PhoneConstants { * connections.<br/> * APN_TYPE_ALL is a special type to indicate that this APN entry can * service all data connections. + * TODO: remove these and use the reference to ApnSetting.TYPE_XXX_STRING instead */ public static final String APN_TYPE_ALL = ApnSetting.TYPE_ALL_STRING; /** APN type for default data traffic */ @@ -153,20 +154,8 @@ public class PhoneConstants { public static final String APN_TYPE_MCX = ApnSetting.TYPE_MCX_STRING; /** APN type for XCAP */ public static final String APN_TYPE_XCAP = ApnSetting.TYPE_XCAP_STRING; - /** Array of all APN types */ - public static final String[] APN_TYPES = {APN_TYPE_DEFAULT, - APN_TYPE_MMS, - APN_TYPE_SUPL, - APN_TYPE_DUN, - APN_TYPE_HIPRI, - APN_TYPE_FOTA, - APN_TYPE_IMS, - APN_TYPE_CBS, - APN_TYPE_IA, - APN_TYPE_EMERGENCY, - APN_TYPE_MCX, - APN_TYPE_XCAP, - }; + // /** APN type for enterprise */ + // public static final String APN_TYPE_ENTERPRISE = ApnSetting.TYPE_ENTERPRISE_STRING; public static final int RIL_CARD_MAX_APPS = 8; diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index e43770fff89c..c0e6ae165d93 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -53,6 +53,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL; import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS; +import static android.net.NetworkCapabilities.NET_CAPABILITY_ENTERPRISE; import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND; import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA; import static android.net.NetworkCapabilities.NET_CAPABILITY_IA; @@ -90,6 +91,10 @@ import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY; import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED; import static android.net.RouteInfo.RTN_UNREACHABLE; +import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_ADDED; +import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.PREFIX_OPERATION_REMOVED; +import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE; +import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS; import static android.os.Process.INVALID_UID; import static android.system.OsConstants.IPPROTO_TCP; @@ -217,6 +222,8 @@ import android.net.Uri; import android.net.VpnManager; import android.net.VpnTransportInfo; import android.net.metrics.IpConnectivityLog; +import android.net.resolv.aidl.Nat64PrefixEventParcel; +import android.net.resolv.aidl.PrivateDnsValidationEventParcel; import android.net.shared.NetworkMonitorUtils; import android.net.shared.PrivateDnsConfig; import android.net.util.MultinetworkPolicyTracker; @@ -344,6 +351,9 @@ public class ConnectivityServiceTest { private static final String TAG = "ConnectivityServiceTest"; private static final int TIMEOUT_MS = 500; + // Broadcasts can take a long time to be delivered. The test will not wait for that long unless + // there is a failure, so use a long timeout. + private static final int BROADCAST_TIMEOUT_MS = 30_000; private static final int TEST_LINGER_DELAY_MS = 400; private static final int TEST_NASCENT_DELAY_MS = 300; // Chosen to be less than the linger and nascent timeout. This ensures that we can distinguish @@ -1681,7 +1691,7 @@ public class ConnectivityServiceTest { } public Intent expectBroadcast() throws Exception { - return expectBroadcast(TIMEOUT_MS); + return expectBroadcast(BROADCAST_TIMEOUT_MS); } public void expectNoBroadcast(int timeoutMs) throws Exception { @@ -2789,7 +2799,8 @@ public class ConnectivityServiceTest { if (capability == NET_CAPABILITY_CBS || capability == NET_CAPABILITY_DUN || capability == NET_CAPABILITY_EIMS || capability == NET_CAPABILITY_FOTA || capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS || - capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP) { + capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP + || capability == NET_CAPABILITY_ENTERPRISE) { assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); } else { assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); @@ -2892,6 +2903,7 @@ public class ConnectivityServiceTest { tryNetworkFactoryRequests(NET_CAPABILITY_IA); tryNetworkFactoryRequests(NET_CAPABILITY_RCS); tryNetworkFactoryRequests(NET_CAPABILITY_XCAP); + tryNetworkFactoryRequests(NET_CAPABILITY_ENTERPRISE); tryNetworkFactoryRequests(NET_CAPABILITY_EIMS); tryNetworkFactoryRequests(NET_CAPABILITY_NOT_METERED); tryNetworkFactoryRequests(NET_CAPABILITY_INTERNET); @@ -5919,6 +5931,16 @@ public class ConnectivityServiceTest { assertEquals("strict.example.com", cbi.getLp().getPrivateDnsServerName()); } + private PrivateDnsValidationEventParcel makePrivateDnsValidationEvent( + final int netId, final String ipAddress, final String hostname, final int validation) { + final PrivateDnsValidationEventParcel event = new PrivateDnsValidationEventParcel(); + event.netId = netId; + event.ipAddress = ipAddress; + event.hostname = hostname; + event.validation = validation; + return event; + } + @Test public void testLinkPropertiesWithPrivateDnsValidationEvents() throws Exception { // The default on Android is opportunistic mode ("Automatic"). @@ -5949,8 +5971,9 @@ public class ConnectivityServiceTest { // Send a validation event for a server that is not part of the current // resolver config. The validation event should be ignored. - mService.mNetdEventCallback.onPrivateDnsValidationEvent( - mCellNetworkAgent.getNetwork().netId, "", "145.100.185.18", true); + mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent( + makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId, "", + "145.100.185.18", VALIDATION_RESULT_SUCCESS)); cellNetworkCallback.assertNoCallback(); // Add a dns server to the LinkProperties. @@ -5967,20 +5990,23 @@ public class ConnectivityServiceTest { // Send a validation event containing a hostname that is not part of // the current resolver config. The validation event should be ignored. - mService.mNetdEventCallback.onPrivateDnsValidationEvent( - mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "hostname", true); + mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent( + makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId, + "145.100.185.16", "hostname", VALIDATION_RESULT_SUCCESS)); cellNetworkCallback.assertNoCallback(); // Send a validation event where validation failed. - mService.mNetdEventCallback.onPrivateDnsValidationEvent( - mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", false); + mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent( + makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId, + "145.100.185.16", "", VALIDATION_RESULT_FAILURE)); cellNetworkCallback.assertNoCallback(); // Send a validation event where validation succeeded for a server in // the current resolver config. A LinkProperties callback with updated // private dns fields should be sent. - mService.mNetdEventCallback.onPrivateDnsValidationEvent( - mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", true); + mService.mResolverUnsolEventCallback.onPrivateDnsValidationEvent( + makePrivateDnsValidationEvent(mCellNetworkAgent.getNetwork().netId, + "145.100.185.16", "", VALIDATION_RESULT_SUCCESS)); cbi = cellNetworkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); cellNetworkCallback.assertNoCallback(); @@ -7824,6 +7850,16 @@ public class ConnectivityServiceTest { return stacked; } + private Nat64PrefixEventParcel makeNat64PrefixEvent(final int netId, final int prefixOperation, + final String prefixAddress, final int prefixLength) { + final Nat64PrefixEventParcel event = new Nat64PrefixEventParcel(); + event.netId = netId; + event.prefixOperation = prefixOperation; + event.prefixAddress = prefixAddress; + event.prefixLength = prefixLength; + return event; + } + @Test public void testStackedLinkProperties() throws Exception { final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24"); @@ -7908,8 +7944,8 @@ public class ConnectivityServiceTest { // When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started. Nat464Xlat clat = getNat464Xlat(mCellNetworkAgent); assertNull(mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getNat64Prefix()); - mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */, - kNat64PrefixString, 96); + mService.mResolverUnsolEventCallback.onNat64PrefixEvent( + makeNat64PrefixEvent(cellNetId, PREFIX_OPERATION_ADDED, kNat64PrefixString, 96)); LinkProperties lpBeforeClat = networkCallback.expectCallback( CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent).getLp(); assertEquals(0, lpBeforeClat.getStackedLinks().size()); @@ -7949,8 +7985,8 @@ public class ConnectivityServiceTest { .thenReturn(getClatInterfaceConfigParcel(myIpv4)); // Change the NAT64 prefix without first removing it. // Expect clatd to be stopped and started with the new prefix. - mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */, - kOtherNat64PrefixString, 96); + mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent( + cellNetId, PREFIX_OPERATION_ADDED, kOtherNat64PrefixString, 96)); networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, (lp) -> lp.getStackedLinks().size() == 0); verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME); @@ -7998,8 +8034,8 @@ public class ConnectivityServiceTest { .thenReturn(getClatInterfaceConfigParcel(myIpv4)); // Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone. - mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */, - kOtherNat64PrefixString, 96); + mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent( + cellNetId, PREFIX_OPERATION_REMOVED, kOtherNat64PrefixString, 96)); networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, (lp) -> lp.getNat64Prefix() == null); @@ -8011,8 +8047,8 @@ public class ConnectivityServiceTest { networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); assertRoutesRemoved(cellNetId, ipv4Subnet); // Directly-connected routes auto-added. verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId); - mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */, - kNat64PrefixString, 96); + mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent( + cellNetId, PREFIX_OPERATION_ADDED, kNat64PrefixString, 96)); networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString()); @@ -8024,8 +8060,8 @@ public class ConnectivityServiceTest { verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME); // NAT64 prefix is removed. Expect that clat is stopped. - mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */, - kNat64PrefixString, 96); + mService.mResolverUnsolEventCallback.onNat64PrefixEvent(makeNat64PrefixEvent( + cellNetId, PREFIX_OPERATION_REMOVED, kNat64PrefixString, 96)); networkCallback.expectLinkPropertiesThat(mCellNetworkAgent, (lp) -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null); assertRoutesRemoved(cellNetId, ipv4Subnet, stackedDefault); @@ -8113,8 +8149,8 @@ public class ConnectivityServiceTest { inOrder.verify(mMockDnsResolver).setPrefix64(netId, ""); inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId); - mService.mNetdEventCallback.onNat64PrefixEvent(netId, true /* added */, - pref64FromDnsStr, 96); + mService.mResolverUnsolEventCallback.onNat64PrefixEvent( + makeNat64PrefixEvent(netId, PREFIX_OPERATION_ADDED, pref64FromDnsStr, 96)); expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns); inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString()); @@ -8147,8 +8183,8 @@ public class ConnectivityServiceTest { inOrder.verify(mMockDnsResolver).stopPrefix64Discovery(netId); // Stopping prefix discovery results in a prefix removed notification. - mService.mNetdEventCallback.onNat64PrefixEvent(netId, false /* added */, - pref64FromDnsStr, 96); + mService.mResolverUnsolEventCallback.onNat64PrefixEvent( + makeNat64PrefixEvent(netId, PREFIX_OPERATION_REMOVED, pref64FromDnsStr, 96)); inOrder.verify(mMockNetd).clatdStart(iface, pref64FromRa.toString()); inOrder.verify(mMockDnsResolver).setPrefix64(netId, pref64FromRa.toString()); @@ -8186,8 +8222,8 @@ public class ConnectivityServiceTest { inOrder.verify(mMockNetd).clatdStop(iface); inOrder.verify(mMockDnsResolver).setPrefix64(netId, ""); inOrder.verify(mMockDnsResolver).startPrefix64Discovery(netId); - mService.mNetdEventCallback.onNat64PrefixEvent(netId, true /* added */, - pref64FromDnsStr, 96); + mService.mResolverUnsolEventCallback.onNat64PrefixEvent( + makeNat64PrefixEvent(netId, PREFIX_OPERATION_ADDED, pref64FromDnsStr, 96)); expectNat64PrefixChange(callback, mWiFiNetworkAgent, pref64FromDns); inOrder.verify(mMockNetd).clatdStart(iface, pref64FromDns.toString()); inOrder.verify(mMockDnsResolver, never()).setPrefix64(eq(netId), any()); diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java index f5b85ca06f92..5760211d9a27 100644 --- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java +++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java @@ -22,6 +22,8 @@ import static android.net.NetworkCapabilities.MAX_TRANSPORT; import static android.net.NetworkCapabilities.MIN_TRANSPORT; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_FAILURE; +import static android.net.resolv.aidl.IDnsResolverUnsolicitedEventListener.VALIDATION_RESULT_SUCCESS; import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE; import static android.provider.Settings.Global.PRIVATE_DNS_MODE; import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; @@ -164,7 +166,8 @@ public class DnsManagerTest { mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_ALTERNATE, - InetAddress.parseNumericAddress("4.4.4.4"), "", true)); + InetAddress.parseNumericAddress("4.4.4.4"), "", + VALIDATION_RESULT_SUCCESS)); LinkProperties fixedLp = new LinkProperties(lp); mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp); assertFalse(fixedLp.isPrivateDnsActive()); @@ -204,7 +207,8 @@ public class DnsManagerTest { // Validate one. mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, - InetAddress.parseNumericAddress("6.6.6.6"), "strictmode.com", true)); + InetAddress.parseNumericAddress("6.6.6.6"), "strictmode.com", + VALIDATION_RESULT_SUCCESS)); fixedLp = new LinkProperties(lp); mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp); assertEquals(Arrays.asList(InetAddress.parseNumericAddress("6.6.6.6")), @@ -212,7 +216,8 @@ public class DnsManagerTest { // Validate the 2nd one. mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, - InetAddress.parseNumericAddress("2001:db8:66:66::1"), "strictmode.com", true)); + InetAddress.parseNumericAddress("2001:db8:66:66::1"), "strictmode.com", + VALIDATION_RESULT_SUCCESS)); fixedLp = new LinkProperties(lp); mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp); assertEquals(Arrays.asList( @@ -232,7 +237,8 @@ public class DnsManagerTest { mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, - InetAddress.parseNumericAddress("3.3.3.3"), "", true)); + InetAddress.parseNumericAddress("3.3.3.3"), "", + VALIDATION_RESULT_SUCCESS)); mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp); assertFalse(lp.isPrivateDnsActive()); assertNull(lp.getPrivateDnsServerName()); @@ -245,7 +251,8 @@ public class DnsManagerTest { mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_UNTRACKED, - InetAddress.parseNumericAddress("3.3.3.3"), "", true)); + InetAddress.parseNumericAddress("3.3.3.3"), "", + VALIDATION_RESULT_SUCCESS)); mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp); assertFalse(lp.isPrivateDnsActive()); assertNull(lp.getPrivateDnsServerName()); @@ -253,7 +260,8 @@ public class DnsManagerTest { // Validation event has untracked ipAddress mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, - InetAddress.parseNumericAddress("4.4.4.4"), "", true)); + InetAddress.parseNumericAddress("4.4.4.4"), "", + VALIDATION_RESULT_SUCCESS)); mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp); assertFalse(lp.isPrivateDnsActive()); assertNull(lp.getPrivateDnsServerName()); @@ -261,8 +269,8 @@ public class DnsManagerTest { // Validation event has untracked hostname mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, - InetAddress.parseNumericAddress("3.3.3.3"), "hostname", - true)); + InetAddress.parseNumericAddress("3.3.3.3"), "hostname", + VALIDATION_RESULT_SUCCESS)); mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp); assertFalse(lp.isPrivateDnsActive()); assertNull(lp.getPrivateDnsServerName()); @@ -270,7 +278,8 @@ public class DnsManagerTest { // Validation event failed mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, - InetAddress.parseNumericAddress("3.3.3.3"), "", false)); + InetAddress.parseNumericAddress("3.3.3.3"), "", + VALIDATION_RESULT_FAILURE)); mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp); assertFalse(lp.isPrivateDnsActive()); assertNull(lp.getPrivateDnsServerName()); @@ -279,7 +288,7 @@ public class DnsManagerTest { mDnsManager.removeNetwork(new Network(TEST_NETID)); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, - InetAddress.parseNumericAddress("3.3.3.3"), "", true)); + InetAddress.parseNumericAddress("3.3.3.3"), "", VALIDATION_RESULT_SUCCESS)); mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp); assertFalse(lp.isPrivateDnsActive()); assertNull(lp.getPrivateDnsServerName()); @@ -293,7 +302,8 @@ public class DnsManagerTest { mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, - InetAddress.parseNumericAddress("3.3.3.3"), "", true)); + InetAddress.parseNumericAddress("3.3.3.3"), "", + VALIDATION_RESULT_SUCCESS)); mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp); assertFalse(lp.isPrivateDnsActive()); assertNull(lp.getPrivateDnsServerName()); @@ -398,7 +408,8 @@ public class DnsManagerTest { mDnsManager.updatePrivateDns(network, mDnsManager.getPrivateDnsConfig()); mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); mDnsManager.updatePrivateDnsValidation( - new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, dnsAddr, "", true)); + new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, dnsAddr, "", + VALIDATION_RESULT_SUCCESS)); mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp); privateDnsCfg = mDnsManager.getPrivateDnsConfig(network); assertTrue(privateDnsCfg.useTls); diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java index 69c21b967917..69b2fb135a8d 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java @@ -36,6 +36,7 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -143,11 +144,18 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform()); mTestLooper.dispatchAll(); + verify(mIpSecSvc, times(2)) + .setNetworkForTunnelInterface( + eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), + eq(TEST_UNDERLYING_NETWORK_RECORD_1.network), + any()); + for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) { verify(mIpSecSvc) .applyTunnelModeTransform( eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(direction), anyInt(), any()); } + assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState()); } @@ -290,4 +298,22 @@ public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnection verifyIkeSessionClosedExceptionalltyNotifiesStatusCallback( new TemporaryFailureException("vcn test"), VCN_ERROR_CODE_INTERNAL_ERROR); } + + @Test + public void testTeardown() throws Exception { + mGatewayConnection.teardownAsynchronously(); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + assertTrue(mGatewayConnection.isQuitting()); + } + + @Test + public void testNonTeardownDisconnectRequest() throws Exception { + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + assertFalse(mGatewayConnection.isQuitting()); + } } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java index 17ae19e086cf..d07d2cf4f1bb 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java @@ -19,6 +19,8 @@ package com.android.server.vcn; import static com.android.server.vcn.VcnGatewayConnection.VcnIkeSession; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -111,4 +113,22 @@ public class VcnGatewayConnectionConnectingStateTest extends VcnGatewayConnectio public void testSafeModeTimeoutNotifiesCallback() { verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState); } + + @Test + public void testTeardown() throws Exception { + mGatewayConnection.teardownAsynchronously(); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + assertTrue(mGatewayConnection.isQuitting()); + } + + @Test + public void testNonTeardownDisconnectRequest() throws Exception { + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + assertFalse(mGatewayConnection.isQuitting()); + } } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java index 9ea641f52e48..5f27fabb62b0 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java @@ -21,9 +21,12 @@ import static android.net.IpSecManager.IpSecTunnelInterface; import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import android.net.IpSecManager; @@ -54,7 +57,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect } @Test - public void testEnterWhileNotRunningTriggersQuit() throws Exception { + public void testEnterWhileQuittingTriggersQuit() throws Exception { final VcnGatewayConnection vgc = new VcnGatewayConnection( mVcnContext, @@ -64,7 +67,7 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect mGatewayStatusCallback, mDeps); - vgc.setIsRunning(false); + vgc.setIsQuitting(true); vgc.transitionTo(vgc.mDisconnectedState); mTestLooper.dispatchAll(); @@ -101,5 +104,18 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect assertNull(mGatewayConnection.getCurrentState()); verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any()); verifySafeModeTimeoutAlarmAndGetCallback(true /* expectCanceled */); + assertTrue(mGatewayConnection.isQuitting()); + verify(mGatewayStatusCallback).onQuit(); + } + + @Test + public void testNonTeardownDisconnectRequest() throws Exception { + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); + assertFalse(mGatewayConnection.isQuitting()); + verify(mGatewayStatusCallback, never()).onQuit(); + // No safe mode timer changes expected. } } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java index 7385204993c0..661e03af4f84 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java @@ -18,6 +18,8 @@ package com.android.server.vcn; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -79,10 +81,20 @@ public class VcnGatewayConnectionDisconnectingStateTest extends VcnGatewayConnec // Should do nothing; already tearing down. assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); verifyTeardownTimeoutAlarmAndGetCallback(false /* expectCanceled */); + assertTrue(mGatewayConnection.isQuitting()); } @Test public void testSafeModeTimeoutNotifiesCallback() { verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState); } + + @Test + public void testNonTeardownDisconnectRequest() throws Exception { + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectingState, mGatewayConnection.getCurrentState()); + assertFalse(mGatewayConnection.isQuitting()); + } } diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java index 5b0850b03f1a..85a0277f8b48 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java @@ -17,6 +17,9 @@ package com.android.server.vcn; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -96,4 +99,22 @@ public class VcnGatewayConnectionRetryTimeoutStateTest extends VcnGatewayConnect public void testSafeModeTimeoutNotifiesCallback() { verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState); } + + @Test + public void testTeardownDisconnectRequest() throws Exception { + mGatewayConnection.teardownAsynchronously(); + mTestLooper.dispatchAll(); + + assertNull(mGatewayConnection.getCurrentState()); + assertTrue(mGatewayConnection.isQuitting()); + } + + @Test + public void testNonTeardownDisconnectRequest() throws Exception { + mGatewayConnection.sendDisconnectRequestedAndAcquireWakelock("TEST", false); + mTestLooper.dispatchAll(); + + assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState()); + assertFalse(mGatewayConnection.isQuitting()); + } } diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java index 9d3368271243..3dd710afed7b 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java @@ -16,6 +16,10 @@ package com.android.server.vcn; +import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; +import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; +import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.mockito.Matchers.any; @@ -33,6 +37,7 @@ import android.net.vcn.VcnGatewayConnectionConfig; import android.net.vcn.VcnGatewayConnectionConfigTest; import android.os.ParcelUuid; import android.os.test.TestLooper; +import android.util.ArraySet; import com.android.server.VcnManagementService.VcnCallback; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; @@ -51,6 +56,11 @@ public class VcnTest { private static final ParcelUuid TEST_SUB_GROUP = new ParcelUuid(new UUID(0, 0)); private static final int NETWORK_SCORE = 0; private static final int PROVIDER_ID = 5; + private static final int[][] TEST_CAPS = + new int[][] { + new int[] {NET_CAPABILITY_INTERNET, NET_CAPABILITY_MMS}, + new int[] {NET_CAPABILITY_DUN} + }; private Context mContext; private VcnContext mVcnContext; @@ -91,13 +101,12 @@ public class VcnTest { mGatewayStatusCallbackCaptor = ArgumentCaptor.forClass(VcnGatewayStatusCallback.class); final VcnConfig.Builder configBuilder = new VcnConfig.Builder(mContext); - for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { + for (final int[] caps : TEST_CAPS) { configBuilder.addGatewayConnectionConfig( - VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(capability)); + VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(caps)); } - configBuilder.addGatewayConnectionConfig(VcnGatewayConnectionConfigTest.buildTestConfig()); - mConfig = configBuilder.build(); + mConfig = configBuilder.build(); mVcn = new Vcn( mVcnContext, @@ -130,8 +139,7 @@ public class VcnTest { @Test public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() { final NetworkRequestListener requestListener = verifyAndGetRequestListener(); - startVcnGatewayWithCapabilities( - requestListener, VcnGatewayConnectionConfigTest.EXPOSED_CAPS); + startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]); final Set<VcnGatewayConnection> gatewayConnections = mVcn.getVcnGatewayConnections(); assertFalse(gatewayConnections.isEmpty()); @@ -153,10 +161,19 @@ public class VcnTest { for (final int capability : VcnGatewayConnectionConfigTest.EXPOSED_CAPS) { startVcnGatewayWithCapabilities(requestListener, capability); } + } + + private void triggerVcnRequestListeners(NetworkRequestListener requestListener) { + for (final int[] caps : TEST_CAPS) { + startVcnGatewayWithCapabilities(requestListener, caps); + } + } - // Each Capability in EXPOSED_CAPS was split into a separate VcnGatewayConnection in #setUp. - // Expect one VcnGatewayConnection per capability. - final int numExpectedGateways = VcnGatewayConnectionConfigTest.EXPOSED_CAPS.length; + public Set<VcnGatewayConnection> startGatewaysAndGetGatewayConnections( + NetworkRequestListener requestListener) { + triggerVcnRequestListeners(requestListener); + + final int numExpectedGateways = TEST_CAPS.length; final Set<VcnGatewayConnection> gatewayConnections = mVcn.getVcnGatewayConnections(); assertEquals(numExpectedGateways, gatewayConnections.size()); @@ -168,7 +185,16 @@ public class VcnTest { any(), mGatewayStatusCallbackCaptor.capture()); - // Doesn't matter which callback this gets - any Gateway entering safe mode should shut down + return gatewayConnections; + } + + @Test + public void testGatewayEnteringSafemodeNotifiesVcn() { + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); + final Set<VcnGatewayConnection> gatewayConnections = + startGatewaysAndGetGatewayConnections(requestListener); + + // Doesn't matter which callback this gets - any Gateway entering Safemode should shut down // all Gateways final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue(); statusCallback.onEnteredSafeMode(); @@ -181,4 +207,31 @@ public class VcnTest { verify(mVcnNetworkProvider).unregisterListener(requestListener); verify(mVcnCallback).onEnteredSafeMode(); } + + @Test + public void testGatewayQuit() { + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); + final Set<VcnGatewayConnection> gatewayConnections = + new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener)); + + final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue(); + statusCallback.onQuit(); + mTestLooper.dispatchAll(); + + // Verify that the VCN requests the networkRequests be resent + assertEquals(1, mVcn.getVcnGatewayConnections().size()); + verify(mVcnNetworkProvider).resendAllRequests(requestListener); + + // Verify that the VcnGatewayConnection is restarted + triggerVcnRequestListeners(requestListener); + mTestLooper.dispatchAll(); + assertEquals(2, mVcn.getVcnGatewayConnections().size()); + verify(mDeps, times(gatewayConnections.size() + 1)) + .newVcnGatewayConnection( + eq(mVcnContext), + eq(TEST_SUB_GROUP), + eq(mSubscriptionSnapshot), + any(), + mGatewayStatusCallbackCaptor.capture()); + } } |