diff options
author | android-build-prod (mdb) <android-build-team-robot@google.com> | 2021-03-05 17:29:41 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2021-03-05 17:29:41 +0000 |
commit | 70b05a53a79a8dcbeb446edb4d91f2a5e8ce953a (patch) | |
tree | 7467b06a85798053826608ac09b9eb241ccdcdc6 | |
parent | 6c21d907df47081d7882b6dc54410794b5db4a1c (diff) | |
parent | b3ed29d3fa2c368cca8fcab7f6775c1acfe4b9ae (diff) | |
download | base-70b05a53a79a8dcbeb446edb4d91f2a5e8ce953a.tar.gz |
Merge "Snap for 7187421 from f80c56df73870eb770265bee5ee297b769cb2341 to sdk-release" into sdk-releaseplatform-tools-31.0.1
56 files changed, 1337 insertions, 472 deletions
diff --git a/Android.bp b/Android.bp index 0d7deb1bfd5e..e79248e9d974 100644 --- a/Android.bp +++ b/Android.bp @@ -526,6 +526,7 @@ java_library { "android.security.apc-java", "android.security.authorization-java", "android.security.usermanager-java", + "android.security.vpnprofilestore-java", "android.system.keystore2-V1-java", "android.system.suspend.control.internal-java", "devicepolicyprotosnano", diff --git a/core/api/current.txt b/core/api/current.txt index 4954875e424a..28d492c70f09 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -39099,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"; @@ -39157,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/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl index b016ed67c4d9..9bf791ba33e0 100644 --- a/core/java/android/net/INetworkPolicyManager.aidl +++ b/core/java/android/net/INetworkPolicyManager.aidl @@ -19,8 +19,6 @@ package android.net; import android.net.INetworkPolicyListener; import android.net.Network; import android.net.NetworkPolicy; -import android.net.NetworkQuotaInfo; -import android.net.NetworkState; import android.net.NetworkTemplate; import android.telephony.SubscriptionPlan; @@ -70,9 +68,6 @@ interface INetworkPolicyManager { int getMultipathPreference(in Network network); - @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) - NetworkQuotaInfo getNetworkQuotaInfo(in NetworkState state); - SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage); void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, String callingPackage); String getSubscriptionPlansOwner(int subId); diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java index 183f500572bd..cc1312bac180 100644 --- a/core/java/android/net/Ikev2VpnProfile.java +++ b/core/java/android/net/Ikev2VpnProfile.java @@ -24,10 +24,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.content.pm.PackageManager; -import android.os.Process; import android.security.Credentials; -import android.security.KeyStore; -import android.security.keystore.AndroidKeyStoreProvider; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.net.VpnProfile; @@ -35,7 +32,9 @@ import com.android.internal.net.VpnProfile; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; +import java.security.Key; import java.security.KeyFactory; +import java.security.KeyStore; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.CertificateEncodingException; @@ -66,6 +65,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { /** Prefix for when a Private Key is stored directly in the profile @hide */ public static final String PREFIX_INLINE = "INLINE:"; + private static final String ANDROID_KEYSTORE_PROVIDER = "AndroidKeyStore"; private static final String MISSING_PARAM_MSG_TMPL = "Required parameter was not provided: %s"; private static final String EMPTY_CERT = ""; @@ -430,32 +430,31 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { return profile; } - /** - * Constructs a Ikev2VpnProfile from an internal-use VpnProfile instance. - * - * <p>Redundant authentication information (not related to profile type) will be discarded. - * - * @hide - */ - @NonNull - public static Ikev2VpnProfile fromVpnProfile(@NonNull VpnProfile profile) - throws IOException, GeneralSecurityException { - return fromVpnProfile(profile, null); + private static PrivateKey getPrivateKeyFromAndroidKeystore(String alias) { + try { + final KeyStore keystore = KeyStore.getInstance(ANDROID_KEYSTORE_PROVIDER); + keystore.load(null); + final Key key = keystore.getKey(alias, null); + if (!(key instanceof PrivateKey)) { + throw new IllegalStateException( + "Unexpected key type returned from android keystore."); + } + return (PrivateKey) key; + } catch (Exception e) { + throw new IllegalStateException("Failed to load key from android keystore.", e); + } } /** * Builds the Ikev2VpnProfile from the given profile. * * @param profile the source VpnProfile to build from - * @param keyStore the Android Keystore instance to use to retrieve the private key, or null if - * the private key is PEM-encoded into the profile. * @return The IKEv2/IPsec VPN profile * @hide */ @NonNull - public static Ikev2VpnProfile fromVpnProfile( - @NonNull VpnProfile profile, @Nullable KeyStore keyStore) - throws IOException, GeneralSecurityException { + public static Ikev2VpnProfile fromVpnProfile(@NonNull VpnProfile profile) + throws GeneralSecurityException { final Builder builder = new Builder(profile.server, profile.ipsecIdentifier); builder.setProxy(profile.proxy); builder.setAllowedAlgorithms(profile.getAllowedAlgorithms()); @@ -479,12 +478,9 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { case TYPE_IKEV2_IPSEC_RSA: final PrivateKey key; if (profile.ipsecSecret.startsWith(PREFIX_KEYSTORE_ALIAS)) { - Objects.requireNonNull(keyStore, "Missing Keystore for aliased PrivateKey"); - final String alias = profile.ipsecSecret.substring(PREFIX_KEYSTORE_ALIAS.length()); - key = AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore( - keyStore, alias, Process.myUid()); + key = getPrivateKeyFromAndroidKeystore(alias); } else if (profile.ipsecSecret.startsWith(PREFIX_INLINE)) { key = getPrivateKey(profile.ipsecSecret.substring(PREFIX_INLINE.length())); } else { 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/NetworkStateSnapshot.java b/core/java/android/net/NetworkStateSnapshot.java index b3d8d4e614da..0d26c2de8698 100644 --- a/core/java/android/net/NetworkStateSnapshot.java +++ b/core/java/android/net/NetworkStateSnapshot.java @@ -24,6 +24,8 @@ import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import com.android.net.module.util.NetworkIdentityUtils; + import java.util.Objects; /** @@ -124,4 +126,15 @@ public final class NetworkStateSnapshot implements Parcelable { public int hashCode() { return Objects.hash(network, networkCapabilities, linkProperties, subscriberId, legacyType); } + + @Override + public String toString() { + return "NetworkStateSnapshot{" + + "network=" + network + + ", networkCapabilities=" + networkCapabilities + + ", linkProperties=" + linkProperties + + ", subscriberId='" + NetworkIdentityUtils.scrubSubscriberId(subscriberId) + '\'' + + ", legacyType=" + legacyType + + '}'; + } } diff --git a/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl b/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl index f8ae492016f0..62de8216ce54 100644 --- a/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl +++ b/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl @@ -17,6 +17,6 @@ package android.net.vcn; /** @hide */ -interface IVcnUnderlyingNetworkPolicyListener { +oneway interface IVcnUnderlyingNetworkPolicyListener { void onPolicyChanged(); }
\ No newline at end of file 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/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/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/LegacyVpnProfileStore.java b/keystore/java/android/security/LegacyVpnProfileStore.java new file mode 100644 index 000000000000..41cfb2707fcf --- /dev/null +++ b/keystore/java/android/security/LegacyVpnProfileStore.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2020 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.security; + +import android.annotation.NonNull; +import android.os.ServiceManager; +import android.os.ServiceSpecificException; +import android.security.keystore.AndroidKeyStoreProvider; +import android.security.vpnprofilestore.IVpnProfileStore; +import android.util.Log; + +/** + * @hide This class allows legacy VPN access to its profiles that were stored in Keystore. + * The storage of unstructured blobs in Android Keystore is going away, because there is no + * architectural or security benefit of storing profiles in keystore over storing them + * in the file system. This class allows access to the blobs that still exist in keystore. + * And it stores new blob in a database that is still owned by Android Keystore. + */ +public class LegacyVpnProfileStore { + private static final String TAG = "LegacyVpnProfileStore"; + + public static final int SYSTEM_ERROR = IVpnProfileStore.ERROR_SYSTEM_ERROR; + public static final int PROFILE_NOT_FOUND = IVpnProfileStore.ERROR_PROFILE_NOT_FOUND; + + private static final String VPN_PROFILE_STORE_SERVICE_NAME = "android.security.vpnprofilestore"; + + private static IVpnProfileStore getService() { + return IVpnProfileStore.Stub.asInterface( + ServiceManager.checkService(VPN_PROFILE_STORE_SERVICE_NAME)); + } + + /** + * Stores the profile under the alias in the profile database. Existing profiles by the + * same name will be replaced. + * @param alias The name of the profile + * @param profile The profile. + * @return true if the profile was successfully added. False otherwise. + * @hide + */ + public static boolean put(@NonNull String alias, @NonNull byte[] profile) { + try { + if (AndroidKeyStoreProvider.isKeystore2Enabled()) { + getService().put(alias, profile); + return true; + } else { + return KeyStore.getInstance().put( + alias, profile, KeyStore.UID_SELF, 0); + } + } catch (Exception e) { + Log.e(TAG, "Failed to put vpn profile.", e); + return false; + } + } + + /** + * Retrieves a profile by the name alias from the profile database. + * @param alias Name of the profile to retrieve. + * @return The unstructured blob, that is the profile that was stored using + * LegacyVpnProfileStore#put or with + * android.security.Keystore.put(Credentials.VPN + alias). + * Returns null if no profile was found. + * @hide + */ + public static byte[] get(@NonNull String alias) { + try { + if (AndroidKeyStoreProvider.isKeystore2Enabled()) { + return getService().get(alias); + } else { + return KeyStore.getInstance().get(alias, true /* suppressKeyNotFoundWarning */); + } + } catch (ServiceSpecificException e) { + if (e.errorCode != PROFILE_NOT_FOUND) { + Log.e(TAG, "Failed to get vpn profile.", e); + } + } catch (Exception e) { + Log.e(TAG, "Failed to get vpn profile.", e); + } + return null; + } + + /** + * Removes a profile by the name alias from the profile database. + * @param alias Name of the profile to be removed. + * @return True if a profile was removed. False if no such profile was found. + * @hide + */ + public static boolean remove(@NonNull String alias) { + try { + if (AndroidKeyStoreProvider.isKeystore2Enabled()) { + getService().remove(alias); + return true; + } else { + return KeyStore.getInstance().delete(alias); + } + } catch (ServiceSpecificException e) { + if (e.errorCode != PROFILE_NOT_FOUND) { + Log.e(TAG, "Failed to remove vpn profile.", e); + } + } catch (Exception e) { + Log.e(TAG, "Failed to remove vpn profile.", e); + } + return false; + } + + /** + * Lists the vpn profiles stored in the database. + * @return An array of strings representing the aliases stored in the profile database. + * The return value may be empty but never null. + * @hide + */ + public static @NonNull String[] list(@NonNull String prefix) { + try { + if (AndroidKeyStoreProvider.isKeystore2Enabled()) { + final String[] aliases = getService().list(prefix); + for (int i = 0; i < aliases.length; ++i) { + aliases[i] = aliases[i].substring(prefix.length()); + } + return aliases; + } else { + final String[] result = KeyStore.getInstance().list(prefix); + return result != null ? result : new String[0]; + } + } catch (Exception e) { + Log.e(TAG, "Failed to list vpn profiles.", e); + } + return new String[0]; + } +} 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/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp index 307d80dc15c0..07866ac34e4c 100644 --- a/media/jni/android_media_MediaCodecList.cpp +++ b/media/jni/android_media_MediaCodecList.cpp @@ -105,6 +105,7 @@ static const JavaMediaCodecListWrapper *getCodecList(JNIEnv *env) { // This should never happen unless something is really wrong jniThrowException( env, "java/lang/RuntimeException", "cannot get MediaCodecList"); + return NULL; } sListWrapper.reset(new JavaMediaCodecListWrapper(mcl)); diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt index a9fd6f248560..d2ed73ef8298 100644 --- a/packages/Connectivity/framework/api/module-lib-current.txt +++ b/packages/Connectivity/framework/api/module-lib-current.txt @@ -6,6 +6,7 @@ package android.net { } public class ConnectivityManager { + method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshot(); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @Nullable android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback); method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle); diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java index 66e7da43cb66..a6dc9ce0517f 100644 --- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java +++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java @@ -1259,6 +1259,25 @@ public class ConnectivityManager { } /** + * Return a list of {@link NetworkStateSnapshot}s, one for each network that is currently + * connected. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.NETWORK_SETTINGS}) + @NonNull + public List<NetworkStateSnapshot> getAllNetworkStateSnapshot() { + try { + return mService.getAllNetworkStateSnapshot(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Returns the {@link Network} object currently serving a given type, or * null if the given type is not connected. * diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl index 160338d396af..cd49258d1c47 100644 --- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl +++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl @@ -31,6 +31,7 @@ import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkRequest; import android.net.NetworkState; +import android.net.NetworkStateSnapshot; import android.net.OemNetworkPreferences; import android.net.ProxyInfo; import android.net.UidRange; @@ -79,6 +80,8 @@ interface IConnectivityManager @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) NetworkState[] getAllNetworkState(); + List<NetworkStateSnapshot> getAllNetworkStateSnapshot(); + boolean isActiveNetworkMetered(); boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress, diff --git a/core/java/android/net/NetworkState.java b/packages/Connectivity/framework/src/android/net/NetworkState.java index 813fde1c15f2..d01026566ca0 100644 --- a/core/java/android/net/NetworkState.java +++ b/packages/Connectivity/framework/src/android/net/NetworkState.java @@ -115,7 +115,8 @@ public class NetworkState implements Parcelable { } @UnsupportedAppUsage - public static final @android.annotation.NonNull Creator<NetworkState> CREATOR = new Creator<NetworkState>() { + @NonNull + public static final Creator<NetworkState> CREATOR = new Creator<NetworkState>() { @Override public NetworkState createFromParcel(Parcel in) { return new NetworkState(in); 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/services/core/Android.bp b/services/core/Android.bp index a1956476e49c..f1ab2aa8b5ec 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -200,7 +200,6 @@ filegroup { "java/com/android/server/TestNetworkService.java", "java/com/android/server/connectivity/AutodestructReference.java", "java/com/android/server/connectivity/ConnectivityConstants.java", - "java/com/android/server/connectivity/DataConnectionStats.java", "java/com/android/server/connectivity/DnsManager.java", "java/com/android/server/connectivity/KeepaliveTracker.java", "java/com/android/server/connectivity/LingerMonitor.java", diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index aacf2770d1c2..0b7dbdebce32 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -203,7 +203,6 @@ import com.android.net.module.util.LinkPropertiesUtils.CompareResult; import com.android.net.module.util.PermissionUtils; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.AutodestructReference; -import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.DnsManager; import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate; import com.android.server.connectivity.KeepaliveTracker; @@ -1213,9 +1212,6 @@ public class ConnectivityService extends IConnectivityManager.Stub mSettingsObserver = new SettingsObserver(mContext, mHandler); registerSettingsCallbacks(); - final DataConnectionStats dataConnectionStats = new DataConnectionStats(mContext, mHandler); - dataConnectionStats.startMonitoring(); - mKeepaliveTracker = new KeepaliveTracker(mContext, mHandler); mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager); mQosCallbackTracker = new QosCallbackTracker(mHandler, mNetworkRequestCounter); @@ -1890,24 +1886,46 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + // TODO: Consider delete this function or turn it into a no-op method. @Override public NetworkState[] getAllNetworkState() { // This contains IMSI details, so make sure the caller is privileged. PermissionUtils.enforceNetworkStackPermission(mContext); final ArrayList<NetworkState> result = new ArrayList<>(); + for (NetworkStateSnapshot snapshot : getAllNetworkStateSnapshot()) { + // NetworkStateSnapshot doesn't contain NetworkInfo, so need to fetch it from the + // NetworkAgentInfo. + final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(snapshot.network); + if (nai != null && nai.networkInfo.isConnected()) { + result.add(new NetworkState(new NetworkInfo(nai.networkInfo), + snapshot.linkProperties, snapshot.networkCapabilities, snapshot.network, + snapshot.subscriberId)); + } + } + return result.toArray(new NetworkState[result.size()]); + } + + @Override + @NonNull + public List<NetworkStateSnapshot> getAllNetworkStateSnapshot() { + // This contains IMSI details, so make sure the caller is privileged. + PermissionUtils.enforceNetworkStackPermission(mContext); + + final ArrayList<NetworkStateSnapshot> result = new ArrayList<>(); for (Network network : getAllNetworks()) { final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); - // TODO: Consider include SUSPENDED networks. + // TODO: Consider include SUSPENDED networks, which should be considered as + // temporary shortage of connectivity of a connected network. if (nai != null && nai.networkInfo.isConnected()) { - // TODO (b/73321673) : NetworkState contains a copy of the + // TODO (b/73321673) : NetworkStateSnapshot contains a copy of the // NetworkCapabilities, which may contain UIDs of apps to which the // network applies. Should the UIDs be cleared so as not to leak or // interfere ? - result.add(nai.getNetworkState()); + result.add(nai.getNetworkStateSnapshot()); } } - return result.toArray(new NetworkState[result.size()]); + return result; } @Override @@ -2388,13 +2406,6 @@ public class ConnectivityService extends IConnectivityManager.Stub final BroadcastOptions opts = BroadcastOptions.makeBasic(); opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.M); options = opts.toBundle(); - final IBatteryStats bs = mDeps.getBatteryStatsService(); - try { - bs.noteConnectivityChanged(intent.getIntExtra( - ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE), - ni.getState().toString()); - } catch (RemoteException e) { - } intent.addFlags(Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); } try { @@ -7172,7 +7183,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 app default network", e); } } @@ -7259,7 +7270,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } void addRequestReassignment(@NonNull final RequestReassignment reassignment) { - if (!Build.IS_USER) { + if (Build.IS_DEBUGGABLE) { // The code is never supposed to add two reassignments of the same request. Make // sure this stays true, but without imposing this expensive check on all // reassignments on all user devices. @@ -9057,7 +9068,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } final ArraySet<NetworkRequestInfo> nris = new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(preference); - updateDefaultNetworksForOemNetworkPreference(nris); + replaceDefaultNetworkRequestsForPreference(nris); mOemNetworkPreferences = preference; // TODO http://b/176496396 persist data to shared preferences. @@ -9070,7 +9081,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private void updateDefaultNetworksForOemNetworkPreference( + private void replaceDefaultNetworkRequestsForPreference( @NonNull final Set<NetworkRequestInfo> nris) { // Pass in a defensive copy as this collection will be updated on remove. handleRemoveNetworkRequests(new ArraySet<>(mDefaultNetworkRequests)); @@ -9156,6 +9167,14 @@ public class ConnectivityService extends IConnectivityManager.Stub return callbackRequestsToRegister; } + private static void setNetworkRequestUids(@NonNull final List<NetworkRequest> requests, + @NonNull final Set<UidRange> uids) { + final Set<UidRange> ranges = new ArraySet<>(uids); + for (final NetworkRequest req : requests) { + req.networkCapabilities.setUids(ranges); + } + } + /** * Class used to generate {@link NetworkRequestInfo} based off of {@link OemNetworkPreferences}. */ @@ -9232,7 +9251,11 @@ public class ConnectivityService extends IConnectivityManager.Stub + " called with invalid preference of " + preference); } - setOemNetworkRequestUids(requests, uids); + final ArraySet ranges = new ArraySet<Integer>(); + for (final int uid : uids) { + ranges.add(new UidRange(uid, uid)); + } + setNetworkRequestUids(requests, ranges); return new NetworkRequestInfo(requests); } @@ -9265,16 +9288,5 @@ public class ConnectivityService extends IConnectivityManager.Stub netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName()); return netCap; } - - private void setOemNetworkRequestUids(@NonNull final List<NetworkRequest> requests, - @NonNull final Set<Integer> uids) { - final Set<UidRange> ranges = new ArraySet<>(); - for (final int uid : uids) { - ranges.add(new UidRange(uid, uid)); - } - for (final NetworkRequest req : requests) { - req.networkCapabilities.setUids(ranges); - } - } } } 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/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java index 5d89bf1b1d82..56aabc208027 100644 --- a/services/core/java/com/android/server/VpnManagerService.java +++ b/services/core/java/com/android/server/VpnManagerService.java @@ -47,7 +47,6 @@ import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import android.security.Credentials; -import android.security.KeyStore; import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; @@ -60,6 +59,7 @@ import com.android.internal.net.VpnProfile; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.server.connectivity.Vpn; +import com.android.server.connectivity.VpnProfileStore; import com.android.server.net.LockdownVpnTracker; import java.io.FileDescriptor; @@ -83,7 +83,7 @@ public class VpnManagerService extends IVpnManager.Stub { private final Dependencies mDeps; private final ConnectivityManager mCm; - private final KeyStore mKeyStore; + private final VpnProfileStore mVpnProfileStore; private final INetworkManagementService mNMS; private final INetd mNetd; private final UserManager mUserManager; @@ -114,9 +114,9 @@ public class VpnManagerService extends IVpnManager.Stub { return new HandlerThread("VpnManagerService"); } - /** Returns the KeyStore instance to be used by this class. */ - public KeyStore getKeyStore() { - return KeyStore.getInstance(); + /** Return the VpnProfileStore to be used by this class */ + public VpnProfileStore getVpnProfileStore() { + return new VpnProfileStore(); } public INetd getNetd() { @@ -135,7 +135,7 @@ public class VpnManagerService extends IVpnManager.Stub { mHandlerThread = mDeps.makeHandlerThread(); mHandlerThread.start(); mHandler = mHandlerThread.getThreadHandler(); - mKeyStore = mDeps.getKeyStore(); + mVpnProfileStore = mDeps.getVpnProfileStore(); mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */); mCm = mContext.getSystemService(ConnectivityManager.class); mNMS = mDeps.getINetworkManagementService(); @@ -289,7 +289,7 @@ public class VpnManagerService extends IVpnManager.Stub { public boolean provisionVpnProfile(@NonNull VpnProfile profile, @NonNull String packageName) { final int user = UserHandle.getUserId(mDeps.getCallingUid()); synchronized (mVpns) { - return mVpns.get(user).provisionVpnProfile(packageName, profile, mKeyStore); + return mVpns.get(user).provisionVpnProfile(packageName, profile); } } @@ -307,7 +307,7 @@ public class VpnManagerService extends IVpnManager.Stub { public void deleteVpnProfile(@NonNull String packageName) { final int user = UserHandle.getUserId(mDeps.getCallingUid()); synchronized (mVpns) { - mVpns.get(user).deleteVpnProfile(packageName, mKeyStore); + mVpns.get(user).deleteVpnProfile(packageName); } } @@ -325,7 +325,7 @@ public class VpnManagerService extends IVpnManager.Stub { final int user = UserHandle.getUserId(mDeps.getCallingUid()); synchronized (mVpns) { throwIfLockdownEnabled(); - mVpns.get(user).startVpnProfile(packageName, mKeyStore); + mVpns.get(user).startVpnProfile(packageName); } } @@ -358,7 +358,7 @@ public class VpnManagerService extends IVpnManager.Stub { } synchronized (mVpns) { throwIfLockdownEnabled(); - mVpns.get(user).startLegacyVpn(profile, mKeyStore, null /* underlying */, egress); + mVpns.get(user).startLegacyVpn(profile, null /* underlying */, egress); } } @@ -396,7 +396,7 @@ public class VpnManagerService extends IVpnManager.Stub { } private boolean isLockdownVpnEnabled() { - return mKeyStore.contains(Credentials.LOCKDOWN_VPN); + return mVpnProfileStore.get(Credentials.LOCKDOWN_VPN) != null; } @Override @@ -417,14 +417,14 @@ public class VpnManagerService extends IVpnManager.Stub { return true; } - byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN); + byte[] profileTag = mVpnProfileStore.get(Credentials.LOCKDOWN_VPN); if (profileTag == null) { loge("Lockdown VPN configured but cannot be read from keystore"); return false; } String profileName = new String(profileTag); final VpnProfile profile = VpnProfile.decode( - profileName, mKeyStore.get(Credentials.VPN + profileName)); + profileName, mVpnProfileStore.get(Credentials.VPN + profileName)); if (profile == null) { loge("Lockdown VPN configured invalid profile " + profileName); setLockdownTracker(null); @@ -437,7 +437,7 @@ public class VpnManagerService extends IVpnManager.Stub { return false; } setLockdownTracker( - new LockdownVpnTracker(mContext, mHandler, mKeyStore, vpn, profile)); + new LockdownVpnTracker(mContext, mHandler, vpn, profile)); } return true; @@ -495,7 +495,7 @@ public class VpnManagerService extends IVpnManager.Stub { return false; } - return vpn.startAlwaysOnVpn(mKeyStore); + return vpn.startAlwaysOnVpn(); } } @@ -510,7 +510,7 @@ public class VpnManagerService extends IVpnManager.Stub { logw("User " + userId + " has no Vpn configuration"); return false; } - return vpn.isAlwaysOnPackageSupported(packageName, mKeyStore); + return vpn.isAlwaysOnPackageSupported(packageName); } } @@ -531,11 +531,11 @@ public class VpnManagerService extends IVpnManager.Stub { logw("User " + userId + " has no Vpn configuration"); return false; } - if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownAllowlist, mKeyStore)) { + if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownAllowlist)) { return false; } if (!startAlwaysOnVpn(userId)) { - vpn.setAlwaysOnPackage(null, false, null, mKeyStore); + vpn.setAlwaysOnPackage(null, false, null); return false; } } @@ -705,7 +705,8 @@ public class VpnManagerService extends IVpnManager.Stub { loge("Starting user already has a VPN"); return; } - userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, mKeyStore); + userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, + new VpnProfileStore()); mVpns.put(userId, userVpn); if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) { updateLockdownVpn(); @@ -777,7 +778,7 @@ public class VpnManagerService extends IVpnManager.Stub { if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName)) { log("Restarting always-on VPN package " + packageName + " for user " + userId); - vpn.startAlwaysOnVpn(mKeyStore); + vpn.startAlwaysOnVpn(); } } } @@ -798,7 +799,7 @@ public class VpnManagerService extends IVpnManager.Stub { if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) { log("Removing always-on VPN package " + packageName + " for user " + userId); - vpn.setAlwaysOnPackage(null, false, null, mKeyStore); + vpn.setAlwaysOnPackage(null, false, null); } } } @@ -843,7 +844,7 @@ public class VpnManagerService extends IVpnManager.Stub { if (mLockdownEnabled && userId == UserHandle.USER_SYSTEM) { final long ident = Binder.clearCallingIdentity(); try { - mKeyStore.delete(Credentials.LOCKDOWN_VPN); + mVpnProfileStore.remove(Credentials.LOCKDOWN_VPN); mLockdownEnabled = false; setLockdownTracker(null); } finally { diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 9986085224b1..146d301dba65 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -16,17 +16,23 @@ package com.android.server.am; +import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED; + +import android.annotation.NonNull; import android.bluetooth.BluetoothActivityEnergyInfo; import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.net.ConnectivityManager; import android.net.INetworkManagementEventObserver; +import android.net.Network; import android.net.NetworkCapabilities; import android.os.BatteryStats; import android.os.BatteryStatsInternal; import android.os.Binder; import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; import android.os.INetworkManagementService; import android.os.Parcel; @@ -66,7 +72,9 @@ import com.android.internal.os.RpmStats; import com.android.internal.util.DumpUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.ParseUtils; +import com.android.net.module.util.NetworkCapabilitiesUtils; import com.android.server.LocalServices; +import com.android.server.connectivity.DataConnectionStats; import com.android.server.net.BaseNetworkObserver; import java.io.File; @@ -113,6 +121,8 @@ public final class BatteryStatsService extends IBatteryStats.Stub private ByteBuffer mUtf8BufferStat = ByteBuffer.allocateDirect(MAX_LOW_POWER_STATS_SIZE); private CharBuffer mUtf16BufferStat = CharBuffer.allocate(MAX_LOW_POWER_STATS_SIZE); private static final int MAX_LOW_POWER_STATS_SIZE = 4096; + private final HandlerThread mHandlerThread; + private final Handler mHandler; @GuardedBy("mStats") private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW; @@ -214,6 +224,23 @@ public final class BatteryStatsService extends IBatteryStats.Stub } } + private ConnectivityManager.NetworkCallback mNetworkCallback = + new ConnectivityManager.NetworkCallback() { + @Override + public void onCapabilitiesChanged(@NonNull Network network, + @NonNull NetworkCapabilities networkCapabilities) { + final String state = networkCapabilities.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + ? "CONNECTED" : "SUSPENDED"; + noteConnectivityChanged(NetworkCapabilitiesUtils.getDisplayTransport( + networkCapabilities.getTransportTypes()), state); + } + + @Override + public void onLost(Network network) { + noteConnectivityChanged(-1, "DISCONNECTED"); + } + }; + BatteryStatsService(Context context, File systemDir, Handler handler) { // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through. mContext = context; @@ -227,6 +254,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub return (umi != null) ? umi.getUserIds() : null; } }; + mHandlerThread = new HandlerThread("batterystats-handler"); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + mStats = new BatteryStatsImpl(systemDir, handler, this, this, mUserManagerUserInfoProvider); mWorker = new BatteryExternalStatsWorker(context, mStats); @@ -244,12 +275,17 @@ public final class BatteryStatsService extends IBatteryStats.Stub public void systemServicesReady() { final INetworkManagementService nms = INetworkManagementService.Stub.asInterface( ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)); + final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); try { nms.registerObserver(mActivityChangeObserver); + cm.registerDefaultNetworkCallback(mNetworkCallback); } catch (RemoteException e) { Slog.e(TAG, "Could not register INetworkManagement event observer " + e); } mStats.systemServicesReady(mContext); + + final DataConnectionStats dataConnectionStats = new DataConnectionStats(mContext, mHandler); + dataConnectionStats.startMonitoring(); } private final class LocalService extends BatteryStatsInternal { diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index cac6cab7074e..1d0e11569c80 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -35,7 +35,7 @@ import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkMonitorManager; import android.net.NetworkRequest; -import android.net.NetworkState; +import android.net.NetworkStateSnapshot; import android.net.QosCallbackException; import android.net.QosFilter; import android.net.QosFilterParcelable; @@ -890,15 +890,18 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { mScore = score; } - public NetworkState getNetworkState() { + /** + * Return a {@link NetworkStateSnapshot} for this network. + */ + @NonNull + public NetworkStateSnapshot getNetworkStateSnapshot() { synchronized (this) { // Network objects are outwardly immutable so there is no point in duplicating. // Duplicating also precludes sharing socket factories and connection pools. final String subscriberId = (networkAgentConfig != null) ? networkAgentConfig.subscriberId : null; - return new NetworkState(new NetworkInfo(networkInfo), - new LinkProperties(linkProperties), - new NetworkCapabilities(networkCapabilities), network, subscriberId); + return new NetworkStateSnapshot(network, new NetworkCapabilities(networkCapabilities), + new LinkProperties(linkProperties), subscriberId, networkInfo.getType()); } } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 01ac81fb2cb5..124c3741ad57 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -100,7 +100,12 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.security.Credentials; -import android.security.KeyStore; +import android.security.KeyStore2; +import android.security.keystore.AndroidKeyStoreProvider; +import android.security.keystore.KeyProperties; +import android.system.keystore2.Domain; +import android.system.keystore2.KeyDescriptor; +import android.system.keystore2.KeyPermission; import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; @@ -131,6 +136,12 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -156,6 +167,7 @@ public class Vpn { private static final String TAG = "Vpn"; private static final String VPN_PROVIDER_NAME_BASE = "VpnNetworkProvider:"; private static final boolean LOGD = true; + private static final String ANDROID_KEYSTORE_PROVIDER = "AndroidKeyStore"; // Length of time (in milliseconds) that an app hosting an always-on VPN is placed on // the device idle allowlist during service launch and VPN bootstrap. @@ -215,6 +227,13 @@ public class Vpn { private final Ikev2SessionCreator mIkev2SessionCreator; private final UserManager mUserManager; + private final VpnProfileStore mVpnProfileStore; + + @VisibleForTesting + VpnProfileStore getVpnProfileStore() { + return mVpnProfileStore; + } + /** * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This * only applies to {@link VpnService} connections. @@ -392,24 +411,25 @@ public class Vpn { } public Vpn(Looper looper, Context context, INetworkManagementService netService, INetd netd, - @UserIdInt int userId, @NonNull KeyStore keyStore) { - this(looper, context, new Dependencies(), netService, netd, userId, keyStore, + @UserIdInt int userId, VpnProfileStore vpnProfileStore) { + this(looper, context, new Dependencies(), netService, netd, userId, vpnProfileStore, new SystemServices(context), new Ikev2SessionCreator()); } @VisibleForTesting public Vpn(Looper looper, Context context, Dependencies deps, INetworkManagementService netService, INetd netd, @UserIdInt int userId, - @NonNull KeyStore keyStore) { - this(looper, context, deps, netService, netd, userId, keyStore, + VpnProfileStore vpnProfileStore) { + this(looper, context, deps, netService, netd, userId, vpnProfileStore, new SystemServices(context), new Ikev2SessionCreator()); } @VisibleForTesting protected Vpn(Looper looper, Context context, Dependencies deps, INetworkManagementService netService, INetd netd, - int userId, @NonNull KeyStore keyStore, SystemServices systemServices, + int userId, VpnProfileStore vpnProfileStore, SystemServices systemServices, Ikev2SessionCreator ikev2SessionCreator) { + mVpnProfileStore = vpnProfileStore; mContext = context; mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */); @@ -445,7 +465,7 @@ public class Vpn { mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE)); - loadAlwaysOnPackage(keyStore); + loadAlwaysOnPackage(); } /** @@ -566,11 +586,9 @@ public class Vpn { * </ul> * * @param packageName the canonical package name of the VPN app - * @param keyStore the keystore instance to use for checking if the app has a Platform VPN - * profile installed. * @return {@code true} if and only if the VPN app exists and supports always-on mode */ - public boolean isAlwaysOnPackageSupported(String packageName, @NonNull KeyStore keyStore) { + public boolean isAlwaysOnPackageSupported(String packageName) { enforceSettingsPermission(); if (packageName == null) { @@ -579,7 +597,7 @@ public class Vpn { final long oldId = Binder.clearCallingIdentity(); try { - if (getVpnProfilePrivileged(packageName, keyStore) != null) { + if (getVpnProfilePrivileged(packageName) != null) { return true; } } finally { @@ -631,17 +649,15 @@ public class Vpn { * @param packageName the package to designate as always-on VPN supplier. * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting. * @param lockdownAllowlist packages to be allowed from lockdown. - * @param keyStore the Keystore instance to use for checking of PlatformVpnProfile(s) * @return {@code true} if the package has been set as always-on, {@code false} otherwise. */ public synchronized boolean setAlwaysOnPackage( @Nullable String packageName, boolean lockdown, - @Nullable List<String> lockdownAllowlist, - @NonNull KeyStore keyStore) { + @Nullable List<String> lockdownAllowlist) { enforceControlPermissionOrInternalCaller(); - if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist, keyStore)) { + if (setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist)) { saveAlwaysOnPackage(); return true; } @@ -658,13 +674,12 @@ public class Vpn { * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting. * @param lockdownAllowlist packages to be allowed to bypass lockdown. This is only used if * {@code lockdown} is {@code true}. Packages must not contain commas. - * @param keyStore the system keystore instance to check for profiles * @return {@code true} if the package has been set as always-on, {@code false} otherwise. */ @GuardedBy("this") private boolean setAlwaysOnPackageInternal( @Nullable String packageName, boolean lockdown, - @Nullable List<String> lockdownAllowlist, @NonNull KeyStore keyStore) { + @Nullable List<String> lockdownAllowlist) { if (VpnConfig.LEGACY_VPN.equals(packageName)) { Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on."); return false; @@ -683,7 +698,7 @@ public class Vpn { final VpnProfile profile; final long oldId = Binder.clearCallingIdentity(); try { - profile = getVpnProfilePrivileged(packageName, keyStore); + profile = getVpnProfilePrivileged(packageName); } finally { Binder.restoreCallingIdentity(oldId); } @@ -758,7 +773,7 @@ public class Vpn { /** Load the always-on package and lockdown config from Settings. */ @GuardedBy("this") - private void loadAlwaysOnPackage(@NonNull KeyStore keyStore) { + private void loadAlwaysOnPackage() { final long token = Binder.clearCallingIdentity(); try { final String alwaysOnPackage = mSystemServices.settingsSecureGetStringForUser( @@ -770,7 +785,7 @@ public class Vpn { final List<String> allowedPackages = TextUtils.isEmpty(allowlistString) ? Collections.emptyList() : Arrays.asList(allowlistString.split(",")); setAlwaysOnPackageInternal( - alwaysOnPackage, alwaysOnLockdown, allowedPackages, keyStore); + alwaysOnPackage, alwaysOnLockdown, allowedPackages); } finally { Binder.restoreCallingIdentity(token); } @@ -779,11 +794,10 @@ public class Vpn { /** * Starts the currently selected always-on VPN * - * @param keyStore the keyStore instance for looking up PlatformVpnProfile(s) * @return {@code true} if the service was started, the service was already connected, or there * was no always-on VPN to start. {@code false} otherwise. */ - public boolean startAlwaysOnVpn(@NonNull KeyStore keyStore) { + public boolean startAlwaysOnVpn() { final String alwaysOnPackage; synchronized (this) { alwaysOnPackage = getAlwaysOnPackage(); @@ -792,8 +806,8 @@ public class Vpn { return true; } // Remove always-on VPN if it's not supported. - if (!isAlwaysOnPackageSupported(alwaysOnPackage, keyStore)) { - setAlwaysOnPackage(null, false, null, keyStore); + if (!isAlwaysOnPackageSupported(alwaysOnPackage)) { + setAlwaysOnPackage(null, false, null); return false; } // Skip if the service is already established. This isn't bulletproof: it's not bound @@ -807,10 +821,9 @@ public class Vpn { final long oldId = Binder.clearCallingIdentity(); try { // Prefer VPN profiles, if any exist. - VpnProfile profile = getVpnProfilePrivileged(alwaysOnPackage, keyStore); + VpnProfile profile = getVpnProfilePrivileged(alwaysOnPackage); if (profile != null) { - startVpnProfilePrivileged(profile, alwaysOnPackage, - null /* keyStore for private key retrieval - unneeded */); + startVpnProfilePrivileged(profile, alwaysOnPackage); // If the above startVpnProfilePrivileged() call returns, the Ikev2VpnProfile was // correctly parsed, and the VPN has started running in a different thread. The only @@ -2011,27 +2024,83 @@ public class Vpn { * secondary thread to perform connection work, returning quickly. * * Should only be called to respond to Binder requests as this enforces caller permission. Use - * {@link #startLegacyVpnPrivileged(VpnProfile, KeyStore, Network, LinkProperties)} to skip the + * {@link #startLegacyVpnPrivileged(VpnProfile, Network, LinkProperties)} to skip the * permission check only when the caller is trusted (or the call is initiated by the system). */ - public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, @Nullable Network underlying, + public void startLegacyVpn(VpnProfile profile, @Nullable Network underlying, LinkProperties egress) { enforceControlPermission(); final long token = Binder.clearCallingIdentity(); try { - startLegacyVpnPrivileged(profile, keyStore, underlying, egress); + startLegacyVpnPrivileged(profile, underlying, egress); } finally { Binder.restoreCallingIdentity(token); } } + private String makeKeystoreEngineGrantString(String alias) { + if (alias == null) { + return null; + } + // If Keystore 2.0 is not enabled the legacy private key prefix is used. + if (!AndroidKeyStoreProvider.isKeystore2Enabled()) { + return Credentials.USER_PRIVATE_KEY + alias; + } + final KeyStore2 keystore2 = KeyStore2.getInstance(); + + KeyDescriptor key = new KeyDescriptor(); + key.domain = Domain.APP; + key.nspace = KeyProperties.NAMESPACE_APPLICATION; + key.alias = alias; + key.blob = null; + + final int grantAccessVector = KeyPermission.USE | KeyPermission.GET_INFO; + + try { + // The native vpn daemon is running as VPN_UID. This tells Keystore 2.0 + // to allow a process running with this UID to access the key designated by + // the KeyDescriptor `key`. `grant` returns a new KeyDescriptor with a grant + // identifier. This identifier needs to be communicated to the vpn daemon. + key = keystore2.grant(key, android.os.Process.VPN_UID, grantAccessVector); + } catch (android.security.KeyStoreException e) { + Log.e(TAG, "Failed to get grant for keystore key.", e); + throw new IllegalStateException("Failed to get grant for keystore key.", e); + } + + // Turn the grant identifier into a string as understood by the keystore boringssl engine + // in system/security/keystore-engine. + return KeyStore2.makeKeystoreEngineGrantString(key.nspace); + } + + private String getCaCertificateFromKeystoreAsPem(@NonNull KeyStore keystore, + @NonNull String alias) + throws KeyStoreException, IOException, CertificateEncodingException { + if (keystore.isCertificateEntry(alias)) { + final Certificate cert = keystore.getCertificate(alias); + if (cert == null) return null; + return new String(Credentials.convertToPem(cert), StandardCharsets.UTF_8); + } else { + final Certificate[] certs = keystore.getCertificateChain(alias); + // If there is none or one entry it means there is no CA entry associated with this + // alias. + if (certs == null || certs.length <= 1) { + return null; + } + // If this is not a (pure) certificate entry, then there is a user certificate which + // will be included at the beginning of the certificate chain. But the caller of this + // function does not expect this certificate to be included, so we cut it off. + return new String(Credentials.convertToPem( + Arrays.copyOfRange(certs, 1, certs.length)), StandardCharsets.UTF_8); + } + } + /** - * Like {@link #startLegacyVpn(VpnProfile, KeyStore, Network, LinkProperties)}, but does not + * Like {@link #startLegacyVpn(VpnProfile, Network, LinkProperties)}, but does not * check permissions under the assumption that the caller is the system. * * Callers are responsible for checking permissions if needed. */ - public void startLegacyVpnPrivileged(VpnProfile profile, KeyStore keyStore, + public void startLegacyVpnPrivileged(VpnProfile profile, @Nullable Network underlying, @NonNull LinkProperties egress) { UserInfo user = mUserManager.getUserInfo(mUserId); if (user.isRestricted() || mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN, @@ -2048,18 +2117,27 @@ public class Vpn { String userCert = ""; String caCert = ""; String serverCert = ""; - if (!profile.ipsecUserCert.isEmpty()) { - privateKey = Credentials.USER_PRIVATE_KEY + profile.ipsecUserCert; - byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecUserCert); - userCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8); - } - if (!profile.ipsecCaCert.isEmpty()) { - byte[] value = keyStore.get(Credentials.CA_CERTIFICATE + profile.ipsecCaCert); - caCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8); - } - if (!profile.ipsecServerCert.isEmpty()) { - byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert); - serverCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8); + + try { + final KeyStore keystore = KeyStore.getInstance(ANDROID_KEYSTORE_PROVIDER); + keystore.load(null); + if (!profile.ipsecUserCert.isEmpty()) { + privateKey = profile.ipsecUserCert; + final Certificate cert = keystore.getCertificate(profile.ipsecUserCert); + userCert = (cert == null) ? null + : new String(Credentials.convertToPem(cert), StandardCharsets.UTF_8); + } + if (!profile.ipsecCaCert.isEmpty()) { + caCert = getCaCertificateFromKeystoreAsPem(keystore, profile.ipsecCaCert); + } + if (!profile.ipsecServerCert.isEmpty()) { + final Certificate cert = keystore.getCertificate(profile.ipsecServerCert); + serverCert = (cert == null) ? null + : new String(Credentials.convertToPem(cert), StandardCharsets.UTF_8); + } + } catch (CertificateException | KeyStoreException | IOException + | NoSuchAlgorithmException e) { + throw new IllegalStateException("Failed to load credentials from AndroidKeyStore", e); } if (userCert == null || caCert == null || serverCert == null) { throw new IllegalStateException("Cannot load credentials"); @@ -2080,7 +2158,7 @@ public class Vpn { // Start VPN profile profile.setAllowedAlgorithms(Ikev2VpnProfile.DEFAULT_ALGORITHMS); - startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN, keyStore); + startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN); return; case VpnProfile.TYPE_IKEV2_IPSEC_PSK: // Ikev2VpnProfiles expect a base64-encoded preshared key. @@ -2089,7 +2167,7 @@ public class Vpn { // Start VPN profile profile.setAllowedAlgorithms(Ikev2VpnProfile.DEFAULT_ALGORITHMS); - startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN, keyStore); + startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN); return; case VpnProfile.TYPE_L2TP_IPSEC_PSK: racoon = new String[] { @@ -2099,8 +2177,8 @@ public class Vpn { break; case VpnProfile.TYPE_L2TP_IPSEC_RSA: racoon = new String[] { - iface, profile.server, "udprsa", privateKey, userCert, - caCert, serverCert, "1701", + iface, profile.server, "udprsa", makeKeystoreEngineGrantString(privateKey), + userCert, caCert, serverCert, "1701", }; break; case VpnProfile.TYPE_IPSEC_XAUTH_PSK: @@ -2111,8 +2189,8 @@ public class Vpn { break; case VpnProfile.TYPE_IPSEC_XAUTH_RSA: racoon = new String[] { - iface, profile.server, "xauthrsa", privateKey, userCert, - caCert, serverCert, profile.username, profile.password, "", gateway, + iface, profile.server, "xauthrsa", makeKeystoreEngineGrantString(privateKey), + userCert, caCert, serverCert, profile.username, profile.password, "", gateway, }; break; case VpnProfile.TYPE_IPSEC_HYBRID_RSA: @@ -3047,14 +3125,12 @@ public class Vpn { * * @param packageName the package name of the app provisioning this profile * @param profile the profile to be stored and provisioned - * @param keyStore the System keystore instance to save VPN profiles * @returns whether or not the app has already been granted user consent */ public synchronized boolean provisionVpnProfile( - @NonNull String packageName, @NonNull VpnProfile profile, @NonNull KeyStore keyStore) { + @NonNull String packageName, @NonNull VpnProfile profile) { checkNotNull(packageName, "No package name provided"); checkNotNull(profile, "No profile provided"); - checkNotNull(keyStore, "KeyStore missing"); verifyCallingUidAndPackage(packageName); enforceNotRestrictedUser(); @@ -3073,11 +3149,9 @@ public class Vpn { // Permissions checked during startVpnProfile() Binder.withCleanCallingIdentity( () -> { - keyStore.put( + getVpnProfileStore().put( getProfileNameForPackage(packageName), - encodedProfile, - Process.SYSTEM_UID, - 0 /* flags */); + encodedProfile); }); // TODO: if package has CONTROL_VPN, grant the ACTIVATE_PLATFORM_VPN appop. @@ -3095,12 +3169,10 @@ public class Vpn { * Deletes an app-provisioned VPN profile. * * @param packageName the package name of the app provisioning this profile - * @param keyStore the System keystore instance to save VPN profiles */ public synchronized void deleteVpnProfile( - @NonNull String packageName, @NonNull KeyStore keyStore) { + @NonNull String packageName) { checkNotNull(packageName, "No package name provided"); - checkNotNull(keyStore, "KeyStore missing"); verifyCallingUidAndPackage(packageName); enforceNotRestrictedUser(); @@ -3112,13 +3184,13 @@ public class Vpn { if (isCurrentIkev2VpnLocked(packageName)) { if (mAlwaysOn) { // Will transitively call prepareInternal(VpnConfig.LEGACY_VPN). - setAlwaysOnPackage(null, false, null, keyStore); + setAlwaysOnPackage(null, false, null); } else { prepareInternal(VpnConfig.LEGACY_VPN); } } - keyStore.delete(getProfileNameForPackage(packageName), Process.SYSTEM_UID); + getVpnProfileStore().remove(getProfileNameForPackage(packageName)); }); } @@ -3130,13 +3202,13 @@ public class Vpn { */ @VisibleForTesting @Nullable - VpnProfile getVpnProfilePrivileged(@NonNull String packageName, @NonNull KeyStore keyStore) { + VpnProfile getVpnProfilePrivileged(@NonNull String packageName) { if (!mDeps.isCallerSystem()) { Log.wtf(TAG, "getVpnProfilePrivileged called as non-System UID "); return null; } - final byte[] encoded = keyStore.get(getProfileNameForPackage(packageName)); + final byte[] encoded = getVpnProfileStore().get(getProfileNameForPackage(packageName)); if (encoded == null) return null; return VpnProfile.decode("" /* Key unused */, encoded); @@ -3150,12 +3222,10 @@ public class Vpn { * will not match during appop checks. * * @param packageName the package name of the app provisioning this profile - * @param keyStore the System keystore instance to retrieve VPN profiles */ public synchronized void startVpnProfile( - @NonNull String packageName, @NonNull KeyStore keyStore) { + @NonNull String packageName) { checkNotNull(packageName, "No package name provided"); - checkNotNull(keyStore, "KeyStore missing"); enforceNotRestrictedUser(); @@ -3166,18 +3236,17 @@ public class Vpn { Binder.withCleanCallingIdentity( () -> { - final VpnProfile profile = getVpnProfilePrivileged(packageName, keyStore); + final VpnProfile profile = getVpnProfilePrivileged(packageName); if (profile == null) { throw new IllegalArgumentException("No profile found for " + packageName); } - startVpnProfilePrivileged(profile, packageName, - null /* keyStore for private key retrieval - unneeded */); + startVpnProfilePrivileged(profile, packageName); }); } private synchronized void startVpnProfilePrivileged( - @NonNull VpnProfile profile, @NonNull String packageName, @Nullable KeyStore keyStore) { + @NonNull VpnProfile profile, @NonNull String packageName) { // Make sure VPN is prepared. This method can be called by user apps via startVpnProfile(), // by the Setting app via startLegacyVpn(), or by ConnectivityService via // startAlwaysOnVpn(), so this is the common place to prepare the VPN. This also has the @@ -3208,7 +3277,7 @@ public class Vpn { case VpnProfile.TYPE_IKEV2_IPSEC_PSK: case VpnProfile.TYPE_IKEV2_IPSEC_RSA: mVpnRunner = - new IkeV2VpnRunner(Ikev2VpnProfile.fromVpnProfile(profile, keyStore)); + new IkeV2VpnRunner(Ikev2VpnProfile.fromVpnProfile(profile)); mVpnRunner.start(); break; default: @@ -3216,7 +3285,7 @@ public class Vpn { Log.d(TAG, "Unknown VPN profile type: " + profile.type); break; } - } catch (IOException | GeneralSecurityException e) { + } catch (GeneralSecurityException e) { // Reset mConfig mConfig = null; diff --git a/services/core/java/com/android/server/connectivity/VpnProfileStore.java b/services/core/java/com/android/server/connectivity/VpnProfileStore.java new file mode 100644 index 000000000000..2f8aebf07e49 --- /dev/null +++ b/services/core/java/com/android/server/connectivity/VpnProfileStore.java @@ -0,0 +1,77 @@ +/* + * 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 com.android.server.connectivity; + +import android.annotation.NonNull; +import android.security.LegacyVpnProfileStore; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * Mockable indirection to the actual profile store. + * @hide + */ +public class VpnProfileStore { + /** + * Stores the profile under the alias in the profile database. Existing profiles by the + * same name will be replaced. + * @param alias The name of the profile + * @param profile The profile. + * @return true if the profile was successfully added. False otherwise. + * @hide + */ + @VisibleForTesting + public boolean put(@NonNull String alias, @NonNull byte[] profile) { + return LegacyVpnProfileStore.put(alias, profile); + } + + /** + * Retrieves a profile by the name alias from the profile database. + * @param alias Name of the profile to retrieve. + * @return The unstructured blob, that is the profile that was stored using + * LegacyVpnProfileStore#put or with + * android.security.Keystore.put(Credentials.VPN + alias). + * Returns null if no profile was found. + * @hide + */ + @VisibleForTesting + public byte[] get(@NonNull String alias) { + return LegacyVpnProfileStore.get(alias); + } + + /** + * Removes a profile by the name alias from the profile database. + * @param alias Name of the profile to be removed. + * @return True if a profile was removed. False if no such profile was found. + * @hide + */ + @VisibleForTesting + public boolean remove(@NonNull String alias) { + return LegacyVpnProfileStore.remove(alias); + } + + /** + * Lists the vpn profiles stored in the database. + * @return An array of strings representing the aliases stored in the profile database. + * The return value may be empty but never null. + * @hide + */ + @VisibleForTesting + public @NonNull String[] list(@NonNull String prefix) { + return LegacyVpnProfileStore.list(prefix); + } +} diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 28aa79d4db9d..f658e33e0530 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -1176,7 +1176,21 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { // Ignore this message. return true; } - setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message)); + boolean tvSystemAudioMode = isSystemAudioControlFeatureEnabled(); + boolean avrSystemAudioMode = HdmiUtils.parseCommandParamSystemAudioStatus(message); + // Set System Audio Mode according to TV's settings. + // Handle <System Audio Mode Status> here only when + // SystemAudioAutoInitiationAction timeout + HdmiDeviceInfo avr = getAvrDeviceInfo(); + if (avr == null) { + setSystemAudioMode(false); + } else if (avrSystemAudioMode != tvSystemAudioMode) { + addAndStartAction(new SystemAudioActionFromTv(this, avr.getLogicalAddress(), + tvSystemAudioMode, null)); + } else { + setSystemAudioMode(tvSystemAudioMode); + } + return true; } 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/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java index 3cc32bef0e67..851ea3d01085 100644 --- a/services/core/java/com/android/server/net/LockdownVpnTracker.java +++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java @@ -35,7 +35,6 @@ import android.net.Network; import android.net.NetworkInfo; import android.net.NetworkRequest; import android.os.Handler; -import android.security.KeyStore; import android.text.TextUtils; import android.util.Log; @@ -63,7 +62,6 @@ public class LockdownVpnTracker { @NonNull private final Handler mHandler; @NonNull private final Vpn mVpn; @NonNull private final VpnProfile mProfile; - @NonNull private final KeyStore mKeyStore; @NonNull private final Object mStateLock = new Object(); @@ -132,7 +130,6 @@ public class LockdownVpnTracker { public LockdownVpnTracker(@NonNull Context context, @NonNull Handler handler, - @NonNull KeyStore keyStore, @NonNull Vpn vpn, @NonNull VpnProfile profile) { mContext = Objects.requireNonNull(context); @@ -140,7 +137,6 @@ public class LockdownVpnTracker { mHandler = Objects.requireNonNull(handler); mVpn = Objects.requireNonNull(vpn); mProfile = Objects.requireNonNull(profile); - mKeyStore = Objects.requireNonNull(keyStore); mNotificationManager = mContext.getSystemService(NotificationManager.class); final Intent configIntent = new Intent(ACTION_VPN_SETTINGS); @@ -212,7 +208,7 @@ public class LockdownVpnTracker { // network is the system default. So, if the VPN is up and underlying network // (e.g., wifi) disconnects, CS will inform apps that the VPN's capabilities have // changed to match the new default network (e.g., cell). - mVpn.startLegacyVpnPrivileged(mProfile, mKeyStore, network, egressProp); + mVpn.startLegacyVpnPrivileged(mProfile, network, egressProp); } catch (IllegalStateException e) { mAcceptedEgressIface = null; Log.e(TAG, "Failed to start VPN", e); diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index e31a9840ec28..2f8047035400 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -167,7 +167,6 @@ import android.net.NetworkIdentity; import android.net.NetworkPolicy; import android.net.NetworkPolicyManager; import android.net.NetworkPolicyManager.UidState; -import android.net.NetworkQuotaInfo; import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.NetworkStack; @@ -884,9 +883,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); try { + // TODO: There shouldn't be a need to receive callback for all changes. mActivityManager.registerUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE|ActivityManager.UID_OBSERVER_GONE, - NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE, "android"); + ActivityManager.PROCESS_STATE_UNKNOWN, "android"); mNetworkManager.registerObserver(mAlertObserver); } catch (RemoteException e) { // ignored; both services live in system_server @@ -3166,14 +3166,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - @Override - @Deprecated - public NetworkQuotaInfo getNetworkQuotaInfo(NetworkState state) { - Log.w(TAG, "Shame on UID " + Binder.getCallingUid() - + " for calling the hidden API getNetworkQuotaInfo(). Shame!"); - return new NetworkQuotaInfo(); - } - private void enforceSubscriptionPlanAccess(int subId, int callingUid, String callingPackage) { // Verify they're not lying about package name mAppOps.checkPackage(callingUid, callingPackage); diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 5e5a53d066f6..fa64df5b1670 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -2299,9 +2299,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ @Override - public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme, - CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, - int logo, int windowFlags, Configuration overrideConfig, int displayId) { + public StartingSurface addSplashScreen(IBinder appToken, int userId, String packageName, + int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, + int icon, int logo, int windowFlags, Configuration overrideConfig, int displayId) { if (!SHOW_SPLASH_SCREENS) { return null; } @@ -2328,10 +2328,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (theme != context.getThemeResId() || labelRes != 0) { try { - context = context.createPackageContext(packageName, CONTEXT_RESTRICTED); + context = context.createPackageContextAsUser(packageName, CONTEXT_RESTRICTED, + UserHandle.of(userId)); context.setTheme(theme); } catch (PackageManager.NameNotFoundException e) { - // Ignore + Slog.w(TAG, "Failed creating package context with package name " + + packageName + " for user " + userId, e); } } diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index b9431a6968f9..cffeaf3f4767 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -933,9 +933,9 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { * @return The starting surface. * */ - public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme, - CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, - int logo, int windowFlags, Configuration overrideConfig, int displayId); + public StartingSurface addSplashScreen(IBinder appToken, int userId, String packageName, + int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, + int icon, int logo, int windowFlags, Configuration overrideConfig, int displayId); /** * Set or clear a window which can behave as the keyguard. diff --git a/services/core/java/com/android/server/wm/SplashScreenStartingData.java b/services/core/java/com/android/server/wm/SplashScreenStartingData.java index 726b7dac6938..f77df2fc06c9 100644 --- a/services/core/java/com/android/server/wm/SplashScreenStartingData.java +++ b/services/core/java/com/android/server/wm/SplashScreenStartingData.java @@ -53,8 +53,8 @@ class SplashScreenStartingData extends StartingData { @Override StartingSurface createStartingSurface(ActivityRecord activity) { - return mService.mPolicy.addSplashScreen(activity.token, mPkg, mTheme, mCompatInfo, - mNonLocalizedLabel, mLabelRes, mIcon, mLogo, mWindowFlags, + return mService.mPolicy.addSplashScreen(activity.token, activity.mUserId, mPkg, mTheme, + mCompatInfo, mNonLocalizedLabel, mLabelRes, mIcon, mLogo, mWindowFlags, mMergedOverrideConfiguration, activity.getDisplayContent().getDisplayId()); } } 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/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 752da31638dd..13c3919cefc5 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -115,7 +115,6 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkPolicy; -import android.net.NetworkPolicyManager; import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; @@ -386,8 +385,7 @@ public class NetworkPolicyManagerServiceTest { Log.d(TAG, "set mUidObserver to " + mUidObserver); return null; } - }).when(mActivityManager).registerUidObserver(any(), anyInt(), - eq(NetworkPolicyManager.FOREGROUND_THRESHOLD_STATE), any(String.class)); + }).when(mActivityManager).registerUidObserver(any(), anyInt(), anyInt(), any(String.class)); mFutureIntent = newRestrictBackgroundChangedFuture(); mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java index 4a8e8dafb57d..979bbdad250b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -109,9 +109,9 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { } @Override - public StartingSurface addSplashScreen(IBinder appToken, String packageName, int theme, - CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, - int logo, int windowFlags, Configuration overrideConfig, int displayId) { + public StartingSurface addSplashScreen(IBinder appToken, int userId, String packageName, + int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, + int icon, int logo, int windowFlags, Configuration overrideConfig, int displayId) { final com.android.server.wm.WindowState window; final ActivityRecord activity; final WindowManagerService wm = mWmSupplier.get(); 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..6f33a8810699 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. @@ -1245,15 +1199,6 @@ interface ITelephony { void shutdownMobileRadios(); /** - * Set phone radio type and access technology. - * - * @param rafs an RadioAccessFamily array to indicate all phone's - * new radio access family. The length of RadioAccessFamily - * must equ]]al to phone count. - */ - void setRadioCapability(in RadioAccessFamily[] rafs); - - /** * Get phone radio type and access technology. * * @param phoneId which phone you want to get 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 ecb596466a22..d5580e08d4da 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -103,6 +103,7 @@ import static com.android.testutils.ConcurrentUtils.await; import static com.android.testutils.ConcurrentUtils.durationOf; import static com.android.testutils.ExceptionUtils.ignoreExceptions; import static com.android.testutils.HandlerUtils.waitForIdleSerialExecutor; +import static com.android.testutils.MiscAsserts.assertContainsAll; import static com.android.testutils.MiscAsserts.assertContainsExactly; import static com.android.testutils.MiscAsserts.assertEmpty; import static com.android.testutils.MiscAsserts.assertLength; @@ -203,6 +204,7 @@ import android.net.NetworkRequest; import android.net.NetworkSpecifier; import android.net.NetworkStack; import android.net.NetworkStackClient; +import android.net.NetworkStateSnapshot; import android.net.NetworkTestResultParcelable; import android.net.OemNetworkPreferences; import android.net.ProxyInfo; @@ -249,7 +251,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.security.Credentials; -import android.security.KeyStore; import android.system.Os; import android.telephony.TelephonyManager; import android.telephony.data.EpsBearerQosSessionAttributes; @@ -281,6 +282,7 @@ import com.android.server.connectivity.NetworkNotificationManager.NotificationTy import com.android.server.connectivity.ProxyTracker; import com.android.server.connectivity.QosCallbackTracker; import com.android.server.connectivity.Vpn; +import com.android.server.connectivity.VpnProfileStore; import com.android.server.net.NetworkPinner; import com.android.server.net.NetworkPolicyManagerInternal; import com.android.testutils.ExceptionUtils; @@ -441,7 +443,7 @@ public class ConnectivityServiceTest { @Mock MockableSystemProperties mSystemProperties; @Mock EthernetManager mEthernetManager; @Mock NetworkPolicyManager mNetworkPolicyManager; - @Mock KeyStore mKeyStore; + @Mock VpnProfileStore mVpnProfileStore; @Mock SystemConfigManager mSystemConfigManager; private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor = @@ -1126,7 +1128,7 @@ public class ConnectivityServiceTest { return mDeviceIdleInternal; } }, - mNetworkManagementService, mMockNetd, userId, mKeyStore); + mNetworkManagementService, mMockNetd, userId, mVpnProfileStore); } public void setUids(Set<UidRange> uids) { @@ -1305,8 +1307,9 @@ public class ConnectivityServiceTest { return mVMSHandlerThread; } - public KeyStore getKeyStore() { - return mKeyStore; + @Override + public VpnProfileStore getVpnProfileStore() { + return mVpnProfileStore; } public INetd getNetd() { @@ -1662,6 +1665,7 @@ public class ConnectivityServiceTest { assertNull(mCm.getActiveNetworkForUid(Process.myUid())); // Test getAllNetworks() assertEmpty(mCm.getAllNetworks()); + assertEmpty(mCm.getAllNetworkStateSnapshot()); } /** @@ -7513,8 +7517,7 @@ public class ConnectivityServiceTest { private void setupLegacyLockdownVpn() { final String profileName = "testVpnProfile"; final byte[] profileTag = profileName.getBytes(StandardCharsets.UTF_8); - when(mKeyStore.contains(Credentials.LOCKDOWN_VPN)).thenReturn(true); - when(mKeyStore.get(Credentials.LOCKDOWN_VPN)).thenReturn(profileTag); + when(mVpnProfileStore.get(Credentials.LOCKDOWN_VPN)).thenReturn(profileTag); final VpnProfile profile = new VpnProfile(profileName); profile.name = "My VPN"; @@ -7522,7 +7525,7 @@ public class ConnectivityServiceTest { profile.dnsServers = "8.8.8.8"; profile.type = VpnProfile.TYPE_IPSEC_XAUTH_PSK; final byte[] encodedProfile = profile.encode(); - when(mKeyStore.get(Credentials.VPN + profileName)).thenReturn(encodedProfile); + when(mVpnProfileStore.get(Credentials.VPN + profileName)).thenReturn(encodedProfile); } private void establishLegacyLockdownVpn(Network underlying) throws Exception { @@ -10659,4 +10662,83 @@ public class ConnectivityServiceTest { // default NCs will be unregistered in tearDown } + + @Test + public void testGetAllNetworkStateSnapshot() throws Exception { + verifyNoNetwork(); + + // Setup test cellular network with specified LinkProperties and NetworkCapabilities, + // verify the content of the snapshot matches. + final LinkProperties cellLp = new LinkProperties(); + final LinkAddress myIpv4Addr = new LinkAddress(InetAddress.getByName("192.0.2.129"), 25); + final LinkAddress myIpv6Addr = new LinkAddress(InetAddress.getByName("2001:db8::1"), 64); + cellLp.setInterfaceName("test01"); + cellLp.addLinkAddress(myIpv4Addr); + cellLp.addLinkAddress(myIpv6Addr); + cellLp.addRoute(new RouteInfo(InetAddress.getByName("fe80::1234"))); + cellLp.addRoute(new RouteInfo(InetAddress.getByName("192.0.2.254"))); + cellLp.addRoute(new RouteInfo(myIpv4Addr, null)); + cellLp.addRoute(new RouteInfo(myIpv6Addr, null)); + final NetworkCapabilities cellNcTemplate = new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_CELLULAR).addCapability(NET_CAPABILITY_MMS).build(); + + final TestNetworkCallback cellCb = new TestNetworkCallback(); + mCm.requestNetwork(new NetworkRequest.Builder().addCapability(NET_CAPABILITY_MMS).build(), + cellCb); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp, cellNcTemplate); + mCellNetworkAgent.connect(true); + cellCb.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); + List<NetworkStateSnapshot> snapshots = mCm.getAllNetworkStateSnapshot(); + assertLength(1, snapshots); + + // Compose the expected cellular snapshot for verification. + final NetworkCapabilities cellNc = + mCm.getNetworkCapabilities(mCellNetworkAgent.getNetwork()); + final NetworkStateSnapshot cellSnapshot = new NetworkStateSnapshot( + mCellNetworkAgent.getNetwork(), cellNc, cellLp, + null, ConnectivityManager.TYPE_MOBILE); + assertEquals(cellSnapshot, snapshots.get(0)); + + // Connect wifi and verify the snapshots. + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(true); + waitForIdle(); + // Compose the expected wifi snapshot for verification. + final NetworkCapabilities wifiNc = + mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()); + final NetworkStateSnapshot wifiSnapshot = new NetworkStateSnapshot( + mWiFiNetworkAgent.getNetwork(), wifiNc, new LinkProperties(), null, + ConnectivityManager.TYPE_WIFI); + + snapshots = mCm.getAllNetworkStateSnapshot(); + assertLength(2, snapshots); + assertContainsAll(snapshots, cellSnapshot, wifiSnapshot); + + // Set cellular as suspended, verify the snapshots will not contain suspended networks. + // TODO: Consider include SUSPENDED networks, which should be considered as + // temporary shortage of connectivity of a connected network. + mCellNetworkAgent.suspend(); + waitForIdle(); + snapshots = mCm.getAllNetworkStateSnapshot(); + assertLength(1, snapshots); + assertEquals(wifiSnapshot, snapshots.get(0)); + + // Disconnect wifi, verify the snapshots contain nothing. + mWiFiNetworkAgent.disconnect(); + waitForIdle(); + snapshots = mCm.getAllNetworkStateSnapshot(); + assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); + assertLength(0, snapshots); + + mCellNetworkAgent.resume(); + waitForIdle(); + snapshots = mCm.getAllNetworkStateSnapshot(); + assertLength(1, snapshots); + assertEquals(cellSnapshot, snapshots.get(0)); + + mCellNetworkAgent.disconnect(); + waitForIdle(); + verifyNoNetwork(); + mCm.unregisterNetworkCallback(cellCb); + } } diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index 7489a0f889dc..b8f7fbca3983 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -91,7 +91,6 @@ import android.os.UserManager; import android.os.test.TestLooper; import android.provider.Settings; import android.security.Credentials; -import android.security.KeyStore; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Range; @@ -196,7 +195,7 @@ public class VpnTest { @Mock private Vpn.Ikev2SessionCreator mIkev2SessionCreator; @Mock private ConnectivityManager mConnectivityManager; @Mock private IpSecService mIpSecService; - @Mock private KeyStore mKeyStore; + @Mock private VpnProfileStore mVpnProfileStore; private final VpnProfile mVpnProfile; private IpSecManager mIpSecManager; @@ -333,17 +332,17 @@ public class VpnTest { assertFalse(vpn.getLockdown()); // Set always-on without lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList(), mKeyStore)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList())); assertTrue(vpn.getAlwaysOn()); assertFalse(vpn.getLockdown()); // Set always-on with lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList(), mKeyStore)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList())); assertTrue(vpn.getAlwaysOn()); assertTrue(vpn.getLockdown()); // Remove always-on configuration. - assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList(), mKeyStore)); + assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList())); assertFalse(vpn.getAlwaysOn()); assertFalse(vpn.getLockdown()); } @@ -354,17 +353,17 @@ public class VpnTest { final UidRange user = PRI_USER_RANGE; // Set always-on without lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null, mKeyStore)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null)); // Set always-on with lockdown. - assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null, mKeyStore)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null)); verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1), new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop) })); // Switch to another app. - assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null, mKeyStore)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null)); verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] { new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1), new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop) @@ -382,14 +381,14 @@ public class VpnTest { // Set always-on with lockdown and allow app PKGS[2] from lockdown. assertTrue(vpn.setAlwaysOnPackage( - PKGS[1], true, Collections.singletonList(PKGS[2]), mKeyStore)); + PKGS[1], true, Collections.singletonList(PKGS[2]))); verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1), new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop) })); // Change allowed app list to PKGS[3]. assertTrue(vpn.setAlwaysOnPackage( - PKGS[1], true, Collections.singletonList(PKGS[3]), mKeyStore)); + PKGS[1], true, Collections.singletonList(PKGS[3]))); verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] { new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop) })); @@ -400,7 +399,7 @@ public class VpnTest { // Change the VPN app. assertTrue(vpn.setAlwaysOnPackage( - PKGS[0], true, Collections.singletonList(PKGS[3]), mKeyStore)); + PKGS[0], true, Collections.singletonList(PKGS[3]))); verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] { new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1), new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1) @@ -411,7 +410,7 @@ public class VpnTest { })); // Remove the list of allowed packages. - assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null, mKeyStore)); + assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null)); verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] { new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1), new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop) @@ -422,7 +421,7 @@ public class VpnTest { // Add the list of allowed packages. assertTrue(vpn.setAlwaysOnPackage( - PKGS[0], true, Collections.singletonList(PKGS[1]), mKeyStore)); + PKGS[0], true, Collections.singletonList(PKGS[1]))); verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] { new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop) })); @@ -433,12 +432,12 @@ public class VpnTest { // Try allowing a package with a comma, should be rejected. assertFalse(vpn.setAlwaysOnPackage( - PKGS[0], true, Collections.singletonList("a.b,c.d"), mKeyStore)); + PKGS[0], true, Collections.singletonList("a.b,c.d"))); // Pass a non-existent packages in the allowlist, they (and only they) should be ignored. // allowed package should change from PGKS[1] to PKGS[2]. assertTrue(vpn.setAlwaysOnPackage( - PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app"), mKeyStore)); + PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app"))); verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] { new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1), new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop) @@ -525,22 +524,22 @@ public class VpnTest { .thenReturn(Collections.singletonList(resInfo)); // null package name should return false - assertFalse(vpn.isAlwaysOnPackageSupported(null, mKeyStore)); + assertFalse(vpn.isAlwaysOnPackageSupported(null)); // Pre-N apps are not supported appInfo.targetSdkVersion = VERSION_CODES.M; - assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0], mKeyStore)); + assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0])); // N+ apps are supported by default appInfo.targetSdkVersion = VERSION_CODES.N; - assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0], mKeyStore)); + assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0])); // Apps that opt out explicitly are not supported appInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT; Bundle metaData = new Bundle(); metaData.putBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, false); svcInfo.metaData = metaData; - assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0], mKeyStore)); + assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0])); } @Test @@ -556,7 +555,7 @@ public class VpnTest { order.verify(mNotificationManager, atLeastOnce()).cancel(anyString(), anyInt()); // Start showing a notification for disconnected once always-on. - vpn.setAlwaysOnPackage(PKGS[0], false, null, mKeyStore); + vpn.setAlwaysOnPackage(PKGS[0], false, null); order.verify(mNotificationManager).notify(anyString(), anyInt(), any()); // Stop showing the notification once connected. @@ -568,7 +567,7 @@ public class VpnTest { order.verify(mNotificationManager).notify(anyString(), anyInt(), any()); // Notification should be cleared after unsetting always-on package. - vpn.setAlwaysOnPackage(null, false, null, mKeyStore); + vpn.setAlwaysOnPackage(null, false, null); order.verify(mNotificationManager).cancel(anyString(), anyInt()); } @@ -608,15 +607,13 @@ public class VpnTest { } private void checkProvisionVpnProfile(Vpn vpn, boolean expectedResult, String... checkedOps) { - assertEquals(expectedResult, vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile, mKeyStore)); + assertEquals(expectedResult, vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile)); // The profile should always be stored, whether or not consent has been previously granted. - verify(mKeyStore) + verify(mVpnProfileStore) .put( eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)), - eq(mVpnProfile.encode()), - eq(Process.SYSTEM_UID), - eq(0)); + eq(mVpnProfile.encode())); for (final String checkedOpStr : checkedOps) { verify(mAppOps).noteOpNoThrow(checkedOpStr, Process.myUid(), TEST_VPN_PKG, @@ -671,7 +668,7 @@ public class VpnTest { bigProfile.name = new String(new byte[Vpn.MAX_VPN_PROFILE_SIZE_BYTES + 1]); try { - vpn.provisionVpnProfile(TEST_VPN_PKG, bigProfile, mKeyStore); + vpn.provisionVpnProfile(TEST_VPN_PKG, bigProfile); fail("Expected IAE due to profile size"); } catch (IllegalArgumentException expected) { } @@ -684,7 +681,7 @@ public class VpnTest { restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); try { - vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile, mKeyStore); + vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile); fail("Expected SecurityException due to restricted user"); } catch (SecurityException expected) { } @@ -694,10 +691,10 @@ public class VpnTest { public void testDeleteVpnProfile() throws Exception { final Vpn vpn = createVpnAndSetupUidChecks(); - vpn.deleteVpnProfile(TEST_VPN_PKG, mKeyStore); + vpn.deleteVpnProfile(TEST_VPN_PKG); - verify(mKeyStore) - .delete(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)), eq(Process.SYSTEM_UID)); + verify(mVpnProfileStore) + .remove(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG))); } @Test @@ -707,7 +704,7 @@ public class VpnTest { restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); try { - vpn.deleteVpnProfile(TEST_VPN_PKG, mKeyStore); + vpn.deleteVpnProfile(TEST_VPN_PKG); fail("Expected SecurityException due to restricted user"); } catch (SecurityException expected) { } @@ -717,24 +714,24 @@ public class VpnTest { public void testGetVpnProfilePrivileged() throws Exception { final Vpn vpn = createVpnAndSetupUidChecks(); - when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) + when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) .thenReturn(new VpnProfile("").encode()); - vpn.getVpnProfilePrivileged(TEST_VPN_PKG, mKeyStore); + vpn.getVpnProfilePrivileged(TEST_VPN_PKG); - verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG))); + verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG))); } @Test public void testStartVpnProfile() throws Exception { final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); - when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) + when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) .thenReturn(mVpnProfile.encode()); - vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore); + vpn.startVpnProfile(TEST_VPN_PKG); - verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG))); + verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG))); verify(mAppOps) .noteOpNoThrow( eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), @@ -748,10 +745,10 @@ public class VpnTest { public void testStartVpnProfileVpnServicePreconsented() throws Exception { final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN); - when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) + when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) .thenReturn(mVpnProfile.encode()); - vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore); + vpn.startVpnProfile(TEST_VPN_PKG); // Verify that the the ACTIVATE_VPN appop was checked, but no error was thrown. verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(), @@ -763,7 +760,7 @@ public class VpnTest { final Vpn vpn = createVpnAndSetupUidChecks(); try { - vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore); + vpn.startVpnProfile(TEST_VPN_PKG); fail("Expected failure due to no user consent"); } catch (SecurityException expected) { } @@ -780,22 +777,22 @@ public class VpnTest { TEST_VPN_PKG, null /* attributionTag */, null /* message */); // Keystore should never have been accessed. - verify(mKeyStore, never()).get(any()); + verify(mVpnProfileStore, never()).get(any()); } @Test public void testStartVpnProfileMissingProfile() throws Exception { final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); - when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))).thenReturn(null); + when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))).thenReturn(null); try { - vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore); + vpn.startVpnProfile(TEST_VPN_PKG); fail("Expected failure due to missing profile"); } catch (IllegalArgumentException expected) { } - verify(mKeyStore).get(vpn.getProfileNameForPackage(TEST_VPN_PKG)); + verify(mVpnProfileStore).get(vpn.getProfileNameForPackage(TEST_VPN_PKG)); verify(mAppOps) .noteOpNoThrow( eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), @@ -812,7 +809,7 @@ public class VpnTest { restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN); try { - vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore); + vpn.startVpnProfile(TEST_VPN_PKG); fail("Expected SecurityException due to restricted user"); } catch (SecurityException expected) { } @@ -938,9 +935,9 @@ public class VpnTest { } private void setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled) { - assertTrue(vpn.setAlwaysOnPackage(TEST_VPN_PKG, lockdownEnabled, null, mKeyStore)); + assertTrue(vpn.setAlwaysOnPackage(TEST_VPN_PKG, lockdownEnabled, null)); - verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG))); + verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG))); verify(mAppOps).setMode( eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), eq(uid), eq(TEST_VPN_PKG), eq(AppOpsManager.MODE_ALLOWED)); @@ -963,11 +960,11 @@ public class VpnTest { final int uid = Process.myUid() + 1; when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt())) .thenReturn(uid); - when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) + when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))) .thenReturn(mVpnProfile.encode()); setAndVerifyAlwaysOnPackage(vpn, uid, false); - assertTrue(vpn.startAlwaysOnVpn(mKeyStore)); + assertTrue(vpn.startAlwaysOnVpn()); // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in // a subsequent CL. @@ -984,7 +981,7 @@ public class VpnTest { InetAddresses.parseNumericAddress("192.0.2.0"), EGRESS_IFACE); lp.addRoute(defaultRoute); - vpn.startLegacyVpn(vpnProfile, mKeyStore, EGRESS_NETWORK, lp); + vpn.startLegacyVpn(vpnProfile, EGRESS_NETWORK, lp); return vpn; } @@ -1186,7 +1183,7 @@ public class VpnTest { .thenReturn(asUserContext); final TestLooper testLooper = new TestLooper(); final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, new TestDeps(), mNetService, - mNetd, userId, mKeyStore, mSystemServices, mIkev2SessionCreator); + mNetd, userId, mVpnProfileStore, mSystemServices, mIkev2SessionCreator); verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat( provider -> provider.getName().contains("VpnNetworkProvider") )); |