diff options
59 files changed, 2687 insertions, 716 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 8b283a2c6fea..28d492c70f09 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -25711,7 +25711,22 @@ package android.net.vcn { public class VcnManager { method @RequiresPermission("carrier privileges") public void clearVcnConfig(@NonNull android.os.ParcelUuid) throws java.io.IOException; + method public void registerVcnStatusCallback(@NonNull android.os.ParcelUuid, @NonNull java.util.concurrent.Executor, @NonNull android.net.vcn.VcnManager.VcnStatusCallback); method @RequiresPermission("carrier privileges") public void setVcnConfig(@NonNull android.os.ParcelUuid, @NonNull android.net.vcn.VcnConfig) throws java.io.IOException; + method public void unregisterVcnStatusCallback(@NonNull android.net.vcn.VcnManager.VcnStatusCallback); + field public static final int VCN_ERROR_CODE_CONFIG_ERROR = 1; // 0x1 + field public static final int VCN_ERROR_CODE_INTERNAL_ERROR = 0; // 0x0 + field public static final int VCN_ERROR_CODE_NETWORK_ERROR = 2; // 0x2 + field public static final int VCN_STATUS_CODE_ACTIVE = 2; // 0x2 + field public static final int VCN_STATUS_CODE_INACTIVE = 1; // 0x1 + field public static final int VCN_STATUS_CODE_NOT_CONFIGURED = 0; // 0x0 + field public static final int VCN_STATUS_CODE_SAFE_MODE = 3; // 0x3 + } + + public abstract static class VcnManager.VcnStatusCallback { + ctor public VcnManager.VcnStatusCallback(); + method public abstract void onGatewayConnectionError(@NonNull int[], int, @Nullable Throwable); + method public abstract void onVcnStatusChanged(int); } } @@ -39084,6 +39099,9 @@ package android.telephony { method public static boolean isConfigForIdentifiedCarrier(android.os.PersistableBundle); method public void notifyConfigChangedForSubId(int); field public static final String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED"; + field public static final int CARRIER_NR_AVAILABILITY_NONE = 0; // 0x0 + field public static final int CARRIER_NR_AVAILABILITY_NSA = 1; // 0x1 + field public static final int CARRIER_NR_AVAILABILITY_SA = 2; // 0x2 field public static final int DATA_CYCLE_THRESHOLD_DISABLED = -2; // 0xfffffffe field public static final int DATA_CYCLE_USE_PLATFORM_DEFAULT = -1; // 0xffffffff field public static final String ENABLE_EAP_METHOD_PREFIX_BOOL = "enable_eap_method_prefix_bool"; @@ -39142,6 +39160,7 @@ package android.telephony { field public static final String KEY_CARRIER_INSTANT_LETTERING_LENGTH_LIMIT_INT = "carrier_instant_lettering_length_limit_int"; field public static final String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool"; field public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string"; + field public static final String KEY_CARRIER_NR_AVAILABILITY_INT = "carrier_nr_availability_int"; field public static final String KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL = "carrier_rcs_provisioning_required_bool"; field public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string"; field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool"; diff --git a/core/api/system-current.txt b/core/api/system-current.txt index fd6d5a5c0520..2f66ef770312 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -165,6 +165,7 @@ package android { field public static final String PACKET_KEEPALIVE_OFFLOAD = "android.permission.PACKET_KEEPALIVE_OFFLOAD"; field public static final String PEERS_MAC_ADDRESS = "android.permission.PEERS_MAC_ADDRESS"; field public static final String PERFORM_CDMA_PROVISIONING = "android.permission.PERFORM_CDMA_PROVISIONING"; + field public static final String PERFORM_IMS_SINGLE_REGISTRATION = "android.permission.PERFORM_IMS_SINGLE_REGISTRATION"; field public static final String PERFORM_SIM_ACTIVATION = "android.permission.PERFORM_SIM_ACTIVATION"; field public static final String POWER_SAVER = "android.permission.POWER_SAVER"; field public static final String PROVIDE_RESOLVER_RANKER_SERVICE = "android.permission.PROVIDE_RESOLVER_RANKER_SERVICE"; @@ -9637,6 +9638,7 @@ package android.telephony { method public void onSrvccStateChanged(int); method public void onVoiceActivationStateChanged(int); field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGED = 23; // 0x17 + field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED = 35; // 0x23 field @RequiresPermission("android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH") public static final int EVENT_ALWAYS_REPORTED_SIGNAL_STRENGTH_CHANGED = 10; // 0xa field @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_BARRING_INFO_CHANGED = 32; // 0x20 field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_CALL_ATTRIBUTES_CHANGED = 27; // 0x1b @@ -9679,6 +9681,10 @@ package android.telephony { field @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000 } + public static interface PhoneStateListener.AllowedNetworkTypesChangedListener { + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onAllowedNetworkTypesChanged(@NonNull java.util.Map<java.lang.Integer,java.lang.Long>); + } + public static interface PhoneStateListener.CallAttributesChangedListener { method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes); } @@ -10069,7 +10075,7 @@ package android.telephony { } public class TelephonyManager { - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void bootstrapAuthenticationRequest(int, @NonNull android.net.Uri, @NonNull android.telephony.gba.UaSecurityProtocolIdentifier, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.BootstrapAuthenticationCallback); + method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) @WorkerThread public void bootstrapAuthenticationRequest(int, @NonNull android.net.Uri, @NonNull android.telephony.gba.UaSecurityProtocolIdentifier, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.BootstrapAuthenticationCallback); method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult changeIccLockPin(@NonNull String, @NonNull String); method public int checkCarrierPrivilegesForPackage(String); @@ -10081,7 +10087,9 @@ package android.telephony { method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void enableVideoCalling(boolean); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getAidForAppType(int); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypes(); + method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypes(); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypesBitmask(); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypesForReason(int); method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallForwarding(int, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CallForwardingInfoCallback); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getCallWaitingStatus(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); @@ -10115,7 +10123,7 @@ package android.telephony { method public int getMaxNumberOfSimultaneouslyActiveSims(); method public static long getMaxNumberVerificationTimeoutMillis(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String[] getMergedImsisFromGroup(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getPreferredNetworkTypeBitmask(); + method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getPreferredNetworkTypeBitmask(); method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public int getRadioPowerState(); method public int getSimApplicationState(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getSimApplicationState(int); @@ -10170,7 +10178,8 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void resetSettings(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int sendThermalMitigationRequest(@NonNull android.telephony.ThermalMitigationRequest); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAllowedNetworkTypes(long); + method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAllowedNetworkTypes(long); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAllowedNetworkTypesForReason(int, long); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallForwarding(@NonNull android.telephony.CallForwardingInfo, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCallWaitingEnabled(boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean); @@ -10185,7 +10194,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setMultiSimCarrierRestriction(boolean); method public int setNrDualConnectivityState(int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunisticNetworkState(boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmask(long); + method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setPreferredNetworkTypeBitmask(long); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadio(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRadioEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setRadioPower(boolean); @@ -10219,6 +10228,9 @@ package android.telephony { field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED"; field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED"; field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED"; + field public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2; // 0x2 + field public static final int ALLOWED_NETWORK_TYPES_REASON_POWER = 1; // 0x1 + field public static final int ALLOWED_NETWORK_TYPES_REASON_USER = 0; // 0x0 field public static final int CALL_WAITING_STATUS_DISABLED = 2; // 0x2 field public static final int CALL_WAITING_STATUS_ENABLED = 1; // 0x1 field public static final int CALL_WAITING_STATUS_NOT_SUPPORTED = 4; // 0x4 @@ -11510,19 +11522,19 @@ package android.telephony.ims { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getProvisioningStatusForCapability(int, int); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public String getProvisioningStringValue(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getRcsProvisioningStatusForCapability(int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isRcsVolteSingleRegistrationCapable() throws android.telephony.ims.ImsException; + method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public boolean isRcsVolteSingleRegistrationCapable() throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerRcsProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.RcsProvisioningCallback) throws android.telephony.ims.ImsException; + method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void registerRcsProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.RcsProvisioningCallback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(int, int, boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningStringValue(int, @NonNull String); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRcsClientConfiguration(@NonNull android.telephony.ims.RcsClientConfiguration) throws android.telephony.ims.ImsException; + method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void setRcsClientConfiguration(@NonNull android.telephony.ims.RcsClientConfiguration) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setRcsProvisioningStatusForCapability(int, boolean); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void triggerRcsReconfiguration(); + method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void triggerRcsReconfiguration(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.Callback); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterRcsProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.RcsProvisioningCallback); - field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE = "android.telephony.ims.action.RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE"; + method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void unregisterRcsProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.RcsProvisioningCallback); + field @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public static final String ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE = "android.telephony.ims.action.RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE"; field public static final String EXTRA_STATUS = "android.telephony.ims.extra.STATUS"; field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.ims.extra.SUBSCRIPTION_ID"; field public static final int KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID = 67; // 0x43 @@ -11787,10 +11799,10 @@ package android.telephony.ims { } public class SipDelegateManager { - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void createSipDelegate(@NonNull android.telephony.ims.DelegateRequest, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.stub.DelegateConnectionStateCallback, @NonNull android.telephony.ims.stub.DelegateConnectionMessageCallback) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void destroySipDelegate(@NonNull android.telephony.ims.SipDelegateConnection, int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSupported() throws android.telephony.ims.ImsException; - method public void triggerFullNetworkRegistration(@NonNull android.telephony.ims.SipDelegateConnection, @IntRange(from=100, to=699) int, @Nullable String); + method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void createSipDelegate(@NonNull android.telephony.ims.DelegateRequest, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.stub.DelegateConnectionStateCallback, @NonNull android.telephony.ims.stub.DelegateConnectionMessageCallback) throws android.telephony.ims.ImsException; + method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void destroySipDelegate(@NonNull android.telephony.ims.SipDelegateConnection, int); + method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public boolean isSupported() throws android.telephony.ims.ImsException; + method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void triggerFullNetworkRegistration(@NonNull android.telephony.ims.SipDelegateConnection, @IntRange(from=100, to=699) int, @Nullable String); field public static final int DENIED_REASON_INVALID = 4; // 0x4 field public static final int DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE = 1; // 0x1 field public static final int DENIED_REASON_NOT_ALLOWED = 2; // 0x2 @@ -11818,10 +11830,12 @@ package android.telephony.ims { public final class SipMessage implements android.os.Parcelable { ctor public SipMessage(@NonNull String, @NonNull String, @NonNull byte[]); method public int describeContents(); + method @Nullable public String getCallIdParameter(); method @NonNull public byte[] getContent(); method @NonNull public byte[] getEncodedMessage(); method @NonNull public String getHeaderSection(); method @NonNull public String getStartLine(); + method @Nullable public String getViaBranchParameter(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.SipMessage> CREATOR; } diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 268002f1dd52..8f1e2defd215 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -232,10 +232,11 @@ 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); - 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); + // 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); } private static final Set<String> ENABLED_ALGOS = diff --git a/core/java/android/net/vcn/IVcnStatusCallback.aidl b/core/java/android/net/vcn/IVcnStatusCallback.aidl index d91cef592d10..236ae8bb11b2 100644 --- a/core/java/android/net/vcn/IVcnStatusCallback.aidl +++ b/core/java/android/net/vcn/IVcnStatusCallback.aidl @@ -18,7 +18,6 @@ package android.net.vcn; /** @hide */ oneway interface IVcnStatusCallback { - void onEnteredSafeMode(); void onVcnStatusChanged(int statusCode); void onGatewayConnectionError( in int[] gatewayNetworkCapabilities, diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java index eb8c251fec78..8ebf757760c3 100644 --- a/core/java/android/net/vcn/VcnManager.java +++ b/core/java/android/net/vcn/VcnManager.java @@ -359,8 +359,6 @@ public class VcnManager { /** * Value indicating that the VCN for the subscription group is not configured, or that the * callback is not privileged for the subscription group. - * - * @hide */ public static final int VCN_STATUS_CODE_NOT_CONFIGURED = 0; @@ -369,8 +367,6 @@ public class VcnManager { * * <p>A VCN is inactive if a {@link VcnConfig} is present for the subscription group, but the * provisioning package is not privileged. - * - * @hide */ public static final int VCN_STATUS_CODE_INACTIVE = 1; @@ -380,8 +376,6 @@ public class VcnManager { * <p>A VCN is active if a {@link VcnConfig} is present for the subscription, the provisioning * package is privileged, and the VCN is not in Safe Mode. In other words, a VCN is considered * active while it is connecting, fully connected, and disconnecting. - * - * @hide */ public static final int VCN_STATUS_CODE_ACTIVE = 2; @@ -391,8 +385,6 @@ public class VcnManager { * <p>A VCN will be put into Safe Mode if any of the gateway connections were unable to * establish a connection within a system-determined timeout (while underlying networks were * available). - * - * @hide */ public static final int VCN_STATUS_CODE_SAFE_MODE = 3; @@ -407,8 +399,6 @@ public class VcnManager { /** * Value indicating that an internal failure occurred in this Gateway Connection. - * - * @hide */ public static final int VCN_ERROR_CODE_INTERNAL_ERROR = 0; @@ -416,8 +406,6 @@ public class VcnManager { * Value indicating that an error with this Gateway Connection's configuration occurred. * * <p>For example, this error code will be returned after authentication failures. - * - * @hide */ public static final int VCN_ERROR_CODE_CONFIG_ERROR = 1; @@ -427,38 +415,19 @@ public class VcnManager { * <p>For example, this error code will be returned if an underlying {@link android.net.Network} * for this Gateway Connection is lost, or if an error occurs while resolving the connection * endpoint address. - * - * @hide */ public static final int VCN_ERROR_CODE_NETWORK_ERROR = 2; - // TODO: make VcnStatusCallback @SystemApi /** * VcnStatusCallback is the interface for Carrier apps to receive updates for their VCNs. * * <p>VcnStatusCallbacks may be registered before {@link VcnConfig}s are provided for a * subscription group. - * - * @hide */ public abstract static class VcnStatusCallback { private VcnStatusCallbackBinder mCbBinder; /** - * Invoked when the VCN for this Callback's subscription group enters safe mode. - * - * <p>A VCN will be put into safe mode if any of the gateway connections were unable to - * establish a connection within a system-determined timeout (while underlying networks were - * available). - * - * <p>A VCN-configuring app may opt to exit safe mode by (re)setting the VCN configuration - * via {@link #setVcnConfig(ParcelUuid, VcnConfig)}. - * - * @hide - */ - public void onEnteredSafeMode() {} - - /** * Invoked when status of the VCN for this callback's subscription group changes. * * @param statusCode the code for the status change encountered by this {@link @@ -467,15 +436,16 @@ public class VcnManager { public abstract void onVcnStatusChanged(@VcnStatusCode int statusCode); /** - * Invoked when a VCN Gateway Connection corresponding to this callback's subscription + * Invoked when a VCN Gateway Connection corresponding to this callback's subscription group * encounters an error. * - * @param networkCapabilities an array of underlying NetworkCapabilities for the Gateway - * Connection that encountered the error for identification purposes. These will be a - * sorted list with no duplicates, matching one of the {@link + * @param networkCapabilities an array of NetworkCapabilities.NET_CAPABILITY_* capabilities + * for the Gateway Connection that encountered the error, for identification purposes. + * These will be a sorted list with no duplicates and will match {@link + * VcnGatewayConnectionConfig#getRequiredUnderlyingCapabilities()} for one of the {@link * VcnGatewayConnectionConfig}s set in the {@link VcnConfig} for this subscription * group. - * @param errorCode {@link VcnErrorCode} to indicate the error that occurred + * @param errorCode the code to indicate the error that occurred * @param detail Throwable to provide additional information about the error, or {@code * null} if none */ @@ -496,6 +466,10 @@ public class VcnManager { * <p>A {@link VcnStatusCallback} will only be invoked if the registering package has carrier * privileges for the specified subscription at the time of invocation. * + * <p>A {@link VcnStatusCallback} is eligible to begin receiving callbacks once it is registered + * and there is a VCN active for its specified subscription group (this may happen after the + * callback is registered). + * * <p>{@link VcnStatusCallback#onVcnStatusChanged(int)} will be invoked on registration with the * current status for the specified subscription group's VCN. If the registrant is not * privileged for this subscription group, {@link #VCN_STATUS_CODE_NOT_CONFIGURED} will be @@ -505,7 +479,6 @@ public class VcnManager { * @param executor The {@link Executor} to be used for invoking callbacks * @param callback The VcnStatusCallback to be registered * @throws IllegalStateException if callback is currently registered with VcnManager - * @hide */ public void registerVcnStatusCallback( @NonNull ParcelUuid subscriptionGroup, @@ -538,7 +511,6 @@ public class VcnManager { * was registered with. * * @param callback The callback to be unregistered - * @hide */ public void unregisterVcnStatusCallback(@NonNull VcnStatusCallback callback) { requireNonNull(callback, "callback must not be null"); @@ -599,12 +571,6 @@ public class VcnManager { } @Override - public void onEnteredSafeMode() { - Binder.withCleanCallingIdentity( - () -> mExecutor.execute(() -> mCallback.onEnteredSafeMode())); - } - - @Override public void onVcnStatusChanged(@VcnStatusCode int statusCode) { Binder.withCleanCallingIdentity( () -> mExecutor.execute(() -> mCallback.onVcnStatusChanged(statusCode))); diff --git a/core/java/android/net/vcn/persistablebundleutils/CertUtils.java b/core/java/android/net/vcn/persistablebundleutils/CertUtils.java new file mode 100644 index 000000000000..b6036b4a6fd1 --- /dev/null +++ b/core/java/android/net/vcn/persistablebundleutils/CertUtils.java @@ -0,0 +1,46 @@ +/* + * 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.net.vcn.persistablebundleutils; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Objects; + +/** + * CertUtils provides utility methods for constructing Certificate. + * + * @hide + */ +public class CertUtils { + private static final String CERT_TYPE_X509 = "X.509"; + + /** Decodes an ASN.1 DER encoded Certificate */ + public static X509Certificate certificateFromByteArray(byte[] derEncoded) { + Objects.requireNonNull(derEncoded, "derEncoded is null"); + + try { + CertificateFactory certFactory = CertificateFactory.getInstance(CERT_TYPE_X509); + InputStream in = new ByteArrayInputStream(derEncoded); + return (X509Certificate) certFactory.generateCertificate(in); + } catch (CertificateException e) { + throw new IllegalArgumentException("Fail to decode certificate", e); + } + } +} diff --git a/core/java/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java b/core/java/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java new file mode 100644 index 000000000000..ce5ec75f01a2 --- /dev/null +++ b/core/java/android/net/vcn/persistablebundleutils/ChildSaProposalUtils.java @@ -0,0 +1,73 @@ +/* + * 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.net.vcn.persistablebundleutils; + +import static com.android.internal.annotations.VisibleForTesting.Visibility; + +import android.annotation.NonNull; +import android.net.ipsec.ike.ChildSaProposal; +import android.os.PersistableBundle; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.util.List; +import java.util.Objects; + +/** + * Provides utility methods to convert ChildSaProposal to/from PersistableBundle. + * + * @hide + */ +@VisibleForTesting(visibility = Visibility.PRIVATE) +public final class ChildSaProposalUtils extends SaProposalUtilsBase { + /** Serializes a ChildSaProposal to a PersistableBundle. */ + @NonNull + public static PersistableBundle toPersistableBundle(ChildSaProposal proposal) { + return SaProposalUtilsBase.toPersistableBundle(proposal); + } + + /** Constructs a ChildSaProposal by deserializing a PersistableBundle. */ + @NonNull + public static ChildSaProposal fromPersistableBundle(@NonNull PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + final ChildSaProposal.Builder builder = new ChildSaProposal.Builder(); + + final PersistableBundle encryptionBundle = in.getPersistableBundle(ENCRYPT_ALGO_KEY); + Objects.requireNonNull(encryptionBundle, "Encryption algo bundle was null"); + final List<EncryptionAlgoKeyLenPair> encryptList = + PersistableBundleUtils.toList(encryptionBundle, EncryptionAlgoKeyLenPair::new); + for (EncryptionAlgoKeyLenPair t : encryptList) { + builder.addEncryptionAlgorithm(t.encryptionAlgo, t.keyLen); + } + + final int[] integrityAlgoIdArray = in.getIntArray(INTEGRITY_ALGO_KEY); + Objects.requireNonNull(integrityAlgoIdArray, "Integrity algo array was null"); + for (int algo : integrityAlgoIdArray) { + builder.addIntegrityAlgorithm(algo); + } + + final int[] dhGroupArray = in.getIntArray(DH_GROUP_KEY); + Objects.requireNonNull(dhGroupArray, "DH Group array was null"); + for (int dh : dhGroupArray) { + builder.addDhGroup(dh); + } + + return builder.build(); + } +} diff --git a/core/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java b/core/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java new file mode 100644 index 000000000000..853a52da766a --- /dev/null +++ b/core/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtils.java @@ -0,0 +1,276 @@ +/* + * 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.net.vcn.persistablebundleutils; + + +import static com.android.internal.annotations.VisibleForTesting.Visibility; + +import android.annotation.NonNull; +import android.net.eap.EapSessionConfig; +import android.net.eap.EapSessionConfig.EapAkaConfig; +import android.net.eap.EapSessionConfig.EapAkaPrimeConfig; +import android.net.eap.EapSessionConfig.EapMethodConfig; +import android.net.eap.EapSessionConfig.EapMsChapV2Config; +import android.net.eap.EapSessionConfig.EapSimConfig; +import android.net.eap.EapSessionConfig.EapTtlsConfig; +import android.net.eap.EapSessionConfig.EapUiccConfig; +import android.os.PersistableBundle; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.Objects; + +/** + * Provides utility methods to convert EapSessionConfig to/from PersistableBundle. + * + * @hide + */ +@VisibleForTesting(visibility = Visibility.PRIVATE) +public final class EapSessionConfigUtils { + private static final String EAP_ID_KEY = "EAP_ID_KEY"; + private static final String EAP_SIM_CONFIG_KEY = "EAP_SIM_CONFIG_KEY"; + private static final String EAP_TTLS_CONFIG_KEY = "EAP_TTLS_CONFIG_KEY"; + private static final String EAP_AKA_CONFIG_KEY = "EAP_AKA_CONFIG_KEY"; + private static final String EAP_MSCHAP_V2_CONFIG_KEY = "EAP_MSCHAP_V2_CONFIG_KEY"; + private static final String EAP_AKA_PRIME_CONFIG_KEY = "EAP_AKA_PRIME_CONFIG_KEY"; + + /** Serializes an EapSessionConfig to a PersistableBundle. */ + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull EapSessionConfig config) { + final PersistableBundle result = new PersistableBundle(); + + result.putPersistableBundle( + EAP_ID_KEY, PersistableBundleUtils.fromByteArray(config.getEapIdentity())); + + if (config.getEapSimConfig() != null) { + result.putPersistableBundle( + EAP_SIM_CONFIG_KEY, + EapSimConfigUtils.toPersistableBundle(config.getEapSimConfig())); + } + + if (config.getEapTtlsConfig() != null) { + result.putPersistableBundle( + EAP_TTLS_CONFIG_KEY, + EapTtlsConfigUtils.toPersistableBundle(config.getEapTtlsConfig())); + } + + if (config.getEapAkaConfig() != null) { + result.putPersistableBundle( + EAP_AKA_CONFIG_KEY, + EapAkaConfigUtils.toPersistableBundle(config.getEapAkaConfig())); + } + + if (config.getEapMsChapV2Config() != null) { + result.putPersistableBundle( + EAP_MSCHAP_V2_CONFIG_KEY, + EapMsChapV2ConfigUtils.toPersistableBundle(config.getEapMsChapV2Config())); + } + + if (config.getEapAkaPrimeConfig() != null) { + result.putPersistableBundle( + EAP_AKA_PRIME_CONFIG_KEY, + EapAkaPrimeConfigUtils.toPersistableBundle(config.getEapAkaPrimeConfig())); + } + + return result; + } + + /** Constructs an EapSessionConfig by deserializing a PersistableBundle. */ + @NonNull + public static EapSessionConfig fromPersistableBundle(@NonNull PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + final EapSessionConfig.Builder builder = new EapSessionConfig.Builder(); + + final PersistableBundle eapIdBundle = in.getPersistableBundle(EAP_ID_KEY); + Objects.requireNonNull(eapIdBundle, "EAP ID was null"); + builder.setEapIdentity(PersistableBundleUtils.toByteArray(eapIdBundle)); + + final PersistableBundle simBundle = in.getPersistableBundle(EAP_SIM_CONFIG_KEY); + if (simBundle != null) { + EapSimConfigUtils.setBuilderByReadingPersistableBundle(simBundle, builder); + } + + final PersistableBundle ttlsBundle = in.getPersistableBundle(EAP_TTLS_CONFIG_KEY); + if (ttlsBundle != null) { + EapTtlsConfigUtils.setBuilderByReadingPersistableBundle(ttlsBundle, builder); + } + + final PersistableBundle akaBundle = in.getPersistableBundle(EAP_AKA_CONFIG_KEY); + if (akaBundle != null) { + EapAkaConfigUtils.setBuilderByReadingPersistableBundle(akaBundle, builder); + } + + final PersistableBundle msChapV2Bundle = in.getPersistableBundle(EAP_MSCHAP_V2_CONFIG_KEY); + if (msChapV2Bundle != null) { + EapMsChapV2ConfigUtils.setBuilderByReadingPersistableBundle(msChapV2Bundle, builder); + } + + final PersistableBundle akaPrimeBundle = in.getPersistableBundle(EAP_AKA_PRIME_CONFIG_KEY); + if (akaPrimeBundle != null) { + EapAkaPrimeConfigUtils.setBuilderByReadingPersistableBundle(akaPrimeBundle, builder); + } + + return builder.build(); + } + + private static class EapMethodConfigUtils { + private static final String METHOD_TYPE = "METHOD_TYPE"; + + /** Serializes an EapMethodConfig to a PersistableBundle. */ + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull EapMethodConfig config) { + final PersistableBundle result = new PersistableBundle(); + result.putInt(METHOD_TYPE, config.getMethodType()); + return result; + } + } + + private static class EapUiccConfigUtils extends EapMethodConfigUtils { + static final String SUB_ID_KEY = "SUB_ID_KEY"; + static final String APP_TYPE_KEY = "APP_TYPE_KEY"; + + @NonNull + protected static PersistableBundle toPersistableBundle(@NonNull EapUiccConfig config) { + final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config); + result.putInt(SUB_ID_KEY, config.getSubId()); + result.putInt(APP_TYPE_KEY, config.getAppType()); + + return result; + } + } + + private static final class EapSimConfigUtils extends EapUiccConfigUtils { + @NonNull + public static PersistableBundle toPersistableBundle(EapSimConfig config) { + return EapUiccConfigUtils.toPersistableBundle(config); + } + + public static void setBuilderByReadingPersistableBundle( + @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) { + Objects.requireNonNull(in, "PersistableBundle was null"); + builder.setEapSimConfig(in.getInt(SUB_ID_KEY), in.getInt(APP_TYPE_KEY)); + } + } + + private static class EapAkaConfigUtils extends EapUiccConfigUtils { + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull EapAkaConfig config) { + return EapUiccConfigUtils.toPersistableBundle(config); + } + + public static void setBuilderByReadingPersistableBundle( + @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) { + Objects.requireNonNull(in, "PersistableBundle was null"); + builder.setEapAkaConfig(in.getInt(SUB_ID_KEY), in.getInt(APP_TYPE_KEY)); + } + } + + private static final class EapAkaPrimeConfigUtils extends EapAkaConfigUtils { + private static final String NETWORK_NAME_KEY = "NETWORK_NAME_KEY"; + private static final String ALL_MISMATCHED_NETWORK_KEY = "ALL_MISMATCHED_NETWORK_KEY"; + + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull EapAkaPrimeConfig config) { + final PersistableBundle result = EapUiccConfigUtils.toPersistableBundle(config); + result.putString(NETWORK_NAME_KEY, config.getNetworkName()); + result.putBoolean(ALL_MISMATCHED_NETWORK_KEY, config.allowsMismatchedNetworkNames()); + + return result; + } + + public static void setBuilderByReadingPersistableBundle( + @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) { + Objects.requireNonNull(in, "PersistableBundle was null"); + builder.setEapAkaPrimeConfig( + in.getInt(SUB_ID_KEY), + in.getInt(APP_TYPE_KEY), + in.getString(NETWORK_NAME_KEY), + in.getBoolean(ALL_MISMATCHED_NETWORK_KEY)); + } + } + + private static final class EapMsChapV2ConfigUtils extends EapMethodConfigUtils { + private static final String USERNAME_KEY = "USERNAME_KEY"; + private static final String PASSWORD_KEY = "PASSWORD_KEY"; + + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull EapMsChapV2Config config) { + final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config); + result.putString(USERNAME_KEY, config.getUsername()); + result.putString(PASSWORD_KEY, config.getPassword()); + + return result; + } + + public static void setBuilderByReadingPersistableBundle( + @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) { + Objects.requireNonNull(in, "PersistableBundle was null"); + builder.setEapMsChapV2Config(in.getString(USERNAME_KEY), in.getString(PASSWORD_KEY)); + } + } + + private static final class EapTtlsConfigUtils extends EapMethodConfigUtils { + private static final String TRUST_CERT_KEY = "TRUST_CERT_KEY"; + private static final String EAP_SESSION_CONFIG_KEY = "EAP_SESSION_CONFIG_KEY"; + + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull EapTtlsConfig config) { + final PersistableBundle result = EapMethodConfigUtils.toPersistableBundle(config); + try { + if (config.getServerCaCert() != null) { + final PersistableBundle caBundle = + PersistableBundleUtils.fromByteArray( + config.getServerCaCert().getEncoded()); + result.putPersistableBundle(TRUST_CERT_KEY, caBundle); + } + } catch (CertificateEncodingException e) { + throw new IllegalStateException("Fail to encode the certificate"); + } + + result.putPersistableBundle( + EAP_SESSION_CONFIG_KEY, + EapSessionConfigUtils.toPersistableBundle(config.getInnerEapSessionConfig())); + + return result; + } + + public static void setBuilderByReadingPersistableBundle( + @NonNull PersistableBundle in, @NonNull EapSessionConfig.Builder builder) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + final PersistableBundle caBundle = in.getPersistableBundle(TRUST_CERT_KEY); + X509Certificate caCert = null; + if (caBundle != null) { + caCert = + CertUtils.certificateFromByteArray( + PersistableBundleUtils.toByteArray(caBundle)); + } + + final PersistableBundle eapSessionConfigBundle = + in.getPersistableBundle(EAP_SESSION_CONFIG_KEY); + Objects.requireNonNull(eapSessionConfigBundle, "Inner EAP Session Config was null"); + final EapSessionConfig eapSessionConfig = + EapSessionConfigUtils.fromPersistableBundle(eapSessionConfigBundle); + + builder.setEapTtlsConfig(caCert, eapSessionConfig); + } + } +} diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java new file mode 100644 index 000000000000..6acb34ebb78e --- /dev/null +++ b/core/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtils.java @@ -0,0 +1,143 @@ +/* + * 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.net.vcn.persistablebundleutils; + +import static com.android.internal.annotations.VisibleForTesting.Visibility; + +import android.annotation.NonNull; +import android.net.InetAddresses; +import android.net.ipsec.ike.IkeDerAsn1DnIdentification; +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeIdentification; +import android.net.ipsec.ike.IkeIpv4AddrIdentification; +import android.net.ipsec.ike.IkeIpv6AddrIdentification; +import android.net.ipsec.ike.IkeKeyIdIdentification; +import android.net.ipsec.ike.IkeRfc822AddrIdentification; +import android.os.PersistableBundle; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.util.Objects; + +import javax.security.auth.x500.X500Principal; + +/** + * Abstract utility class to convert IkeIdentification to/from PersistableBundle. + * + * @hide + */ +@VisibleForTesting(visibility = Visibility.PRIVATE) +public final class IkeIdentificationUtils { + private static final String ID_TYPE_KEY = "ID_TYPE_KEY"; + + private static final String DER_ASN1_DN_KEY = "DER_ASN1_DN_KEY"; + private static final String FQDN_KEY = "FQDN_KEY"; + private static final String KEY_ID_KEY = "KEY_ID_KEY"; + private static final String IP4_ADDRESS_KEY = "IP4_ADDRESS_KEY"; + private static final String IP6_ADDRESS_KEY = "IP6_ADDRESS_KEY"; + private static final String RFC822_ADDRESS_KEY = "RFC822_ADDRESS_KEY"; + + private static final int ID_TYPE_DER_ASN1_DN = 1; + private static final int ID_TYPE_FQDN = 2; + private static final int ID_TYPE_IPV4_ADDR = 3; + private static final int ID_TYPE_IPV6_ADDR = 4; + private static final int ID_TYPE_KEY_ID = 5; + private static final int ID_TYPE_RFC822_ADDR = 6; + + /** Serializes an IkeIdentification to a PersistableBundle. */ + @NonNull + public static PersistableBundle toPersistableBundle(@NonNull IkeIdentification ikeId) { + if (ikeId instanceof IkeDerAsn1DnIdentification) { + final PersistableBundle result = createPersistableBundle(ID_TYPE_DER_ASN1_DN); + IkeDerAsn1DnIdentification id = (IkeDerAsn1DnIdentification) ikeId; + result.putPersistableBundle( + DER_ASN1_DN_KEY, + PersistableBundleUtils.fromByteArray(id.derAsn1Dn.getEncoded())); + return result; + } else if (ikeId instanceof IkeFqdnIdentification) { + final PersistableBundle result = createPersistableBundle(ID_TYPE_FQDN); + IkeFqdnIdentification id = (IkeFqdnIdentification) ikeId; + result.putString(FQDN_KEY, id.fqdn); + return result; + } else if (ikeId instanceof IkeIpv4AddrIdentification) { + final PersistableBundle result = createPersistableBundle(ID_TYPE_IPV4_ADDR); + IkeIpv4AddrIdentification id = (IkeIpv4AddrIdentification) ikeId; + result.putString(IP4_ADDRESS_KEY, id.ipv4Address.getHostAddress()); + return result; + } else if (ikeId instanceof IkeIpv6AddrIdentification) { + final PersistableBundle result = createPersistableBundle(ID_TYPE_IPV6_ADDR); + IkeIpv6AddrIdentification id = (IkeIpv6AddrIdentification) ikeId; + result.putString(IP6_ADDRESS_KEY, id.ipv6Address.getHostAddress()); + return result; + } else if (ikeId instanceof IkeKeyIdIdentification) { + final PersistableBundle result = createPersistableBundle(ID_TYPE_KEY_ID); + IkeKeyIdIdentification id = (IkeKeyIdIdentification) ikeId; + result.putPersistableBundle(KEY_ID_KEY, PersistableBundleUtils.fromByteArray(id.keyId)); + return result; + } else if (ikeId instanceof IkeRfc822AddrIdentification) { + final PersistableBundle result = createPersistableBundle(ID_TYPE_RFC822_ADDR); + IkeRfc822AddrIdentification id = (IkeRfc822AddrIdentification) ikeId; + result.putString(RFC822_ADDRESS_KEY, id.rfc822Name); + return result; + } else { + throw new IllegalStateException("Unrecognized IkeIdentification subclass"); + } + } + + private static PersistableBundle createPersistableBundle(int idType) { + final PersistableBundle result = new PersistableBundle(); + result.putInt(ID_TYPE_KEY, idType); + return result; + } + + /** Constructs an IkeIdentification by deserializing a PersistableBundle. */ + @NonNull + public static IkeIdentification fromPersistableBundle(@NonNull PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + int idType = in.getInt(ID_TYPE_KEY); + switch (idType) { + case ID_TYPE_DER_ASN1_DN: + final PersistableBundle dnBundle = in.getPersistableBundle(DER_ASN1_DN_KEY); + Objects.requireNonNull(dnBundle, "ASN1 DN was null"); + return new IkeDerAsn1DnIdentification( + new X500Principal(PersistableBundleUtils.toByteArray(dnBundle))); + case ID_TYPE_FQDN: + return new IkeFqdnIdentification(in.getString(FQDN_KEY)); + case ID_TYPE_IPV4_ADDR: + final String v4AddressStr = in.getString(IP4_ADDRESS_KEY); + Objects.requireNonNull(v4AddressStr, "IPv4 address was null"); + return new IkeIpv4AddrIdentification( + (Inet4Address) InetAddresses.parseNumericAddress(v4AddressStr)); + case ID_TYPE_IPV6_ADDR: + final String v6AddressStr = in.getString(IP6_ADDRESS_KEY); + Objects.requireNonNull(v6AddressStr, "IPv6 address was null"); + return new IkeIpv6AddrIdentification( + (Inet6Address) InetAddresses.parseNumericAddress(v6AddressStr)); + case ID_TYPE_KEY_ID: + final PersistableBundle keyIdBundle = in.getPersistableBundle(KEY_ID_KEY); + Objects.requireNonNull(in, "Key ID was null"); + return new IkeKeyIdIdentification(PersistableBundleUtils.toByteArray(keyIdBundle)); + case ID_TYPE_RFC822_ADDR: + return new IkeRfc822AddrIdentification(in.getString(RFC822_ADDRESS_KEY)); + default: + throw new IllegalStateException("Unrecognized IKE ID type: " + idType); + } + } +} diff --git a/core/java/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java b/core/java/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java new file mode 100644 index 000000000000..1459671f4136 --- /dev/null +++ b/core/java/android/net/vcn/persistablebundleutils/IkeSaProposalUtils.java @@ -0,0 +1,87 @@ +/* + * 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.net.vcn.persistablebundleutils; + +import static com.android.internal.annotations.VisibleForTesting.Visibility; + +import android.annotation.NonNull; +import android.net.ipsec.ike.IkeSaProposal; +import android.os.PersistableBundle; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.util.List; +import java.util.Objects; + +/** + * Provides utility methods to convert IkeSaProposal to/from PersistableBundle. + * + * @hide + */ +@VisibleForTesting(visibility = Visibility.PRIVATE) +public final class IkeSaProposalUtils extends SaProposalUtilsBase { + private static final String PRF_KEY = "PRF_KEY"; + + /** Serializes an IkeSaProposal to a PersistableBundle. */ + @NonNull + public static PersistableBundle toPersistableBundle(IkeSaProposal proposal) { + final PersistableBundle result = SaProposalUtilsBase.toPersistableBundle(proposal); + + final int[] prfArray = + proposal.getPseudorandomFunctions().stream().mapToInt(i -> i).toArray(); + result.putIntArray(PRF_KEY, prfArray); + + return result; + } + + /** Constructs an IkeSaProposal by deserializing a PersistableBundle. */ + @NonNull + public static IkeSaProposal fromPersistableBundle(@NonNull PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + final IkeSaProposal.Builder builder = new IkeSaProposal.Builder(); + + final PersistableBundle encryptionBundle = in.getPersistableBundle(ENCRYPT_ALGO_KEY); + Objects.requireNonNull(encryptionBundle, "Encryption algo bundle was null"); + final List<EncryptionAlgoKeyLenPair> encryptList = + PersistableBundleUtils.toList(encryptionBundle, EncryptionAlgoKeyLenPair::new); + for (EncryptionAlgoKeyLenPair t : encryptList) { + builder.addEncryptionAlgorithm(t.encryptionAlgo, t.keyLen); + } + + final int[] integrityAlgoIdArray = in.getIntArray(INTEGRITY_ALGO_KEY); + Objects.requireNonNull(integrityAlgoIdArray, "Integrity algo array was null"); + for (int algo : integrityAlgoIdArray) { + builder.addIntegrityAlgorithm(algo); + } + + final int[] dhGroupArray = in.getIntArray(DH_GROUP_KEY); + Objects.requireNonNull(dhGroupArray, "DH Group array was null"); + for (int dh : dhGroupArray) { + builder.addDhGroup(dh); + } + + final int[] prfArray = in.getIntArray(PRF_KEY); + Objects.requireNonNull(prfArray, "PRF array was null"); + for (int prf : prfArray) { + builder.addPseudorandomFunction(prf); + } + + return builder.build(); + } +} diff --git a/core/java/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java b/core/java/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java new file mode 100644 index 000000000000..0c9ee8432798 --- /dev/null +++ b/core/java/android/net/vcn/persistablebundleutils/SaProposalUtilsBase.java @@ -0,0 +1,96 @@ +/* + * 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.net.vcn.persistablebundleutils; + +import android.annotation.NonNull; +import android.net.ipsec.ike.SaProposal; +import android.os.PersistableBundle; +import android.util.Pair; + +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Abstract utility class to convert SaProposal to/from PersistableBundle. + * + * @hide + */ +abstract class SaProposalUtilsBase { + static final String ENCRYPT_ALGO_KEY = "ENCRYPT_ALGO_KEY"; + static final String INTEGRITY_ALGO_KEY = "INTEGRITY_ALGO_KEY"; + static final String DH_GROUP_KEY = "DH_GROUP_KEY"; + + static class EncryptionAlgoKeyLenPair { + private static final String ALGO_KEY = "ALGO_KEY"; + private static final String KEY_LEN_KEY = "KEY_LEN_KEY"; + + public final int encryptionAlgo; + public final int keyLen; + + EncryptionAlgoKeyLenPair(int encryptionAlgo, int keyLen) { + this.encryptionAlgo = encryptionAlgo; + this.keyLen = keyLen; + } + + EncryptionAlgoKeyLenPair(PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + this.encryptionAlgo = in.getInt(ALGO_KEY); + this.keyLen = in.getInt(KEY_LEN_KEY); + } + + public PersistableBundle toPersistableBundle() { + final PersistableBundle result = new PersistableBundle(); + + result.putInt(ALGO_KEY, encryptionAlgo); + result.putInt(KEY_LEN_KEY, keyLen); + + return result; + } + } + + /** + * Serializes common info of a SaProposal to a PersistableBundle. + * + * @hide + */ + @NonNull + static PersistableBundle toPersistableBundle(SaProposal proposal) { + final PersistableBundle result = new PersistableBundle(); + + final List<EncryptionAlgoKeyLenPair> encryptAlgoKeyLenPairs = new ArrayList<>(); + for (Pair<Integer, Integer> pair : proposal.getEncryptionAlgorithms()) { + encryptAlgoKeyLenPairs.add(new EncryptionAlgoKeyLenPair(pair.first, pair.second)); + } + final PersistableBundle encryptionBundle = + PersistableBundleUtils.fromList( + encryptAlgoKeyLenPairs, EncryptionAlgoKeyLenPair::toPersistableBundle); + result.putPersistableBundle(ENCRYPT_ALGO_KEY, encryptionBundle); + + final int[] integrityAlgoIdArray = + proposal.getIntegrityAlgorithms().stream().mapToInt(i -> i).toArray(); + result.putIntArray(INTEGRITY_ALGO_KEY, integrityAlgoIdArray); + + final int[] dhGroupArray = proposal.getDhGroups().stream().mapToInt(i -> i).toArray(); + result.putIntArray(DH_GROUP_KEY, dhGroupArray); + + return result; + } +} diff --git a/core/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java b/core/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java new file mode 100644 index 000000000000..e62acac14bd7 --- /dev/null +++ b/core/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtils.java @@ -0,0 +1,285 @@ +/* + * 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.net.vcn.persistablebundleutils; + +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + +import static com.android.internal.annotations.VisibleForTesting.Visibility; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.InetAddresses; +import android.net.ipsec.ike.ChildSaProposal; +import android.net.ipsec.ike.IkeTrafficSelector; +import android.net.ipsec.ike.TunnelModeChildSessionParams; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Address; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DhcpServer; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4DnsServer; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv4Netmask; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6Address; +import android.net.ipsec.ike.TunnelModeChildSessionParams.ConfigRequestIpv6DnsServer; +import android.net.ipsec.ike.TunnelModeChildSessionParams.TunnelModeChildConfigRequest; +import android.os.PersistableBundle; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.vcn.util.PersistableBundleUtils; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Provides utility methods to convert TunnelModeChildSessionParams to/from PersistableBundle. + * + * @hide + */ +@VisibleForTesting(visibility = Visibility.PRIVATE) +public final class TunnelModeChildSessionParamsUtils { + private static final String TAG = TunnelModeChildSessionParamsUtils.class.getSimpleName(); + + private static final String INBOUND_TS_KEY = "INBOUND_TS_KEY"; + private static final String OUTBOUND_TS_KEY = "OUTBOUND_TS_KEY"; + private static final String SA_PROPOSALS_KEY = "SA_PROPOSALS_KEY"; + private static final String HARD_LIFETIME_SEC_KEY = "HARD_LIFETIME_SEC_KEY"; + private static final String SOFT_LIFETIME_SEC_KEY = "SOFT_LIFETIME_SEC_KEY"; + private static final String CONFIG_REQUESTS_KEY = "CONFIG_REQUESTS_KEY"; + + private static class ConfigRequest { + private static final int TYPE_IPV4_ADDRESS = 1; + private static final int TYPE_IPV6_ADDRESS = 2; + private static final int TYPE_IPV4_DNS = 3; + private static final int TYPE_IPV6_DNS = 4; + private static final int TYPE_IPV4_DHCP = 5; + private static final int TYPE_IPV4_NETMASK = 6; + + private static final String TYPE_KEY = "type"; + private static final String VALUE_KEY = "address"; + private static final String IP6_PREFIX_LEN = "ip6PrefixLen"; + + private static final int PREFIX_LEN_UNUSED = -1; + + public final int type; + public final int ip6PrefixLen; + + // Null when it is an empty request + @Nullable public final InetAddress address; + + ConfigRequest(TunnelModeChildConfigRequest config) { + int prefixLen = PREFIX_LEN_UNUSED; + + if (config instanceof ConfigRequestIpv4Address) { + type = TYPE_IPV4_ADDRESS; + address = ((ConfigRequestIpv4Address) config).getAddress(); + } else if (config instanceof ConfigRequestIpv6Address) { + type = TYPE_IPV6_ADDRESS; + address = ((ConfigRequestIpv6Address) config).getAddress(); + if (address != null) { + prefixLen = ((ConfigRequestIpv6Address) config).getPrefixLength(); + } + } else if (config instanceof ConfigRequestIpv4DnsServer) { + type = TYPE_IPV4_DNS; + address = null; + } else if (config instanceof ConfigRequestIpv6DnsServer) { + type = TYPE_IPV6_DNS; + address = null; + } else if (config instanceof ConfigRequestIpv4DhcpServer) { + type = TYPE_IPV4_DHCP; + address = null; + } else if (config instanceof ConfigRequestIpv4Netmask) { + type = TYPE_IPV4_NETMASK; + address = null; + } else { + throw new IllegalStateException("Unknown TunnelModeChildConfigRequest"); + } + + ip6PrefixLen = prefixLen; + } + + ConfigRequest(PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + type = in.getInt(TYPE_KEY); + ip6PrefixLen = in.getInt(IP6_PREFIX_LEN); + + String addressStr = in.getString(VALUE_KEY); + if (addressStr == null) { + address = null; + } else { + address = InetAddresses.parseNumericAddress(addressStr); + } + } + + @NonNull + public PersistableBundle toPersistableBundle() { + final PersistableBundle result = new PersistableBundle(); + + result.putInt(TYPE_KEY, type); + result.putInt(IP6_PREFIX_LEN, ip6PrefixLen); + + if (address != null) { + result.putString(VALUE_KEY, address.getHostAddress()); + } + + return result; + } + } + + /** Serializes a TunnelModeChildSessionParams to a PersistableBundle. */ + @NonNull + public static PersistableBundle toPersistableBundle( + @NonNull TunnelModeChildSessionParams params) { + final PersistableBundle result = new PersistableBundle(); + + final PersistableBundle saProposalBundle = + PersistableBundleUtils.fromList( + params.getSaProposals(), ChildSaProposalUtils::toPersistableBundle); + result.putPersistableBundle(SA_PROPOSALS_KEY, saProposalBundle); + + final PersistableBundle inTsBundle = + PersistableBundleUtils.fromList( + params.getInboundTrafficSelectors(), + IkeTrafficSelectorUtils::toPersistableBundle); + result.putPersistableBundle(INBOUND_TS_KEY, inTsBundle); + + final PersistableBundle outTsBundle = + PersistableBundleUtils.fromList( + params.getOutboundTrafficSelectors(), + IkeTrafficSelectorUtils::toPersistableBundle); + result.putPersistableBundle(OUTBOUND_TS_KEY, outTsBundle); + + result.putInt(HARD_LIFETIME_SEC_KEY, params.getHardLifetimeSeconds()); + result.putInt(SOFT_LIFETIME_SEC_KEY, params.getSoftLifetimeSeconds()); + + final List<ConfigRequest> reqList = new ArrayList<>(); + for (TunnelModeChildConfigRequest req : params.getConfigurationRequests()) { + reqList.add(new ConfigRequest(req)); + } + final PersistableBundle configReqListBundle = + PersistableBundleUtils.fromList(reqList, ConfigRequest::toPersistableBundle); + result.putPersistableBundle(CONFIG_REQUESTS_KEY, configReqListBundle); + + return result; + } + + private static List<IkeTrafficSelector> getTsFromPersistableBundle( + PersistableBundle in, String key) { + PersistableBundle tsBundle = in.getPersistableBundle(key); + Objects.requireNonNull(tsBundle, "Value for key " + key + " was null"); + return PersistableBundleUtils.toList( + tsBundle, IkeTrafficSelectorUtils::fromPersistableBundle); + } + + /** Constructs a TunnelModeChildSessionParams by deserializing a PersistableBundle. */ + @NonNull + public static TunnelModeChildSessionParams fromPersistableBundle( + @NonNull PersistableBundle in) { + Objects.requireNonNull(in, "PersistableBundle was null"); + + final TunnelModeChildSessionParams.Builder builder = + new TunnelModeChildSessionParams.Builder(); + + final PersistableBundle proposalBundle = in.getPersistableBundle(SA_PROPOSALS_KEY); + Objects.requireNonNull(proposalBundle, "SA proposal was null"); + final List<ChildSaProposal> proposals = + PersistableBundleUtils.toList( + proposalBundle, ChildSaProposalUtils::fromPersistableBundle); + for (ChildSaProposal p : proposals) { + builder.addSaProposal(p); + } + + for (IkeTrafficSelector ts : getTsFromPersistableBundle(in, INBOUND_TS_KEY)) { + builder.addInboundTrafficSelectors(ts); + } + + for (IkeTrafficSelector ts : getTsFromPersistableBundle(in, OUTBOUND_TS_KEY)) { + builder.addOutboundTrafficSelectors(ts); + } + + builder.setLifetimeSeconds( + in.getInt(HARD_LIFETIME_SEC_KEY), in.getInt(SOFT_LIFETIME_SEC_KEY)); + final PersistableBundle configReqListBundle = in.getPersistableBundle(CONFIG_REQUESTS_KEY); + Objects.requireNonNull(configReqListBundle, "Config request list was null"); + final List<ConfigRequest> reqList = + PersistableBundleUtils.toList(configReqListBundle, ConfigRequest::new); + + boolean hasIpv4AddressReq = false; + boolean hasIpv4NetmaskReq = false; + for (ConfigRequest req : reqList) { + switch (req.type) { + case ConfigRequest.TYPE_IPV4_ADDRESS: + hasIpv4AddressReq = true; + if (req.address == null) { + builder.addInternalAddressRequest(AF_INET); + } else { + builder.addInternalAddressRequest((Inet4Address) req.address); + } + break; + case ConfigRequest.TYPE_IPV6_ADDRESS: + if (req.address == null) { + builder.addInternalAddressRequest(AF_INET6); + } else { + builder.addInternalAddressRequest( + (Inet6Address) req.address, req.ip6PrefixLen); + } + break; + case ConfigRequest.TYPE_IPV4_NETMASK: + // Do not need to set netmask because it will be automatically set by the + // builder when an IPv4 internal address request is set. + hasIpv4NetmaskReq = true; + break; + case ConfigRequest.TYPE_IPV4_DNS: + if (req.address != null) { + Log.w(TAG, "Requesting a specific IPv4 DNS server is unsupported"); + } + builder.addInternalDnsServerRequest(AF_INET); + break; + case ConfigRequest.TYPE_IPV6_DNS: + if (req.address != null) { + Log.w(TAG, "Requesting a specific IPv6 DNS server is unsupported"); + } + builder.addInternalDnsServerRequest(AF_INET6); + break; + case ConfigRequest.TYPE_IPV4_DHCP: + if (req.address != null) { + Log.w(TAG, "Requesting a specific IPv4 DHCP server is unsupported"); + } + builder.addInternalDhcpServerRequest(AF_INET); + break; + default: + throw new IllegalArgumentException( + "Unrecognized config request type: " + req.type); + } + } + + if (hasIpv4AddressReq != hasIpv4NetmaskReq) { + Log.w( + TAG, + String.format( + "Expect IPv4 address request and IPv4 netmask request either both" + + " exist or both absent, but found hasIpv4AddressReq exists? %b," + + " hasIpv4AddressReq exists? %b, ", + hasIpv4AddressReq, hasIpv4NetmaskReq)); + } + + return builder.build(); + } +} diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index 9ffc5aa0022c..bf2898137967 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -333,7 +333,7 @@ public class ZygoteProcess { * started. * @param pkgDataInfoMap Map from related package names to private data directory * volume UUID and inode number. - * @param whitelistedDataInfoMap Map from allowlisted package names to private data directory + * @param allowlistedDataInfoList Map from allowlisted package names to private data directory * volume UUID and inode number. * @param bindMountAppsData whether zygote needs to mount CE and DE data. * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data. @@ -359,7 +359,7 @@ public class ZygoteProcess { @Nullable Map<String, Pair<String, Long>> pkgDataInfoMap, @Nullable Map<String, Pair<String, Long>> - whitelistedDataInfoMap, + allowlistedDataInfoList, boolean bindMountAppsData, boolean bindMountAppStorageDirs, @Nullable String[] zygoteArgs) { @@ -373,7 +373,7 @@ public class ZygoteProcess { runtimeFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false, packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges, - pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData, + pkgDataInfoMap, allowlistedDataInfoList, bindMountAppsData, bindMountAppStorageDirs, zygoteArgs); } catch (ZygoteStartFailedEx ex) { Log.e(LOG_TAG, @@ -615,7 +615,7 @@ public class ZygoteProcess { * @param disabledCompatChanges a list of disabled compat changes for the process being started. * @param pkgDataInfoMap Map from related package names to private data directory volume UUID * and inode number. - * @param whitelistedDataInfoMap Map from allowlisted package names to private data directory + * @param allowlistedDataInfoList Map from allowlisted package names to private data directory * volume UUID and inode number. * @param bindMountAppsData whether zygote needs to mount CE and DE data. * @param bindMountAppStorageDirs whether zygote needs to mount Android/obb and Android/data. @@ -642,7 +642,7 @@ public class ZygoteProcess { @Nullable Map<String, Pair<String, Long>> pkgDataInfoMap, @Nullable Map<String, Pair<String, Long>> - whitelistedDataInfoMap, + allowlistedDataInfoList, boolean bindMountAppsData, boolean bindMountAppStorageDirs, @Nullable String[] extraArgs) @@ -733,12 +733,12 @@ public class ZygoteProcess { } argsForZygote.add(sb.toString()); } - if (whitelistedDataInfoMap != null && whitelistedDataInfoMap.size() > 0) { + if (allowlistedDataInfoList != null && allowlistedDataInfoList.size() > 0) { StringBuilder sb = new StringBuilder(); - sb.append(Zygote.WHITELISTED_DATA_INFO_MAP); + sb.append(Zygote.ALLOWLISTED_DATA_INFO_MAP); sb.append("="); boolean started = false; - for (Map.Entry<String, Pair<String, Long>> entry : whitelistedDataInfoMap.entrySet()) { + for (Map.Entry<String, Pair<String, Long>> entry : allowlistedDataInfoList.entrySet()) { if (started) { sb.append(','); } @@ -1318,7 +1318,7 @@ public class ZygoteProcess { true /* startChildZygote */, null /* packageName */, ZYGOTE_POLICY_FLAG_SYSTEM_PROCESS /* zygotePolicyFlags */, false /* isTopApp */, null /* disabledCompatChanges */, null /* pkgDataInfoMap */, - null /* whitelistedDataInfoMap */, true /* bindMountAppsData*/, + null /* allowlistedDataInfoList */, true /* bindMountAppsData*/, /* bindMountAppStorageDirs */ false, extraArgs); } catch (ZygoteStartFailedEx ex) { diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 727769cb5ab8..9cb76c1ffb5d 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -5280,6 +5280,19 @@ public final class Telephony { public static final String COLUMN_ALLOWED_NETWORK_TYPES = "allowed_network_types"; /** + * TelephonyProvider column name for allowed network types with all of reasons. Indicate + * which network types are allowed for + * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER}, + * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER}, + * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER}. + * <P>Type: TEXT </P> + * + * @hide + */ + public static final String COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS = + "allowed_network_types_for_reasons"; + + /** * TelephonyProvider column name for RCS configuration. * <p>TYPE: BLOB * diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index 03d3755111aa..18da3a610f36 100644 --- a/core/java/android/telephony/PhoneStateListener.java +++ b/core/java/android/telephony/PhoneStateListener.java @@ -1020,6 +1020,19 @@ public class PhoneStateListener { @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_DATA_ENABLED_CHANGED = 34; + /** + * Event for changes to allowed network list based on all active subscriptions. + * + * <p>Requires permission {@link android.Manifest.permission#READ_PHONE_STATE} or the calling + * app has carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}). + * + * @hide + * @see AllowedNetworkTypesChangedListener#onAllowedNetworkTypesChanged + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public static final int EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED = 35; + /** @hide */ @IntDef(prefix = { "EVENT_" }, value = { EVENT_SERVICE_STATE_CHANGED, @@ -1055,7 +1068,8 @@ public class PhoneStateListener { EVENT_REGISTRATION_FAILURE, EVENT_BARRING_INFO_CHANGED, EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED, - EVENT_DATA_ENABLED_CHANGED + EVENT_DATA_ENABLED_CHANGED, + EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED }) @Retention(RetentionPolicy.SOURCE) public @interface TelephonyEvent {} @@ -1803,6 +1817,41 @@ public class PhoneStateListener { } /** + * Interface for the current allowed network type list listener. This list involves values of + * allowed network type for each of reasons. + * + * @hide + */ + @SystemApi + public interface AllowedNetworkTypesChangedListener { + /** + * Callback invoked when the current allowed network type list has changed on the + * registered subscription. + * Note, the registered subscription is associated with {@link TelephonyManager} object + * on which + * {@link TelephonyManager#registerPhoneStateListener(Executor, PhoneStateListener)} + * was called. + * If this TelephonyManager object was created with + * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the + * given subscription ID. Otherwise, this callback applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. + * + * @param allowedNetworkTypesList Map associating all allowed network type reasons + * ({@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER}, + * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER}, and + * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER}) with reason's allowed + * network type values. + * For example: + * map{{TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER, long type value}, + * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER, long type value}, + * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER, long type value}} + */ + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + void onAllowedNetworkTypesChanged( + @NonNull Map<Integer, Long> allowedNetworkTypesList); + } + + /** * Interface for call attributes listener. * * @hide @@ -2811,6 +2860,16 @@ public class PhoneStateListener { () -> mExecutor.execute(() -> listener.onDataEnabledChanged( enabled, reason))); } + + public void onAllowedNetworkTypesChanged(Map allowedNetworkTypesList) { + AllowedNetworkTypesChangedListener listener = + (AllowedNetworkTypesChangedListener) mPhoneStateListenerWeakRef.get(); + if (listener == null) return; + + Binder.withCleanCallingIdentity( + () -> mExecutor.execute( + () -> listener.onAllowedNetworkTypesChanged(allowedNetworkTypesList))); + } } private void log(String s) { diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index 299a292936ae..8c516516a9de 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -25,9 +25,6 @@ import android.compat.annotation.EnabledAfter; import android.content.Context; import android.os.Binder; import android.os.Build; -import android.os.Handler; -import android.os.HandlerExecutor; -import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; import android.telephony.Annotation.CallState; @@ -802,6 +799,22 @@ public class TelephonyRegistryManager { } } + /** + * Notify emergency number list changed on certain subscription. + * + * @param subId for which emergency number list changed. + * @param slotIndex for which emergency number list changed. Can be derived from subId except + * when subId is invalid. + */ + public void notifyAllowedNetworkTypesChanged(int subId, int slotIndex, + Map<Integer, Long> allowedNetworkTypeList) { + try { + sRegistry.notifyAllowedNetworkTypesChanged(slotIndex, subId, allowedNetworkTypeList); + } catch (RemoteException ex) { + // system process is dead + } + } + public @NonNull Set<Integer> getEventsFromListener(@NonNull PhoneStateListener listener) { Set<Integer> eventList = new ArraySet<>(); @@ -930,6 +943,10 @@ public class TelephonyRegistryManager { eventList.add(PhoneStateListener.EVENT_DATA_ENABLED_CHANGED); } + if (listener instanceof PhoneStateListener.AllowedNetworkTypesChangedListener) { + eventList.add(PhoneStateListener.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED); + } + return eventList; } diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 1c4e4a2b119e..644e032103b8 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -202,7 +202,7 @@ public final class Zygote { public static final String PKG_DATA_INFO_MAP = "--pkg-data-info-map"; /** List of allowlisted packages and its app data info: volume uuid and inode. */ - public static final String WHITELISTED_DATA_INFO_MAP = "--whitelisted-data-info-map"; + public static final String ALLOWLISTED_DATA_INFO_MAP = "--allowlisted-data-info-map"; /** Bind mount app storage dirs to lower fs not via fuse */ public static final String BIND_MOUNT_APP_STORAGE_DIRS = "--bind-mount-storage-dirs"; @@ -324,7 +324,7 @@ public final class Zygote { * @param isTopApp true if the process is for top (high priority) application. * @param pkgDataInfoList A list that stores related packages and its app data * info: volume uuid and inode. - * @param whitelistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps. + * @param allowlistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps. * @param bindMountAppDataDirs True if the zygote needs to mount data dirs. * @param bindMountAppStorageDirs True if the zygote needs to mount storage dirs. * @@ -334,14 +334,14 @@ public final class Zygote { static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, - boolean isTopApp, String[] pkgDataInfoList, String[] whitelistedDataInfoList, + boolean isTopApp, String[] pkgDataInfoList, String[] allowlistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) { ZygoteHooks.preFork(); int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp, - pkgDataInfoList, whitelistedDataInfoList, bindMountAppDataDirs, + pkgDataInfoList, allowlistedDataInfoList, bindMountAppDataDirs, bindMountAppStorageDirs); if (pid == 0) { // Note that this event ends at the end of handleChildProc, @@ -364,7 +364,7 @@ public final class Zygote { int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, String[] pkgDataInfoList, - String[] whitelistedDataInfoList, boolean bindMountAppDataDirs, + String[] allowlistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs); /** @@ -392,18 +392,18 @@ public final class Zygote { * volume uuid and CE dir inode. For example, pkgDataInfoList = [app_a_pkg_name, * app_a_data_volume_uuid, app_a_ce_inode, app_b_pkg_name, app_b_data_volume_uuid, * app_b_ce_inode, ...]; - * @param whitelistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps. + * @param allowlistedDataInfoList Like pkgDataInfoList, but it's for allowlisted apps. * @param bindMountAppDataDirs True if the zygote needs to mount data dirs. * @param bindMountAppStorageDirs True if the zygote needs to mount storage dirs. */ private static void specializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, - String[] pkgDataInfoList, String[] whitelistedDataInfoList, + String[] pkgDataInfoList, String[] allowlistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) { nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, startChildZygote, instructionSet, appDataDir, isTopApp, - pkgDataInfoList, whitelistedDataInfoList, + pkgDataInfoList, allowlistedDataInfoList, bindMountAppDataDirs, bindMountAppStorageDirs); // Note that this event ends at the end of handleChildProc. @@ -428,7 +428,7 @@ public final class Zygote { private static native void nativeSpecializeAppProcess(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, boolean startChildZygote, String instructionSet, String appDataDir, boolean isTopApp, - String[] pkgDataInfoList, String[] whitelistedDataInfoList, + String[] pkgDataInfoList, String[] allowlistedDataInfoList, boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs); /** @@ -807,7 +807,7 @@ public final class Zygote { args.mRuntimeFlags, rlimits, args.mMountExternal, args.mSeInfo, args.mNiceName, args.mStartChildZygote, args.mInstructionSet, args.mAppDataDir, args.mIsTopApp, - args.mPkgDataInfoList, args.mWhitelistedDataInfoList, + args.mPkgDataInfoList, args.mAllowlistedDataInfoList, args.mBindMountAppDataDirs, args.mBindMountAppStorageDirs); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java index 65b454d47db2..ef8398294c5b 100644 --- a/core/java/com/android/internal/os/ZygoteArguments.java +++ b/core/java/com/android/internal/os/ZygoteArguments.java @@ -230,7 +230,7 @@ class ZygoteArguments { * A list that stores all allowlisted app data info: volume uuid and inode. * Null if it does need to do app data isolation. */ - String[] mWhitelistedDataInfoList; + String[] mAllowlistedDataInfoList; /** * @see Zygote#BIND_MOUNT_APP_STORAGE_DIRS @@ -475,8 +475,8 @@ class ZygoteArguments { } } else if (arg.startsWith(Zygote.PKG_DATA_INFO_MAP)) { mPkgDataInfoList = getAssignmentList(arg); - } else if (arg.startsWith(Zygote.WHITELISTED_DATA_INFO_MAP)) { - mWhitelistedDataInfoList = getAssignmentList(arg); + } else if (arg.startsWith(Zygote.ALLOWLISTED_DATA_INFO_MAP)) { + mAllowlistedDataInfoList = getAssignmentList(arg); } else if (arg.equals(Zygote.BIND_MOUNT_APP_STORAGE_DIRS)) { mBindMountAppStorageDirs = true; } else if (arg.equals(Zygote.BIND_MOUNT_APP_DATA_DIRS)) { diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 37c75907061c..1673362028f9 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -265,7 +265,7 @@ class ZygoteConnection { fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote, parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList, - parsedArgs.mWhitelistedDataInfoList, parsedArgs.mBindMountAppDataDirs, + parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs); try { diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl index 854fb17e692b..ee94ef8ddda3 100644 --- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -71,4 +71,5 @@ oneway interface IPhoneStateListener { void onBarringInfoChanged(in BarringInfo barringInfo); void onPhysicalChannelConfigChanged(in List<PhysicalChannelConfig> configs); void onDataEnabledChanged(boolean enabled, int reason); + void onAllowedNetworkTypesChanged(in Map allowedNetworkTypeList); } diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 47e696a86334..8d691586dfb1 100644 --- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -94,4 +94,5 @@ interface ITelephonyRegistry { void notifyPhysicalChannelConfigForSubscriber(in int subId, in List<PhysicalChannelConfig> configs); void notifyDataEnabled(in int phoneId, int subId, boolean enabled, int reason); + void notifyAllowedNetworkTypesChanged(in int phoneId, in int subId, in Map allowedNetworkTypeList); } diff --git a/core/jni/OWNERS b/core/jni/OWNERS index 19c6a625646e..c0c4b7054674 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -46,6 +46,7 @@ per-file EphemeralStorage* = file:platform/system/libhwbinder:/OWNERS per-file android_hardware_SensorManager* = arthuri@google.com, bduddie@google.com, stange@google.com per-file *Zygote* = file:/ZYGOTE_OWNERS +per-file fd_utils.* = file:/ZYGOTE_OWNERS per-file Android.bp = file:platform/build/soong:/OWNERS per-file android_animation_* = file:/core/java/android/animation/OWNERS per-file android_app_admin_* = file:/core/java/android/app/admin/OWNERS diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index bcfb06b15ab8..836074f1d5f7 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -1400,16 +1400,15 @@ static void insertPackagesToMergedList(JNIEnv* env, } static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list, - jobjectArray whitelisted_data_info_list, uid_t uid, const char* process_name, - jstring managed_nice_name, fail_fn_t fail_fn) { - - std::vector<std::string> merged_data_info_list; - insertPackagesToMergedList(env, merged_data_info_list, pkg_data_info_list, - process_name, managed_nice_name, fail_fn); - insertPackagesToMergedList(env, merged_data_info_list, whitelisted_data_info_list, - process_name, managed_nice_name, fail_fn); + jobjectArray allowlisted_data_info_list, uid_t uid, + const char* process_name, jstring managed_nice_name, fail_fn_t fail_fn) { + std::vector<std::string> merged_data_info_list; + insertPackagesToMergedList(env, merged_data_info_list, pkg_data_info_list, process_name, + managed_nice_name, fail_fn); + insertPackagesToMergedList(env, merged_data_info_list, allowlisted_data_info_list, process_name, + managed_nice_name, fail_fn); - isolateAppData(env, merged_data_info_list, uid, process_name, managed_nice_name, fail_fn); + isolateAppData(env, merged_data_info_list, uid, process_name, managed_nice_name, fail_fn); } /** @@ -1510,240 +1509,242 @@ static void BindMountStorageDirs(JNIEnv* env, jobjectArray pkg_data_info_list, } // Utility routine to specialize a zygote child process. -static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, - jint runtime_flags, jobjectArray rlimits, - jlong permitted_capabilities, jlong effective_capabilities, - jint mount_external, jstring managed_se_info, - jstring managed_nice_name, bool is_system_server, - bool is_child_zygote, jstring managed_instruction_set, - jstring managed_app_data_dir, bool is_top_app, - jobjectArray pkg_data_info_list, - jobjectArray whitelisted_data_info_list, - bool mount_data_dirs, bool mount_storage_dirs) { - const char* process_name = is_system_server ? "system_server" : "zygote"; - auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1); - auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1); +static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, jint runtime_flags, + jobjectArray rlimits, jlong permitted_capabilities, + jlong effective_capabilities, jint mount_external, + jstring managed_se_info, jstring managed_nice_name, + bool is_system_server, bool is_child_zygote, + jstring managed_instruction_set, jstring managed_app_data_dir, + bool is_top_app, jobjectArray pkg_data_info_list, + jobjectArray allowlisted_data_info_list, bool mount_data_dirs, + bool mount_storage_dirs) { + const char* process_name = is_system_server ? "system_server" : "zygote"; + auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1); + auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1); + + auto se_info = extract_fn(managed_se_info); + auto nice_name = extract_fn(managed_nice_name); + auto instruction_set = extract_fn(managed_instruction_set); + auto app_data_dir = extract_fn(managed_app_data_dir); + + // Keep capabilities across UID change, unless we're staying root. + if (uid != 0) { + EnableKeepCapabilities(fail_fn); + } - auto se_info = extract_fn(managed_se_info); - auto nice_name = extract_fn(managed_nice_name); - auto instruction_set = extract_fn(managed_instruction_set); - auto app_data_dir = extract_fn(managed_app_data_dir); + SetInheritable(permitted_capabilities, fail_fn); - // Keep capabilities across UID change, unless we're staying root. - if (uid != 0) { - EnableKeepCapabilities(fail_fn); - } + DropCapabilitiesBoundingSet(fail_fn); - SetInheritable(permitted_capabilities, fail_fn); + bool need_pre_initialize_native_bridge = !is_system_server && instruction_set.has_value() && + android::NativeBridgeAvailable() && + // Native bridge may be already initialized if this + // is an app forked from app-zygote. + !android::NativeBridgeInitialized() && + android::NeedsNativeBridge(instruction_set.value().c_str()); - DropCapabilitiesBoundingSet(fail_fn); + MountEmulatedStorage(uid, mount_external, need_pre_initialize_native_bridge, fail_fn); - bool need_pre_initialize_native_bridge = - !is_system_server && - instruction_set.has_value() && - android::NativeBridgeAvailable() && - // Native bridge may be already initialized if this - // is an app forked from app-zygote. - !android::NativeBridgeInitialized() && - android::NeedsNativeBridge(instruction_set.value().c_str()); + // Make sure app is running in its own mount namespace before isolating its data directories. + ensureInAppMountNamespace(fail_fn); - MountEmulatedStorage(uid, mount_external, need_pre_initialize_native_bridge, fail_fn); + // Sandbox data and jit profile directories by overlaying a tmpfs on those dirs and bind + // mount all related packages separately. + if (mount_data_dirs) { + isolateAppData(env, pkg_data_info_list, allowlisted_data_info_list, uid, process_name, + managed_nice_name, fail_fn); + isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn); + } + // MOUNT_EXTERNAL_INSTALLER, MOUNT_EXTERNAL_PASS_THROUGH, MOUNT_EXTERNAL_ANDROID_WRITABLE apps + // will have mount_storage_dirs == false here (set by ProcessList.needsStorageDataIsolation()), + // and hence they won't bind mount storage dirs. + if (mount_storage_dirs) { + BindMountStorageDirs(env, pkg_data_info_list, uid, process_name, managed_nice_name, + fail_fn); + } - // Make sure app is running in its own mount namespace before isolating its data directories. - ensureInAppMountNamespace(fail_fn); + // If this zygote isn't root, it won't be able to create a process group, + // since the directory is owned by root. + if (!is_system_server && getuid() == 0) { + const int rc = createProcessGroup(uid, getpid()); + if (rc == -EROFS) { + ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?"); + } else if (rc != 0) { + ALOGE("createProcessGroup(%d, %d) failed: %s", uid, /* pid= */ 0, strerror(-rc)); + } + } - // Sandbox data and jit profile directories by overlaying a tmpfs on those dirs and bind - // mount all related packages separately. - if (mount_data_dirs) { - isolateAppData(env, pkg_data_info_list, whitelisted_data_info_list, - uid, process_name, managed_nice_name, fail_fn); - isolateJitProfile(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn); - } - // MOUNT_EXTERNAL_INSTALLER, MOUNT_EXTERNAL_PASS_THROUGH, MOUNT_EXTERNAL_ANDROID_WRITABLE apps - // will have mount_storage_dirs == false here (set by ProcessList.needsStorageDataIsolation()), - // and hence they won't bind mount storage dirs. - if (mount_storage_dirs) { - BindMountStorageDirs(env, pkg_data_info_list, uid, process_name, managed_nice_name, fail_fn); - } + SetGids(env, gids, is_child_zygote, fail_fn); + SetRLimits(env, rlimits, fail_fn); - // If this zygote isn't root, it won't be able to create a process group, - // since the directory is owned by root. - if (!is_system_server && getuid() == 0) { - const int rc = createProcessGroup(uid, getpid()); - if (rc == -EROFS) { - ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?"); - } else if (rc != 0) { - ALOGE("createProcessGroup(%d, %d) failed: %s", uid, /* pid= */ 0, strerror(-rc)); + if (need_pre_initialize_native_bridge) { + // Due to the logic behind need_pre_initialize_native_bridge we know that + // instruction_set contains a value. + android::PreInitializeNativeBridge(app_data_dir.has_value() ? app_data_dir.value().c_str() + : nullptr, + instruction_set.value().c_str()); } - } - SetGids(env, gids, is_child_zygote, fail_fn); - SetRLimits(env, rlimits, fail_fn); - - if (need_pre_initialize_native_bridge) { - // Due to the logic behind need_pre_initialize_native_bridge we know that - // instruction_set contains a value. - android::PreInitializeNativeBridge( - app_data_dir.has_value() ? app_data_dir.value().c_str() : nullptr, - instruction_set.value().c_str()); - } + if (setresgid(gid, gid, gid) == -1) { + fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno))); + } - if (setresgid(gid, gid, gid) == -1) { - fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno))); - } + // Must be called when the new process still has CAP_SYS_ADMIN, in this case, + // before changing uid from 0, which clears capabilities. The other + // alternative is to call prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that + // breaks SELinux domain transition (see b/71859146). As the result, + // privileged syscalls used below still need to be accessible in app process. + SetUpSeccompFilter(uid, is_child_zygote); - // Must be called when the new process still has CAP_SYS_ADMIN, in this case, - // before changing uid from 0, which clears capabilities. The other - // alternative is to call prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that - // breaks SELinux domain transition (see b/71859146). As the result, - // privileged syscalls used below still need to be accessible in app process. - SetUpSeccompFilter(uid, is_child_zygote); + // Must be called before losing the permission to set scheduler policy. + SetSchedulerPolicy(fail_fn, is_top_app); - // Must be called before losing the permission to set scheduler policy. - SetSchedulerPolicy(fail_fn, is_top_app); + if (setresuid(uid, uid, uid) == -1) { + fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno))); + } - if (setresuid(uid, uid, uid) == -1) { - fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno))); - } + // The "dumpable" flag of a process, which controls core dump generation, is + // overwritten by the value in /proc/sys/fs/suid_dumpable when the effective + // user or group ID changes. See proc(5) for possible values. In most cases, + // the value is 0, so core dumps are disabled for zygote children. However, + // when running in a Chrome OS container, the value is already set to 2, + // which allows the external crash reporter to collect all core dumps. Since + // only system crashes are interested, core dump is disabled for app + // processes. This also ensures compliance with CTS. + int dumpable = prctl(PR_GET_DUMPABLE); + if (dumpable == -1) { + ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno)); + RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed"); + } - // The "dumpable" flag of a process, which controls core dump generation, is - // overwritten by the value in /proc/sys/fs/suid_dumpable when the effective - // user or group ID changes. See proc(5) for possible values. In most cases, - // the value is 0, so core dumps are disabled for zygote children. However, - // when running in a Chrome OS container, the value is already set to 2, - // which allows the external crash reporter to collect all core dumps. Since - // only system crashes are interested, core dump is disabled for app - // processes. This also ensures compliance with CTS. - int dumpable = prctl(PR_GET_DUMPABLE); - if (dumpable == -1) { - ALOGE("prctl(PR_GET_DUMPABLE) failed: %s", strerror(errno)); - RuntimeAbort(env, __LINE__, "prctl(PR_GET_DUMPABLE) failed"); - } + if (dumpable == 2 && uid >= AID_APP) { + if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) { + ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno)); + RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 0) failed"); + } + } - if (dumpable == 2 && uid >= AID_APP) { - if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) == -1) { - ALOGE("prctl(PR_SET_DUMPABLE, 0) failed: %s", strerror(errno)); - RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 0) failed"); + // Set process properties to enable debugging if required. + if ((runtime_flags & RuntimeFlags::DEBUG_ENABLE_JDWP) != 0) { + EnableDebugger(); + } + if ((runtime_flags & RuntimeFlags::PROFILE_FROM_SHELL) != 0) { + // simpleperf needs the process to be dumpable to profile it. + if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) { + ALOGE("prctl(PR_SET_DUMPABLE) failed: %s", strerror(errno)); + RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 1) failed"); + } } - } - // Set process properties to enable debugging if required. - if ((runtime_flags & RuntimeFlags::DEBUG_ENABLE_JDWP) != 0) { - EnableDebugger(); - } - if ((runtime_flags & RuntimeFlags::PROFILE_FROM_SHELL) != 0) { - // simpleperf needs the process to be dumpable to profile it. - if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) { - ALOGE("prctl(PR_SET_DUMPABLE) failed: %s", strerror(errno)); - RuntimeAbort(env, __LINE__, "prctl(PR_SET_DUMPABLE, 1) failed"); + HeapTaggingLevel heap_tagging_level; + switch (runtime_flags & RuntimeFlags::MEMORY_TAG_LEVEL_MASK) { + case RuntimeFlags::MEMORY_TAG_LEVEL_TBI: + heap_tagging_level = M_HEAP_TAGGING_LEVEL_TBI; + break; + case RuntimeFlags::MEMORY_TAG_LEVEL_ASYNC: + heap_tagging_level = M_HEAP_TAGGING_LEVEL_ASYNC; + break; + case RuntimeFlags::MEMORY_TAG_LEVEL_SYNC: + heap_tagging_level = M_HEAP_TAGGING_LEVEL_SYNC; + break; + default: + heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE; + break; + } + mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level); + + // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART + // runtime. + runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK; + + // Avoid heap zero initialization for applications without MTE. Zero init may + // cause app compat problems, use more memory, or reduce performance. While it + // would be nice to have them for apps, we will have to wait until they are + // proven out, have more efficient hardware, and/or apply them only to new + // applications. + if (!(runtime_flags & RuntimeFlags::NATIVE_HEAP_ZERO_INIT)) { + mallopt(M_BIONIC_ZERO_INIT, 0); } - } - HeapTaggingLevel heap_tagging_level; - switch (runtime_flags & RuntimeFlags::MEMORY_TAG_LEVEL_MASK) { - case RuntimeFlags::MEMORY_TAG_LEVEL_TBI: - heap_tagging_level = M_HEAP_TAGGING_LEVEL_TBI; - break; - case RuntimeFlags::MEMORY_TAG_LEVEL_ASYNC: - heap_tagging_level = M_HEAP_TAGGING_LEVEL_ASYNC; - break; - case RuntimeFlags::MEMORY_TAG_LEVEL_SYNC: - heap_tagging_level = M_HEAP_TAGGING_LEVEL_SYNC; - break; - default: - heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE; - break; - } - mallopt(M_BIONIC_SET_HEAP_TAGGING_LEVEL, heap_tagging_level); + // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART + // runtime. + runtime_flags &= ~RuntimeFlags::NATIVE_HEAP_ZERO_INIT; - // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime. - runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK; + bool forceEnableGwpAsan = false; + switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) { + default: + case RuntimeFlags::GWP_ASAN_LEVEL_NEVER: + break; + case RuntimeFlags::GWP_ASAN_LEVEL_ALWAYS: + forceEnableGwpAsan = true; + [[fallthrough]]; + case RuntimeFlags::GWP_ASAN_LEVEL_LOTTERY: + android_mallopt(M_INITIALIZE_GWP_ASAN, &forceEnableGwpAsan, sizeof(forceEnableGwpAsan)); + } + // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART + // runtime. + runtime_flags &= ~RuntimeFlags::GWP_ASAN_LEVEL_MASK; + + if (NeedsNoRandomizeWorkaround()) { + // Work around ARM kernel ASLR lossage (http://b/5817320). + int old_personality = personality(0xffffffff); + int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE); + if (new_personality == -1) { + ALOGW("personality(%d) failed: %s", new_personality, strerror(errno)); + } + } - // Avoid heap zero initialization for applications without MTE. Zero init may - // cause app compat problems, use more memory, or reduce performance. While it - // would be nice to have them for apps, we will have to wait until they are - // proven out, have more efficient hardware, and/or apply them only to new - // applications. - if (!(runtime_flags & RuntimeFlags::NATIVE_HEAP_ZERO_INIT)) { - mallopt(M_BIONIC_ZERO_INIT, 0); - } + SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities, + fail_fn); - // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime. - runtime_flags &= ~RuntimeFlags::NATIVE_HEAP_ZERO_INIT; + __android_log_close(); + AStatsSocket_close(); - bool forceEnableGwpAsan = false; - switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) { - default: - case RuntimeFlags::GWP_ASAN_LEVEL_NEVER: - break; - case RuntimeFlags::GWP_ASAN_LEVEL_ALWAYS: - forceEnableGwpAsan = true; - [[fallthrough]]; - case RuntimeFlags::GWP_ASAN_LEVEL_LOTTERY: - android_mallopt(M_INITIALIZE_GWP_ASAN, &forceEnableGwpAsan, sizeof(forceEnableGwpAsan)); - } - // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime. - runtime_flags &= ~RuntimeFlags::GWP_ASAN_LEVEL_MASK; + const char* se_info_ptr = se_info.has_value() ? se_info.value().c_str() : nullptr; + const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr; - if (NeedsNoRandomizeWorkaround()) { - // Work around ARM kernel ASLR lossage (http://b/5817320). - int old_personality = personality(0xffffffff); - int new_personality = personality(old_personality | ADDR_NO_RANDOMIZE); - if (new_personality == -1) { - ALOGW("personality(%d) failed: %s", new_personality, strerror(errno)); + if (selinux_android_setcontext(uid, is_system_server, se_info_ptr, nice_name_ptr) == -1) { + fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid, + is_system_server, se_info_ptr, nice_name_ptr)); } - } - - SetCapabilities(permitted_capabilities, effective_capabilities, permitted_capabilities, fail_fn); - - __android_log_close(); - AStatsSocket_close(); - - const char* se_info_ptr = se_info.has_value() ? se_info.value().c_str() : nullptr; - const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr; - if (selinux_android_setcontext(uid, is_system_server, se_info_ptr, nice_name_ptr) == -1) { - fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", - uid, is_system_server, se_info_ptr, nice_name_ptr)); - } + // Make it easier to debug audit logs by setting the main thread's name to the + // nice name rather than "app_process". + if (nice_name.has_value()) { + SetThreadName(nice_name.value()); + } else if (is_system_server) { + SetThreadName("system_server"); + } - // Make it easier to debug audit logs by setting the main thread's name to the - // nice name rather than "app_process". - if (nice_name.has_value()) { - SetThreadName(nice_name.value()); - } else if (is_system_server) { - SetThreadName("system_server"); - } + // Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers). + UnsetChldSignalHandler(); - // Unset the SIGCHLD handler, but keep ignoring SIGHUP (rationale in SetSignalHandlers). - UnsetChldSignalHandler(); + if (is_system_server) { + env->CallStaticVoidMethod(gZygoteClass, gCallPostForkSystemServerHooks, runtime_flags); + if (env->ExceptionCheck()) { + fail_fn("Error calling post fork system server hooks."); + } - if (is_system_server) { - env->CallStaticVoidMethod(gZygoteClass, gCallPostForkSystemServerHooks, runtime_flags); - if (env->ExceptionCheck()) { - fail_fn("Error calling post fork system server hooks."); + // TODO(b/117874058): Remove hardcoded label here. + static const char* kSystemServerLabel = "u:r:system_server:s0"; + if (selinux_android_setcon(kSystemServerLabel) != 0) { + fail_fn(CREATE_ERROR("selinux_android_setcon(%s)", kSystemServerLabel)); + } } - // TODO(oth): Remove hardcoded label here (b/117874058). - static const char* kSystemServerLabel = "u:r:system_server:s0"; - if (selinux_android_setcon(kSystemServerLabel) != 0) { - fail_fn(CREATE_ERROR("selinux_android_setcon(%s)", kSystemServerLabel)); + if (is_child_zygote) { + initUnsolSocketToSystemServer(); } - } - if (is_child_zygote) { - initUnsolSocketToSystemServer(); - } + env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags, + is_system_server, is_child_zygote, managed_instruction_set); - env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags, - is_system_server, is_child_zygote, managed_instruction_set); + // Reset the process priority to the default value. + setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_DEFAULT); - // Reset the process priority to the default value. - setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_DEFAULT); - - if (env->ExceptionCheck()) { - fail_fn("Error calling post fork hooks."); - } + if (env->ExceptionCheck()) { + fail_fn("Error calling post fork hooks."); + } } static uint64_t GetEffectiveCapabilityMask(JNIEnv* env) { @@ -2068,12 +2069,11 @@ static void com_android_internal_os_Zygote_nativePreApplicationInit(JNIEnv*, jcl NO_PAC_FUNC static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( - JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, - jint runtime_flags, jobjectArray rlimits, - jint mount_external, jstring se_info, jstring nice_name, + JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags, + jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app, - jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, + jobjectArray pkg_data_info_list, jobjectArray allowlisted_data_info_list, jboolean mount_data_dirs, jboolean mount_storage_dirs) { jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote); @@ -2108,14 +2108,11 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( pid_t pid = zygote::ForkCommon(env, false, fds_to_close, fds_to_ignore, true); if (pid == 0) { - SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, - capabilities, capabilities, - mount_external, se_info, nice_name, false, - is_child_zygote == JNI_TRUE, instruction_set, app_data_dir, - is_top_app == JNI_TRUE, pkg_data_info_list, - whitelisted_data_info_list, - mount_data_dirs == JNI_TRUE, - mount_storage_dirs == JNI_TRUE); + SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities, + mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE, + instruction_set, app_data_dir, is_top_app == JNI_TRUE, pkg_data_info_list, + allowlisted_data_info_list, mount_data_dirs == JNI_TRUE, + mount_storage_dirs == JNI_TRUE); } return pid; } @@ -2147,12 +2144,11 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( if (pid == 0) { // System server prcoess does not need data isolation so no need to // know pkg_data_info_list. - SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, - permitted_capabilities, effective_capabilities, - MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true, + SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities, + effective_capabilities, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true, false, nullptr, nullptr, /* is_top_app= */ false, /* pkg_data_info_list */ nullptr, - /* whitelisted_data_info_list */ nullptr, false, false); + /* allowlisted_data_info_list */ nullptr, false, false); } else if (pid > 0) { // The zygote process checks whether the child process has died or not. ALOGI("System server process %d has been created", pid); @@ -2260,7 +2256,7 @@ static void com_android_internal_os_Zygote_nativeAllowFileAcrossFork( if (!path_cstr) { RuntimeAbort(env, __LINE__, "path_cstr == nullptr"); } - FileDescriptorWhitelist::Get()->Allow(path_cstr); + FileDescriptorAllowlist::Get()->Allow(path_cstr); } static void com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter( @@ -2295,20 +2291,19 @@ static void com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter( * @param is_top_app If the process is for top (high priority) application */ static void com_android_internal_os_Zygote_nativeSpecializeAppProcess( - JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, - jint runtime_flags, jobjectArray rlimits, - jint mount_external, jstring se_info, jstring nice_name, - jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, jboolean is_top_app, - jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, - jboolean mount_data_dirs, jboolean mount_storage_dirs) { - jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote); - - SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, - capabilities, capabilities, - mount_external, se_info, nice_name, false, - is_child_zygote == JNI_TRUE, instruction_set, app_data_dir, - is_top_app == JNI_TRUE, pkg_data_info_list, whitelisted_data_info_list, - mount_data_dirs == JNI_TRUE, mount_storage_dirs == JNI_TRUE); + JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags, + jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name, + jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir, + jboolean is_top_app, jobjectArray pkg_data_info_list, + jobjectArray allowlisted_data_info_list, jboolean mount_data_dirs, + jboolean mount_storage_dirs) { + jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote); + + SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, capabilities, capabilities, + mount_external, se_info, nice_name, false, is_child_zygote == JNI_TRUE, + instruction_set, app_data_dir, is_top_app == JNI_TRUE, pkg_data_info_list, + allowlisted_data_info_list, mount_data_dirs == JNI_TRUE, + mount_storage_dirs == JNI_TRUE); } /** diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index c73aae58fe7f..eac1d9922c9a 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -31,8 +31,8 @@ #include <android-base/stringprintf.h> #include <android-base/strings.h> -// Static whitelist of open paths that the zygote is allowed to keep open. -static const char* kPathWhitelist[] = { +// Static allowlist of open paths that the zygote is allowed to keep open. +static const char* kPathAllowlist[] = { "/dev/null", "/dev/socket/zygote", "/dev/socket/zygote_secondary", @@ -51,118 +51,114 @@ static const char* kPathWhitelist[] = { static const char kFdPath[] = "/proc/self/fd"; // static -FileDescriptorWhitelist* FileDescriptorWhitelist::Get() { - if (instance_ == nullptr) { - instance_ = new FileDescriptorWhitelist(); - } - return instance_; +FileDescriptorAllowlist* FileDescriptorAllowlist::Get() { + if (instance_ == nullptr) { + instance_ = new FileDescriptorAllowlist(); + } + return instance_; } static bool IsArtMemfd(const std::string& path) { return android::base::StartsWith(path, "/memfd:/boot-image-methods.art"); } -bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { - // Check the static whitelist path. - for (const auto& whitelist_path : kPathWhitelist) { - if (path == whitelist_path) - return true; - } +bool FileDescriptorAllowlist::IsAllowed(const std::string& path) const { + // Check the static allowlist path. + for (const auto& allowlist_path : kPathAllowlist) { + if (path == allowlist_path) return true; + } - // Check any paths added to the dynamic whitelist. - for (const auto& whitelist_path : whitelist_) { - if (path == whitelist_path) - return true; - } + // Check any paths added to the dynamic allowlist. + for (const auto& allowlist_path : allowlist_) { + if (path == allowlist_path) return true; + } - // Framework jars are allowed. - static const char* kFrameworksPrefix[] = { - "/system/framework/", - "/system_ext/framework/", - }; + // Framework jars are allowed. + static const char* kFrameworksPrefix[] = { + "/system/framework/", + "/system_ext/framework/", + }; - static const char* kJarSuffix = ".jar"; + static const char* kJarSuffix = ".jar"; - for (const auto& frameworks_prefix : kFrameworksPrefix) { - if (android::base::StartsWith(path, frameworks_prefix) - && android::base::EndsWith(path, kJarSuffix)) { - return true; + for (const auto& frameworks_prefix : kFrameworksPrefix) { + if (android::base::StartsWith(path, frameworks_prefix) && + android::base::EndsWith(path, kJarSuffix)) { + return true; + } } - } - // Jars from APEXes are allowed. This matches /apex/**/javalib/*.jar. - static const char* kApexPrefix = "/apex/"; - static const char* kApexJavalibPathSuffix = "/javalib"; - if (android::base::StartsWith(path, kApexPrefix) && android::base::EndsWith(path, kJarSuffix) && - android::base::EndsWith(android::base::Dirname(path), kApexJavalibPathSuffix)) { - return true; - } + // Jars from APEXes are allowed. This matches /apex/**/javalib/*.jar. + static const char* kApexPrefix = "/apex/"; + static const char* kApexJavalibPathSuffix = "/javalib"; + if (android::base::StartsWith(path, kApexPrefix) && android::base::EndsWith(path, kJarSuffix) && + android::base::EndsWith(android::base::Dirname(path), kApexJavalibPathSuffix)) { + return true; + } - // the in-memory file created by ART through memfd_create is allowed. - if (IsArtMemfd(path)) { - return true; - } + // the in-memory file created by ART through memfd_create is allowed. + if (IsArtMemfd(path)) { + return true; + } - // Whitelist files needed for Runtime Resource Overlay, like these: - // /system/vendor/overlay/framework-res.apk - // /system/vendor/overlay-subdir/pg/framework-res.apk - // /vendor/overlay/framework-res.apk - // /vendor/overlay/PG/android-framework-runtime-resource-overlay.apk - // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap - // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap - // See AssetManager.cpp for more details on overlay-subdir. - static const char* kOverlayDir = "/system/vendor/overlay/"; - static const char* kVendorOverlayDir = "/vendor/overlay"; - static const char* kVendorOverlaySubdir = "/system/vendor/overlay-subdir/"; - static const char* kSystemProductOverlayDir = "/system/product/overlay/"; - static const char* kProductOverlayDir = "/product/overlay"; - static const char* kSystemSystemExtOverlayDir = "/system/system_ext/overlay/"; - static const char* kSystemExtOverlayDir = "/system_ext/overlay"; - static const char* kSystemOdmOverlayDir = "/system/odm/overlay"; - static const char* kOdmOverlayDir = "/odm/overlay"; - static const char* kSystemOemOverlayDir = "/system/oem/overlay"; - static const char* kOemOverlayDir = "/oem/overlay"; - static const char* kApkSuffix = ".apk"; - - if ((android::base::StartsWith(path, kOverlayDir) - || android::base::StartsWith(path, kVendorOverlaySubdir) - || android::base::StartsWith(path, kVendorOverlayDir) - || android::base::StartsWith(path, kSystemProductOverlayDir) - || android::base::StartsWith(path, kProductOverlayDir) - || android::base::StartsWith(path, kSystemSystemExtOverlayDir) - || android::base::StartsWith(path, kSystemExtOverlayDir) - || android::base::StartsWith(path, kSystemOdmOverlayDir) - || android::base::StartsWith(path, kOdmOverlayDir) - || android::base::StartsWith(path, kSystemOemOverlayDir) - || android::base::StartsWith(path, kOemOverlayDir)) - && android::base::EndsWith(path, kApkSuffix) - && path.find("/../") == std::string::npos) { - return true; - } + // Allowlist files needed for Runtime Resource Overlay, like these: + // /system/vendor/overlay/framework-res.apk + // /system/vendor/overlay-subdir/pg/framework-res.apk + // /vendor/overlay/framework-res.apk + // /vendor/overlay/PG/android-framework-runtime-resource-overlay.apk + // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap + // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap + // See AssetManager.cpp for more details on overlay-subdir. + static const char* kOverlayDir = "/system/vendor/overlay/"; + static const char* kVendorOverlayDir = "/vendor/overlay"; + static const char* kVendorOverlaySubdir = "/system/vendor/overlay-subdir/"; + static const char* kSystemProductOverlayDir = "/system/product/overlay/"; + static const char* kProductOverlayDir = "/product/overlay"; + static const char* kSystemSystemExtOverlayDir = "/system/system_ext/overlay/"; + static const char* kSystemExtOverlayDir = "/system_ext/overlay"; + static const char* kSystemOdmOverlayDir = "/system/odm/overlay"; + static const char* kOdmOverlayDir = "/odm/overlay"; + static const char* kSystemOemOverlayDir = "/system/oem/overlay"; + static const char* kOemOverlayDir = "/oem/overlay"; + static const char* kApkSuffix = ".apk"; + + if ((android::base::StartsWith(path, kOverlayDir) || + android::base::StartsWith(path, kVendorOverlaySubdir) || + android::base::StartsWith(path, kVendorOverlayDir) || + android::base::StartsWith(path, kSystemProductOverlayDir) || + android::base::StartsWith(path, kProductOverlayDir) || + android::base::StartsWith(path, kSystemSystemExtOverlayDir) || + android::base::StartsWith(path, kSystemExtOverlayDir) || + android::base::StartsWith(path, kSystemOdmOverlayDir) || + android::base::StartsWith(path, kOdmOverlayDir) || + android::base::StartsWith(path, kSystemOemOverlayDir) || + android::base::StartsWith(path, kOemOverlayDir)) && + android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) { + return true; + } - static const char* kOverlayIdmapPrefix = "/data/resource-cache/"; - static const char* kOverlayIdmapSuffix = ".apk@idmap"; - if (android::base::StartsWith(path, kOverlayIdmapPrefix) - && android::base::EndsWith(path, kOverlayIdmapSuffix) - && path.find("/../") == std::string::npos) { - return true; - } + static const char* kOverlayIdmapPrefix = "/data/resource-cache/"; + static const char* kOverlayIdmapSuffix = ".apk@idmap"; + if (android::base::StartsWith(path, kOverlayIdmapPrefix) && + android::base::EndsWith(path, kOverlayIdmapSuffix) && + path.find("/../") == std::string::npos) { + return true; + } - // All regular files that are placed under this path are whitelisted automatically. - static const char* kZygoteWhitelistPath = "/vendor/zygote_whitelist/"; - if (android::base::StartsWith(path, kZygoteWhitelistPath) - && path.find("/../") == std::string::npos) { - return true; - } + // All regular files that are placed under this path are allowlisted + // automatically. The directory name is maintained for compatibility. + static const char* kZygoteAllowlistPath = "/vendor/zygote_whitelist/"; + if (android::base::StartsWith(path, kZygoteAllowlistPath) && + path.find("/../") == std::string::npos) { + return true; + } - return false; + return false; } -FileDescriptorWhitelist::FileDescriptorWhitelist() - : whitelist_() { -} +FileDescriptorAllowlist::FileDescriptorAllowlist() : allowlist_() {} -FileDescriptorWhitelist* FileDescriptorWhitelist::instance_ = nullptr; +FileDescriptorAllowlist* FileDescriptorAllowlist::instance_ = nullptr; // Keeps track of all relevant information (flags, offset etc.) of an // open zygote file descriptor. @@ -215,7 +211,7 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, fail_fn_t fail_fn) fail_fn(android::base::StringPrintf("Unable to stat %d", fd)); } - const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get(); + const FileDescriptorAllowlist* allowlist = FileDescriptorAllowlist::Get(); if (S_ISSOCK(f_stat.st_mode)) { std::string socket_name; @@ -223,16 +219,15 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, fail_fn_t fail_fn) fail_fn("Unable to get socket name"); } - if (!whitelist->IsAllowed(socket_name)) { - fail_fn(android::base::StringPrintf("Socket name not whitelisted : %s (fd=%d)", - socket_name.c_str(), - fd)); + if (!allowlist->IsAllowed(socket_name)) { + fail_fn(android::base::StringPrintf("Socket name not allowlisted : %s (fd=%d)", + socket_name.c_str(), fd)); } return new FileDescriptorInfo(fd); } - // We only handle whitelisted regular files and character devices. Whitelisted + // We only handle allowlisted regular files and character devices. Allowlisted // character devices must provide a guarantee of sensible behaviour when // reopened. // @@ -266,8 +261,8 @@ FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, fail_fn_t fail_fn) strerror(errno))); } - if (!whitelist->IsAllowed(file_path)) { - fail_fn(android::base::StringPrintf("Not whitelisted (%d): %s", fd, file_path.c_str())); + if (!allowlist->IsAllowed(file_path)) { + fail_fn(android::base::StringPrintf("Not allowlisted (%d): %s", fd, file_path.c_str())); } // File descriptor flags : currently on FD_CLOEXEC. We can set these diff --git a/core/jni/fd_utils.h b/core/jni/fd_utils.h index 2caf1575981a..14c318e8e84a 100644 --- a/core/jni/fd_utils.h +++ b/core/jni/fd_utils.h @@ -33,42 +33,40 @@ class FileDescriptorInfo; // This type is duplicated in com_android_internal_os_Zygote.cpp typedef const std::function<void(std::string)>& fail_fn_t; -// Whitelist of open paths that the zygote is allowed to keep open. +// Allowlist of open paths that the zygote is allowed to keep open. // -// In addition to the paths listed in kPathWhitelist in file_utils.cpp, and +// In addition to the paths listed in kPathAllowlist in file_utils.cpp, and // paths dynamically added with Allow(), all files ending with ".jar" -// under /system/framework" are whitelisted. See IsAllowed() for the canonical +// under /system/framework" are allowlisted. See IsAllowed() for the canonical // definition. // -// If the whitelisted path is associated with a regular file or a +// If the allowlisted path is associated with a regular file or a // character device, the file is reopened after a fork with the same -// offset and mode. If the whilelisted path is associated with a +// offset and mode. If the allowlisted path is associated with a // AF_UNIX socket, the socket will refer to /dev/null after each // fork, and all operations on it will fail. -class FileDescriptorWhitelist { - public: - // Lazily creates the global whitelist. - static FileDescriptorWhitelist* Get(); +class FileDescriptorAllowlist { +public: + // Lazily creates the global allowlist. + static FileDescriptorAllowlist* Get(); - // Adds a path to the whitelist. - void Allow(const std::string& path) { - whitelist_.push_back(path); - } + // Adds a path to the allowlist. + void Allow(const std::string& path) { allowlist_.push_back(path); } - // Returns true iff. a given path is whitelisted. A path is whitelisted - // if it belongs to the whitelist (see kPathWhitelist) or if it's a path - // under /system/framework that ends with ".jar" or if it is a system - // framework overlay. - bool IsAllowed(const std::string& path) const; + // Returns true iff. a given path is allowlisted. A path is allowlisted + // if it belongs to the allowlist (see kPathAllowlist) or if it's a path + // under /system/framework that ends with ".jar" or if it is a system + // framework overlay. + bool IsAllowed(const std::string& path) const; - private: - FileDescriptorWhitelist(); +private: + FileDescriptorAllowlist(); - static FileDescriptorWhitelist* instance_; + static FileDescriptorAllowlist* instance_; - std::vector<std::string> whitelist_; + std::vector<std::string> allowlist_; - DISALLOW_COPY_AND_ASSIGN(FileDescriptorWhitelist); + DISALLOW_COPY_AND_ASSIGN(FileDescriptorAllowlist); }; // A FileDescriptorTable is a collection of FileDescriptorInfo objects diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 9302b693704c..2f352e955d29 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1032,6 +1032,14 @@ android:description="@string/permdesc_accessImsCallService" android:protectionLevel="signature|privileged" /> + <!-- @SystemApi @hide Allows an application to perform IMS Single Registration related actions. + Only granted if the application is a system app AND is in the Default SMS Role. + The permission is revoked when the app is taken out of the Default SMS Role. + <p>Protection level: signature|privileged + --> + <permission android:name="android.permission.PERFORM_IMS_SINGLE_REGISTRATION" + android:protectionLevel="signature|privileged" /> + <!-- Allows an application to read the user's call log. <p class="note"><strong>Note:</strong> If your app uses the {@link #READ_CONTACTS} permission and <em>both</em> your <a diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index e939b65f3b8a..354d83c293e6 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -353,6 +353,7 @@ applications that come with the platform <permission name="android.permission.PACKAGE_USAGE_STATS" /> <!-- Needed for test only --> <permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD" /> + <permission name="android.permission.PERFORM_IMS_SINGLE_REGISTRATION" /> <permission name="android.permission.POWER_SAVER" /> <permission name="android.permission.READ_CARRIER_APP_INFO"/> <permission name="android.permission.READ_FRAME_BUFFER"/> diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index c79c12cd3343..72735a787b7f 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -279,8 +279,10 @@ import javax.security.auth.x500.X500Principal; * } */ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAuthArgs { - private static final X500Principal DEFAULT_CERT_SUBJECT = + private static final X500Principal DEFAULT_ATTESTATION_CERT_SUBJECT = new X500Principal("CN=Android Keystore Key"); + private static final X500Principal DEFAULT_SELF_SIGNED_CERT_SUBJECT = + new X500Principal("CN=Fake"); private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1"); private static final Date DEFAULT_CERT_NOT_BEFORE = new Date(0L); // Jan 1 1970 private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048 @@ -366,7 +368,11 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu } if (certificateSubject == null) { - certificateSubject = DEFAULT_CERT_SUBJECT; + if (attestationChallenge == null) { + certificateSubject = DEFAULT_SELF_SIGNED_CERT_SUBJECT; + } else { + certificateSubject = DEFAULT_ATTESTATION_CERT_SUBJECT; + } } if (certificateNotBefore == null) { certificateNotBefore = DEFAULT_CERT_NOT_BEFORE; diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index cd7449ad0d8e..211638bdb42a 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -339,6 +339,9 @@ <!-- Permission required for CTS test - CtsTelephonyTestCases --> <uses-permission android:name="android.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE" /> + <!-- Permission required for CTS test - CtsTelephonyTestCases --> + <uses-permission android:name="android.permission.PERFORM_IMS_SINGLE_REGISTRATION" /> + <!-- Permission needed for CTS test - DisplayTest --> <uses-permission android:name="android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS" /> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java index d18902a7796b..2f783eb37a32 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java @@ -386,7 +386,7 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi private final NetworkCallback mNetworkCallback = new NetworkCallback() { @Override public void onAvailable(Network network) { - if (DEBUG) Log.d(TAG, "onAvailable " + network.netId); + if (DEBUG) Log.d(TAG, "onAvailable " + network.getNetId()); updateState(); fireCallbacks(); }; @@ -395,7 +395,7 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi // how long the VPN connection is held on to. @Override public void onLost(Network network) { - if (DEBUG) Log.d(TAG, "onLost " + network.netId); + if (DEBUG) Log.d(TAG, "onLost " + network.getNetId()); updateState(); fireCallbacks(); }; diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 84de6ec8e0ca..aacf2770d1c2 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3831,7 +3831,24 @@ public class ConnectivityService extends IConnectivityManager.Stub removeListenRequestFromNetworks(req); } } - mDefaultNetworkRequests.remove(nri); + if (mDefaultNetworkRequests.remove(nri)) { + // If this request was one of the defaults, then the UID rules need to be updated + // WARNING : if the app(s) for which this network request is the default are doing + // traffic, this will kill their connected sockets, even if an equivalent request + // is going to be reinstated right away ; unconnected traffic will go on the default + // until the new default is set, which will happen very soon. + // TODO : The only way out of this is to diff old defaults and new defaults, and only + // remove ranges for those requests that won't have a replacement + final NetworkAgentInfo satisfier = nri.getSatisfier(); + if (null != satisfier) { + try { + mNetd.networkRemoveUidRanges(satisfier.network.getNetId(), + toUidRangeStableParcels(nri.getUids())); + } catch (RemoteException e) { + loge("Exception setting network preference default network", e); + } + } + } mNetworkRequestCounter.decrementCount(nri.mUid); mNetworkRequestInfoLogs.log("RELEASE " + nri); @@ -4473,16 +4490,13 @@ public class ConnectivityService extends IConnectivityManager.Stub case EVENT_SET_REQUIRE_VPN_FOR_UIDS: handleSetRequireVpnForUids(toBool(msg.arg1), (UidRange[]) msg.obj); break; - case EVENT_SET_OEM_NETWORK_PREFERENCE: + case EVENT_SET_OEM_NETWORK_PREFERENCE: { final Pair<OemNetworkPreferences, IOnSetOemNetworkPreferenceListener> arg = (Pair<OemNetworkPreferences, IOnSetOemNetworkPreferenceListener>) msg.obj; - try { - handleSetOemNetworkPreference(arg.first, arg.second); - } catch (RemoteException e) { - loge("handleMessage.EVENT_SET_OEM_NETWORK_PREFERENCE failed", e); - } + handleSetOemNetworkPreference(arg.first, arg.second); break; + } case EVENT_REPORT_NETWORK_ACTIVITY: mNetworkActivityTracker.handleReportNetworkActivity(); break; @@ -5240,11 +5254,20 @@ public class ConnectivityService extends IConnectivityManager.Stub ensureAllNetworkRequestsHaveType(r); mRequests = initializeRequests(r); mNetworkRequestForCallback = nri.getNetworkRequestForCallback(); + // Note here that the satisfier may have corresponded to an old request, that + // this code doesn't try to take over. While it is a small discrepancy in the + // structure of these requests, it will be fixed by the next rematch and it's + // not as bad as having an NRI not storing its real satisfier. + // Fixing this discrepancy would require figuring out in the copying code what + // is the new request satisfied by this, which is a bit complex and not very + // useful as no code is using it until rematch fixes it. + mSatisfier = nri.mSatisfier; mMessenger = nri.mMessenger; mBinder = nri.mBinder; mPid = nri.mPid; mUid = nri.mUid; mPendingIntent = nri.mPendingIntent; + mNetworkRequestCounter.incrementCountOrThrow(mUid); mCallingAttributionTag = nri.mCallingAttributionTag; } @@ -5291,6 +5314,8 @@ public class ConnectivityService extends IConnectivityManager.Stub public String toString() { return "uid/pid:" + mUid + "/" + mPid + " active request Id: " + (mActiveRequest == null ? null : mActiveRequest.requestId) + + " callback request Id: " + + mNetworkRequestForCallback.requestId + " " + mRequests + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent); } @@ -7147,7 +7172,7 @@ public class ConnectivityService extends IConnectivityManager.Stub toUidRangeStableParcels(nri.getUids())); } } catch (RemoteException | ServiceSpecificException e) { - loge("Exception setting OEM network preference default network :" + e); + loge("Exception setting OEM network preference default network", e); } } @@ -7202,13 +7227,13 @@ public class ConnectivityService extends IConnectivityManager.Stub private static class NetworkReassignment { static class RequestReassignment { @NonNull public final NetworkRequestInfo mNetworkRequestInfo; - @NonNull public final NetworkRequest mOldNetworkRequest; - @NonNull public final NetworkRequest mNewNetworkRequest; + @Nullable public final NetworkRequest mOldNetworkRequest; + @Nullable public final NetworkRequest mNewNetworkRequest; @Nullable public final NetworkAgentInfo mOldNetwork; @Nullable public final NetworkAgentInfo mNewNetwork; RequestReassignment(@NonNull final NetworkRequestInfo networkRequestInfo, - @NonNull final NetworkRequest oldNetworkRequest, - @NonNull final NetworkRequest newNetworkRequest, + @Nullable final NetworkRequest oldNetworkRequest, + @Nullable final NetworkRequest newNetworkRequest, @Nullable final NetworkAgentInfo oldNetwork, @Nullable final NetworkAgentInfo newNetwork) { mNetworkRequestInfo = networkRequestInfo; @@ -7219,7 +7244,9 @@ public class ConnectivityService extends IConnectivityManager.Stub } public String toString() { - return mNetworkRequestInfo.mRequests.get(0).requestId + " : " + final NetworkRequest requestToShow = null != mNewNetworkRequest + ? mNewNetworkRequest : mNetworkRequestInfo.mRequests.get(0); + return requestToShow.requestId + " : " + (null != mOldNetwork ? mOldNetwork.network.getNetId() : "null") + " → " + (null != mNewNetwork ? mNewNetwork.network.getNetId() : "null"); } @@ -7279,14 +7306,14 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void updateSatisfiersForRematchRequest(@NonNull final NetworkRequestInfo nri, - @NonNull final NetworkRequest previousRequest, - @NonNull final NetworkRequest newRequest, + @Nullable final NetworkRequest previousRequest, + @Nullable final NetworkRequest newRequest, @Nullable final NetworkAgentInfo previousSatisfier, @Nullable final NetworkAgentInfo newSatisfier, final long now) { if (null != newSatisfier && mNoServiceNetwork != newSatisfier) { if (VDBG) log("rematch for " + newSatisfier.toShortString()); - if (null != previousSatisfier && mNoServiceNetwork != previousSatisfier) { + if (null != previousRequest && null != previousSatisfier) { if (VDBG || DDBG) { log(" accepting network in place of " + previousSatisfier.toShortString()); } @@ -7303,12 +7330,13 @@ public class ConnectivityService extends IConnectivityManager.Stub newSatisfier.unlingerRequest(NetworkRequest.REQUEST_ID_NONE); } + // if newSatisfier is not null, then newRequest may not be null. newSatisfier.unlingerRequest(newRequest.requestId); if (!newSatisfier.addRequest(newRequest)) { Log.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has " + newRequest); } - } else if (null != previousSatisfier) { + } else if (null != previousRequest && null != previousSatisfier) { if (DBG) { log("Network " + previousSatisfier.toShortString() + " stopped satisfying" + " request " + previousRequest.requestId); @@ -9022,7 +9050,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private void handleSetOemNetworkPreference( @NonNull final OemNetworkPreferences preference, - @NonNull final IOnSetOemNetworkPreferenceListener listener) throws RemoteException { + @Nullable final IOnSetOemNetworkPreferenceListener listener) { Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null"); if (DBG) { log("set OEM network preferences :" + preference.toString()); @@ -9034,7 +9062,11 @@ public class ConnectivityService extends IConnectivityManager.Stub // TODO http://b/176496396 persist data to shared preferences. if (null != listener) { - listener.onComplete(); + try { + listener.onComplete(); + } catch (RemoteException e) { + loge("handleMessage.EVENT_SET_OEM_NETWORK_PREFERENCE failed", e); + } } } @@ -9050,10 +9082,10 @@ public class ConnectivityService extends IConnectivityManager.Stub mDefaultNetworkRequests.addAll(nris); final ArraySet<NetworkRequestInfo> perAppCallbackRequestsToUpdate = getPerAppCallbackRequestsToUpdate(); - handleRemoveNetworkRequests(perAppCallbackRequestsToUpdate); final ArraySet<NetworkRequestInfo> nrisToRegister = new ArraySet<>(nris); nrisToRegister.addAll( createPerAppCallbackRequestsToRegister(perAppCallbackRequestsToUpdate)); + handleRemoveNetworkRequests(perAppCallbackRequestsToUpdate); handleRegisterNetworkRequests(nrisToRegister); } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index c02e1deb484e..c51a60621312 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -317,6 +317,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private int[] mDataEnabledReason; + private Map<Integer, Long> mAllowedNetworkTypesList; + /** * Per-phone map of precise data connection state. The key of the map is the pair of transport * type and APN setting. This is the cache to prevent redundant callbacks to the listeners. @@ -629,6 +631,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mPhysicalChannelConfigs = new ArrayList<>(); mIsDataEnabled = new boolean[numPhones]; mDataEnabledReason = new int[numPhones]; + mAllowedNetworkTypesList = new HashMap<>(); for (int i = 0; i < numPhones; i++) { mCallState[i] = TelephonyManager.CALL_STATE_IDLE; mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE; @@ -1161,6 +1164,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { remove(r.binder); } } + if (events.contains( + PhoneStateListener.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED)) { + try { + r.callback.onAllowedNetworkTypesChanged(mAllowedNetworkTypesList); + } catch (RemoteException ex) { + remove(r.binder); + } + } } } } @@ -2405,6 +2416,44 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } + /** + * Notify that the allowed network type has changed. + * + * @param phoneId the phone id. + * @param subId the subId. + * @param allowedNetworkTypesList Map associating all allowed network type reasons with reason's + * allowed network type values. + */ + public void notifyAllowedNetworkTypesChanged(int phoneId, int subId, + Map allowedNetworkTypesList) { + if (!checkNotifyPermission("notifyAllowedNetworkTypesChanged()")) { + return; + } + + synchronized (mRecords) { + if (validatePhoneId(phoneId)) { + mAllowedNetworkTypesList = allowedNetworkTypesList; + + for (Record r : mRecords) { + if (r.matchPhoneStateListenerEvent( + PhoneStateListener.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED) + && idMatch(r.subId, subId, phoneId)) { + try { + if (VDBG) { + log("notifyAllowedNetworkTypesChanged: AllowedNetworkTypesList= " + + mAllowedNetworkTypesList.toString()); + } + r.callback.onAllowedNetworkTypesChanged(mAllowedNetworkTypesList); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + } + handleRemoveListLocked(); + } + } + @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java index 8d5d3d939e4b..ad2f52401e93 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -35,6 +35,7 @@ import android.net.vcn.IVcnManagementService; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; +import android.net.vcn.VcnManager; import android.net.vcn.VcnManager.VcnErrorCode; import android.net.vcn.VcnUnderlyingNetworkPolicy; import android.net.wifi.WifiInfo; @@ -724,6 +725,26 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } + private boolean isCallbackPermissioned( + @NonNull VcnStatusCallbackInfo cbInfo, @NonNull ParcelUuid subgroup) { + if (!subgroup.equals(cbInfo.mSubGroup)) { + return false; + } + + if (!mLastSnapshot.packageHasPermissionsForSubscriptionGroup(subgroup, cbInfo.mPkgName)) { + return false; + } + + if (!mLocationPermissionChecker.checkLocationPermission( + cbInfo.mPkgName, + "VcnStatusCallback" /* featureId */, + cbInfo.mUid, + null /* message */)) { + return false; + } + return true; + } + /** Registers the provided callback for receiving VCN status updates. */ @Override public void registerVcnStatusCallback( @@ -758,6 +779,27 @@ public class VcnManagementService extends IVcnManagementService.Stub { } mRegisteredStatusCallbacks.put(cbBinder, cbInfo); + + // now that callback is registered, send it the VCN's current status + final VcnConfig vcnConfig = mConfigs.get(subGroup); + final Vcn vcn = mVcns.get(subGroup); + final int vcnStatus; + if (vcnConfig == null || !isCallbackPermissioned(cbInfo, subGroup)) { + vcnStatus = VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED; + } else if (vcn == null) { + vcnStatus = VcnManager.VCN_STATUS_CODE_INACTIVE; + } else if (vcn.isActive()) { + vcnStatus = VcnManager.VCN_STATUS_CODE_ACTIVE; + } else { + // TODO(b/181789060): create Vcn.getStatus() and Log.WTF() for unknown status + vcnStatus = VcnManager.VCN_STATUS_CODE_SAFE_MODE; + } + + try { + cbInfo.mCallback.onVcnStatusChanged(vcnStatus); + } catch (RemoteException e) { + Slog.d(TAG, "VcnStatusCallback threw on VCN status change", e); + } } } finally { Binder.restoreCallingIdentity(identity); @@ -806,26 +848,6 @@ public class VcnManagementService extends IVcnManagementService.Stub { mSubGroup = Objects.requireNonNull(subGroup, "Missing subGroup"); } - private boolean isCallbackPermissioned(@NonNull VcnStatusCallbackInfo cbInfo) { - if (!mSubGroup.equals(cbInfo.mSubGroup)) { - return false; - } - - if (!mLastSnapshot.packageHasPermissionsForSubscriptionGroup( - mSubGroup, cbInfo.mPkgName)) { - return false; - } - - if (!mLocationPermissionChecker.checkLocationPermission( - cbInfo.mPkgName, - "VcnStatusCallback" /* featureId */, - cbInfo.mUid, - null /* message */)) { - return false; - } - return true; - } - @Override public void onEnteredSafeMode() { synchronized (mLock) { @@ -838,7 +860,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Notify all registered StatusCallbacks for this subGroup for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { - if (isCallbackPermissioned(cbInfo)) { + if (isCallbackPermissioned(cbInfo, mSubGroup)) { Binder.withCleanCallingIdentity( () -> cbInfo.mCallback.onVcnStatusChanged( @@ -862,7 +884,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { // Notify all registered StatusCallbacks for this subGroup for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) { - if (isCallbackPermissioned(cbInfo)) { + if (isCallbackPermissioned(cbInfo, mSubGroup)) { Binder.withCleanCallingIdentity( () -> cbInfo.mCallback.onGatewayConnectionError( diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index b2d694b20d80..28aa79d4db9d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -768,8 +768,19 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { mSelectRequestBuffer.process(); resetSelectRequestBuffer(); - addAndStartAction(new HotplugDetectionAction(HdmiCecLocalDeviceTv.this)); - addAndStartAction(new PowerStatusMonitorAction(HdmiCecLocalDeviceTv.this)); + List<HotplugDetectionAction> hotplugActions + = getActions(HotplugDetectionAction.class); + if (hotplugActions.isEmpty()) { + addAndStartAction( + new HotplugDetectionAction(HdmiCecLocalDeviceTv.this)); + } + + List<PowerStatusMonitorAction> powerStatusActions + = getActions(PowerStatusMonitorAction.class); + if (powerStatusActions.isEmpty()) { + addAndStartAction( + new PowerStatusMonitorAction(HdmiCecLocalDeviceTv.this)); + } HdmiDeviceInfo avr = getAvrDeviceInfo(); if (avr != null) { diff --git a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java index 8c404249cfd5..6f7473d60121 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecStandbyModeHandler.java @@ -106,9 +106,7 @@ public final class HdmiCecStandbyModeHandler { addHandler(Constants.MESSAGE_SET_STREAM_PATH, mBystander); addHandler(Constants.MESSAGE_STANDBY, mBystander); addHandler(Constants.MESSAGE_SET_MENU_LANGUAGE, mBystander); - addHandler(Constants.MESSAGE_DEVICE_VENDOR_ID, mBystander); addHandler(Constants.MESSAGE_USER_CONTROL_RELEASED, mBystander); - addHandler(Constants.MESSAGE_REPORT_POWER_STATUS, mBystander); addHandler(Constants.MESSAGE_FEATURE_ABORT, mBystander); addHandler(Constants.MESSAGE_INACTIVE_SOURCE, mBystander); addHandler(Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS, mBystander); @@ -133,6 +131,8 @@ public final class HdmiCecStandbyModeHandler { addHandler(Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID, mBypasser); addHandler(Constants.MESSAGE_GIVE_OSD_NAME, mBypasser); addHandler(Constants.MESSAGE_SET_OSD_NAME, mBypasser); + addHandler(Constants.MESSAGE_DEVICE_VENDOR_ID, mBypasser); + addHandler(Constants.MESSAGE_REPORT_POWER_STATUS, mBypasser); addHandler(Constants.MESSAGE_USER_CONTROL_PRESSED, mUserControlProcessedHandler); diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java index 7e00fd69a148..364aa2cb41ae 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java @@ -193,6 +193,17 @@ class RebootEscrowManager { 0); } + public int getLoadEscrowDataRetryLimit() { + return DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA, + "load_escrow_data_retry_count", DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT); + } + + public int getLoadEscrowDataRetryIntervalSeconds() { + return DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA, + "load_escrow_data_retry_interval_seconds", + DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS); + } + public void reportMetric(boolean success) { // TODO(b/179105110) design error code; and report the true value for other fields. FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED, 0, 1, 1, @@ -251,11 +262,8 @@ class RebootEscrowManager { List<UserInfo> users, List<UserInfo> rebootEscrowUsers) { Objects.requireNonNull(retryHandler); - final int retryLimit = DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA, - "load_escrow_data_retry_count", DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT); - final int retryIntervalInSeconds = DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA, - "load_escrow_data_retry_interval_seconds", - DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS); + final int retryLimit = mInjector.getLoadEscrowDataRetryLimit(); + final int retryIntervalInSeconds = mInjector.getLoadEscrowDataRetryIntervalSeconds(); if (attemptNumber < retryLimit) { Slog.i(TAG, "Scheduling loadRebootEscrowData retry number: " + attemptNumber); diff --git a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java index 9c471b85eb76..ec80521be2e5 100644 --- a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java +++ b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java @@ -136,7 +136,7 @@ public class ResumeOnRebootServiceProvider { } /** Bind to the service */ - public void bindToService(long timeOut) throws TimeoutException { + public void bindToService(long timeOut) throws RemoteException, TimeoutException { if (mBinder == null || !mBinder.asBinder().isBinderAlive()) { CountDownLatch connectionLatch = new CountDownLatch(1); Intent intent = new Intent(); @@ -210,27 +210,25 @@ public class ResumeOnRebootServiceProvider { private void throwTypedException( ParcelableException exception) - throws IOException { - if (exception.getCause() instanceof IOException) { + throws IOException, RemoteException { + if (exception != null && exception.getCause() instanceof IOException) { exception.maybeRethrow(IOException.class); - } else if (exception.getCause() instanceof IllegalStateException) { - exception.maybeRethrow(IllegalStateException.class); } else { - // This should not happen. Wrap the cause in IllegalStateException so that it - // doesn't disrupt the exception handling - throw new IllegalStateException(exception.getCause()); + // Wrap the exception and throw it as a RemoteException. + throw new RemoteException(TAG + " wrap/unwrap failed", exception, + true /* enableSuppression */, true /* writableStackTrace */); } } private void waitForLatch(CountDownLatch latch, String reason, long timeOut) - throws TimeoutException { + throws RemoteException, TimeoutException { try { if (!latch.await(timeOut, TimeUnit.SECONDS)) { throw new TimeoutException("Latch wait for " + reason + " elapsed"); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); - throw new IllegalStateException("Latch wait for " + reason + " interrupted"); + throw new RemoteException("Latch wait for " + reason + " interrupted"); } } } diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index 8b3aaf7be871..76d4142df037 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -3950,13 +3950,15 @@ public class StatsPullAtomService extends SystemService { ConnectivityManager.NetworkCallback { @Override public void onAvailable(Network network) { - FrameworkStatsLog.write(FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED, network.netId, + FrameworkStatsLog.write(FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED, + network.getNetId(), FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED__STATE__CONNECTED); } @Override public void onLost(Network network) { - FrameworkStatsLog.write(FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED, network.netId, + FrameworkStatsLog.write(FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED, + network.getNetId(), FrameworkStatsLog.CONNECTIVITY_STATE_CHANGED__STATE__DISCONNECTED); } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java index a896f1b0d60f..b51f4df43259 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java @@ -44,6 +44,7 @@ import android.content.ContextWrapper; import android.content.pm.UserInfo; import android.hardware.rebootescrow.IRebootEscrow; import android.os.Handler; +import android.os.HandlerThread; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.os.UserManager; @@ -62,6 +63,7 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import java.io.File; +import java.io.IOException; import java.util.ArrayList; import javax.crypto.SecretKey; @@ -181,6 +183,18 @@ public class RebootEscrowManagerTests { } @Override + public int getLoadEscrowDataRetryLimit() { + // Try two times + return 2; + } + + @Override + public int getLoadEscrowDataRetryIntervalSeconds() { + // Retry in 1 seconds + return 1; + } + + @Override public void reportMetric(boolean success) { mInjected.reportMetric(success); } @@ -448,6 +462,46 @@ public class RebootEscrowManagerTests { } @Test + public void loadRebootEscrowDataIfAvailable_ServerBased_RetrySuccess() throws Exception { + setServerBasedRebootEscrowProvider(); + + when(mInjected.getBootCount()).thenReturn(0); + RebootEscrowListener mockListener = mock(RebootEscrowListener.class); + mService.setRebootEscrowListener(mockListener); + mService.prepareRebootEscrow(); + + clearInvocations(mServiceConnection); + mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN); + verify(mockListener).onPreparedForReboot(eq(true)); + verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong()); + + // Use x -> x for both wrap & unwrap functions. + when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong())) + .thenAnswer(invocation -> invocation.getArgument(0)); + assertTrue(mService.armRebootEscrowIfNeeded()); + verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong()); + assertTrue(mStorage.hasRebootEscrowServerBlob()); + + // pretend reboot happens here + when(mInjected.getBootCount()).thenReturn(1); + ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class); + doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture()); + + when(mServiceConnection.unwrap(any(), anyLong())) + .thenThrow(new IOException()) + .thenAnswer(invocation -> invocation.getArgument(0)); + + HandlerThread thread = new HandlerThread("RebootEscrowManagerTest"); + thread.start(); + mService.loadRebootEscrowDataIfAvailable(new Handler(thread.getLooper())); + // Sleep 5s for the retry to complete + Thread.sleep(5 * 1000); + verify(mServiceConnection, times(2)).unwrap(any(), anyLong()); + assertTrue(metricsSuccessCaptor.getValue()); + verify(mKeyStoreManager).clearKeyStoreEncryptionKey(); + } + + @Test public void loadRebootEscrowDataIfAvailable_TooManyBootsInBetween_NoMetrics() throws Exception { when(mInjected.getBootCount()).thenReturn(0); diff --git a/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java b/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java index c7e7cd5ec64e..179248dd2cf9 100644 --- a/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java +++ b/telephony/common/com/android/internal/telephony/SipMessageParsingUtils.java @@ -65,6 +65,11 @@ public class SipMessageParsingUtils { // compact form of the via header key private static final String VIA_SIP_HEADER_KEY_COMPACT = "v"; + // call-id header key + private static final String CALL_ID_SIP_HEADER_KEY = "call-id"; + // compact form of the call-id header key + private static final String CALL_ID_SIP_HEADER_KEY_COMPACT = "i"; + /** * @return true if the SIP message start line is considered a request (based on known request * methods). @@ -124,6 +129,17 @@ public class SipMessageParsingUtils { return null; } + /** + * Return the call-id header key's associated value. + * @param headerString The string containing the headers of the SIP message. + */ + public static String getCallId(String headerString) { + // search for the call-Id header, there should only be one in the header. + List<Pair<String, String>> headers = parseHeaders(headerString, true, + CALL_ID_SIP_HEADER_KEY, CALL_ID_SIP_HEADER_KEY_COMPACT); + return !headers.isEmpty() ? headers.get(0).second : null; + } + private static String[] splitStartLineAndVerify(String startLine) { String[] splitLine = startLine.split(" "); if (isStartLineMalformed(splitLine)) return null; diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java index 225e3f760d20..38fa9077f188 100644 --- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java @@ -640,6 +640,67 @@ public final class TelephonyPermissions { } /** + * Given a list of permissions, check to see if the caller has at least one of them. If the + * caller has none of these permissions, throw a SecurityException. + */ + public static void enforceAnyPermissionGranted(Context context, int uid, String message, + String... permissions) { + if (permissions.length == 0) return; + boolean isGranted = false; + for (String perm : permissions) { + if (context.checkCallingOrSelfPermission(perm) == PERMISSION_GRANTED) { + isGranted = true; + break; + } + } + + if (isGranted) return; + + StringBuilder b = new StringBuilder(message); + b.append(": Neither user "); + b.append(uid); + b.append(" nor current process has "); + b.append(permissions[0]); + for (int i = 1; i < permissions.length; i++) { + b.append(" or "); + b.append(permissions[i]); + } + throw new SecurityException(b.toString()); + } + + /** + * Given a list of permissions, check to see if the caller has at least one of them granted. If + * not, check to see if the caller has carrier privileges. If the caller does not have any of + * these permissions, throw a SecurityException. + */ + public static void enforceAnyPermissionGrantedOrCarrierPrivileges(Context context, int subId, + int uid, String message, String... permissions) { + if (permissions.length == 0) return; + boolean isGranted = false; + for (String perm : permissions) { + if (context.checkCallingOrSelfPermission(perm) == PERMISSION_GRANTED) { + isGranted = true; + break; + } + } + + if (isGranted) return; + if (checkCarrierPrivilegeForSubId(context, subId)) return; + + StringBuilder b = new StringBuilder(message); + b.append(": Neither user "); + b.append(uid); + b.append(" nor current process has "); + b.append(permissions[0]); + for (int i = 1; i < permissions.length; i++) { + b.append(" or "); + b.append(permissions[i]); + } + b.append(" or carrier privileges"); + throw new SecurityException(b.toString()); + } + + /** * Throws if the caller is not of a shell (or root) UID. * * @param callingUid pass Binder.callingUid(). diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index b82c78bcf2dd..9c9670c99c2d 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -17,6 +17,7 @@ package android.telephony; import android.Manifest; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -37,6 +38,8 @@ import android.telephony.ims.ImsSsData; import com.android.internal.telephony.ICarrierConfigLoader; import com.android.telephony.Rlog; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.concurrent.TimeUnit; /** @@ -103,6 +106,32 @@ public class CarrierConfigManager { */ public static final int USSD_OVER_IMS_ONLY = 3; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "CARRIER_NR_AVAILABILITY_" }, value = { + CARRIER_NR_AVAILABILITY_NONE, + CARRIER_NR_AVAILABILITY_NSA, + CARRIER_NR_AVAILABILITY_SA, + }) + public @interface DeviceNrCapability {} + + /** + * Indicates CARRIER_NR_AVAILABILITY_NONE determine that the carrier does not enable 5G NR. + */ + public static final int CARRIER_NR_AVAILABILITY_NONE = 0; + + /** + * Indicates CARRIER_NR_AVAILABILITY_NSA determine that the carrier enable the non-standalone + * (NSA) mode of 5G NR. + */ + public static final int CARRIER_NR_AVAILABILITY_NSA = 1 << 0; + + /** + * Indicates CARRIER_NR_AVAILABILITY_SA determine that the carrier enable the standalone (SA) + * mode of 5G NR. + */ + public static final int CARRIER_NR_AVAILABILITY_SA = 1 << 1; + private final Context mContext; /** @@ -1774,10 +1803,23 @@ public class CarrierConfigManager { "show_precise_failed_cause_bool"; /** - * Boolean to decide whether NR is enabled. - * @hide + * Bit-field integer to determine whether the carrier enable the non-standalone (NSA) mode of + * 5G NR, standalone (SA) mode of 5G NR + * + * <UL> + * <LI>CARRIER_NR_AVAILABILITY_NONE: non-NR = 0 </LI> + * <LI>CARRIER_NR_AVAILABILITY_NSA: NSA = 1 << 0</LI> + * <LI>CARRIER_NR_AVAILABILITY_SA: SA = 1 << 1</LI> + * </UL> + * <p> The value of this key must be bitwise OR of + * {@link #CARRIER_NR_AVAILABILITY_NONE}, {@link #CARRIER_NR_AVAILABILITY_NSA}, + * {@link #CARRIER_NR_AVAILABILITY_SA}. + * + * <p> For example, if both NSA and SA are used, the value of key is 3 (1 << 0 | 1 << 1). + * If the carrier doesn't support 5G NR, the value of key is 0 (non-NR). + * If the key is invalid or not configured, a default value 3 (NSA|SA = 3) will apply. */ - public static final String KEY_NR_ENABLED_BOOL = "nr_enabled_bool"; + public static final String KEY_CARRIER_NR_AVAILABILITY_INT = "carrier_nr_availability_int"; /** * Boolean to decide whether LTE is enabled. @@ -4546,7 +4588,8 @@ public class CarrierConfigManager { sDefaults.putString(KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, ""); sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true); sDefaults.putInt(KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT, 20000); - sDefaults.putBoolean(KEY_NR_ENABLED_BOOL, true); + sDefaults.putInt(KEY_CARRIER_NR_AVAILABILITY_INT, + CARRIER_NR_AVAILABILITY_NSA | CARRIER_NR_AVAILABILITY_SA); sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true); sDefaults.putBoolean(KEY_SUPPORT_TDSCDMA_BOOL, false); sDefaults.putStringArray(KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY, null); diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 4e481b3ad837..85fe14ef8062 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -907,7 +907,8 @@ public class SubscriptionManager { * Indicate which network type is allowed. By default it's enabled. * @hide */ - public static final String ALLOWED_NETWORK_TYPES = SimInfo.COLUMN_ALLOWED_NETWORK_TYPES; + public static final String ALLOWED_NETWORK_TYPES = + SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS; /** * Broadcast Action: The user has changed one of the default subs related to diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 716317d0f810..f12ff93ecb36 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -7735,21 +7735,13 @@ public class TelephonyManager { * * @return the preferred network type. * @hide - * @deprecated Use {@link #getPreferredNetworkTypeBitmask} instead. + * @deprecated Use {@link #getAllowedNetworkTypesBitmask} instead. */ @Deprecated @RequiresPermission((android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)) @UnsupportedAppUsage public @PrefNetworkMode int getPreferredNetworkType(int subId) { - try { - ITelephony telephony = getITelephony(); - if (telephony != null) { - return telephony.getPreferredNetworkType(subId); - } - } catch (RemoteException ex) { - Rlog.e(TAG, "getPreferredNetworkType RemoteException", ex); - } - return -1; + return RadioAccessFamily.getNetworkTypeFromRaf((int) getAllowedNetworkTypesBitmask()); } /** @@ -7765,24 +7757,47 @@ public class TelephonyManager { * @return The bitmask of preferred network types. * * @hide + * @deprecated Use {@link #getAllowedNetworkTypesBitmask} instead. */ + @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @SystemApi public @NetworkTypeBitMask long getPreferredNetworkTypeBitmask() { + return getAllowedNetworkTypesBitmask(); + } + + /** + * Get the allowed network type bitmask. + * Note that the device can only register on the network of {@link NetworkTypeBitmask} + * (except for emergency call cases). + * + * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()} + * + * <p>Requires Permission: + * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE} + * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * + * @return The bitmask of allowed network types. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SystemApi + public @NetworkTypeBitMask long getAllowedNetworkTypesBitmask() { try { ITelephony telephony = getITelephony(); if (telephony != null) { - return (long) RadioAccessFamily.getRafFromNetworkType( - telephony.getPreferredNetworkType(getSubId())); + return (long) telephony.getAllowedNetworkTypesBitmask(getSubId()); } } catch (RemoteException ex) { - Rlog.e(TAG, "getPreferredNetworkTypeBitmask RemoteException", ex); + Rlog.e(TAG, "getAllowedNetworkTypesBitmask RemoteException", ex); } return 0; } /** - * Get the allowed network types. + * Get the allowed network types by carriers. * * <p>Requires Permission: * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE} @@ -7790,14 +7805,17 @@ public class TelephonyManager { * * @return the allowed network type bitmask * @hide + * @deprecated Use {@link #getAllowedNetworkTypesForReason} instead. */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @SystemApi + @Deprecated public @NetworkTypeBitMask long getAllowedNetworkTypes() { try { ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.getAllowedNetworkTypes(getSubId()); + return telephony.getAllowedNetworkTypesForReason(getSubId(), + TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER); } } catch (RemoteException ex) { Rlog.e(TAG, "getAllowedNetworkTypes RemoteException", ex); @@ -8019,7 +8037,7 @@ public class TelephonyManager { return false; } - /** + /** * Get the network selection mode. * * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the @@ -8116,7 +8134,7 @@ public class TelephonyManager { * @param networkType the preferred network type * @return true on success; false on any failure. * @hide - * @deprecated Use {@link #setPreferredNetworkTypeBitmask} instead. + * @deprecated Use {@link #setAllowedNetworkTypesForReason} instead. */ @Deprecated @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @@ -8124,7 +8142,9 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.setPreferredNetworkType(subId, networkType); + return telephony.setAllowedNetworkTypesForReason(subId, + TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER, + RadioAccessFamily.getRafFromNetworkType(networkType)); } } catch (RemoteException ex) { Rlog.e(TAG, "setPreferredNetworkType RemoteException", ex); @@ -8151,16 +8171,17 @@ public class TelephonyManager { * @param networkTypeBitmask The bitmask of preferred network types. * @return true on success; false on any failure. * @hide + * @deprecated Use {@link #setAllowedNetworkTypesForReason} instead. */ + @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @SystemApi public boolean setPreferredNetworkTypeBitmask(@NetworkTypeBitMask long networkTypeBitmask) { try { ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.setPreferredNetworkType( - getSubId(), RadioAccessFamily.getNetworkTypeFromRaf( - (int) networkTypeBitmask)); + return telephony.setAllowedNetworkTypesForReason(getSubId(), + TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER, networkTypeBitmask); } } catch (RemoteException ex) { Rlog.e(TAG, "setPreferredNetworkTypeBitmask RemoteException", ex); @@ -8181,7 +8202,9 @@ public class TelephonyManager { * @param allowedNetworkTypes The bitmask of allowed network types. * @return true on success; false on any failure. * @hide + * @deprecated Use {@link #setAllowedNetworkTypesForReason} instead. */ + @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature( enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported", @@ -8191,7 +8214,8 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.setAllowedNetworkTypes(getSubId(), allowedNetworkTypes); + return telephony.setAllowedNetworkTypesForReason(getSubId(), + TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER, allowedNetworkTypes); } } catch (RemoteException ex) { Rlog.e(TAG, "setAllowedNetworkTypes RemoteException", ex); @@ -8201,27 +8225,53 @@ public class TelephonyManager { /** @hide */ @IntDef({ - ALLOWED_NETWORK_TYPES_REASON_POWER + ALLOWED_NETWORK_TYPES_REASON_USER, + ALLOWED_NETWORK_TYPES_REASON_POWER, + ALLOWED_NETWORK_TYPES_REASON_CARRIER }) @Retention(RetentionPolicy.SOURCE) - public @interface AllowedNetworkTypesReason{} + public @interface AllowedNetworkTypesReason { + } + + /** + * To indicate allowed network type change is requested by user. + * + * @hide + */ + @SystemApi + public static final int ALLOWED_NETWORK_TYPES_REASON_USER = 0; /** * To indicate allowed network type change is requested by power manager. * Power Manger configuration won't affect the settings configured through - * {@link setAllowedNetworkTypes} and will result in allowing network types that are in both + * other reasons and will result in allowing network types that are in both * configurations (i.e intersection of both sets). + * * @hide */ - public static final int ALLOWED_NETWORK_TYPES_REASON_POWER = 0; + @SystemApi + public static final int ALLOWED_NETWORK_TYPES_REASON_POWER = 1; + + /** + * To indicate allowed network type change is requested by carrier. + * Carrier configuration won't affect the settings configured through + * other reasons and will result in allowing network types that are in both + * configurations (i.e intersection of both sets). + * + * @hide + */ + @SystemApi + public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2; /** * Set the allowed network types of the device and * provide the reason triggering the allowed network change. * This can be called for following reasons * <ol> + * <li>Allowed network types control by USER {@link #ALLOWED_NETWORK_TYPES_REASON_USER} * <li>Allowed network types control by power manager * {@link #ALLOWED_NETWORK_TYPES_REASON_POWER} + * <li>Allowed network types control by carrier {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER} * </ol> * This API will result in allowing an intersection of allowed network types for all reasons, * including the configuration done through other reasons. @@ -8237,15 +8287,17 @@ public class TelephonyManager { * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed. * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @RequiresFeature( enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported", value = TelephonyManager.CAPABILITY_ALLOWED_NETWORK_TYPES_USED) public void setAllowedNetworkTypesForReason(@AllowedNetworkTypesReason int reason, @NetworkTypeBitMask long allowedNetworkTypes) { - if (reason != ALLOWED_NETWORK_TYPES_REASON_POWER) { + if (!isValidAllowedNetworkTypesReason(reason)) { throw new IllegalArgumentException("invalid AllowedNetworkTypesReason."); } + try { ITelephony telephony = getITelephony(); if (telephony != null) { @@ -8264,28 +8316,29 @@ public class TelephonyManager { * Get the allowed network types for certain reason. * * {@link #getAllowedNetworkTypesForReason} returns allowed network type for a - * specific reason. For effective allowed network types configured on device, - * query {@link getEffectiveAllowedNetworkTypes} + * specific reason. * * <p>Requires Permission: * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE} * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). - *s + * * @param reason the reason the allowed network type change is taking place * @return the allowed network type bitmask - * @throws IllegalStateException if the Telephony process is not currently available. + * @throws IllegalStateException if the Telephony process is not currently available. * @throws IllegalArgumentException if invalid AllowedNetworkTypesReason is passed. * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @RequiresFeature( enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported", value = TelephonyManager.CAPABILITY_ALLOWED_NETWORK_TYPES_USED) public @NetworkTypeBitMask long getAllowedNetworkTypesForReason( @AllowedNetworkTypesReason int reason) { - if (reason != ALLOWED_NETWORK_TYPES_REASON_POWER) { + if (!isValidAllowedNetworkTypesReason(reason)) { throw new IllegalArgumentException("invalid AllowedNetworkTypesReason."); } + try { ITelephony telephony = getITelephony(); if (telephony != null) { @@ -8299,44 +8352,27 @@ public class TelephonyManager { } return -1; } - /** - * Get bit mask of all network types. - * - * @return bit mask of all network types + * Verifies that the reason provided is valid. * @hide */ - public static @NetworkTypeBitMask long getAllNetworkTypesBitmask() { - return NETWORK_STANDARDS_FAMILY_BITMASK_3GPP | NETWORK_STANDARDS_FAMILY_BITMASK_3GPP2; + public static boolean isValidAllowedNetworkTypesReason(@AllowedNetworkTypesReason int reason) { + switch (reason) { + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER: + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER: + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER: + return true; + } + return false; } - /** - * Get the allowed network types configured on the device. - * This API will return an intersection of allowed network types for all reasons, - * including the configuration done through setAllowedNetworkTypes - * - * <p>Requires Permission: - * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE} - * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). + * Get bit mask of all network types. * - * @return the allowed network type bitmask - * @throws IllegalStateException if the Telephony process is not currently available. + * @return bit mask of all network types * @hide */ - @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - public @NetworkTypeBitMask long getEffectiveAllowedNetworkTypes() { - try { - ITelephony telephony = getITelephony(); - if (telephony != null) { - return telephony.getEffectiveAllowedNetworkTypes(getSubId()); - } else { - throw new IllegalStateException("telephony service is null."); - } - } catch (RemoteException ex) { - Rlog.e(TAG, "getEffectiveAllowedNetworkTypes RemoteException", ex); - ex.rethrowFromSystemServer(); - } - return -1; + public static @NetworkTypeBitMask long getAllNetworkTypesBitmask() { + return NETWORK_STANDARDS_FAMILY_BITMASK_3GPP | NETWORK_STANDARDS_FAMILY_BITMASK_3GPP2; } /** @@ -14610,8 +14646,13 @@ public class TelephonyManager { * <li>Generate the ks_NAF/ ks_Ext_NAF to be returned via the callback.</li> * </ol> * - * <p> Requires Permission: MODIFY_PHONE_STATE or that the calling app has carrier - * privileges (see {@link #hasCarrierPrivileges}). + * <p> Requires Permission: + * <ul> + * <li>{@link android.Manifest.permission#MODIFY_PHONE_STATE},</li> + * <li>{@link android.Manifest.permission#PERFORM_IMS_SINGLE_REGISTRATION},</li> + * <li>or that the caller has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges()}).</li> + * </ul> * @param appType icc application type, like {@link #APPTYPE_USIM} or {@link * #APPTYPE_ISIM} or {@link#APPTYPE_UNKNOWN} * @param nafId Network Application Function(NAF) fully qualified domain name and @@ -14638,7 +14679,8 @@ public class TelephonyManager { */ @SystemApi @WorkerThread - @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + @RequiresPermission(anyOf = {android.Manifest.permission.MODIFY_PHONE_STATE, + Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void bootstrapAuthenticationRequest( @UiccAppTypeExt int appType, @NonNull Uri nafId, @NonNull UaSecurityProtocolIdentifier securityProtocol, diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java index 08eec29d5ac2..a9ccb6aa64f2 100644 --- a/telephony/java/android/telephony/ims/ProvisioningManager.java +++ b/telephony/java/android/telephony/ims/ProvisioningManager.java @@ -32,6 +32,7 @@ import android.os.ServiceSpecificException; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyFrameworkInitializer; +import android.telephony.TelephonyManager; import android.telephony.ims.aidl.IImsConfigCallback; import android.telephony.ims.aidl.IRcsConfigCallback; import android.telephony.ims.feature.MmTelFeature; @@ -1300,7 +1301,7 @@ public class ProvisioningManager { * provisioning. * <p> * Requires Permission: Manifest.permission.MODIFY_PHONE_STATE or that the calling app has - * carrier privileges (see {@link #hasCarrierPrivileges}). + * carrier privileges (see {@link TelephonyManager#hasCarrierPrivileges}). * @param config The XML file to be read. ASCII/UTF8 encoded text if not compressed. * @param isCompressed The XML file is compressed in gzip format and must be decompressed * before being read. @@ -1330,7 +1331,7 @@ public class ProvisioningManager { * the intent is valid. and {@link #EXTRA_STATUS} to specify RCS VoLTE single registration * status. */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresPermission(Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE = "android.telephony.ims.action.RCS_SINGLE_REGISTRATION_CAPABILITY_UPDATE"; @@ -1375,7 +1376,7 @@ public class ProvisioningManager { * provisioning status events {@link #registerRcsProvisioningChangedCallback} * @param rcc RCS client configuration {@link RcsClientConfiguration} */ - @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @RequiresPermission(Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void setRcsClientConfiguration( @NonNull RcsClientConfiguration rcc) throws ImsException { try { @@ -1390,6 +1391,14 @@ public class ProvisioningManager { /** * Returns a flag to indicate whether or not the device supports IMS single registration for * MMTEL and RCS features as well as if the carrier has provisioned the feature. + * + * <p> Requires Permission: + * <ul> + * <li>{@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE},</li> + * <li>{@link android.Manifest.permission#PERFORM_IMS_SINGLE_REGISTRATION},</li> + * <li>or that the caller has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges()}).</li> + * </ul> * @return true if IMS single registration is capable at this time, or false otherwise * @throws ImsException If the remote ImsService is not available for * any reason or the subscription associated with this instance is no @@ -1398,7 +1407,8 @@ public class ProvisioningManager { * @see PackageManager#FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION for whether or not this * device supports IMS single registration. */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresPermission(anyOf = {Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public boolean isRcsVolteSingleRegistrationCapable() throws ImsException { try { return getITelephony().isRcsVolteSingleRegistrationCapable(mSubId); @@ -1408,36 +1418,44 @@ public class ProvisioningManager { } /** - * Registers a new {@link RcsProvisioningCallback} to listen to changes to - * RCS provisioning xml. - * - * <p>RCS application must be the default messaging application and must - * have already registered its {@link RcsClientConfiguration} by using - * {@link #setRcsClientConfiguration} before it registers the provisioning - * callback. If ProvisioningManager has a valid RCS configuration at the - * time of callback registration and a reconfiguration is not required - * due to RCS client parameters change, then the callback shall be invoked - * immediately with the xml. - * When the subscription associated with this callback is removed (SIM removed, - * ESIM swap,etc...), this callback will automatically be removed. - * - * @param executor The {@link Executor} to call the callback methods on - * @param callback The rcs provisioning callback to be registered. - * @see #unregisterRcsProvisioningChangedCallback(RcsProvisioningCallback) - * @see SubscriptionManager.OnSubscriptionsChangedListener - * @throws IllegalArgumentException if the subscription associated with this - * callback is not active (SIM is not inserted, ESIM inactive) or the - * subscription is invalid. - * @throws ImsException if the subscription associated with this callback is - * valid, but the {@link ImsService} associated with the subscription is not - * available. This can happen if the service crashed, for example. - * It shall also throw this exception when the RCS client parameters for the - * application are not valid. In that case application must set the client - * params (See {@link #setRcsClientConfiguration}) and re register the - * callback. - * See {@link ImsException#getCode()} for a more detailed reason. - */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + * Registers a new {@link RcsProvisioningCallback} to listen to changes to + * RCS provisioning xml. + * + * <p>RCS application must be the default messaging application and must + * have already registered its {@link RcsClientConfiguration} by using + * {@link #setRcsClientConfiguration} before it registers the provisioning + * callback. If ProvisioningManager has a valid RCS configuration at the + * time of callback registration and a reconfiguration is not required + * due to RCS client parameters change, then the callback shall be invoked + * immediately with the xml. + * When the subscription associated with this callback is removed (SIM removed, + * ESIM swap,etc...), this callback will automatically be removed. + * <p> Requires Permission: + * <ul> + * <li>{@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE},</li> + * <li>{@link android.Manifest.permission#PERFORM_IMS_SINGLE_REGISTRATION},</li> + * <li>or that the caller has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges()}).</li> + * </ul> + * + * @param executor The {@link Executor} to call the callback methods on + * @param callback The rcs provisioning callback to be registered. + * @see #unregisterRcsProvisioningChangedCallback(RcsProvisioningCallback) + * @see SubscriptionManager.OnSubscriptionsChangedListener + * @throws IllegalArgumentException if the subscription associated with this + * callback is not active (SIM is not inserted, ESIM inactive) or the + * subscription is invalid. + * @throws ImsException if the subscription associated with this callback is + * valid, but the {@link ImsService} associated with the subscription is not + * available. This can happen if the service crashed, for example. + * It shall also throw this exception when the RCS client parameters for the + * application are not valid. In that case application must set the client + * params (See {@link #setRcsClientConfiguration}) and re register the + * callback. + * See {@link ImsException#getCode()} for a more detailed reason. + */ + @RequiresPermission(anyOf = {Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void registerRcsProvisioningChangedCallback( @NonNull @CallbackExecutor Executor executor, @NonNull RcsProvisioningCallback callback) throws ImsException { @@ -1459,13 +1477,22 @@ public class ProvisioningManager { * removed, ESIM swap, etc...), this callback will automatically be * removed. If this method is called for an inactive subscription, it * will result in a no-op. + * <p> Requires Permission: + * <ul> + * <li>{@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE},</li> + * <li>{@link android.Manifest.permission#PERFORM_IMS_SINGLE_REGISTRATION},</li> + * <li>or that the caller has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges()}).</li> + * </ul> + * * @param callback The existing {@link RcsProvisioningCallback} to be * removed. * @see #registerRcsProvisioningChangedCallback * @throws IllegalArgumentException if the subscription associated with this callback is * invalid. */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresPermission(anyOf = {Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void unregisterRcsProvisioningChangedCallback( @NonNull RcsProvisioningCallback callback) { try { @@ -1480,7 +1507,7 @@ public class ProvisioningManager { * Reconfiguration triggered by the RCS application. Most likely cause * is the 403 forbidden to a HTTP request. */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresPermission(Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void triggerRcsReconfiguration() { try { getITelephony().triggerRcsReconfiguration(mSubId); diff --git a/telephony/java/android/telephony/ims/SipDelegateManager.java b/telephony/java/android/telephony/ims/SipDelegateManager.java index 04421c9a2449..399b6dc88cef 100644 --- a/telephony/java/android/telephony/ims/SipDelegateManager.java +++ b/telephony/java/android/telephony/ims/SipDelegateManager.java @@ -28,7 +28,6 @@ import android.content.pm.PackageManager; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.telephony.BinderCacheManager; -import android.telephony.CarrierConfigManager; import android.telephony.ims.aidl.IImsRcsController; import android.telephony.ims.aidl.SipDelegateConnectionAidlWrapper; import android.telephony.ims.stub.DelegateConnectionMessageCallback; @@ -275,7 +274,8 @@ public class SipDelegateManager { * @see CarrierConfigManager.Ims#KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL * @see PackageManager#FEATURE_TELEPHONY_IMS_SINGLE_REGISTRATION */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresPermission(anyOf = {Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public boolean isSupported() throws ImsException { try { IImsRcsController controller = mBinderCache.getBinder(); @@ -317,7 +317,7 @@ public class SipDelegateManager { * @throws ImsException Thrown if there was a problem communicating with the ImsService * associated with this SipDelegateManager. See {@link ImsException#getCode()}. */ - @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @RequiresPermission(Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void createSipDelegate(@NonNull DelegateRequest request, @NonNull Executor executor, @NonNull DelegateConnectionStateCallback dc, @NonNull DelegateConnectionMessageCallback mc) throws ImsException { @@ -351,7 +351,7 @@ public class SipDelegateManager { * @param delegateConnection The SipDelegateConnection to destroy. * @param reason The reason for why this SipDelegateConnection was destroyed. */ - @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @RequiresPermission(Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void destroySipDelegate(@NonNull SipDelegateConnection delegateConnection, @SipDelegateDestroyReason int reason) { @@ -392,6 +392,7 @@ public class SipDelegateManager { * this condition. May be {@code null} if there was no reason String provided from the * network. */ + @RequiresPermission(Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void triggerFullNetworkRegistration(@NonNull SipDelegateConnection connection, @IntRange(from = 100, to = 699) int sipCode, @Nullable String sipReason) { if (connection == null) { diff --git a/telephony/java/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java index 9cfa640fce18..ad6d73c39962 100644 --- a/telephony/java/android/telephony/ims/SipMessage.java +++ b/telephony/java/android/telephony/ims/SipMessage.java @@ -19,6 +19,7 @@ package android.telephony.ims; import static java.nio.charset.StandardCharsets.UTF_8; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.os.Build; import android.os.Parcel; @@ -46,6 +47,8 @@ public final class SipMessage implements Parcelable { private final String mStartLine; private final String mHeaderSection; private final byte[] mContent; + private final String mViaBranchParam; + private final String mCallIdParam; /** * Represents a partially encoded SIP message. @@ -63,6 +66,9 @@ public final class SipMessage implements Parcelable { mStartLine = startLine; mHeaderSection = headerSection; mContent = content; + + mViaBranchParam = SipMessageParsingUtils.getTransactionId(mHeaderSection); + mCallIdParam = SipMessageParsingUtils.getCallId(mHeaderSection); } /** @@ -73,6 +79,8 @@ public final class SipMessage implements Parcelable { mHeaderSection = source.readString(); mContent = new byte[source.readInt()]; source.readByteArray(mContent); + mViaBranchParam = source.readString(); + mCallIdParam = source.readString(); } /** @@ -97,6 +105,25 @@ public final class SipMessage implements Parcelable { return mContent; } + /** + * @return the branch parameter enclosed in the Via header key's value. See RFC 3261 section + * 20.42 for more information on the Via header. If {@code null}, then there was either no + * Via parameter found in this SIP message's headers or no branch parameter found in the + * Via header. + */ + public @Nullable String getViaBranchParameter() { + return mViaBranchParam; + } + + /** + * @return the value associated with the call-id header of this SIP message. See RFC 3261 + * section 20.8 for more information on the call-id header. If {@code null}, then there was no + * call-id header found in this SIP message's headers. + */ + public @Nullable String getCallIdParameter() { + return mCallIdParam; + } + @Override public int describeContents() { return 0; @@ -108,6 +135,8 @@ public final class SipMessage implements Parcelable { dest.writeString(mHeaderSection); dest.writeInt(mContent.length); dest.writeByteArray(mContent); + dest.writeString(mViaBranchParam); + dest.writeString(mCallIdParam); } public static final @NonNull Creator<SipMessage> CREATOR = new Creator<SipMessage>() { diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java index 9d919015087d..739946be2e5b 100644 --- a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java +++ b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java @@ -31,8 +31,6 @@ import android.telephony.ims.stub.SipDelegate; import android.text.TextUtils; import android.util.Log; -import com.android.internal.telephony.SipMessageParsingUtils; - import java.util.ArrayList; import java.util.Set; import java.util.concurrent.Executor; @@ -188,7 +186,7 @@ public class SipDelegateAidlWrapper implements DelegateStateCallback, DelegateMe } private void notifyLocalMessageFailedToBeReceived(SipMessage m, int reason) { - String transactionId = SipMessageParsingUtils.getTransactionId(m.getHeaderSection()); + String transactionId = m.getViaBranchParameter(); if (TextUtils.isEmpty(transactionId)) { Log.w(LOG_TAG, "failure to parse SipMessage."); throw new IllegalArgumentException("Malformed SipMessage, can not determine " diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java index c877aca8ba96..3cd27264295c 100644 --- a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java +++ b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java @@ -32,8 +32,6 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; -import com.android.internal.telephony.SipMessageParsingUtils; - import java.util.List; import java.util.NoSuchElementException; import java.util.concurrent.Executor; @@ -268,7 +266,7 @@ public class SipDelegateConnectionAidlWrapper implements SipDelegateConnection, } private void notifyLocalMessageFailedToSend(SipMessage m, int reason) { - String transactionId = SipMessageParsingUtils.getTransactionId(m.getHeaderSection()); + String transactionId = m.getViaBranchParameter(); if (TextUtils.isEmpty(transactionId)) { Log.w(LOG_TAG, "sendMessage detected a malformed SipMessage and can not get a " + "transaction ID."); diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 9fe06dc32c28..a05374c63052 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -797,24 +797,15 @@ interface ITelephony { * @return {@code true} on success; {@code false} on any failure. */ boolean rebootModem(int slotIndex); - /* - * Get the calculated preferred network type. - * Used for device configuration by some CDMA operators. - * @param callingPackage The package making the call. - * @param callingFeatureId The feature in the package. - * - * @return the calculated preferred network type, defined in RILConstants.java. - */ - int getCalculatedPreferredNetworkType(String callingPackage, String callingFeatureId); /* - * Get the preferred network type. + * Get the allowed network type. * Used for device configuration by some CDMA operators. * * @param subId the id of the subscription to query. - * @return the preferred network type, defined in RILConstants.java. + * @return the allowed network type bitmask, defined in RILConstants.java. */ - int getPreferredNetworkType(int subId); + int getAllowedNetworkTypesBitmask(int subId); /** * Check whether DUN APN is required for tethering with subId. @@ -940,23 +931,6 @@ interface ITelephony { int subId, in OperatorInfo operatorInfo, boolean persisSelection); /** - * Get the allowed network types that store in the telephony provider. - * - * @param subId the id of the subscription. - * @return allowedNetworkTypes the allowed network types. - */ - long getAllowedNetworkTypes(int subId); - - /** - * Set the allowed network types. - * - * @param subId the id of the subscription. - * @param allowedNetworkTypes the allowed network types. - * @return true on success; false on any failure. - */ - boolean setAllowedNetworkTypes(int subId, long allowedNetworkTypes); - - /** * Get the allowed network types for certain reason. * * @param subId the id of the subscription. @@ -966,16 +940,6 @@ interface ITelephony { long getAllowedNetworkTypesForReason(int subId, int reason); /** - * Get the effective allowed network types on the device. This API will - * return an intersection of allowed network types for all reasons, - * including the configuration done through setAllowedNetworkTypes - * - * @param subId the id of the subscription. - * @return allowedNetworkTypes the allowed network types. - */ - long getEffectiveAllowedNetworkTypes(int subId); - - /** * Set the allowed network types and provide the reason triggering the allowed network change. * * @param subId the id of the subscription. @@ -986,16 +950,6 @@ interface ITelephony { boolean setAllowedNetworkTypesForReason(int subId, int reason, long allowedNetworkTypes); /** - * Set the preferred network type. - * Used for device configuration by some CDMA operators. - * - * @param subId the id of the subscription to update. - * @param networkType the preferred network type, defined in RILConstants.java. - * @return true on success; false on any failure. - */ - boolean setPreferredNetworkType(int subId, int networkType); - - /** * Get the user enabled state of Mobile Data. * * TODO: remove and use isUserDataEnabled. diff --git a/tests/net/common/java/android/net/CaptivePortalTest.java b/tests/net/common/java/android/net/CaptivePortalTest.java index 4cdf6a2a4b36..15d3398d43c0 100644 --- a/tests/net/common/java/android/net/CaptivePortalTest.java +++ b/tests/net/common/java/android/net/CaptivePortalTest.java @@ -25,6 +25,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.testutils.DevSdkIgnoreRule; +import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; import org.junit.Rule; @@ -53,6 +54,12 @@ public class CaptivePortalTest { public void appRequest(final int request) throws RemoteException { mCode = request; } + + // This is only @Override on R- + public void logEvent(int eventId, String packageName) throws RemoteException { + mCode = eventId; + mPackageName = packageName; + } } private interface TestFunctor { @@ -91,14 +98,24 @@ public class CaptivePortalTest { assertEquals(result.mCode, CaptivePortal.APP_REQUEST_REEVALUATION_REQUIRED); } - /** - * Test testLogEvent is expected to do nothing but shouldn't crash, because the API logEvent - * has been deprecated. - */ + @IgnoreUpTo(Build.VERSION_CODES.R) @Test public void testLogEvent() { + /** + * From S testLogEvent is expected to do nothing but shouldn't crash (the API + * logEvent has been deprecated). + */ final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.logEvent( 0, TEST_PACKAGE_NAME)); } + + @IgnoreAfter(Build.VERSION_CODES.R) + @Test + public void testLogEvent_UntilR() { + final MyCaptivePortalImpl result = runCaptivePortalTest(c -> c.logEvent( + 42, TEST_PACKAGE_NAME)); + assertEquals(result.mCode, 42); + assertEquals(result.mPackageName, TEST_PACKAGE_NAME); + } } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index d637ffa9b24b..d9830c38ff3e 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -9932,12 +9932,11 @@ public class ConnectivityServiceTest { .build(); // Act on ConnectivityService.setOemNetworkPreference() - final TestOemListenerCallback mOnSetOemNetworkPreferenceTestListener = - new TestOemListenerCallback(); - mService.setOemNetworkPreference(pref, mOnSetOemNetworkPreferenceTestListener); + final TestOemListenerCallback oemPrefListener = new TestOemListenerCallback(); + mService.setOemNetworkPreference(pref, oemPrefListener); // Verify call returned successfully - mOnSetOemNetworkPreferenceTestListener.expectOnComplete(); + oemPrefListener.expectOnComplete(); } private static class TestOemListenerCallback implements IOnSetOemNetworkPreferenceListener { diff --git a/tests/vcn/assets/self-signed-ca.pem b/tests/vcn/assets/self-signed-ca.pem new file mode 100644 index 000000000000..5135ea7077a8 --- /dev/null +++ b/tests/vcn/assets/self-signed-ca.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDPjCCAiagAwIBAgIICrKLpR7LxlowDQYJKoZIhvcNAQELBQAwPTELMAkGA1UE +BhMCVVMxEDAOBgNVBAoTB0FuZHJvaWQxHDAaBgNVBAMTE2NhLnRlc3QuYW5kcm9p +ZC5uZXQwHhcNMTkwNzE2MTcxNTUyWhcNMjkwNzEzMTcxNTUyWjA9MQswCQYDVQQG +EwJVUzEQMA4GA1UEChMHQW5kcm9pZDEcMBoGA1UEAxMTY2EudGVzdC5hbmRyb2lk +Lm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANsvTwad2Nie0VOy +Xb1VtHL0R760Jm4vr14JWMcX4oiE6jUdTNdXQ0CGb65wvulP2aEeukFH0D/cvBMR +Bv9+haEwo9/grIXg9ALNKp+GfuZYw/dfnUMHFn3g2+SUgP6BoMZc4lkHktjkDKxp +99Q6h4NP/ip1labkhBeB9+Z6l78LTixKRKspNITWASJed9bjzshYxKHi6dJy3maQ +1LwYKmK7PEGRpoDoT8yZhFbxsVDUojGnJKH1RLXVOn/psG6dI/+IsbTipAttj5zc +g2VAD56PZG2Jd+vsup+g4Dy72hyy242x5c/H2LKZn4X0B0B+IXyii/ZVc+DJldQ5 +JqplOL8CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFGYUzuvZUaVJl8mcxejuFiUNGcTfMA0GCSqGSIb3DQEBCwUAA4IB +AQDQYeqjvHsK2ZqSqxakDp0nu36Plbj48Wvx1ru7GW2faz7i0w/Zkxh06zniILCb +QJRjDebSTHc5SSbCFrRTvqagaLDhbH42/hQncWqIoJqW+pmznJET4JiBO0sqzm05 +yQWsLI/h9Ir28Y2g5N+XPBU0VVVejQqH4iI0iwQx7y7ABssQ0Xa/K73VPbeGaKd6 +Prt4wjJvTlIL2yE2+0MggJ3F2rNptL5SDpg3g+4/YQ6wVRBFil95kUqplEsCtU4P +t+8RghiEmsRx/8CywKfZ5Hex87ODhsSDmDApcefbd5gxoWVkqxZUkPcKwYv1ucm8 +u4r44fj4/9W0Zeooav5Yoh1q +-----END CERTIFICATE-----
\ No newline at end of file diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java index 66590c92579b..7515971b8307 100644 --- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java +++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java @@ -203,9 +203,6 @@ public class VcnManagerTest { IVcnStatusCallback cbBinder = new VcnStatusCallbackBinder(INLINE_EXECUTOR, mMockStatusCallback); - cbBinder.onEnteredSafeMode(); - verify(mMockStatusCallback).onEnteredSafeMode(); - cbBinder.onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE); verify(mMockStatusCallback).onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE); diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java new file mode 100644 index 000000000000..bc8e9d3200b6 --- /dev/null +++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/EapSessionConfigUtilsTest.java @@ -0,0 +1,113 @@ +/* + * 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.net.vcn.persistablebundleutils; + +import static android.telephony.TelephonyManager.APPTYPE_USIM; + +import static org.junit.Assert.assertEquals; + +import android.net.eap.EapSessionConfig; +import android.os.PersistableBundle; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class EapSessionConfigUtilsTest { + private static final byte[] EAP_ID = "test@android.net".getBytes(StandardCharsets.US_ASCII); + private static final String USERNAME = "username"; + private static final String PASSWORD = "password"; + private static final int SUB_ID = 1; + private static final String NETWORK_NAME = "android.net"; + private static final boolean ALLOW_MISMATCHED_NETWORK_NAMES = true; + + private EapSessionConfig.Builder createBuilderWithId() { + return new EapSessionConfig.Builder().setEapIdentity(EAP_ID); + } + + private static void verifyPersistableBundleEncodeDecodeIsLossless(EapSessionConfig config) { + final PersistableBundle bundle = EapSessionConfigUtils.toPersistableBundle(config); + final EapSessionConfig resultConfig = EapSessionConfigUtils.fromPersistableBundle(bundle); + + assertEquals(config, resultConfig); + } + + @Test + public void testSetEapMsChapV2EncodeDecodeIsLossless() throws Exception { + final EapSessionConfig config = + createBuilderWithId().setEapMsChapV2Config(USERNAME, PASSWORD).build(); + + verifyPersistableBundleEncodeDecodeIsLossless(config); + } + + @Test + public void testSetEapSimEncodeDecodeIsLossless() throws Exception { + final EapSessionConfig config = + createBuilderWithId().setEapSimConfig(SUB_ID, APPTYPE_USIM).build(); + + verifyPersistableBundleEncodeDecodeIsLossless(config); + } + + @Test + public void testSetEapAkaEncodeDecodeIsLossless() throws Exception { + final EapSessionConfig config = + createBuilderWithId().setEapAkaConfig(SUB_ID, APPTYPE_USIM).build(); + + verifyPersistableBundleEncodeDecodeIsLossless(config); + } + + @Test + public void testSetEapAkaPrimeEncodeDecodeIsLossless() throws Exception { + final EapSessionConfig config = + createBuilderWithId() + .setEapAkaPrimeConfig( + SUB_ID, APPTYPE_USIM, NETWORK_NAME, ALLOW_MISMATCHED_NETWORK_NAMES) + .build(); + + verifyPersistableBundleEncodeDecodeIsLossless(config); + } + + @Test + public void testSetEapTtlsEncodeDecodeIsLossless() throws Exception { + final InputStream inputStream = + InstrumentationRegistry.getContext() + .getResources() + .getAssets() + .open("self-signed-ca.pem"); + final CertificateFactory factory = CertificateFactory.getInstance("X.509"); + final X509Certificate trustedCa = + (X509Certificate) factory.generateCertificate(inputStream); + + final EapSessionConfig innerConfig = + new EapSessionConfig.Builder().setEapMsChapV2Config(USERNAME, PASSWORD).build(); + + final EapSessionConfig config = + new EapSessionConfig.Builder().setEapTtlsConfig(trustedCa, innerConfig).build(); + + verifyPersistableBundleEncodeDecodeIsLossless(config); + } +} diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java new file mode 100644 index 000000000000..4f3930f9b5af --- /dev/null +++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/IkeIdentificationUtilsTest.java @@ -0,0 +1,87 @@ +/* + * 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.net.vcn.persistablebundleutils; + +import static org.junit.Assert.assertEquals; + +import android.net.ipsec.ike.IkeDerAsn1DnIdentification; +import android.net.ipsec.ike.IkeFqdnIdentification; +import android.net.ipsec.ike.IkeIdentification; +import android.net.ipsec.ike.IkeIpv4AddrIdentification; +import android.net.ipsec.ike.IkeIpv6AddrIdentification; +import android.net.ipsec.ike.IkeKeyIdIdentification; +import android.net.ipsec.ike.IkeRfc822AddrIdentification; +import android.os.PersistableBundle; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; + +import javax.security.auth.x500.X500Principal; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class IkeIdentificationUtilsTest { + private static void verifyPersistableBundleEncodeDecodeIsLossless(IkeIdentification id) { + final PersistableBundle bundle = IkeIdentificationUtils.toPersistableBundle(id); + final IkeIdentification result = IkeIdentificationUtils.fromPersistableBundle(bundle); + + assertEquals(result, id); + } + + @Test + public void testPersistableBundleEncodeDecodeIpv4AddressId() throws Exception { + final Inet4Address ipv4Address = (Inet4Address) InetAddress.getByName("192.0.2.100"); + verifyPersistableBundleEncodeDecodeIsLossless(new IkeIpv4AddrIdentification(ipv4Address)); + } + + @Test + public void testPersistableBundleEncodeDecodeIpv6AddressId() throws Exception { + final Inet6Address ipv6Address = (Inet6Address) InetAddress.getByName("2001:db8:2::100"); + verifyPersistableBundleEncodeDecodeIsLossless(new IkeIpv6AddrIdentification(ipv6Address)); + } + + @Test + public void testPersistableBundleEncodeDecodeRfc822AddrId() throws Exception { + verifyPersistableBundleEncodeDecodeIsLossless(new IkeFqdnIdentification("ike.android.net")); + } + + @Test + public void testPersistableBundleEncodeDecodeFqdnId() throws Exception { + verifyPersistableBundleEncodeDecodeIsLossless( + new IkeRfc822AddrIdentification("androidike@example.com")); + } + + @Test + public void testPersistableBundleEncodeDecodeKeyId() throws Exception { + verifyPersistableBundleEncodeDecodeIsLossless( + new IkeKeyIdIdentification("androidIkeKeyId".getBytes())); + } + + @Test + public void testPersistableBundleEncodeDecodeDerAsn1DnId() throws Exception { + verifyPersistableBundleEncodeDecodeIsLossless( + new IkeDerAsn1DnIdentification( + new X500Principal("CN=small.server.test.android.net, O=Android, C=US"))); + } +} diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java new file mode 100644 index 000000000000..8ae8692b4f75 --- /dev/null +++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/SaProposalUtilsTest.java @@ -0,0 +1,78 @@ +/* + * 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.net.vcn.persistablebundleutils; + +import static org.junit.Assert.assertEquals; + +import android.net.ipsec.ike.ChildSaProposal; +import android.net.ipsec.ike.IkeSaProposal; +import android.net.ipsec.ike.SaProposal; +import android.os.PersistableBundle; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class SaProposalUtilsTest { + @Test + public void testPersistableBundleEncodeDecodeIsLosslessIkeProposal() throws Exception { + final IkeSaProposal proposal = + new IkeSaProposal.Builder() + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_3DES, SaProposal.KEY_LEN_UNUSED) + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_AES_CBC, SaProposal.KEY_LEN_AES_128) + .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA1_96) + .addIntegrityAlgorithm(SaProposal.INTEGRITY_ALGORITHM_HMAC_SHA2_256_128) + .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_AES128_XCBC) + .addPseudorandomFunction(SaProposal.PSEUDORANDOM_FUNCTION_SHA2_256) + .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP) + .addDhGroup(SaProposal.DH_GROUP_3072_BIT_MODP) + .build(); + + final PersistableBundle bundle = IkeSaProposalUtils.toPersistableBundle(proposal); + final SaProposal resultProposal = IkeSaProposalUtils.fromPersistableBundle(bundle); + + assertEquals(proposal, resultProposal); + } + + /** Package private so that TunnelModeChildSessionParamsUtilsTest can use it */ + static ChildSaProposal buildTestChildSaProposal() { + return new ChildSaProposal.Builder() + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_128) + .addEncryptionAlgorithm( + SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12, SaProposal.KEY_LEN_AES_192) + .addDhGroup(SaProposal.DH_GROUP_1024_BIT_MODP) + .addDhGroup(SaProposal.DH_GROUP_4096_BIT_MODP) + .build(); + } + + @Test + public void testPersistableBundleEncodeDecodeIsLosslessChildProposal() throws Exception { + final ChildSaProposal proposal = buildTestChildSaProposal(); + + final PersistableBundle bundle = ChildSaProposalUtils.toPersistableBundle(proposal); + final SaProposal resultProposal = ChildSaProposalUtils.fromPersistableBundle(bundle); + + assertEquals(proposal, resultProposal); + } +} diff --git a/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java new file mode 100644 index 000000000000..b3cd0ab80599 --- /dev/null +++ b/tests/vcn/java/android/net/vcn/persistablebundleutils/TunnelModeChildSessionParamsUtilsTest.java @@ -0,0 +1,117 @@ +/* + * 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.net.vcn.persistablebundleutils; + +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; + +import static org.junit.Assert.assertEquals; + +import android.net.InetAddresses; +import android.net.ipsec.ike.ChildSaProposal; +import android.net.ipsec.ike.IkeTrafficSelector; +import android.net.ipsec.ike.TunnelModeChildSessionParams; +import android.os.PersistableBundle; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class TunnelModeChildSessionParamsUtilsTest { + private TunnelModeChildSessionParams.Builder createBuilderMinimum() { + final ChildSaProposal saProposal = SaProposalUtilsTest.buildTestChildSaProposal(); + return new TunnelModeChildSessionParams.Builder().addSaProposal(saProposal); + } + + private static void verifyPersistableBundleEncodeDecodeIsLossless( + TunnelModeChildSessionParams params) { + final PersistableBundle bundle = + TunnelModeChildSessionParamsUtils.toPersistableBundle(params); + final TunnelModeChildSessionParams result = + TunnelModeChildSessionParamsUtils.fromPersistableBundle(bundle); + + assertEquals(params, result); + } + + @Test + public void testMinimumParamsEncodeDecodeIsLossless() throws Exception { + final TunnelModeChildSessionParams sessionParams = createBuilderMinimum().build(); + verifyPersistableBundleEncodeDecodeIsLossless(sessionParams); + } + + @Test + public void testSetTsEncodeDecodeIsLossless() throws Exception { + final IkeTrafficSelector tsInbound = + new IkeTrafficSelector( + 16, + 65520, + InetAddresses.parseNumericAddress("192.0.2.100"), + InetAddresses.parseNumericAddress("192.0.2.101")); + final IkeTrafficSelector tsOutbound = + new IkeTrafficSelector( + 32, + 256, + InetAddresses.parseNumericAddress("192.0.2.200"), + InetAddresses.parseNumericAddress("192.0.2.255")); + + final TunnelModeChildSessionParams sessionParams = + createBuilderMinimum() + .addInboundTrafficSelectors(tsInbound) + .addOutboundTrafficSelectors(tsOutbound) + .build(); + verifyPersistableBundleEncodeDecodeIsLossless(sessionParams); + } + + @Test + public void testSetLifetimesEncodeDecodeIsLossless() throws Exception { + final int hardLifetime = (int) TimeUnit.HOURS.toSeconds(3L); + final int softLifetime = (int) TimeUnit.HOURS.toSeconds(1L); + + final TunnelModeChildSessionParams sessionParams = + createBuilderMinimum().setLifetimeSeconds(hardLifetime, softLifetime).build(); + verifyPersistableBundleEncodeDecodeIsLossless(sessionParams); + } + + @Test + public void testSetConfigRequestsEncodeDecodeIsLossless() throws Exception { + final int ipv6PrefixLen = 64; + final Inet4Address ipv4Address = + (Inet4Address) InetAddresses.parseNumericAddress("192.0.2.100"); + final Inet6Address ipv6Address = + (Inet6Address) InetAddresses.parseNumericAddress("2001:db8::1"); + + final TunnelModeChildSessionParams sessionParams = + createBuilderMinimum() + .addInternalAddressRequest(AF_INET) + .addInternalAddressRequest(AF_INET6) + .addInternalAddressRequest(ipv4Address) + .addInternalAddressRequest(ipv6Address, ipv6PrefixLen) + .addInternalDnsServerRequest(AF_INET) + .addInternalDnsServerRequest(AF_INET6) + .addInternalDhcpServerRequest(AF_INET) + .build(); + verifyPersistableBundleEncodeDecodeIsLossless(sessionParams); + } +} diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index 9b500a7271d7..73a6b88e29ed 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -100,6 +100,8 @@ import java.util.UUID; public class VcnManagementServiceTest { private static final String TEST_PACKAGE_NAME = VcnManagementServiceTest.class.getPackage().getName(); + private static final String TEST_CB_PACKAGE_NAME = + VcnManagementServiceTest.class.getPackage().getName() + ".callback"; private static final ParcelUuid TEST_UUID_1 = new ParcelUuid(new UUID(0, 0)); private static final ParcelUuid TEST_UUID_2 = new ParcelUuid(new UUID(1, 1)); private static final VcnConfig TEST_VCN_CONFIG; @@ -288,6 +290,14 @@ public class VcnManagementServiceTest { private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( Set<ParcelUuid> activeSubscriptionGroups, Map<Integer, ParcelUuid> subIdToGroupMap) { + return triggerSubscriptionTrackerCbAndGetSnapshot( + activeSubscriptionGroups, subIdToGroupMap, true /* hasCarrierPrivileges */); + } + + private TelephonySubscriptionSnapshot triggerSubscriptionTrackerCbAndGetSnapshot( + Set<ParcelUuid> activeSubscriptionGroups, + Map<Integer, ParcelUuid> subIdToGroupMap, + boolean hasCarrierPrivileges) { final TelephonySubscriptionSnapshot snapshot = mock(TelephonySubscriptionSnapshot.class); doReturn(activeSubscriptionGroups).when(snapshot).getActiveSubscriptionGroups(); @@ -295,7 +305,7 @@ public class VcnManagementServiceTest { (activeSubscriptionGroups == null || activeSubscriptionGroups.isEmpty()) ? Collections.emptySet() : Collections.singleton(TEST_PACKAGE_NAME); - doReturn(true) + doReturn(hasCarrierPrivileges) .when(snapshot) .packageHasPermissionsForSubscriptionGroup( argThat(val -> activeSubscriptionGroups.contains(val)), @@ -549,13 +559,6 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); } - private void setUpVcnSubscription(int subId, ParcelUuid subGroup) { - mVcnMgmtSvc.setVcnConfig(subGroup, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); - - triggerSubscriptionTrackerCbAndGetSnapshot( - Collections.singleton(subGroup), Collections.singletonMap(subId, subGroup)); - } - private void verifyMergedNetworkCapabilities( NetworkCapabilities mergedCapabilities, @Transport int transportType, @@ -573,9 +576,23 @@ public class VcnManagementServiceTest { } private void setupSubscriptionAndStartVcn(int subId, ParcelUuid subGrp, boolean isVcnActive) { - setUpVcnSubscription(subId, subGrp); + setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive, true /* hasCarrierPrivileges */); + } + + private void setupSubscriptionAndStartVcn( + int subId, ParcelUuid subGrp, boolean isVcnActive, boolean hasCarrierPrivileges) { + mVcnMgmtSvc.systemReady(); + triggerSubscriptionTrackerCbAndGetSnapshot( + Collections.singleton(subGrp), + Collections.singletonMap(subId, subGrp), + hasCarrierPrivileges); + final Vcn vcn = startAndGetVcnInstance(subGrp); doReturn(isVcnActive).when(vcn).isActive(); + + doReturn(true) + .when(mLocationPermissionChecker) + .checkLocationPermission(eq(TEST_PACKAGE_NAME), any(), eq(TEST_UID), any()); } private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport( @@ -721,7 +738,7 @@ public class VcnManagementServiceTest { verify(mMockPolicyListener).onPolicyChanged(); } - private void verifyVcnCallback( + private void triggerVcnSafeMode( @NonNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot) throws Exception { verify(mMockDeps) @@ -732,20 +749,20 @@ public class VcnManagementServiceTest { eq(snapshot), mVcnCallbackCaptor.capture()); - mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); - VcnCallback vcnCallback = mVcnCallbackCaptor.getValue(); vcnCallback.onEnteredSafeMode(); - - verify(mMockPolicyListener).onPolicyChanged(); } @Test - public void testVcnCallbackOnEnteredSafeMode() throws Exception { + public void testVcnEnteringSafeModeNotifiesPolicyListeners() throws Exception { TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1)); - verifyVcnCallback(TEST_UUID_1, snapshot); + mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + + triggerVcnSafeMode(TEST_UUID_1, snapshot); + + verify(mMockPolicyListener).onPolicyChanged(); } private void triggerVcnStatusCallbackOnEnteredSafeMode( @@ -758,6 +775,9 @@ public class VcnManagementServiceTest { TelephonySubscriptionSnapshot snapshot = triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(subGroup)); + setupSubscriptionAndStartVcn( + TEST_SUBSCRIPTION_ID, subGroup, true /* isActive */, hasPermissionsforSubGroup); + doReturn(hasPermissionsforSubGroup) .when(snapshot) .packageHasPermissionsForSubscriptionGroup(eq(subGroup), eq(pkgName)); @@ -768,10 +788,7 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.registerVcnStatusCallback(subGroup, mMockStatusCallback, pkgName); - // Trigger systemReady() to set up LocationPermissionChecker - mVcnMgmtSvc.systemReady(); - - verifyVcnCallback(subGroup, snapshot); + triggerVcnSafeMode(subGroup, snapshot); } @Test @@ -825,6 +842,83 @@ public class VcnManagementServiceTest { assertEquals(TEST_PACKAGE_NAME, cbInfo.mPkgName); assertEquals(TEST_UID, cbInfo.mUid); verify(mMockIBinder).linkToDeath(eq(cbInfo), anyInt()); + + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED); + } + + @Test + public void testRegisterVcnStatusCallback_MissingPermission() throws Exception { + setupSubscriptionAndStartVcn( + TEST_SUBSCRIPTION_ID, + TEST_UUID_1, + true /* isActive */, + false /* hasCarrierPrivileges */); + + mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME); + + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED); + } + + @Test + public void testRegisterVcnStatusCallback_VcnInactive() throws Exception { + setupSubscriptionAndStartVcn( + TEST_SUBSCRIPTION_ID, + TEST_UUID_1, + true /* isActive */, + true /* hasCarrierPrivileges */); + + // VCN is currently active. Lose carrier privileges for TEST_PACKAGE and hit teardown + // timeout so the VCN goes inactive. + final TelephonySubscriptionSnapshot snapshot = + triggerSubscriptionTrackerCbAndGetSnapshot( + Collections.singleton(TEST_UUID_1), + Collections.singletonMap(TEST_SUBSCRIPTION_ID, TEST_UUID_1), + false /* hasCarrierPrivileges */); + mTestLooper.moveTimeForward(VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS); + mTestLooper.dispatchAll(); + + // Giving TEST_PACKAGE privileges again will restart the VCN (which will indicate ACTIVE + // when the status callback is registered). Instead, setup permissions for TEST_CB_PACKAGE + // so that it's permissioned to receive INACTIVE (instead of NOT_CONFIGURED) without + // reactivating the VCN. + doReturn(true) + .when(snapshot) + .packageHasPermissionsForSubscriptionGroup( + eq(TEST_UUID_1), eq(TEST_CB_PACKAGE_NAME)); + doReturn(true) + .when(mLocationPermissionChecker) + .checkLocationPermission(eq(TEST_CB_PACKAGE_NAME), any(), eq(TEST_UID), any()); + + mVcnMgmtSvc.registerVcnStatusCallback( + TEST_UUID_1, mMockStatusCallback, TEST_CB_PACKAGE_NAME); + + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_INACTIVE); + } + + @Test + public void testRegisterVcnStatusCallback_VcnActive() throws Exception { + setupSubscriptionAndStartVcn( + TEST_SUBSCRIPTION_ID, + TEST_UUID_1, + true /* isActive */, + true /* hasCarrierPrivileges */); + + mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME); + + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE); + } + + @Test + public void testRegisterVcnStatusCallback_VcnSafeMode() throws Exception { + setupSubscriptionAndStartVcn( + TEST_SUBSCRIPTION_ID, + TEST_UUID_1, + false /* isActive */, + true /* hasCarrierPrivileges */); + + mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_1, mMockStatusCallback, TEST_PACKAGE_NAME); + + verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE); } @Test(expected = IllegalStateException.class) |