diff options
187 files changed, 6923 insertions, 1571 deletions
diff --git a/Android.bp b/Android.bp index d40f11598553..470932378383 100644 --- a/Android.bp +++ b/Android.bp @@ -306,8 +306,8 @@ filegroup { genrule { name: "statslog-telephony-common-java-gen", tools: ["stats-log-api-gen"], - cmd: "$(location stats-log-api-gen) --java $(out) --module telephony_common" - + " --javaPackage com.android.internal.telephony --javaClass TelephonyCommonStatsLog", + cmd: "$(location stats-log-api-gen) --java $(out) --module telephony_common" + + " --javaPackage com.android.internal.telephony --javaClass TelephonyCommonStatsLog", out: ["com/android/internal/telephony/TelephonyCommonStatsLog.java"], } @@ -363,6 +363,13 @@ filegroup { ":platform-compat-native-aidl", // AIDL sources from external directories + ":android.hardware.security.keymint-V1-java-source", + ":android.hardware.security.secureclock-V1-java-source", + ":android.security.apc-java-source", + ":android.security.authorization-java-source", + ":android.security.maintenance-java-source", + ":android.security.vpnprofilestore-java-source", + ":android.system.keystore2-V1-java-source", ":credstore_aidl", ":dumpstate_aidl", ":framework_native_aidl", @@ -523,11 +530,6 @@ java_library { "android.hardware.vibrator-V1.1-java", "android.hardware.vibrator-V1.2-java", "android.hardware.vibrator-V1.3-java", - "android.security.apc-java", - "android.security.authorization-java", - "android.security.maintenance-java", - "android.security.vpnprofilestore-java", - "android.system.keystore2-V1-java", "android.system.suspend.control.internal-java", "devicepolicyprotosnano", @@ -605,7 +607,6 @@ java_library { // TODO: remove gps_debug and protolog.conf.json when the build system propagates "required" properly. "gps_debug.conf", "icu4j-platform-compat-config", - "libcore-platform-compat-config", "protolog.conf.json.gz", "services-platform-compat-config", "documents-ui-compat-config", @@ -685,7 +686,7 @@ genrule { name: "statslog-framework-java-gen", tools: ["stats-log-api-gen"], cmd: "$(location stats-log-api-gen) --java $(out) --module framework" + - " --javaPackage com.android.internal.util --javaClass FrameworkStatsLog --worksource", + " --javaPackage com.android.internal.util --javaClass FrameworkStatsLog --worksource", out: ["com/android/internal/util/FrameworkStatsLog.java"], } @@ -786,7 +787,7 @@ filegroup { java_library { name: "framework-annotations-lib", - srcs: [ ":framework-annotations" ], + srcs: [":framework-annotations"], sdk_version: "core_current", } @@ -1013,7 +1014,6 @@ cc_library { }, } - // This is the full proto version of libplatformprotos. It may only // be used by test code that is not shipped on the device. cc_library { @@ -1174,7 +1174,7 @@ java_library { "core/java/android/os/RemoteException.java", "core/java/android/util/AndroidException.java", ], - libs: [ "unsupportedappusage" ], + libs: ["unsupportedappusage"], dxflags: ["--core-library"], installable: false, diff --git a/StubLibraries.bp b/StubLibraries.bp index fd614a7e3dc3..6316c4a6f19f 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -434,6 +434,7 @@ droidstubs { "core/java/android/os/RemoteException.java", "core/java/android/util/AndroidException.java", ], + libs: ["framework-annotations-lib"], installable: false, sdk_version: "core_platform", annotations_enabled: true, @@ -447,7 +448,7 @@ droidstubs { java_library_static { name: "hwbinder.stubs", sdk_version: "core_current", - libs: ["stub-annotations"], + libs: ["framework-annotations-lib"], srcs: [ ":hwbinder-stubs-docs", ], diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java index 24b8055b9a57..a3fa8ac9958c 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java @@ -1006,6 +1006,41 @@ public class JobInfo implements Parcelable { mJobId = jobId; } + /** + * Creates a new Builder of JobInfo from an existing instance. + * @hide + */ + public Builder(@NonNull JobInfo job) { + mJobId = job.getId(); + mJobService = job.getService(); + mExtras = job.getExtras(); + mTransientExtras = job.getTransientExtras(); + mClipData = job.getClipData(); + mClipGrantFlags = job.getClipGrantFlags(); + mPriority = job.getPriority(); + mFlags = job.getFlags(); + mConstraintFlags = job.getConstraintFlags(); + mNetworkRequest = job.getRequiredNetwork(); + mNetworkDownloadBytes = job.getEstimatedNetworkDownloadBytes(); + mNetworkUploadBytes = job.getEstimatedNetworkUploadBytes(); + mTriggerContentUris = job.getTriggerContentUris() != null + ? new ArrayList<>(Arrays.asList(job.getTriggerContentUris())) : null; + mTriggerContentUpdateDelay = job.getTriggerContentUpdateDelay(); + mTriggerContentMaxDelay = job.getTriggerContentMaxDelay(); + mIsPersisted = job.isPersisted(); + mMinLatencyMillis = job.getMinLatencyMillis(); + mMaxExecutionDelayMillis = job.getMaxExecutionDelayMillis(); + mIsPeriodic = job.isPeriodic(); + mHasEarlyConstraint = job.hasEarlyConstraint(); + mHasLateConstraint = job.hasLateConstraint(); + mIntervalMillis = job.getIntervalMillis(); + mFlexMillis = job.getFlexMillis(); + mInitialBackoffMillis = job.getInitialBackoffMillis(); + // mBackoffPolicySet isn't set but it's fine since this is copying from an already valid + // job. + mBackoffPolicy = job.getBackoffPolicy(); + } + /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public Builder setPriority(int priority) { diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java index d7be2595e88b..ea8e7bc4ab06 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java +++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java @@ -28,6 +28,7 @@ import android.app.job.JobWorkItem; import android.content.ClipData; import android.content.ComponentName; import android.net.Network; +import android.net.NetworkRequest; import android.net.Uri; import android.os.RemoteException; import android.os.UserHandle; @@ -35,6 +36,7 @@ import android.provider.MediaStore; import android.text.format.DateFormat; import android.util.ArraySet; import android.util.Pair; +import android.util.Range; import android.util.Slog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; @@ -52,6 +54,7 @@ import com.android.server.job.JobStatusShortInfoProto; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.function.Predicate; /** @@ -486,8 +489,15 @@ public final class JobStatus { // Later, when we check if a given network satisfies the required // network, we need to know the UID that is requesting it, so push // our source UID into place. - job.getRequiredNetwork().networkCapabilities.setSingleUid(this.sourceUid); + final JobInfo.Builder builder = new JobInfo.Builder(job); + final NetworkRequest.Builder requestBuilder = + new NetworkRequest.Builder(job.getRequiredNetwork()); + requestBuilder.setUids( + Collections.singleton(new Range<Integer>(this.sourceUid, this.sourceUid))); + builder.setRequiredNetwork(requestBuilder.build()); + job = builder.build(); } + final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class); mHasMediaBackupExemption = !job.hasLateConstraint() && exemptedMediaUrisOnly && requiresNetwork && this.sourcePackageName.equals(jsi.getMediaBackupPackage()); diff --git a/core/api/current.txt b/core/api/current.txt index be9dccce637a..ef067858c530 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -8689,6 +8689,8 @@ package android.bluetooth { field public static final String ACTION_NAME_CHANGED = "android.bluetooth.device.action.NAME_CHANGED"; field public static final String ACTION_PAIRING_REQUEST = "android.bluetooth.device.action.PAIRING_REQUEST"; field public static final String ACTION_UUID = "android.bluetooth.device.action.UUID"; + field public static final int ADDRESS_TYPE_PUBLIC = 0; // 0x0 + field public static final int ADDRESS_TYPE_RANDOM = 1; // 0x1 field public static final int BOND_BONDED = 12; // 0xc field public static final int BOND_BONDING = 11; // 0xb field public static final int BOND_NONE = 10; // 0xa @@ -12137,6 +12139,7 @@ package android.content.pm { field public static final String FEATURE_FINGERPRINT = "android.hardware.fingerprint"; field public static final String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management"; field public static final String FEATURE_GAMEPAD = "android.hardware.gamepad"; + field public static final String FEATURE_HARDWARE_KEYSTORE = "android.hardware.hardware_keystore"; field public static final String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors"; field public static final String FEATURE_HOME_SCREEN = "android.software.home_screen"; field public static final String FEATURE_IDENTITY_CREDENTIAL_HARDWARE = "android.hardware.identity_credential"; @@ -20443,7 +20446,9 @@ package android.media { method @NonNull public android.media.MediaFormat getOutputFormat(int); method @NonNull public android.media.MediaCodec.OutputFrame getOutputFrame(int); method @Nullable public android.media.Image getOutputImage(int); + method @Nullable public android.media.MediaCodec.ParameterDescriptor getParameterDescriptor(@NonNull String); method @NonNull public android.media.MediaCodec.QueueRequest getQueueRequest(int); + method @NonNull public java.util.List<java.lang.String> getSupportedVendorParameters(); method @Nullable public static android.media.Image mapHardwareBuffer(@NonNull android.hardware.HardwareBuffer); method public void queueInputBuffer(int, int, int, long, int) throws android.media.MediaCodec.CryptoException; method public void queueSecureInputBuffer(int, int, @NonNull android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException; @@ -20462,6 +20467,8 @@ package android.media { method public void signalEndOfInputStream(); method public void start(); method public void stop(); + method public void subscribeToVendorParameters(@NonNull java.util.List<java.lang.String>); + method public void unsubscribeFromVendorParameters(@NonNull java.util.List<java.lang.String>); field public static final int BUFFER_FLAG_CODEC_CONFIG = 2; // 0x2 field public static final int BUFFER_FLAG_END_OF_STREAM = 4; // 0x4 field public static final int BUFFER_FLAG_KEY_FRAME = 1; // 0x1 @@ -20583,6 +20590,11 @@ package android.media { method public long getPresentationTimeUs(); } + public static class MediaCodec.ParameterDescriptor { + method @NonNull public String getName(); + method public int getType(); + } + public final class MediaCodec.QueueRequest { method public void queue(); method @NonNull public android.media.MediaCodec.QueueRequest setByteBufferParameter(@NonNull String, @NonNull java.nio.ByteBuffer); @@ -25721,7 +25733,7 @@ package android.net.vcn { public abstract static class VcnManager.VcnStatusCallback { ctor public VcnManager.VcnStatusCallback(); method public abstract void onGatewayConnectionError(@NonNull int[], int, @Nullable Throwable); - method public abstract void onVcnStatusChanged(int); + method public abstract void onStatusChanged(int); } } @@ -33589,7 +33601,7 @@ package android.provider { field public static final String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS"; field public static final String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS"; field public static final String ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION"; - field public static final String ACTION_MANAGE_ALL_SUBSCRIPTIONS_SETTINGS = "android.settings.MANAGE_ALL_SUBSCRIPTIONS_SETTINGS"; + field public static final String ACTION_MANAGE_ALL_SIM_PROFILES_SETTINGS = "android.settings.MANAGE_ALL_SIM_PROFILES_SETTINGS"; field public static final String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS"; field public static final String ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION"; field public static final String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS"; @@ -34217,6 +34229,9 @@ package android.provider { method public static android.net.Uri getUriForSubscriptionIdAndField(int, String); field public static final String AUTHORITY = "service-state"; field public static final android.net.Uri CONTENT_URI; + field public static final String DATA_NETWORK_TYPE = "data_network_type"; + field public static final String DATA_REG_STATE = "data_reg_state"; + field public static final String DUPLEX_MODE = "duplex_mode"; field public static final String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection"; field public static final String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric"; field public static final String VOICE_REG_STATE = "voice_reg_state"; @@ -39094,7 +39109,6 @@ 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 @@ -39155,7 +39169,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_NR_AVAILABILITIES_INT_ARRAY = "carrier_nr_availabilities_int_array"; 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"; @@ -39390,6 +39404,7 @@ package android.telephony { field public static final String KEY_NON_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC_INT = "ims.non_rcs_capabilities_cache_expiration_sec_int"; field public static final String KEY_PREFIX = "ims."; field public static final String KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL = "ims.rcs_bulk_capability_exchange_bool"; + field public static final String KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY = "ims.rcs_feature_tag_allowed_string_array"; field public static final String KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT = "ims.wifi_off_deferring_time_millis_int"; } @@ -40661,7 +40676,6 @@ package android.telephony { method public static int[] calculateLength(String, boolean); method @Deprecated public static android.telephony.SmsMessage createFromPdu(byte[]); method public static android.telephony.SmsMessage createFromPdu(byte[], String); - method @Nullable public static android.telephony.SmsMessage createSmsSubmitPdu(@NonNull byte[], boolean); method public String getDisplayMessageBody(); method public String getDisplayOriginatingAddress(); method public String getEmailBody(); @@ -41024,6 +41038,7 @@ package android.telephony { method @Deprecated public String iccTransmitApduBasicChannel(int, int, int, int, int, String); method @Deprecated public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String); method public boolean isConcurrentVoiceAndDataSupported(); + method public boolean isDataCapable(); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isDataConnectionAllowed(); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabled(); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabledForReason(int); diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 03aadbb05806..3b7a617f2e16 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -48,17 +48,12 @@ package android.net { public class NetworkPolicyManager { method @NonNull public static String blockedReasonsToString(int); - method public static boolean isUidBlocked(int, boolean); + method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public int getMultipathPreference(@NonNull android.net.Network); + method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public int getRestrictBackgroundStatus(int); + method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean); + method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidRestrictedOnMeteredNetworks(int); method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void registerNetworkPolicyCallback(@Nullable java.util.concurrent.Executor, @NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback); method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void unregisterNetworkPolicyCallback(@NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback); - field public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 262144; // 0x40000 - field public static final int BLOCKED_METERED_REASON_DATA_SAVER = 65536; // 0x10000 - field public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 131072; // 0x20000 - field public static final int BLOCKED_REASON_APP_STANDBY = 4; // 0x4 - field public static final int BLOCKED_REASON_BATTERY_SAVER = 1; // 0x1 - field public static final int BLOCKED_REASON_DOZE = 2; // 0x2 - field public static final int BLOCKED_REASON_NONE = 0; // 0x0 - field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8 } public static interface NetworkPolicyManager.NetworkPolicyCallback { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 6867a0a89565..4676523bbd6c 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -161,6 +161,7 @@ package android { field public static final String OBSERVE_NETWORK_POLICY = "android.permission.OBSERVE_NETWORK_POLICY"; field public static final String OBSERVE_ROLE_HOLDERS = "android.permission.OBSERVE_ROLE_HOLDERS"; field public static final String OPEN_ACCESSIBILITY_DETAILS_SETTINGS = "android.permission.OPEN_ACCESSIBILITY_DETAILS_SETTINGS"; + field public static final String OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD = "android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"; field public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG"; field public static final String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT"; field public static final String PACKET_KEEPALIVE_OFFLOAD = "android.permission.PACKET_KEEPALIVE_OFFLOAD"; @@ -1125,6 +1126,21 @@ package android.app.compat { method public static boolean isChangeEnabled(long); method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, @NonNull String, @NonNull android.os.UserHandle); method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, int); + method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void setPackageOverride(@NonNull String, @NonNull java.util.Map<java.lang.Long,android.app.compat.PackageOverride>); + } + + public final class PackageOverride { + method public long getMaxVersionCode(); + method public long getMinVersionCode(); + method public boolean isEnabled(); + } + + public static final class PackageOverride.Builder { + ctor public PackageOverride.Builder(); + method @NonNull public android.app.compat.PackageOverride build(); + method @NonNull public android.app.compat.PackageOverride.Builder setEnabled(boolean); + method @NonNull public android.app.compat.PackageOverride.Builder setMaxVersionCode(long); + method @NonNull public android.app.compat.PackageOverride.Builder setMinVersionCode(long); } } @@ -1533,7 +1549,6 @@ package android.bluetooth { method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean disconnect(android.bluetooth.BluetoothDevice); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int); - method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPriority(android.bluetooth.BluetoothDevice, int); } public final class BluetoothHearingAid implements android.bluetooth.BluetoothProfile { @@ -1728,6 +1743,17 @@ package android.bluetooth.le { field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.ResultStorageDescriptor> CREATOR; } + public final class ScanFilter implements android.os.Parcelable { + method public int getAddressType(); + method @Nullable public byte[] getIrk(); + } + + public static final class ScanFilter.Builder { + method @NonNull public android.bluetooth.le.ScanFilter.Builder setDeviceAddress(@NonNull String, int); + method @NonNull public android.bluetooth.le.ScanFilter.Builder setDeviceAddress(@NonNull String, int, @NonNull byte[]); + field public static final int LEN_IRK_OCTETS = 16; // 0x10 + } + public final class ScanSettings implements android.os.Parcelable { field public static final int SCAN_MODE_AMBIENT_DISCOVERY = 3; // 0x3 field public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; // 0x1 @@ -9528,7 +9554,8 @@ package android.telephony { public final class DataSpecificRegistrationInfo implements android.os.Parcelable { method public int describeContents(); - method @NonNull public android.telephony.LteVopsSupportInfo getLteVopsSupportInfo(); + method @Deprecated @NonNull public android.telephony.LteVopsSupportInfo getLteVopsSupportInfo(); + method @Nullable public android.telephony.VopsSupportInfo getVopsSupportInfo(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.DataSpecificRegistrationInfo> CREATOR; } @@ -9573,14 +9600,16 @@ package android.telephony { field public static final int LCE_TYPE_SECONDARY = 1; // 0x1 } - public final class LteVopsSupportInfo implements android.os.Parcelable { + public final class LteVopsSupportInfo extends android.telephony.VopsSupportInfo { ctor public LteVopsSupportInfo(int, int); - method public int describeContents(); method public int getEmcBearerSupport(); method public int getVopsSupport(); - method public void writeToParcel(android.os.Parcel, int); + method public boolean isEmergencyServiceFallbackSupported(); + method public boolean isEmergencyServiceSupported(); + method public boolean isVopsSupported(); + method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.LteVopsSupportInfo> CREATOR; - field public static final int LTE_STATUS_NOT_AVAILABLE = 1; // 0x1 + field @Deprecated public static final int LTE_STATUS_NOT_AVAILABLE = 1; // 0x1 field public static final int LTE_STATUS_NOT_SUPPORTED = 3; // 0x3 field public static final int LTE_STATUS_SUPPORTED = 2; // 0x2 } @@ -9651,6 +9680,29 @@ package android.telephony { field public static final int RESULT_SUCCESS = 0; // 0x0 } + public final class NrVopsSupportInfo extends android.telephony.VopsSupportInfo { + ctor public NrVopsSupportInfo(int, int, int); + method public int getEmcSupport(); + method public int getEmfSupport(); + method public int getVopsSupport(); + method public boolean isEmergencyServiceFallbackSupported(); + method public boolean isEmergencyServiceSupported(); + method public boolean isVopsSupported(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.NrVopsSupportInfo> CREATOR; + field public static final int NR_STATUS_EMC_5GCN_ONLY = 1; // 0x1 + field public static final int NR_STATUS_EMC_EUTRA_5GCN_ONLY = 2; // 0x2 + field public static final int NR_STATUS_EMC_NOT_SUPPORTED = 0; // 0x0 + field public static final int NR_STATUS_EMC_NR_EUTRA_5GCN = 3; // 0x3 + field public static final int NR_STATUS_EMF_5GCN_ONLY = 1; // 0x1 + field public static final int NR_STATUS_EMF_EUTRA_5GCN_ONLY = 2; // 0x2 + field public static final int NR_STATUS_EMF_NOT_SUPPORTED = 0; // 0x0 + field public static final int NR_STATUS_EMF_NR_EUTRA_5GCN = 3; // 0x3 + field public static final int NR_STATUS_VOPS_3GPP_SUPPORTED = 1; // 0x1 + field public static final int NR_STATUS_VOPS_NON_3GPP_SUPPORTED = 2; // 0x2 + field public static final int NR_STATUS_VOPS_NOT_SUPPORTED = 0; // 0x0 + } + public interface NumberVerificationCallback { method public default void onCallReceived(@NonNull String); method public default void onVerificationFailed(int); @@ -10070,7 +10122,7 @@ package android.telephony { } public static interface TelephonyCallback.AllowedNetworkTypesListener { - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onAllowedNetworkTypesChanged(@NonNull java.util.Map<java.lang.Integer,java.lang.Long>); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onAllowedNetworkTypesChanged(int, long); } public static interface TelephonyCallback.CallAttributesListener { @@ -10297,6 +10349,7 @@ package android.telephony { field public static final String CAPABILITY_ALLOWED_NETWORK_TYPES_USED = "CAPABILITY_ALLOWED_NETWORK_TYPES_USED"; field public static final String CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE = "CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE"; field public static final String CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE = "CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE"; + field public static final String CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING = "CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING"; field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1 field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0 @@ -10450,6 +10503,16 @@ package android.telephony { method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings); } + public abstract class VopsSupportInfo implements android.os.Parcelable { + method public int describeContents(); + method public abstract boolean equals(Object); + method public abstract int hashCode(); + method public abstract boolean isEmergencyServiceFallbackSupported(); + method public abstract boolean isEmergencyServiceSupported(); + method public abstract boolean isVopsSupported(); + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.VopsSupportInfo> CREATOR; + } + } package android.telephony.cdma { @@ -10639,16 +10702,30 @@ package android.telephony.data { public final class EpsBearerQosSessionAttributes implements android.os.Parcelable android.net.QosSessionAttributes { method public int describeContents(); - method public long getGuaranteedDownlinkBitRate(); - method public long getGuaranteedUplinkBitRate(); - method public long getMaxDownlinkBitRate(); - method public long getMaxUplinkBitRate(); - method public int getQci(); + method public long getGuaranteedDownlinkBitRateKbps(); + method public long getGuaranteedUplinkBitRateKbps(); + method public long getMaxDownlinkBitRateKbps(); + method public long getMaxUplinkBitRateKbps(); + method public int getQosIdentifier(); method @NonNull public java.util.List<java.net.InetSocketAddress> getRemoteAddresses(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.EpsBearerQosSessionAttributes> CREATOR; } + public final class NrQosSessionAttributes implements android.os.Parcelable android.net.QosSessionAttributes { + method public int describeContents(); + method @NonNull public java.time.Duration getBitRateWindowDuration(); + method public long getGuaranteedDownlinkBitRateKbps(); + method public long getGuaranteedUplinkBitRateKbps(); + method public long getMaxDownlinkBitRateKbps(); + method public long getMaxUplinkBitRateKbps(); + method @IntRange(from=1, to=63) public int getQosFlowIdentifier(); + method public int getQosIdentifier(); + method @NonNull public java.util.List<java.net.InetSocketAddress> getRemoteAddresses(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.NrQosSessionAttributes> CREATOR; + } + public abstract class QualifiedNetworksService extends android.app.Service { ctor public QualifiedNetworksService(); method @NonNull public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int); @@ -11697,6 +11774,7 @@ package android.telephony.ims { method @Nullable public android.telephony.ims.RcsContactPresenceTuple getCapabilityTuple(@NonNull String); method @NonNull public java.util.List<android.telephony.ims.RcsContactPresenceTuple> getCapabilityTuples(); method @NonNull public android.net.Uri getContactUri(); + method @NonNull public java.util.Set<java.lang.String> getFeatureTags(); method public int getRequestResult(); method public int getSourceType(); method public void writeToParcel(@NonNull android.os.Parcel, int); @@ -11711,6 +11789,14 @@ package android.telephony.ims { field public static final int SOURCE_TYPE_NETWORK = 0; // 0x0 } + public static final class RcsContactUceCapability.OptionsBuilder { + ctor public RcsContactUceCapability.OptionsBuilder(@NonNull android.net.Uri); + method @NonNull public android.telephony.ims.RcsContactUceCapability.OptionsBuilder addFeatureTag(@NonNull String); + method @NonNull public android.telephony.ims.RcsContactUceCapability.OptionsBuilder addFeatureTags(@NonNull java.util.Set<java.lang.String>); + method @NonNull public android.telephony.ims.RcsContactUceCapability build(); + method @NonNull public android.telephony.ims.RcsContactUceCapability.OptionsBuilder setRequestResult(int); + } + public static final class RcsContactUceCapability.PresenceBuilder { ctor public RcsContactUceCapability.PresenceBuilder(@NonNull android.net.Uri, int, int); method @NonNull public android.telephony.ims.RcsContactUceCapability.PresenceBuilder addCapabilityTuple(@NonNull android.telephony.ims.RcsContactPresenceTuple); @@ -12004,7 +12090,7 @@ package android.telephony.ims.feature { package android.telephony.ims.stub { public interface CapabilityExchangeEventListener { - method public void onRemoteCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.List<java.lang.String>, @NonNull android.telephony.ims.stub.CapabilityExchangeEventListener.OptionsRequestCallback) throws android.telephony.ims.ImsException; + method public void onRemoteCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.Set<java.lang.String>, @NonNull android.telephony.ims.stub.CapabilityExchangeEventListener.OptionsRequestCallback) throws android.telephony.ims.ImsException; method public void onRequestPublishCapabilities(int) throws android.telephony.ims.ImsException; method public void onUnpublish() throws android.telephony.ims.ImsException; } @@ -12200,7 +12286,7 @@ package android.telephony.ims.stub { public class RcsCapabilityExchangeImplBase { ctor public RcsCapabilityExchangeImplBase(@NonNull java.util.concurrent.Executor); method public void publishCapabilities(@NonNull String, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.PublishResponseCallback); - method public void sendOptionsCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.List<java.lang.String>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.OptionsResponseCallback); + method public void sendOptionsCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.Set<java.lang.String>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.OptionsResponseCallback); method public void subscribeForCapabilities(@NonNull java.util.Collection<android.net.Uri>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.SubscribeResponseCallback); field public static final int COMMAND_CODE_FETCH_ERROR = 3; // 0x3 field public static final int COMMAND_CODE_GENERIC_FAILURE = 1; // 0x1 @@ -12369,7 +12455,7 @@ package android.util { package android.uwb { public final class AngleMeasurement implements android.os.Parcelable { - ctor public AngleMeasurement(double, double, double); + ctor public AngleMeasurement(@FloatRange(from=-3.141592653589793, to=3.141592653589793) double, @FloatRange(from=0.0, to=3.141592653589793) double, @FloatRange(from=0.0, to=1.0) double); method public int describeContents(); method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel(); method @FloatRange(from=0.0, to=3.141592653589793) public double getErrorRadians(); diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt index 0c02c43b1084..8895494e01d3 100644 --- a/core/api/system-removed.txt +++ b/core/api/system-removed.txt @@ -48,6 +48,14 @@ package android.app.prediction { } +package android.bluetooth { + + public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile { + method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPriority(android.bluetooth.BluetoothDevice, int); + } + +} + package android.content { public class Intent implements java.lang.Cloneable android.os.Parcelable { diff --git a/core/api/test-current.txt b/core/api/test-current.txt index a0ff97e1f338..1d094c3d7f40 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -996,6 +996,8 @@ package android.net { public class NetworkPolicyManager { method public boolean getRestrictBackground(); + method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean); + method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidRestrictedOnMeteredNetworks(int); method @NonNull public static String resolveNetworkId(@NonNull android.net.wifi.WifiConfiguration); method public void setRestrictBackground(boolean); } @@ -1650,6 +1652,7 @@ package android.telephony { public class ServiceState implements android.os.Parcelable { method public void addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo); method public int getDataNetworkType(); + method public int getDataRegState(); method public void setCdmaSystemAndNetworkId(int, int); method public void setCellBandwidths(int[]); method public void setChannelNumber(int); diff --git a/core/java/android/app/compat/CompatChanges.java b/core/java/android/app/compat/CompatChanges.java index ab38832458d6..74e1ece3fa89 100644 --- a/core/java/android/app/compat/CompatChanges.java +++ b/core/java/android/app/compat/CompatChanges.java @@ -104,16 +104,15 @@ public final class CompatChanges { * * @param packageName The package name of the app in question. * @param overrides A map from changeId to the override applied for this change id. - * @hide */ - @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG) - public static void setPackageOverride(String packageName, - Map<Long, PackageOverride> overrides) { + @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) + public static void setPackageOverride(@NonNull String packageName, + @NonNull Map<Long, PackageOverride> overrides) { IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface( ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE)); CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(overrides); try { - platformCompat.setOverridesFromInstaller(config, packageName); + platformCompat.setOverridesOnReleaseBuilds(config, packageName); } catch (RemoteException e) { e.rethrowFromSystemServer(); } diff --git a/core/java/android/app/compat/PackageOverride.java b/core/java/android/app/compat/PackageOverride.java index 9f97cd41128a..59b355523a30 100644 --- a/core/java/android/app/compat/PackageOverride.java +++ b/core/java/android/app/compat/PackageOverride.java @@ -17,8 +17,9 @@ package android.app.compat; import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.SystemApi; import android.os.Parcel; -import android.os.Parcelable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -32,15 +33,16 @@ import java.lang.annotation.RetentionPolicy; * * @hide */ -public class PackageOverride implements Parcelable { +@SystemApi +public final class PackageOverride { + /** @hide */ @IntDef({ VALUE_UNDEFINED, VALUE_ENABLED, VALUE_DISABLED }) @Retention(RetentionPolicy.SOURCE) - /** @hide */ public @interface EvaluatedOverride { } @@ -75,10 +77,6 @@ public class PackageOverride implements Parcelable { this.mEnabled = enabled; } - private PackageOverride(Parcel in) { - this(in.readLong(), in.readLong(), in.readBoolean()); - } - /** * Evaluate the override for the given {@code versionCode}. If no override is defined for * the specified version code, {@link #VALUE_UNDEFINED} is returned. @@ -114,25 +112,23 @@ public class PackageOverride implements Parcelable { } /** Returns the enabled value for the override. */ - public boolean getEnabled() { + public boolean isEnabled() { return mEnabled; } /** @hide */ - @Override - public int describeContents() { - return 0; - } - - /** @hide */ - @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(Parcel dest) { dest.writeLong(mMinVersionCode); dest.writeLong(mMaxVersionCode); dest.writeBoolean(mEnabled); } /** @hide */ + public static PackageOverride createFromParcel(Parcel in) { + return new PackageOverride(in.readLong(), in.readLong(), in.readBoolean()); + } + + /** @hide */ @Override public String toString() { if (mMinVersionCode == Long.MIN_VALUE && mMaxVersionCode == Long.MAX_VALUE) { @@ -141,25 +137,10 @@ public class PackageOverride implements Parcelable { return String.format("[%d,%d,%b]", mMinVersionCode, mMaxVersionCode, mEnabled); } - /** @hide */ - public static final Creator<PackageOverride> CREATOR = - new Creator<PackageOverride>() { - - @Override - public PackageOverride createFromParcel(Parcel in) { - return new PackageOverride(in); - } - - @Override - public PackageOverride[] newArray(int size) { - return new PackageOverride[size]; - } - }; - /** * Builder to construct a PackageOverride. */ - public static class Builder { + public static final class Builder { private long mMinVersionCode = Long.MIN_VALUE; private long mMaxVersionCode = Long.MAX_VALUE; private boolean mEnabled; @@ -169,6 +150,7 @@ public class PackageOverride implements Parcelable { * * default value: {@code Long.MIN_VALUE}. */ + @NonNull public Builder setMinVersionCode(long minVersionCode) { mMinVersionCode = minVersionCode; return this; @@ -179,6 +161,7 @@ public class PackageOverride implements Parcelable { * * default value: {@code Long.MAX_VALUE}. */ + @NonNull public Builder setMaxVersionCode(long maxVersionCode) { mMaxVersionCode = maxVersionCode; return this; @@ -189,6 +172,7 @@ public class PackageOverride implements Parcelable { * * default value: {@code false}. */ + @NonNull public Builder setEnabled(boolean enabled) { mEnabled = enabled; return this; @@ -200,6 +184,7 @@ public class PackageOverride implements Parcelable { * @throws IllegalArgumentException if {@code minVersionCode} is larger than * {@code maxVersionCode}. */ + @NonNull public PackageOverride build() { if (mMinVersionCode > mMaxVersionCode) { throw new IllegalArgumentException("minVersionCode must not be larger than " diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index cc0b22afe38d..38863c2c8ccf 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -52,6 +52,8 @@ import android.os.SystemProperties; import android.util.Log; import android.util.Pair; +import com.android.internal.util.Preconditions; + import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -3118,6 +3120,25 @@ public final class BluetoothAdapter { return true; } + /** + * Determines whether a String Bluetooth address, such as "00:43:A8:23:10:F0" + * is a RANDOM STATIC address. + * + * RANDOM STATIC: (addr & 0b11) == 0b11 + * RANDOM RESOLVABLE: (addr & 0b11) == 0b10 + * RANDOM non-RESOLVABLE: (addr & 0b11) == 0b00 + * + * @param address Bluetooth address as string + * @return true if the 2 Least Significant Bits of the address equals 0b11. + * + * @hide + */ + public static boolean isAddressRandomStatic(@NonNull String address) { + Preconditions.checkNotNull(address); + return checkBluetoothAddress(address) + && (Integer.parseInt(address.split(":")[5], 16) & 0b11) == 0b11; + } + @UnsupportedAppUsage /*package*/ IBluetoothManager getBluetoothManager() { return mManagerService; diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 41bc77651db6..c30b8af3da53 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -1002,6 +1002,24 @@ public final class BluetoothDevice implements Parcelable { public static final String EXTRA_MAS_INSTANCE = "android.bluetooth.device.extra.MAS_INSTANCE"; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = { "ADDRESS_TYPE_" }, + value = { + /** Hardware MAC Address */ + ADDRESS_TYPE_PUBLIC, + /** Address is either resolvable, non-resolvable or static.*/ + ADDRESS_TYPE_RANDOM, + } + ) + public @interface AddressType {} + + /** Hardware MAC Address of the device */ + public static final int ADDRESS_TYPE_PUBLIC = 0; + /** Address is either resolvable, non-resolvable or static. */ + public static final int ADDRESS_TYPE_RANDOM = 1; + /** * Lazy initialization. Guaranteed final after first object constructed, or * getService() called. @@ -1010,6 +1028,7 @@ public final class BluetoothDevice implements Parcelable { private static volatile IBluetooth sService; private final String mAddress; + @AddressType private final int mAddressType; /*package*/ @UnsupportedAppUsage @@ -1064,6 +1083,7 @@ public final class BluetoothDevice implements Parcelable { } mAddress = address; + mAddressType = ADDRESS_TYPE_PUBLIC; } @Override diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index 4fb557780d04..632572dea3c6 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -567,6 +567,7 @@ public final class BluetoothHeadset implements BluetoothProfile { * @return true if priority is set, false on error * @hide * @deprecated Replaced with {@link #setConnectionPolicy(BluetoothDevice, int)} + * @removed */ @Deprecated @SystemApi diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java index 7511fd051e41..3c20dcac8ca3 100644 --- a/core/java/android/bluetooth/le/ScanFilter.java +++ b/core/java/android/bluetooth/le/ScanFilter.java @@ -16,15 +16,19 @@ package android.bluetooth.le; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothDevice.AddressType; import android.os.Parcel; import android.os.ParcelUuid; import android.os.Parcelable; import com.android.internal.util.BitUtils; +import com.android.internal.util.Preconditions; import java.util.Arrays; import java.util.List; @@ -53,6 +57,11 @@ public final class ScanFilter implements Parcelable { @Nullable private final String mDeviceAddress; + private final @AddressType int mAddressType; + + @Nullable + private final byte[] mIrk; + @Nullable private final ParcelUuid mServiceUuid; @Nullable @@ -79,12 +88,12 @@ public final class ScanFilter implements Parcelable { /** @hide */ public static final ScanFilter EMPTY = new ScanFilter.Builder().build(); - private ScanFilter(String name, String deviceAddress, ParcelUuid uuid, ParcelUuid uuidMask, ParcelUuid solicitationUuid, ParcelUuid solicitationUuidMask, ParcelUuid serviceDataUuid, byte[] serviceData, byte[] serviceDataMask, - int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask) { + int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask, + @AddressType int addressType, @Nullable byte[] irk) { mDeviceName = name; mServiceUuid = uuid; mServiceUuidMask = uuidMask; @@ -97,6 +106,8 @@ public final class ScanFilter implements Parcelable { mManufacturerId = manufacturerId; mManufacturerData = manufacturerData; mManufacturerDataMask = manufacturerDataMask; + mAddressType = addressType; + mIrk = irk; } @Override @@ -280,6 +291,23 @@ public final class ScanFilter implements Parcelable { return mDeviceAddress; } + /** + * @hide + */ + @SystemApi + public @AddressType int getAddressType() { + return mAddressType; + } + + /** + * @hide + */ + @SystemApi + @Nullable + public byte[] getIrk() { + return mIrk; + } + @Nullable public byte[] getServiceData() { return mServiceData; @@ -516,8 +544,16 @@ public final class ScanFilter implements Parcelable { */ public static final class Builder { + /** + * @hide + */ + @SystemApi + public static final int LEN_IRK_OCTETS = 16; + private String mDeviceName; private String mDeviceAddress; + private @AddressType int mAddressType = BluetoothDevice.ADDRESS_TYPE_PUBLIC; + private byte[] mIrk; private ParcelUuid mServiceUuid; private ParcelUuid mUuidMask; @@ -546,14 +582,130 @@ public final class ScanFilter implements Parcelable { * * @param deviceAddress The device Bluetooth address for the filter. It needs to be in the * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link - * BluetoothAdapter#checkBluetoothAddress}. + * BluetoothAdapter#checkBluetoothAddress}. The @AddressType is defaulted to {@link + * BluetoothDevice#ADDRESS_TYPE_PUBLIC} * @throws IllegalArgumentException If the {@code deviceAddress} is invalid. */ public Builder setDeviceAddress(String deviceAddress) { - if (deviceAddress != null && !BluetoothAdapter.checkBluetoothAddress(deviceAddress)) { + return setDeviceAddress(deviceAddress, BluetoothDevice.ADDRESS_TYPE_PUBLIC); + } + + /** + * Set filter on Address with AddressType + * + * <p>This key is used to resolve a private address from a public address. + * + * @param deviceAddress The device Bluetooth address for the filter. It needs to be in the + * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link + * BluetoothAdapter#checkBluetoothAddress}. May be any type of address. + * @param addressType indication of the type of address + * e.g. {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC} + * or {@link BluetoothDevice#ADDRESS_TYPE_RANDOM} + * + * @throws IllegalArgumentException If the {@code deviceAddress} is invalid. + * @throws IllegalArgumentException If the {@code addressType} is invalid length + * @throws NullPointerException if {@code deviceAddress} is null. + * + * @hide + */ + @NonNull + @SystemApi + public Builder setDeviceAddress(@NonNull String deviceAddress, + @AddressType int addressType) { + return setDeviceAddressInternal(deviceAddress, addressType, null); + } + + /** + * Set filter on Address with AddressType and the Identity Resolving Key (IRK). + * + * <p>The IRK is used to resolve a {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC} from + * a PRIVATE_ADDRESS type. + * + * @param deviceAddress The device Bluetooth address for the filter. It needs to be in the + * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link + * BluetoothAdapter#checkBluetoothAddress}. This Address type must only be PUBLIC OR RANDOM + * STATIC. + * @param addressType indication of the type of address + * e.g. {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC} + * or {@link BluetoothDevice#ADDRESS_TYPE_RANDOM} + * @param irk non-null byte array representing the Identity Resolving Key + * + * @throws IllegalArgumentException If the {@code deviceAddress} is invalid. + * @throws IllegalArgumentException if the {@code irk} is invalid length. + * @throws IllegalArgumentException If the {@code addressType} is invalid length or is not + * PUBLIC or RANDOM STATIC when an IRK is present. + * @throws NullPointerException if {@code deviceAddress} or {@code irk} is null. + * + * @hide + */ + @NonNull + @SystemApi + public Builder setDeviceAddress(@NonNull String deviceAddress, + @AddressType int addressType, + @NonNull byte[] irk) { + Preconditions.checkNotNull(irk); + if (irk.length != LEN_IRK_OCTETS) { + throw new IllegalArgumentException("'irk' is invalid length!"); + } + return setDeviceAddressInternal(deviceAddress, addressType, irk); + } + + /** + * Set filter on Address with AddressType and the Identity Resolving Key (IRK). + * + * <p>Internal setter for the device address + * + * @param deviceAddress The device Bluetooth address for the filter. It needs to be in the + * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link + * BluetoothAdapter#checkBluetoothAddress}. + * @param addressType indication of the type of address + * e.g. {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC} + * @param irk non-null byte array representing the Identity Resolving Address; nullable + * internally. + * + * @throws IllegalArgumentException If the {@code deviceAddress} is invalid. + * @throws IllegalArgumentException If the {@code addressType} is invalid length. + * @throws NullPointerException if {@code deviceAddress} is null. + * + * @hide + */ + @NonNull + private Builder setDeviceAddressInternal(@NonNull String deviceAddress, + @AddressType int addressType, + @Nullable byte[] irk) { + + // Make sure our deviceAddress is valid! + Preconditions.checkNotNull(deviceAddress); + if (!BluetoothAdapter.checkBluetoothAddress(deviceAddress)) { throw new IllegalArgumentException("invalid device address " + deviceAddress); } + + // Verify type range + if (addressType < BluetoothDevice.ADDRESS_TYPE_PUBLIC + || addressType > BluetoothDevice.ADDRESS_TYPE_RANDOM) { + throw new IllegalArgumentException("'addressType' is invalid!"); + } + + // IRK can only be used for a PUBLIC or RANDOM (STATIC) Address. + if (addressType == BluetoothDevice.ADDRESS_TYPE_RANDOM) { + // Don't want a bad combination of address and irk! + if (irk != null) { + // Since there are 3 possible RANDOM subtypes we must check to make sure + // the correct type of address is used. + if (!BluetoothAdapter.isAddressRandomStatic(deviceAddress)) { + throw new IllegalArgumentException( + "Invalid combination: IRK requires either a PUBLIC or " + + "RANDOM (STATIC) Address"); + } + } + } + + // PUBLIC doesn't require extra work + // Without an IRK any address may be accepted + mDeviceAddress = deviceAddress; + mAddressType = addressType; + mIrk = irk; return this; } @@ -727,7 +879,8 @@ public final class ScanFilter implements Parcelable { mServiceUuid, mUuidMask, mServiceSolicitationUuid, mServiceSolicitationUuidMask, mServiceDataUuid, mServiceData, mServiceDataMask, - mManufacturerId, mManufacturerData, mManufacturerDataMask); + mManufacturerId, mManufacturerData, mManufacturerDataMask, + mAddressType, mIrk); } } } diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS index d0d406a0c9e6..01b554a56720 100644 --- a/core/java/android/content/OWNERS +++ b/core/java/android/content/OWNERS @@ -8,3 +8,5 @@ per-file Intent.java = patb@google.com per-file AutofillOptions* = file:/core/java/android/service/autofill/OWNERS per-file ContentCaptureOptions* = file:/core/java/android/service/contentcapture/OWNERS per-file LocusId* = file:/core/java/android/service/contentcapture/OWNERS +per-file ComponentCallbacksController = file:/services/core/java/com/android/server/wm/OWNERS +per-file ComponentCallbacksController = charlesccchen@google.com diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 7e17256f0229..23f5e3ab6c1f 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3167,8 +3167,57 @@ public abstract class PackageManager { public static final String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking"; /** - * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: - * The device has a StrongBox hardware-backed Keystore. + * Feature for {@link #getSystemAvailableFeatures} and + * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device implements + * the Android Keystore backed by an isolated execution environment. The version indicates + * which features are implemented in the isolated execution environment: + * <ul> + * <li>100: Hardware support for ECDH (see {@link javax.crypto.KeyAgreement}) and support + * for app-generated attestation keys (see {@link + * android.security.keystore.KeyGenParameterSpec.Builder#setAttestKeyAlias(String)}). + * <li>41: Hardware enforcement of device-unlocked keys (see {@link + * android.security.keystore.KeyGenParameterSpec.Builder#setUnlockedDeviceRequired(boolean)}). + * <li>40: Support for wrapped key import (see {@link + * android.security.keystore.WrappedKeyEntry}), optional support for ID attestation (see {@link + * android.security.keystore.KeyGenParameterSpec.Builder#setDevicePropertiesAttestationIncluded(boolean)}), + * attestation (see {@link + * android.security.keystore.KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])}), + * AES, HMAC, ECDSA and RSA support where the secret or private key never leaves secure + * hardware, and support for requiring user authentication before a key can be used. + * </ul> + * This feature version is guaranteed to be set for all devices launching with Android 12 and + * may be set on devices launching with an earlier version. If the feature version is set, it + * will at least have the value 40. If it's not set the device may have a version of + * hardware-backed keystore but it may not support all features listed above. + */ + @SdkConstant(SdkConstantType.FEATURE) + public static final String FEATURE_HARDWARE_KEYSTORE = "android.hardware.hardware_keystore"; + + /** + * Feature for {@link #getSystemAvailableFeatures}, {@link #hasSystemFeature(String)}, and + * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device implements + * the Android Keystore backed by a dedicated secure processor referred to as + * <a href="https://source.android.com/security/best-practices/hardware#strongbox-keymaster"> + * StrongBox</a>. If this feature has a version, the version number indicates which features are + * implemented in StrongBox: + * <ul> + * <li>100: Hardware support for ECDH (see {@link javax.crypto.KeyAgreement}) and support + * for app-generated attestation keys (see {@link + * android.security.keystore.KeyGenParameterSpec.Builder#setAttestKeyAlias(String)}). + * <li>41: Hardware enforcement of device-unlocked keys (see {@link + * android.security.keystore.KeyGenParameterSpec.Builder#setUnlockedDeviceRequired(boolean)}). + * <li>40: Support for wrapped key import (see {@link + * android.security.keystore.WrappedKeyEntry}), optional support for ID attestation (see {@link + * android.security.keystore.KeyGenParameterSpec.Builder#setDevicePropertiesAttestationIncluded(boolean)}), + * attestation (see {@link + * android.security.keystore.KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])}), + * AES, HMAC, ECDSA and RSA support where the secret or private key never leaves secure + * hardware, and support for requiring user authentication before a key can be used. + * </ul> + * If a device has StrongBox, this feature version number is guaranteed to be set for all + * devices launching with Android 12 and may be set on devices launching with an earlier + * version. If the feature version is set, it will at least have the value 40. If it's not + * set the device may have StrongBox but it may not support all features listed above. */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_STRONGBOX_KEYSTORE = diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl index 9bf791ba33e0..171c6a2c6a19 100644 --- a/core/java/android/net/INetworkPolicyManager.aidl +++ b/core/java/android/net/INetworkPolicyManager.aidl @@ -62,6 +62,7 @@ interface INetworkPolicyManager { 3 - enabled */ int getRestrictBackgroundByCaller(); + int getRestrictBackgroundStatus(int uid); void setDeviceIdleMode(boolean enabled); void setWifiMeteredOverride(String networkId, int meteredOverride); diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index c544c3275cf3..68606ec90dc9 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -204,81 +204,6 @@ public class NetworkPolicyManager { public @interface SubscriptionOverrideMask {} /** - * Flag to indicate that an app is not subject to any restrictions that could result in its - * network access blocked. - * - * @hide - */ - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public static final int BLOCKED_REASON_NONE = 0; - - /** - * Flag to indicate that an app is subject to Battery saver restrictions that would - * result in its network access being blocked. - * - * @hide - */ - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public static final int BLOCKED_REASON_BATTERY_SAVER = 1 << 0; - - /** - * Flag to indicate that an app is subject to Doze restrictions that would - * result in its network access being blocked. - * - * @hide - */ - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public static final int BLOCKED_REASON_DOZE = 1 << 1; - - /** - * Flag to indicate that an app is subject to App Standby restrictions that would - * result in its network access being blocked. - * - * @hide - */ - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public static final int BLOCKED_REASON_APP_STANDBY = 1 << 2; - - /** - * Flag to indicate that an app is subject to Restricted mode restrictions that would - * result in its network access being blocked. - * - * @hide - */ - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public static final int BLOCKED_REASON_RESTRICTED_MODE = 1 << 3; - - /** - * Flag to indicate that an app is subject to Data saver restrictions that would - * result in its metered network access being blocked. - * - * @hide - */ - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public static final int BLOCKED_METERED_REASON_DATA_SAVER = 1 << 16; - - /** - * Flag to indicate that an app is subject to user restrictions that would - * result in its metered network access being blocked. - * - * @hide - */ - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 1 << 17; - - /** - * Flag to indicate that an app is subject to Device admin restrictions that would - * result in its metered network access being blocked. - * - * @hide - */ - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 1 << 18; - - /** @hide */ - public static final int BLOCKED_METERED_REASON_MASK = 0xffff0000; - - /** * Flag to indicate that app is not exempt from any network restrictions. * * @hide @@ -326,25 +251,23 @@ public class NetworkPolicyManager { * @hide */ public static final int ALLOWED_METERED_REASON_USER_EXEMPTED = 1 << 16; - - /** @hide */ - public static final int ALLOWED_METERED_REASON_MASK = 0xffff0000; - /** + * Flag to indicate that app is exempt from certain metered network restrictions because of it + * being a system component. + * * @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = true, prefix = {"BLOCKED_"}, value = { - BLOCKED_REASON_NONE, - BLOCKED_REASON_BATTERY_SAVER, - BLOCKED_REASON_DOZE, - BLOCKED_REASON_APP_STANDBY, - BLOCKED_REASON_RESTRICTED_MODE, - BLOCKED_METERED_REASON_DATA_SAVER, - BLOCKED_METERED_REASON_USER_RESTRICTED, - BLOCKED_METERED_REASON_ADMIN_DISABLED, - }) - public @interface BlockedReason {} + public static final int ALLOWED_METERED_REASON_SYSTEM = 1 << 17; + /** + * Flag to indicate that app is exempt from certain metered network restrictions because of it + * being in the foreground. + * + * @hide + */ + public static final int ALLOWED_METERED_REASON_FOREGROUND = 1 << 18; + + /** @hide */ + public static final int ALLOWED_METERED_REASON_MASK = 0xffff0000; private final Context mContext; @UnsupportedAppUsage @@ -529,6 +452,26 @@ public class NetworkPolicyManager { } /** + * Determines if an UID is subject to metered network restrictions while running in background. + * + * @param uid The UID whose status needs to be checked. + * @return {@link ConnectivityManager#RESTRICT_BACKGROUND_STATUS_DISABLED}, + * {@link ConnectivityManager##RESTRICT_BACKGROUND_STATUS_ENABLED}, + * or {@link ConnectivityManager##RESTRICT_BACKGROUND_STATUS_WHITELISTED} to denote + * the current status of the UID. + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) + public int getRestrictBackgroundStatus(int uid) { + try { + return mService.getRestrictBackgroundStatus(uid); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Override connections to be temporarily marked as either unmetered or congested, * along with automatic timeouts if desired. * @@ -610,9 +553,8 @@ public class NetworkPolicyManager { * @param meteredNetwork True if the network is metered. * @return true if networking is blocked for the given uid according to current networking * policies. - * - * @hide */ + @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork) { try { return mService.isUidNetworkingBlocked(uid, meteredNetwork); @@ -651,9 +593,8 @@ public class NetworkPolicyManager { * * @param uid The target uid. * @return true if the given uid is restricted from doing networking on metered networks. - * - * @hide */ + @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidRestrictedOnMeteredNetworks(int uid) { try { return mService.isUidRestrictedOnMeteredNetworks(uid); @@ -663,11 +604,15 @@ public class NetworkPolicyManager { } /** - * Get multipath preference for the given network. + * Gets a hint on whether it is desirable to use multipath data transfer on the given network. + * + * @return One of the ConnectivityManager.MULTIPATH_PREFERENCE_* constants. * * @hide */ - public int getMultipathPreference(Network network) { + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) + public int getMultipathPreference(@NonNull Network network) { try { return mService.getMultipathPreference(network); } catch (RemoteException e) { @@ -840,35 +785,6 @@ public class NetworkPolicyManager { } /** - * Returns whether network access of an UID is blocked or not based on {@code blockedReasons} - * corresponding to it. - * - * {@code blockedReasons} would be a bitwise {@code OR} combination of the - * {@code BLOCKED_REASON_*} and/or {@code BLOCKED_METERED_REASON_*} constants. - * - * @param blockedReasons Value indicating the reasons for why the network access of an UID is - * blocked. If the value is equal to {@link #BLOCKED_REASON_NONE}, then - * it indicates that an app's network access is not blocked. - * @param meteredNetwork Value indicating whether the network is metered or not. - * @return Whether network access is blocked or not. - * @hide - */ - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - public static boolean isUidBlocked(@BlockedReason int blockedReasons, boolean meteredNetwork) { - if (blockedReasons == BLOCKED_REASON_NONE) { - return false; - } - final int blockedOnAllNetworksReason = (blockedReasons & ~BLOCKED_METERED_REASON_MASK); - if (blockedOnAllNetworksReason != BLOCKED_REASON_NONE) { - return true; - } - if (meteredNetwork) { - return blockedReasons != BLOCKED_REASON_NONE; - } - return false; - } - - /** * Returns the {@code string} representation of {@code blockedReasons} argument. * * @param blockedReasons Value indicating the reasons for why the network access of an UID is @@ -877,7 +793,7 @@ public class NetworkPolicyManager { */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @NonNull - public static String blockedReasonsToString(@BlockedReason int blockedReasons) { + public static String blockedReasonsToString(int blockedReasons) { return DebugUtils.flagsToString(NetworkPolicyManager.class, "BLOCKED_", blockedReasons); } @@ -941,7 +857,7 @@ public class NetworkPolicyManager { * @hide */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) - default void onUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {} + default void onUidBlockedReasonChanged(int uid, int blockedReasons) {} } /** @hide */ @@ -956,8 +872,7 @@ public class NetworkPolicyManager { } @Override - public void onBlockedReasonChanged(int uid, @BlockedReason int oldBlockedReasons, - @BlockedReason int newBlockedReasons) { + public void onBlockedReasonChanged(int uid, int oldBlockedReasons, int newBlockedReasons) { if (oldBlockedReasons != newBlockedReasons) { dispatchOnUidBlockedReasonChanged(mExecutor, mCallback, uid, newBlockedReasons); } @@ -965,7 +880,7 @@ public class NetworkPolicyManager { } private static void dispatchOnUidBlockedReasonChanged(@Nullable Executor executor, - @NonNull NetworkPolicyCallback callback, int uid, @BlockedReason int blockedReasons) { + @NonNull NetworkPolicyCallback callback, int uid, int blockedReasons) { if (executor == null) { callback.onUidBlockedReasonChanged(uid, blockedReasons); } else { diff --git a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl index 4078b249218c..74c3ba44b69e 100644 --- a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl +++ b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl @@ -23,6 +23,6 @@ package android.net.netstats.provider; */ oneway interface INetworkStatsProvider { void onRequestStatsUpdate(int token); - void onSetLimit(String iface, long quotaBytes); void onSetAlert(long quotaBytes); + void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes); } diff --git a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl index bd336dd348fe..7eaa01e262fe 100644 --- a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl +++ b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl @@ -26,6 +26,6 @@ import android.net.NetworkStats; oneway interface INetworkStatsProviderCallback { void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); void notifyAlertReached(); - void notifyLimitReached(); + void notifyWarningOrLimitReached(); void unregister(); } diff --git a/core/java/android/net/netstats/provider/NetworkStatsProvider.java b/core/java/android/net/netstats/provider/NetworkStatsProvider.java index 7639d2244cfe..65b336ad6fce 100644 --- a/core/java/android/net/netstats/provider/NetworkStatsProvider.java +++ b/core/java/android/net/netstats/provider/NetworkStatsProvider.java @@ -29,7 +29,8 @@ import android.os.RemoteException; @SystemApi public abstract class NetworkStatsProvider { /** - * A value used by {@link #onSetLimit} and {@link #onSetAlert} indicates there is no limit. + * A value used by {@link #onSetLimit}, {@link #onSetAlert} and {@link #onSetWarningAndLimit} + * indicates there is no limit. */ public static final int QUOTA_UNLIMITED = -1; @@ -42,13 +43,13 @@ public abstract class NetworkStatsProvider { } @Override - public void onSetLimit(String iface, long quotaBytes) { - NetworkStatsProvider.this.onSetLimit(iface, quotaBytes); + public void onSetAlert(long quotaBytes) { + NetworkStatsProvider.this.onSetAlert(quotaBytes); } @Override - public void onSetAlert(long quotaBytes) { - NetworkStatsProvider.this.onSetAlert(quotaBytes); + public void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes) { + NetworkStatsProvider.this.onSetWarningAndLimit(iface, warningBytes, limitBytes); } }; @@ -145,11 +146,28 @@ public abstract class NetworkStatsProvider { } /** - * Notify system that the quota set by {@code onSetLimit} has been reached. + * Notify system that the warning set by {@link #onSetWarningAndLimit} has been reached. + * + * @hide + */ + // TODO: Expose as system API. + public void notifyWarningReached() { + try { + // Reuse the code path to notify warning reached with limit reached + // since framework handles them in the same way. + getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached(); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Notify system that the quota set by {@link #onSetLimit} or limit set by + * {@link #onSetWarningAndLimit} has been reached. */ public void notifyLimitReached() { try { - getProviderCallbackBinderOrThrow().notifyLimitReached(); + getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached(); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } @@ -180,9 +198,35 @@ public abstract class NetworkStatsProvider { * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. */ + // TODO: deprecate this once onSetWarningAndLimit is ready. public abstract void onSetLimit(@NonNull String iface, long quotaBytes); /** + * Called by {@code NetworkStatsService} when setting the interface quotas for the specified + * upstream interface. If a provider implements {@link #onSetWarningAndLimit}, the system + * will not call {@link #onSetLimit}. When this method is called, the implementation + * should behave as follows: + * 1. If {@code warningBytes} is reached on {@code iface}, block all further traffic on + * {@code iface} and call {@link NetworkStatsProvider@notifyWarningReached()}. + * 2. If {@code limitBytes} is reached on {@code iface}, block all further traffic on + * {@code iface} and call {@link NetworkStatsProvider#notifyLimitReached()}. + * + * @param iface the interface requiring the operation. + * @param warningBytes the warning defined as the number of bytes, starting from zero and + * counting from now. A value of {@link #QUOTA_UNLIMITED} indicates + * there is no warning. + * @param limitBytes the limit defined as the number of bytes, starting from zero and counting + * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. + * + * @hide + */ + // TODO: Expose as system API. + public void onSetWarningAndLimit(@NonNull String iface, long warningBytes, long limitBytes) { + // Backward compatibility for those who didn't override this function. + onSetLimit(iface, limitBytes); + } + + /** * Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations * MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes * have been reached. Unlike {@link #onSetLimit(String, long)}, the custom implementation should diff --git a/core/java/android/net/vcn/IVcnManagementService.aidl b/core/java/android/net/vcn/IVcnManagementService.aidl index 6a3cb42ed75d..5b79f7311b6d 100644 --- a/core/java/android/net/vcn/IVcnManagementService.aidl +++ b/core/java/android/net/vcn/IVcnManagementService.aidl @@ -29,7 +29,7 @@ import android.os.ParcelUuid; */ interface IVcnManagementService { void setVcnConfig(in ParcelUuid subscriptionGroup, in VcnConfig config, in String opPkgName); - void clearVcnConfig(in ParcelUuid subscriptionGroup); + void clearVcnConfig(in ParcelUuid subscriptionGroup, in String opPkgName); void addVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener); void removeVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener); diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java index b73fdbff8ef3..abd41dacdeb6 100644 --- a/core/java/android/net/vcn/VcnManager.java +++ b/core/java/android/net/vcn/VcnManager.java @@ -154,7 +154,7 @@ public class VcnManager { requireNonNull(subscriptionGroup, "subscriptionGroup was null"); try { - mService.clearVcnConfig(subscriptionGroup); + mService.clearVcnConfig(subscriptionGroup, mContext.getOpPackageName()); } catch (ServiceSpecificException e) { throw new IOException(e); } catch (RemoteException e) { @@ -439,7 +439,7 @@ public class VcnManager { * @param statusCode the code for the status change encountered by this {@link * VcnStatusCallback}'s subscription group. */ - public abstract void onVcnStatusChanged(@VcnStatusCode int statusCode); + public abstract void onStatusChanged(@VcnStatusCode int statusCode); /** * Invoked when a VCN Gateway Connection corresponding to this callback's subscription group @@ -476,7 +476,7 @@ public class VcnManager { * and there is a VCN active for its specified subscription group (this may happen after the * callback is registered). * - * <p>{@link VcnStatusCallback#onVcnStatusChanged(int)} will be invoked on registration with the + * <p>{@link VcnStatusCallback#onStatusChanged(int)} will be invoked on registration with the * current status for the specified subscription group's VCN. If the registrant is not * privileged for this subscription group, {@link #VCN_STATUS_CODE_NOT_CONFIGURED} will be * returned. @@ -580,7 +580,7 @@ public class VcnManager { @Override public void onVcnStatusChanged(@VcnStatusCode int statusCode) { Binder.withCleanCallingIdentity( - () -> mExecutor.execute(() -> mCallback.onVcnStatusChanged(statusCode))); + () -> mExecutor.execute(() -> mCallback.onStatusChanged(statusCode))); } // TODO(b/180521637): use ServiceSpecificException for safer Exception 'parceling' diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 6425c250f317..f5130bcf3088 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -543,6 +543,16 @@ public class Binder implements IBinder { public final native void markVintfStability(); /** + * Use a VINTF-stability binder w/o VINTF requirements. Should be called + * on a binder before it is sent out of process. + * + * This must be called before the object is sent to another process. + * + * @hide + */ + public final native void forceDowngradeToSystemStability(); + + /** * Flush any Binder commands pending in the current thread to the kernel * driver. This can be * useful to call before performing an operation that may block for a long diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 6d3b58c7db20..385a815798dc 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1009,8 +1009,8 @@ public final class Settings { * Output: Nothing. */ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) - public static final String ACTION_MANAGE_ALL_SUBSCRIPTIONS_SETTINGS = - "android.settings.MANAGE_ALL_SUBSCRIPTIONS_SETTINGS"; + public static final String ACTION_MANAGE_ALL_SIM_PROFILES_SETTINGS = + "android.settings.MANAGE_ALL_SIM_PROFILES_SETTINGS"; /** * Activity Action: Show screen for controlling which apps can draw on top of other apps. diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 753abea2cfe2..a3a910acae63 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -4557,6 +4557,15 @@ public final class Telephony { public static final String VOICE_REG_STATE = "voice_reg_state"; /** + * An integer value indicating the current data service state. + * <p> + * Valid values: {@link ServiceState#STATE_IN_SERVICE}, + * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY}, + * {@link ServiceState#STATE_POWER_OFF}. + */ + public static final String DATA_REG_STATE = "data_reg_state"; + + /** * The current registered operator numeric id. * <p> * In GSM/UMTS, numeric format is 3 digit country code plus 2 or 3 digit @@ -4572,6 +4581,24 @@ public final class Telephony { * This is the same as {@link ServiceState#getIsManualSelection()}. */ public static final String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection"; + + /** + * The current data network type. + * <p> + * This is the same as {@link TelephonyManager#getDataNetworkType()}. + */ + public static final String DATA_NETWORK_TYPE = "data_network_type"; + + /** + * An integer value indicating the current duplex mode if the radio technology is LTE, + * LTE-CA or NR. + * <p> + * Valid values: {@link ServiceState#DUPLEX_MODE_UNKNOWN}, + * {@link ServiceState#DUPLEX_MODE_FDD}, {@link ServiceState#DUPLEX_MODE_TDD}. + * <p> + * This is the same as {@link ServiceState#getDuplexMode()}. + */ + public static final String DUPLEX_MODE = "duplex_mode"; } /** diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index fcb92889e69f..bbb1d0caac6a 100644 --- a/core/java/android/telephony/PhoneStateListener.java +++ b/core/java/android/telephony/PhoneStateListener.java @@ -1577,7 +1577,7 @@ public class PhoneStateListener { // default implementation empty } - public void onAllowedNetworkTypesChanged(Map allowedNetworkTypesList) { + public void onAllowedNetworkTypesChanged(int reason, long allowedNetworkType) { // default implementation empty } diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java index 0402ed07b7be..e49c82cfbd54 100644 --- a/core/java/android/telephony/TelephonyCallback.java +++ b/core/java/android/telephony/TelephonyCallback.java @@ -544,9 +544,6 @@ public class TelephonyCallback { /** * 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 AllowedNetworkTypesListener#onAllowedNetworkTypesChanged */ @@ -1287,30 +1284,34 @@ public class TelephonyCallback { public interface AllowedNetworkTypesListener { /** * Callback invoked when the current allowed network type list has changed on the - * registered subscription. + * registered subscription for a specified reason. * Note, the registered subscription is associated with {@link TelephonyManager} object - * on which - * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)} + * on which {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)} * 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}, - * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER}, and - * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G}) with reason's allowed - * network type values. + * @param reason an allowed network type reasons. + * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER + * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER + * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER + * @see TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G + * + * @param allowedNetworkType an allowed network type bitmask value. (for example, + * the long bitmask value is {{@link TelephonyManager#NETWORK_TYPE_BITMASK_NR}| + * {@link TelephonyManager#NETWORK_TYPE_BITMASK_LTE}}) + * * 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}, - * {TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G, long type value}} + * If the latest allowed network type is changed by user, then the system + * notifies the {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER} and + * long type value}. */ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) - void onAllowedNetworkTypesChanged(@NonNull Map<Integer, Long> allowedNetworkTypesList); + void onAllowedNetworkTypesChanged( + @TelephonyManager.AllowedNetworkTypesReason int reason, + @TelephonyManager.NetworkTypeBitMask long allowedNetworkType); } /** @@ -1741,14 +1742,15 @@ public class TelephonyCallback { enabled, reason))); } - public void onAllowedNetworkTypesChanged(Map allowedNetworkTypesList) { + public void onAllowedNetworkTypesChanged(int reason, long allowedNetworkType) { AllowedNetworkTypesListener listener = (AllowedNetworkTypesListener) mTelephonyCallbackWeakRef.get(); if (listener == null) return; Binder.withCleanCallingIdentity( () -> mExecutor.execute( - () -> listener.onAllowedNetworkTypesChanged(allowedNetworkTypesList))); + () -> listener.onAllowedNetworkTypesChanged(reason, + allowedNetworkType))); } public void onLinkCapacityEstimateChanged( diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index 5a8318f2aa5e..b111ec339ed7 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -825,16 +825,18 @@ public class TelephonyRegistryManager { } /** - * Notify emergency number list changed on certain subscription. - * - * @param slotIndex for which emergency number list changed. Can be derived from subId except - * when subId is invalid. - * @param subId for which emergency number list changed. + * Notify the allowed network types has changed for a specific subscription and the specific + * reason. + * @param slotIndex for which allowed network types changed. + * @param subId for which allowed network types changed. + * @param reason an allowed network type reasons. + * @param allowedNetworkType an allowed network type bitmask value. */ public void notifyAllowedNetworkTypesChanged(int slotIndex, int subId, - Map<Integer, Long> allowedNetworkTypeList) { + int reason, long allowedNetworkType) { try { - sRegistry.notifyAllowedNetworkTypesChanged(slotIndex, subId, allowedNetworkTypeList); + sRegistry.notifyAllowedNetworkTypesChanged(slotIndex, subId, reason, + allowedNetworkType); } catch (RemoteException ex) { // system process is dead } diff --git a/core/java/android/uwb/AngleMeasurement.java b/core/java/android/uwb/AngleMeasurement.java index 8c771baaea37..3d603737c48c 100644 --- a/core/java/android/uwb/AngleMeasurement.java +++ b/core/java/android/uwb/AngleMeasurement.java @@ -48,7 +48,10 @@ public final class AngleMeasurement implements Parcelable { * @throws IllegalArgumentException if the radians, errorRadians, or confidenceLevel is out of * allowed range */ - public AngleMeasurement(double radians, double errorRadians, double confidenceLevel) { + public AngleMeasurement( + @FloatRange(from = -Math.PI, to = +Math.PI) double radians, + @FloatRange(from = 0.0, to = +Math.PI) double errorRadians, + @FloatRange(from = 0.0, to = 1.0) double confidenceLevel) { if (radians < -Math.PI || radians > Math.PI) { throw new IllegalArgumentException("Invalid radians: " + radians); } diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS index 31f6f6afdd53..4a1d68547f70 100644 --- a/core/java/android/view/OWNERS +++ b/core/java/android/view/OWNERS @@ -9,6 +9,7 @@ sumir@google.com ogunwale@google.com jjaggi@google.com roosa@google.com +jreck@google.com # Display per-file Display*.java = file:/services/core/java/com/android/server/display/OWNERS diff --git a/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java index 1c222a73eabc..9a02b7b7aae9 100644 --- a/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java +++ b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java @@ -40,8 +40,7 @@ public final class CompatibilityOverrideConfig implements Parcelable { overrides = new HashMap<>(); for (int i = 0; i < keyCount; i++) { long key = in.readLong(); - PackageOverride override = in.readParcelable(PackageOverride.class.getClassLoader()); - overrides.put(key, override); + overrides.put(key, PackageOverride.createFromParcel(in)); } } @@ -55,7 +54,7 @@ public final class CompatibilityOverrideConfig implements Parcelable { dest.writeInt(overrides.size()); for (Long key : overrides.keySet()) { dest.writeLong(key); - dest.writeParcelable(overrides.get(key), 0); + overrides.get(key).writeToParcel(dest); } } diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl index 60213e4411c3..78d1d22c401e 100644 --- a/core/java/com/android/internal/compat/IPlatformCompat.aidl +++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl @@ -151,15 +151,23 @@ interface IPlatformCompat { void setOverrides(in CompatibilityChangeConfig overrides, in String packageName); /** - * Adds overrides to compatibility changes. + * Adds overrides to compatibility changes on release builds. * - * <p>Kills the app to allow the changes to take effect. + * <p>The caller to this API needs to hold + * {@code android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD} and all change ids + * in {@code overrides} need to annotated with {@link android.compat.annotation.Overridable}. + * + * A release build in this definition means that {@link android.os.Build#IS_DEBUGGABLE} needs to + * be {@code false}. + * + * <p>Note that this does not kill the app, and therefore overrides read from the app process + * will not be updated. Overrides read from the system process do take effect. * * @param overrides parcelable containing the compat change overrides to be applied * @param packageName the package name of the app whose changes will be overridden * @throws SecurityException if overriding changes is not permitted */ - void setOverridesFromInstaller(in CompatibilityOverrideConfig overrides, in String packageName); + void setOverridesOnReleaseBuilds(in CompatibilityOverrideConfig overrides, in String packageName); /** * Adds overrides to compatibility changes. diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl index 3e7e5a52605b..b90722c620a1 100644 --- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -72,6 +72,6 @@ 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); + void onAllowedNetworkTypesChanged(in int reason, in long allowedNetworkType); void onLinkCapacityEstimateChanged(in List<LinkCapacityEstimate> linkCapacityEstimateList); } diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 23dbf9a88eb7..0e35c84fa226 100644 --- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -95,8 +95,7 @@ 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); + void notifyAllowedNetworkTypesChanged(in int phoneId, in int subId, in int reason, in long allowedNetworkType); void notifyLinkCapacityEstimateChanged(in int phoneId, in int subId, in List<LinkCapacityEstimate> linkCapacityEstimateList); } diff --git a/core/jni/android_net_NetworkUtils.cpp b/core/jni/android_net_NetworkUtils.cpp index a781a377694b..1cee8955a7a2 100644 --- a/core/jni/android_net_NetworkUtils.cpp +++ b/core/jni/android_net_NetworkUtils.cpp @@ -102,11 +102,6 @@ static jint android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, job return setNetworkForSocket(netId, AFileDescriptor_getFD(env, javaFd)); } -static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jint uid, jint netId) -{ - return (jboolean) !queryUserAccess(uid, netId); -} - static bool checkLenAndCopy(JNIEnv* env, const jbyteArray& addr, int len, void* dst) { if (env->GetArrayLength(addr) != len) { @@ -246,7 +241,6 @@ static const JNINativeMethod gNetworkUtilMethods[] = { { "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess }, { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution }, { "bindSocketToNetwork", "(Ljava/io/FileDescriptor;I)I", (void*) android_net_utils_bindSocketToNetwork }, - { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess }, { "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter }, { "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter }, { "getTcpRepairWindow", "(Ljava/io/FileDescriptor;)Landroid/net/TcpRepairWindow;", (void*) android_net_utils_getTcpRepairWindow }, diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 249950419441..e4dddd277b0b 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -486,9 +486,15 @@ public: } void markVintf() { + AutoMutex _l(mLock); mVintf = true; } + void forceDowngradeToSystemStability() { + AutoMutex _l(mLock); + mVintf = false; + } + sp<IBinder> getExtension() { AutoMutex _l(mLock); sp<JavaBBinder> b = mBinder.promote(); @@ -1013,6 +1019,12 @@ static void android_os_Binder_markVintfStability(JNIEnv* env, jobject clazz) { jbh->markVintf(); } +static void android_os_Binder_forceDowngradeToSystemStability(JNIEnv* env, jobject clazz) { + JavaBBinderHolder* jbh = + (JavaBBinderHolder*) env->GetLongField(clazz, gBinderOffsets.mObject); + jbh->forceDowngradeToSystemStability(); +} + static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz) { IPCThreadState::self()->flushCommands(); @@ -1076,6 +1088,7 @@ static const JNINativeMethod gBinderMethods[] = { { "clearCallingWorkSource", "()J", (void*)android_os_Binder_clearCallingWorkSource }, { "restoreCallingWorkSource", "(J)V", (void*)android_os_Binder_restoreCallingWorkSource }, { "markVintfStability", "()V", (void*)android_os_Binder_markVintfStability}, + { "forceDowngradeToSystemStability", "()V", (void*)android_os_Binder_forceDowngradeToSystemStability}, { "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands }, { "getNativeBBinderHolder", "()J", (void*)android_os_Binder_getNativeBBinderHolder }, { "getNativeFinalizer", "()J", (void*)android_os_Binder_getNativeFinalizer }, diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 61e7d0ad9a73..f65d7a7540e4 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -5123,9 +5123,16 @@ <permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" android:protectionLevel="signature|privileged" /> <!-- Allows an app to override compat change config. + This permission only allows to override config on debuggable builds or test-apks and is + therefore a less powerful version of OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD. @hide <p>Not for use by third-party applications.</p> --> <permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG" android:protectionLevel="signature|privileged" /> + <!-- @SystemApi Allows an app to override compat change config on release builds. + Only ChangeIds that are annotated as @Overridable can be overridden on release builds. + @hide --> + <permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD" + android:protectionLevel="signature|privileged" /> <!-- Allows input events to be monitored. Very dangerous! @hide --> <permission android:name="android.permission.MONITOR_INPUT" diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 0f6f15de6458..bfe7802726a3 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3415,10 +3415,6 @@ <!-- True if assistant app should be pinned via Pinner Service --> <bool name="config_pinnerAssistantApp">false</bool> - <!-- List of files pinned by the Pinner Service with the JIT Zygote boot image b/119800099 --> - <string-array translatable="false" name="config_jitzygoteBootImagePinnerServiceFiles"> - </string-array> - <!-- Number of days preloaded file cache should be preserved on a device before it can be deleted --> <integer name="config_keepPreloadsMinDays">7</integer> @@ -4343,6 +4339,11 @@ check after reboot or airplane mode toggling --> <bool translatable="false" name="reset_geo_fencing_check_after_boot_or_apm">false</bool> + <!-- Boolean indicating whether all CB messages should be disabled on this device. This config + is intended to be used by OEMs who need to disable CB messages for regulatory requirements, + (e.g. the device is a tablet in a country where tablets should not receive CB messages) --> + <bool translatable="false" name="config_disable_all_cb_messages">false</bool> + <!-- Screen Wake Keys Determines whether the specified key groups can be used to wake up the device. --> <bool name="config_wakeOnDpadKeyPress">true</bool> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index ad24b79779d4..2901de5b57a2 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3062,7 +3062,6 @@ <java-symbol type="bool" name="config_pinnerCameraApp" /> <java-symbol type="bool" name="config_pinnerHomeApp" /> <java-symbol type="bool" name="config_pinnerAssistantApp" /> - <java-symbol type="array" name="config_jitzygoteBootImagePinnerServiceFiles" /> <java-symbol type="string" name="config_doubleTouchGestureEnableFile" /> @@ -3848,6 +3847,7 @@ <java-symbol type="layout" name="chooser_action_button" /> <java-symbol type="dimen" name="chooser_action_button_icon_size" /> <java-symbol type="string" name="config_defaultNearbySharingComponent" /> + <java-symbol type="bool" name="config_disable_all_cb_messages" /> <java-symbol type="drawable" name="ic_close" /> <java-symbol type="bool" name="config_automotiveHideNavBarForKeyboard" /> diff --git a/core/tests/coretests/src/android/content/OWNERS b/core/tests/coretests/src/android/content/OWNERS index c61a4b538a44..0b945895ad7f 100644 --- a/core/tests/coretests/src/android/content/OWNERS +++ b/core/tests/coretests/src/android/content/OWNERS @@ -2,3 +2,5 @@ per-file AssetTest.java = file:/core/java/android/content/res/OWNERS per-file ContextTest.java = file:/services/core/java/com/android/server/wm/OWNERS per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS +per-file ComponentCallbacksControllerTest = file:/services/core/java/com/android/server/wm/OWNERS +per-file ComponentCallbacksControllerTest = charlesccchen@google.com diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index fe5c1be05927..d048efcfd12c 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -1196,13 +1196,11 @@ public class Typeface { /** @hide */ public boolean isSupportedAxes(int axis) { - if (mSupportedAxes == null) { - synchronized (this) { + synchronized (this) { + if (mSupportedAxes == null) { + mSupportedAxes = nativeGetSupportedAxes(native_instance); if (mSupportedAxes == null) { - mSupportedAxes = nativeGetSupportedAxes(native_instance); - if (mSupportedAxes == null) { - mSupportedAxes = EMPTY_AXES; - } + mSupportedAxes = EMPTY_AXES; } } } diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java index 35b1c169f283..72cea0cacd12 100644 --- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java +++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java @@ -139,4 +139,18 @@ public class AndroidKeyStoreMaintenance { return SYSTEM_ERROR; } } + + /** + * Informs Keystore 2.0 that an off body event was detected. + */ + public static void onDeviceOffBody() { + if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return; + try { + getService().onDeviceOffBody(); + } catch (Exception e) { + // TODO This fails open. This is not a regression with respect to keystore1 but it + // should get fixed. + Log.e(TAG, "Error while reporting device off body event.", e); + } + } } diff --git a/keystore/java/android/security/GenerateRkpKey.java b/keystore/java/android/security/GenerateRkpKey.java new file mode 100644 index 000000000000..a1a7aa85519f --- /dev/null +++ b/keystore/java/android/security/GenerateRkpKey.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.RemoteException; + +/** + * GenerateKey is a helper class to handle interactions between Keystore and the RemoteProvisioner + * app. There are two cases where Keystore should use this class. + * + * (1) : An app generates a new attested key pair, so Keystore calls notifyKeyGenerated to let the + * RemoteProvisioner app check if the state of the attestation key pool is getting low enough + * to warrant provisioning more attestation certificates early. + * + * (2) : An app attempts to generate a new key pair, but the keystore service discovers it is out of + * attestation key pairs and cannot provide one for the given application. Keystore can then + * make a blocking call on notifyEmpty to allow the RemoteProvisioner app to get another + * attestation certificate chain provisioned. + * + * In most cases, the proper usage of (1) should preclude the need for (2). + * + * @hide + */ +public class GenerateRkpKey { + + private IGenerateRkpKeyService mBinder; + private Context mContext; + + private ServiceConnection mConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + mBinder = IGenerateRkpKeyService.Stub.asInterface(service); + } + + @Override + public void onServiceDisconnected(ComponentName className) { + mBinder = null; + } + }; + + /** + * Constructor which takes a Context object. + */ + public GenerateRkpKey(Context context) { + mContext = context; + } + + /** + * Fulfills the use case of (2) described in the class documentation. Blocks until the + * RemoteProvisioner application can get new attestation keys signed by the server. + */ + public void notifyEmpty(int securityLevel) throws RemoteException { + Intent intent = new Intent(IGenerateRkpKeyService.class.getName()); + ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); + intent.setComponent(comp); + if (comp == null || !mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) { + throw new RemoteException("Failed to bind to GenerateKeyService"); + } + if (mBinder != null) { + mBinder.generateKey(securityLevel); + } + mContext.unbindService(mConnection); + } + + /** + * FUlfills the use case of (1) described in the class documentation. Non blocking call. + */ + public void notifyKeyGenerated(int securityLevel) throws RemoteException { + Intent intent = new Intent(IGenerateRkpKeyService.class.getName()); + ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); + intent.setComponent(comp); + if (comp == null || !mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) { + throw new RemoteException("Failed to bind to GenerateKeyService"); + } + if (mBinder != null) { + mBinder.notifyKeyGenerated(securityLevel); + } + mContext.unbindService(mConnection); + } +} diff --git a/keystore/java/android/security/GenerateRkpKeyException.java b/keystore/java/android/security/GenerateRkpKeyException.java new file mode 100644 index 000000000000..a2d65e4e7119 --- /dev/null +++ b/keystore/java/android/security/GenerateRkpKeyException.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security; + +/** + * Thrown on problems in attempting to attest to a key using a remotely provisioned key. + * + * @hide + */ +public class GenerateRkpKeyException extends Exception { + + /** + * Constructs a new {@code GenerateRkpKeyException}. + */ + public GenerateRkpKeyException() { + } +} diff --git a/keystore/java/android/security/IGenerateRkpKeyService.aidl b/keystore/java/android/security/IGenerateRkpKeyService.aidl new file mode 100644 index 000000000000..5f1d6693c23a --- /dev/null +++ b/keystore/java/android/security/IGenerateRkpKeyService.aidl @@ -0,0 +1,36 @@ +/** + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security; + +/** + * Interface to allow the framework to notify the RemoteProvisioner app when keys are empty. This + * will be used if Keystore replies with an error code NO_KEYS_AVAILABLE in response to an + * attestation request. The framework can then synchronously call generateKey() to get more + * attestation keys generated and signed. Upon return, the caller can be certain an attestation key + * is available. + * + * @hide + */ +interface IGenerateRkpKeyService { + /** + * Ping the provisioner service to let it know an app generated a key. This may or may not have + * consumed a remotely provisioned attestation key, so the RemoteProvisioner app should check. + */ + oneway void notifyKeyGenerated(in int securityLevel); + /** Ping the provisioner service to indicate there are no remaining attestation keys left. */ + void generateKey(in int securityLevel); +} diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index a08f390c9fd3..b05149ef75bc 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -1204,6 +1204,7 @@ public class KeyStore { * Notify keystore that the device went off-body. */ public void onDeviceOffBody() { + AndroidKeyStoreMaintenance.onDeviceOffBody(); try { mBinder.onDeviceOffBody(); } catch (RemoteException e) { diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java index d0cad233c93e..df579bba9dc2 100644 --- a/keystore/java/android/security/KeyStore2.java +++ b/keystore/java/android/security/KeyStore2.java @@ -18,8 +18,7 @@ package android.security; import android.annotation.NonNull; import android.compat.annotation.ChangeId; -import android.compat.annotation.EnabledAfter; -import android.os.Build; +import android.compat.annotation.Disabled; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; @@ -86,7 +85,7 @@ public class KeyStore2 { * successfully conclude an operation. */ @ChangeId - @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R) + @Disabled // See b/180133780 static final long KEYSTORE_OPERATION_CREATION_MAY_FAIL = 169897160L; // Never use mBinder directly, use KeyStore2.getService() instead or better yet diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java index 11c36893d984..1eb854187b32 100644 --- a/keystore/java/android/security/keystore/AttestationUtils.java +++ b/keystore/java/android/security/keystore/AttestationUtils.java @@ -287,6 +287,8 @@ public abstract class AttestationUtils { keyStore.deleteEntry(keystoreAlias); return certificateChain; + } catch (SecurityException e) { + throw e; } catch (Exception e) { throw new DeviceIdAttestationException("Unable to perform attestation", e); } diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 5cb2c3b41517..9ca551b26aab 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -288,7 +288,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048 private final String mKeystoreAlias; - private final int mNamespace; + private final @KeyProperties.Namespace int mNamespace; private final int mKeySize; private final AlgorithmParameterSpec mSpec; private final X500Principal mCertificateSubject; @@ -331,7 +331,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu */ public KeyGenParameterSpec( String keyStoreAlias, - int namespace, + @KeyProperties.Namespace int namespace, int keySize, AlgorithmParameterSpec spec, X500Principal certificateSubject, @@ -472,7 +472,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu * @hide */ @SystemApi - public int getNamespace() { + public @KeyProperties.Namespace int getNamespace() { return mNamespace; } @@ -896,7 +896,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu private final String mKeystoreAlias; private @KeyProperties.PurposeEnum int mPurposes; - private int mNamespace = KeyProperties.NAMESPACE_APPLICATION; + private @KeyProperties.Namespace int mNamespace = KeyProperties.NAMESPACE_APPLICATION; private int mKeySize = -1; private AlgorithmParameterSpec mSpec; private X500Principal mCertificateSubject; @@ -1051,7 +1051,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu */ @SystemApi @NonNull - public Builder setNamespace(int namespace) { + public Builder setNamespace(@KeyProperties.Namespace int namespace) { mNamespace = namespace; return this; } diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java index 7b0fa91380e1..682d12a65ea3 100644 --- a/keystore/java/android/security/keystore/KeyProperties.java +++ b/keystore/java/android/security/keystore/KeyProperties.java @@ -892,6 +892,22 @@ public abstract class KeyProperties { } /** + * Namespaces provide system developers and vendors with a way to use keystore without + * requiring an applications uid. Namespaces can be configured using SEPolicy. + * See <a href="https://source.android.com/security/keystore#access-control"> + * Keystore 2.0 access-control</a> + * {@See KeyGenParameterSpec.Builder#setNamespace} + * {@See android.security.keystore2.AndroidKeyStoreLoadStoreParameter} + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "NAMESPACE_" }, value = { + NAMESPACE_APPLICATION, + NAMESPACE_WIFI, + }) + public @interface Namespace {} + + /** * This value indicates the implicit keystore namespace of the calling application. * It is used by default. Only select system components can choose a different namespace * which it must be configured in SEPolicy. @@ -912,14 +928,12 @@ public abstract class KeyProperties { * For legacy support, translate namespaces into known UIDs. * @hide */ - public static int namespaceToLegacyUid(int namespace) { + public static int namespaceToLegacyUid(@Namespace int namespace) { switch (namespace) { case NAMESPACE_APPLICATION: return KeyStore.UID_SELF; case NAMESPACE_WIFI: return Process.WIFI_UID; - // TODO Translate WIFI and VPN UIDs once the namespaces are defined. - // b/171305388 and b/171305607 default: throw new IllegalArgumentException("No UID corresponding to namespace " + namespace); @@ -930,14 +944,12 @@ public abstract class KeyProperties { * For legacy support, translate namespaces into known UIDs. * @hide */ - public static int legacyUidToNamespace(int uid) { + public static @Namespace int legacyUidToNamespace(int uid) { switch (uid) { case KeyStore.UID_SELF: return NAMESPACE_APPLICATION; case Process.WIFI_UID: return NAMESPACE_WIFI; - // TODO Translate WIFI and VPN UIDs once the namespaces are defined. - // b/171305388 and b/171305607 default: throw new IllegalArgumentException("No namespace corresponding to uid " + uid); diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java index e401add9ece7..2d8901a37c05 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java @@ -24,6 +24,9 @@ import android.hardware.security.keymint.KeyPurpose; import android.hardware.security.keymint.SecurityLevel; import android.hardware.security.keymint.Tag; import android.os.Build; +import android.os.RemoteException; +import android.security.GenerateRkpKey; +import android.security.GenerateRkpKeyException; import android.security.KeyPairGeneratorSpec; import android.security.KeyStore; import android.security.KeyStore2; @@ -520,6 +523,18 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato @Override public KeyPair generateKeyPair() { + try { + return generateKeyPairHelper(); + } catch (GenerateRkpKeyException e) { + try { + return generateKeyPairHelper(); + } catch (GenerateRkpKeyException f) { + throw new ProviderException("Failed to provision new attestation keys."); + } + } + } + + private KeyPair generateKeyPairHelper() throws GenerateRkpKeyException { if (mKeyStore == null || mSpec == null) { throw new IllegalStateException("Not initialized"); } @@ -557,13 +572,30 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato AndroidKeyStorePublicKey publicKey = AndroidKeyStoreProvider.makeAndroidKeyStorePublicKeyFromKeyEntryResponse( descriptor, metadata, iSecurityLevel, mKeymasterAlgorithm); - + GenerateRkpKey keyGen = new GenerateRkpKey(KeyStore.getApplicationContext()); + try { + if (mSpec.getAttestationChallenge() != null) { + keyGen.notifyKeyGenerated(securityLevel); + } + } catch (RemoteException e) { + // This is not really an error state, and necessarily does not apply to non RKP + // systems or hybrid systems where RKP is not currently turned on. + Log.d(TAG, "Couldn't connect to the RemoteProvisioner backend."); + } success = true; return new KeyPair(publicKey, publicKey.getPrivateKey()); } catch (android.security.KeyStoreException e) { switch(e.getErrorCode()) { case KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE: throw new StrongBoxUnavailableException("Failed to generated key pair.", e); + case ResponseCode.OUT_OF_KEYS: + GenerateRkpKey keyGen = new GenerateRkpKey(KeyStore.getApplicationContext()); + try { + keyGen.notifyEmpty(securityLevel); + } catch (RemoteException f) { + throw new ProviderException("Failed to talk to RemoteProvisioner", f); + } + throw new GenerateRkpKeyException(); default: ProviderException p = new ProviderException("Failed to generate key pair.", e); if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) { diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreLoadStoreParameter.java b/keystore/java/android/security/keystore2/AndroidKeyStoreLoadStoreParameter.java index 0c6744f9822c..25b1c864b5d1 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreLoadStoreParameter.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreLoadStoreParameter.java @@ -16,6 +16,8 @@ package android.security.keystore2; +import android.security.keystore.KeyProperties; + import java.security.KeyStore; import java.security.KeyStore.ProtectionParameter; @@ -24,9 +26,9 @@ import java.security.KeyStore.ProtectionParameter; */ public class AndroidKeyStoreLoadStoreParameter implements KeyStore.LoadStoreParameter { - private final int mNamespace; + private final @KeyProperties.Namespace int mNamespace; - public AndroidKeyStoreLoadStoreParameter(int namespace) { + public AndroidKeyStoreLoadStoreParameter(@KeyProperties.Namespace int namespace) { mNamespace = namespace; } @@ -35,7 +37,7 @@ public class AndroidKeyStoreLoadStoreParameter implements KeyStore.LoadStorePara return null; } - int getNamespace() { + @KeyProperties.Namespace int getNamespace() { return mNamespace; } } diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java index 39607aeb3852..32f98a2538f3 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java @@ -100,7 +100,7 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { public static final String NAME = "AndroidKeyStore"; private KeyStore2 mKeyStore; - private int mNamespace = KeyProperties.NAMESPACE_APPLICATION; + private @KeyProperties.Namespace int mNamespace = KeyProperties.NAMESPACE_APPLICATION; @Override public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, @@ -1125,7 +1125,7 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { @Override public void engineLoad(LoadStoreParameter param) throws IOException, NoSuchAlgorithmException, CertificateException { - int namespace = KeyProperties.NAMESPACE_APPLICATION; + @KeyProperties.Namespace int namespace = KeyProperties.NAMESPACE_APPLICATION; if (param != null) { if (param instanceof AndroidKeyStoreLoadStoreParameter) { namespace = ((AndroidKeyStoreLoadStoreParameter) param).getNamespace(); diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 0780c6875eb5..7062f83fe575 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -45,6 +45,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -4554,6 +4555,128 @@ final public class MediaCodec { private native void native_enableOnFrameRenderedListener(boolean enable); + /** + * Returns a list of vendor parameter names. + * <p> + * This method can be called in any codec state except for released state. + * + * @return a list containing supported vendor parameters; an empty + * list if no vendor parameters are supported. The order of the + * parameters is arbitrary. + * @throws IllegalStateException if in the Released state. + */ + @NonNull + public List<String> getSupportedVendorParameters() { + return native_getSupportedVendorParameters(); + } + + @NonNull + private native List<String> native_getSupportedVendorParameters(); + + /** + * Contains description of a parameter. + */ + public static class ParameterDescriptor { + private ParameterDescriptor() {} + + /** + * Returns the name of the parameter. + */ + @NonNull + public String getName() { + return mName; + } + + /** + * Returns the type of the parameter. + * {@link MediaFormat#TYPE_NULL} is never returned. + */ + @MediaFormat.Type + public int getType() { + return mType; + } + + private String mName; + private @MediaFormat.Type int mType; + } + + /** + * Describe a parameter with the name. + * <p> + * This method can be called in any codec state except for released state. + * + * @param name name of the parameter to describe, typically one from + * {@link #getSupportedVendorParameters}. + * @return {@link ParameterDescriptor} object that describes the parameter. + * {@code null} if unrecognized / not able to describe. + * @throws IllegalStateException if in the Released state. + */ + @Nullable + public ParameterDescriptor getParameterDescriptor(@NonNull String name) { + return native_getParameterDescriptor(name); + } + + @Nullable + private native ParameterDescriptor native_getParameterDescriptor(@NonNull String name); + + /** + * Subscribe to vendor parameters, so that changes to these parameters generate + * output format change event. + * <p> + * Unrecognized parameter names or standard (non-vendor) parameter names will be ignored. + * {@link #reset} also resets the list of subscribed parameters. + * If a parameter in {@code names} is already subscribed, it will remain subscribed. + * <p> + * This method can be called in any codec state except for released state. When called in + * running state with newly subscribed parameters, it takes effect no later than the + * processing of the subsequently queued buffer. For the new parameters, the codec will generate + * output format change event. + * <p> + * Note that any vendor parameters set in a {@link #configure} or + * {@link #setParameters} call are automatically subscribed. + * <p> + * See also {@link #INFO_OUTPUT_FORMAT_CHANGED} or {@link Callback#onOutputFormatChanged} + * for output format change events. + * + * @param names names of the vendor parameters to subscribe. This may be an empty list, + * and in that case this method will not change the list of subscribed parameters. + * @throws IllegalStateException if in the Released state. + */ + public void subscribeToVendorParameters(@NonNull List<String> names) { + native_subscribeToVendorParameters(names); + } + + private native void native_subscribeToVendorParameters(@NonNull List<String> names); + + /** + * Unsubscribe from vendor parameters, so that changes to these parameters + * no longer generate output format change event. + * <p> + * Unrecognized parameter names, standard (non-vendor) parameter names will be ignored. + * {@link #reset} also resets the list of subscribed parameters. + * If a parameter in {@code names} is already unsubscribed, it will remain unsubscribed. + * <p> + * This method can be called in any codec state except for released state. When called in + * running state with newly unsubscribed parameters, it takes effect no later than the + * processing of the subsequently queued buffer. + * <p> + * Note that any vendor parameters set in a {@link #configure} or + * {@link #setParameters} call are automatically subscribed, and with this method + * they can be unsubscribed. + * <p> + * See also {@link #INFO_OUTPUT_FORMAT_CHANGED} or {@link Callback#onOutputFormatChanged} + * for output format change events. + * + * @param names names of the vendor parameters to unsubscribe. This may be an empty list, + * and in that case this method will not change the list of subscribed parameters. + * @throws IllegalStateException if in the Released state. + */ + public void unsubscribeFromVendorParameters(@NonNull List<String> names) { + native_unsubscribeFromVendorParameters(names); + } + + private native void native_unsubscribeFromVendorParameters(@NonNull List<String> names); + private EventHandler getEventHandlerOn( @Nullable Handler handler, @NonNull EventHandler lastHandler) { if (handler == null) { diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 0b0e162d4faf..b3eb8ba77639 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -53,6 +53,7 @@ #include <media/MediaCodecBuffer.h> #include <media/hardware/VideoAPI.h> +#include <media/stagefright/CodecBase.h> #include <media/stagefright/MediaCodec.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> @@ -82,6 +83,16 @@ enum { EVENT_FRAME_RENDERED = 3, }; +// From MediaFormat.java +enum { + TYPE_NULL = 0, + TYPE_INTEGER = 1, + TYPE_LONG = 2, + TYPE_FLOAT = 3, + TYPE_STRING = 4, + TYPE_BYTE_BUFFER = 5, +}; + static struct CryptoErrorCodes { jint cryptoErrorNoKey; jint cryptoErrorKeyExpired; @@ -138,6 +149,8 @@ static struct { } gByteBufferInfo; static struct { + jclass clazz; + jmethodID ctorId; jmethodID sizeId; jmethodID getId; jmethodID addId; @@ -152,6 +165,13 @@ static struct { jfieldID lockId; } gLinearBlockInfo; +static struct { + jclass clazz; + jmethodID ctorId; + jfieldID nameId; + jfieldID typeId; +} gDescriptorInfo; + struct fields_t { jmethodID postEventFromNativeID; jmethodID lockAndGetContextID; @@ -922,6 +942,74 @@ void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const in (void)mCodec->setParameters(msg); } +status_t JMediaCodec::querySupportedVendorParameters(JNIEnv *env, jobject *namesObj) { + std::vector<std::string> names; + status_t status = mCodec->querySupportedVendorParameters(&names); + if (status != OK) { + return status; + } + *namesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId); + for (const std::string &name : names) { + ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(name.c_str())}; + (void)env->CallBooleanMethod(*namesObj, gArrayListInfo.addId, nameStr.get()); + } + return OK; +} + +status_t JMediaCodec::describeParameter(JNIEnv *env, jstring name, jobject *descObj) { + const char *tmp = env->GetStringUTFChars(name, nullptr); + CodecParameterDescriptor desc; + status_t status = mCodec->describeParameter(tmp, &desc); + env->ReleaseStringUTFChars(name, tmp); + if (status != OK) { + return status; + } + jint type = TYPE_NULL; + switch (desc.type) { + case AMessage::kTypeInt32: type = TYPE_INTEGER; break; + case AMessage::kTypeSize: + case AMessage::kTypeInt64: type = TYPE_LONG; break; + case AMessage::kTypeFloat: type = TYPE_FLOAT; break; + case AMessage::kTypeString: type = TYPE_STRING; break; + case AMessage::kTypeBuffer: type = TYPE_BYTE_BUFFER; break; + default: type = TYPE_NULL; break; + } + if (type == TYPE_NULL) { + return BAD_VALUE; + } + *descObj = env->NewObject(gDescriptorInfo.clazz, gDescriptorInfo.ctorId); + env->SetObjectField(*descObj, gDescriptorInfo.nameId, name); + env->SetIntField(*descObj, gDescriptorInfo.typeId, type); + return OK; +} + +static void BuildVectorFromList(JNIEnv *env, jobject list, std::vector<std::string> *vec) { + ScopedLocalRef<jclass> listClazz{env, env->FindClass("java/util/List")}; + ScopedLocalRef<jclass> iterClazz{env, env->FindClass("java/util/Iterator")}; + jmethodID hasNextID = env->GetMethodID(iterClazz.get(), "hasNext", "()Z"); + jmethodID nextID = env->GetMethodID(iterClazz.get(), "next", "()Ljava/lang/Object;"); + jobject it = env->CallObjectMethod( + list, env->GetMethodID(listClazz.get(), "iterator", "()Ljava/util/Iterator;")); + while (env->CallBooleanMethod(it, hasNextID)) { + jstring name = (jstring)env->CallObjectMethod(it, nextID); + const char *tmp = env->GetStringUTFChars(name, nullptr); + vec->push_back(tmp); + env->ReleaseStringUTFChars(name, tmp); + } +} + +status_t JMediaCodec::subscribeToVendorParameters(JNIEnv *env, jobject namesObj) { + std::vector<std::string> names; + BuildVectorFromList(env, namesObj, &names); + return mCodec->subscribeToVendorParameters(names); +} + +status_t JMediaCodec::unsubscribeFromVendorParameters(JNIEnv *env, jobject namesObj) { + std::vector<std::string> names; + BuildVectorFromList(env, namesObj, &names); + return mCodec->unsubscribeFromVendorParameters(names); +} + static jthrowable createCodecException( JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) { ScopedLocalRef<jclass> clazz( @@ -2602,6 +2690,73 @@ static void android_media_MediaCodec_setAudioPresentation( codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId); } +static jobject android_media_MediaCodec_getSupportedVendorParameters( + JNIEnv *env, jobject thiz) { + sp<JMediaCodec> codec = getMediaCodec(env, thiz); + + if (codec == NULL || codec->initCheck() != OK) { + throwExceptionAsNecessary(env, INVALID_OPERATION); + return NULL; + } + + jobject ret = NULL; + status_t status = codec->querySupportedVendorParameters(env, &ret); + if (status != OK) { + throwExceptionAsNecessary(env, status); + } + + return ret; +} + +static jobject android_media_MediaCodec_getParameterDescriptor( + JNIEnv *env, jobject thiz, jstring name) { + sp<JMediaCodec> codec = getMediaCodec(env, thiz); + + if (codec == NULL || codec->initCheck() != OK) { + throwExceptionAsNecessary(env, INVALID_OPERATION); + return NULL; + } + + jobject ret = NULL; + status_t status = codec->describeParameter(env, name, &ret); + if (status != OK) { + ret = NULL; + } + return ret; +} + +static void android_media_MediaCodec_subscribeToVendorParameters( + JNIEnv *env, jobject thiz, jobject names) { + sp<JMediaCodec> codec = getMediaCodec(env, thiz); + + if (codec == NULL || codec->initCheck() != OK) { + throwExceptionAsNecessary(env, INVALID_OPERATION); + return; + } + + status_t status = codec->subscribeToVendorParameters(env, names); + if (status != OK) { + throwExceptionAsNecessary(env, status); + } + return; +} + +static void android_media_MediaCodec_unsubscribeFromVendorParameters( + JNIEnv *env, jobject thiz, jobject names) { + sp<JMediaCodec> codec = getMediaCodec(env, thiz); + + if (codec == NULL || codec->initCheck() != OK) { + throwExceptionAsNecessary(env, INVALID_OPERATION); + return; + } + + status_t status = codec->unsubscribeFromVendorParameters(env, names); + if (status != OK) { + throwExceptionAsNecessary(env, status); + } + return; +} + static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) { ScopedLocalRef<jclass> clazz( env, env->FindClass("android/media/MediaCodec")); @@ -2861,6 +3016,10 @@ static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) { clazz.reset(env->FindClass("java/util/ArrayList")); CHECK(clazz.get() != NULL); + gArrayListInfo.clazz = (jclass)env->NewGlobalRef(clazz.get()); + + gArrayListInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V"); + CHECK(gArrayListInfo.ctorId != NULL); gArrayListInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I"); CHECK(gArrayListInfo.sizeId != NULL); @@ -2891,6 +3050,19 @@ static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) { gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;"); CHECK(gLinearBlockInfo.lockId != NULL); + + clazz.reset(env->FindClass("android/media/MediaCodec$ParameterDescriptor")); + CHECK(clazz.get() != NULL); + gDescriptorInfo.clazz = (jclass)env->NewGlobalRef(clazz.get()); + + gDescriptorInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V"); + CHECK(gDescriptorInfo.ctorId != NULL); + + gDescriptorInfo.nameId = env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;"); + CHECK(gDescriptorInfo.nameId != NULL); + + gDescriptorInfo.typeId = env->GetFieldID(clazz.get(), "mType", "I"); + CHECK(gDescriptorInfo.typeId != NULL); } static void android_media_MediaCodec_native_setup( @@ -3217,6 +3389,21 @@ static const JNINativeMethod gMethods[] = { { "native_setAudioPresentation", "(II)V", (void *)android_media_MediaCodec_setAudioPresentation }, + { "native_getSupportedVendorParameters", "()Ljava/util/List;", + (void *)android_media_MediaCodec_getSupportedVendorParameters }, + + { "native_getParameterDescriptor", + "(Ljava/lang/String;)Landroid/media/MediaCodec$ParameterDescriptor;", + (void *)android_media_MediaCodec_getParameterDescriptor }, + + { "native_subscribeToVendorParameters", + "(Ljava/util/List;)V", + (void *)android_media_MediaCodec_subscribeToVendorParameters}, + + { "native_unsubscribeFromVendorParameters", + "(Ljava/util/List;)V", + (void *)android_media_MediaCodec_unsubscribeFromVendorParameters}, + { "native_init", "()V", (void *)android_media_MediaCodec_native_init }, { "native_setup", "(Ljava/lang/String;ZZ)V", diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h index a58f9a74b563..33f481d746c1 100644 --- a/media/jni/android_media_MediaCodec.h +++ b/media/jni/android_media_MediaCodec.h @@ -162,6 +162,14 @@ struct JMediaCodec : public AHandler { void selectAudioPresentation(const int32_t presentationId, const int32_t programId); + status_t querySupportedVendorParameters(JNIEnv *env, jobject *names); + + status_t describeParameter(JNIEnv *env, jstring name, jobject *desc); + + status_t subscribeToVendorParameters(JNIEnv *env, jobject names); + + status_t unsubscribeFromVendorParameters(JNIEnv *env, jobject names); + bool hasCryptoOrDescrambler() { return mHasCryptoOrDescrambler; } protected: diff --git a/packages/Connectivity/TEST_MAPPING b/packages/Connectivity/TEST_MAPPING new file mode 100644 index 000000000000..94f9232bc482 --- /dev/null +++ b/packages/Connectivity/TEST_MAPPING @@ -0,0 +1,19 @@ +{ + "imports": [ + { + "path": "frameworks/base/core/java/android/net" + }, + { + "path": "packages/modules/NetworkStack" + }, + { + "path": "packages/modules/CaptivePortalLogin" + }, + { + "path": "packages/modules/Connectivity" + }, + { + "path": "packages/modules/Connectivity/Tethering" + } + ] +}
\ No newline at end of file diff --git a/packages/Connectivity/framework/Android.bp b/packages/Connectivity/framework/Android.bp index 86433e1c38f8..017ff51f366d 100644 --- a/packages/Connectivity/framework/Android.bp +++ b/packages/Connectivity/framework/Android.bp @@ -23,6 +23,25 @@ package { default_applicable_licenses: ["frameworks_base_license"], } +java_library { + name: "framework-connectivity-protos", + proto: { + type: "nano", + }, + srcs: [ + // TODO: consider moving relevant .proto files directly to the module directory + ":framework-javastream-protos", + ], + apex_available: [ + "//apex_available:platform", + "com.android.tethering", + ], + jarjar_rules: "jarjar-rules-proto.txt", + visibility: [ + "//visibility:private", + ], +} + filegroup { name: "framework-connectivity-internal-sources", srcs: [ @@ -111,6 +130,7 @@ java_library { "ServiceConnectivityResources", ], static_libs: [ + "framework-connectivity-protos", "net-utils-device-common", ], jarjar_rules: "jarjar-rules.txt", diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt index e415e01fea3a..ad44b27f6d0b 100644 --- a/packages/Connectivity/framework/api/current.txt +++ b/packages/Connectivity/framework/api/current.txt @@ -396,6 +396,7 @@ package android.net { public static class NetworkRequest.Builder { ctor public NetworkRequest.Builder(); + ctor public NetworkRequest.Builder(@NonNull android.net.NetworkRequest); method public android.net.NetworkRequest.Builder addCapability(int); method public android.net.NetworkRequest.Builder addTransportType(int); method public android.net.NetworkRequest build(); diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt index 8629c1971b7b..35e45ecb1853 100644 --- a/packages/Connectivity/framework/api/module-lib-current.txt +++ b/packages/Connectivity/framework/api/module-lib-current.txt @@ -11,16 +11,31 @@ package android.net { method @Nullable public android.net.ProxyInfo getGlobalProxy(); method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange(); method @NonNull public static String getPrivateDnsMode(@NonNull android.content.Context); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackAsUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler); 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, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback); + method @Deprecated public boolean requestRouteToHostAddress(int, java.net.InetAddress); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptPartialConnectivity(@NonNull android.net.Network, boolean, boolean); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptUnvalidated(@NonNull android.net.Network, boolean, boolean); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network); method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setLegacyLockdownVpnEnabled(boolean); + method public static void setPrivateDnsMode(@NonNull android.content.Context, @NonNull String); method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable); + method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setRequireVpnForUids(boolean, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>); 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); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void startCaptivePortalApp(@NonNull android.net.Network); method public void systemReady(); + field public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 262144; // 0x40000 + field public static final int BLOCKED_METERED_REASON_DATA_SAVER = 65536; // 0x10000 + field public static final int BLOCKED_METERED_REASON_MASK = -65536; // 0xffff0000 + field public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 131072; // 0x20000 + field public static final int BLOCKED_REASON_APP_STANDBY = 4; // 0x4 + field public static final int BLOCKED_REASON_BATTERY_SAVER = 1; // 0x1 + field public static final int BLOCKED_REASON_DOZE = 2; // 0x2 + field public static final int BLOCKED_REASON_LOCKDOWN_VPN = 16; // 0x10 + field public static final int BLOCKED_REASON_NONE = 0; // 0x0 + field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8 field public static final String PRIVATE_DNS_MODE_OFF = "off"; field public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic"; field public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname"; @@ -28,18 +43,92 @@ package android.net { field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1 } + public static class ConnectivityManager.NetworkCallback { + method public void onBlockedStatusChanged(@NonNull android.net.Network, int); + } + + public class ConnectivitySettingsManager { + method public static void clearGlobalProxy(@NonNull android.content.Context); + method @Nullable public static String getCaptivePortalHttpUrl(@NonNull android.content.Context); + method public static int getCaptivePortalMode(@NonNull android.content.Context, int); + method @NonNull public static java.time.Duration getConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration); + method @NonNull public static android.util.Range<java.lang.Integer> getDnsResolverSampleRanges(@NonNull android.content.Context); + method @NonNull public static java.time.Duration getDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration); + method public static int getDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, int); + method @Nullable public static android.net.ProxyInfo getGlobalProxy(@NonNull android.content.Context); + method @NonNull public static java.time.Duration getMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration); + method public static boolean getMobileDataAlwaysOn(@NonNull android.content.Context, boolean); + method @Nullable public static String getMobileDataPreferredApps(@NonNull android.content.Context); + method public static int getNetworkAvoidBadWifi(@NonNull android.content.Context); + method @Nullable public static String getNetworkMeteredMultipathPreference(@NonNull android.content.Context); + method public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, int); + method @NonNull public static java.time.Duration getNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration); + method @NonNull public static String getPrivateDnsDefaultMode(@NonNull android.content.Context); + method @Nullable public static String getPrivateDnsHostname(@NonNull android.content.Context); + method public static boolean getWifiAlwaysRequested(@NonNull android.content.Context, boolean); + method @NonNull public static java.time.Duration getWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration); + method public static void setCaptivePortalHttpUrl(@NonNull android.content.Context, @Nullable String); + method public static void setCaptivePortalMode(@NonNull android.content.Context, int); + method public static void setConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration); + method public static void setDnsResolverSampleRanges(@NonNull android.content.Context, @NonNull android.util.Range<java.lang.Integer>); + method public static void setDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration); + method public static void setDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, @IntRange(from=0, to=100) int); + method public static void setGlobalProxy(@NonNull android.content.Context, @NonNull android.net.ProxyInfo); + method public static void setMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration); + method public static void setMobileDataAlwaysOn(@NonNull android.content.Context, boolean); + method public static void setMobileDataPreferredApps(@NonNull android.content.Context, @Nullable String); + method public static void setNetworkAvoidBadWifi(@NonNull android.content.Context, int); + method public static void setNetworkMeteredMultipathPreference(@NonNull android.content.Context, @NonNull String); + method public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, @IntRange(from=0) int); + method public static void setNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration); + method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull String); + method public static void setPrivateDnsHostname(@NonNull android.content.Context, @Nullable String); + method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean); + method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration); + field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2 + field public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; // 0x0 + field public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; // 0x1 + field public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2; // 0x2 + field public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0; // 0x0 + field public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1; // 0x1 + } + public final class NetworkAgentConfig implements android.os.Parcelable { method @Nullable public String getSubscriberId(); + method public boolean isBypassableVpn(); } public static final class NetworkAgentConfig.Builder { + method @NonNull public android.net.NetworkAgentConfig.Builder setBypassableVpn(boolean); method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String); } public final class NetworkCapabilities implements android.os.Parcelable { + ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, long); + method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids(); + method public boolean hasUnwantedCapability(int); + field public static final long REDACT_ALL = -1L; // 0xffffffffffffffffL + field public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1L; // 0x1L + field public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 2L; // 0x2L + field public static final long REDACT_FOR_NETWORK_SETTINGS = 4L; // 0x4L + field public static final long REDACT_NONE = 0L; // 0x0L field public static final int TRANSPORT_TEST = 7; // 0x7 } + public static final class NetworkCapabilities.Builder { + method @NonNull public android.net.NetworkCapabilities.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>); + } + + public class NetworkRequest implements android.os.Parcelable { + method public boolean hasUnwantedCapability(int); + } + + public static class NetworkRequest.Builder { + method @NonNull public android.net.NetworkRequest.Builder addUnwantedCapability(int); + method @NonNull public android.net.NetworkRequest.Builder removeUnwantedCapability(int); + method @NonNull public android.net.NetworkRequest.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>); + } + public class ParseException extends java.lang.RuntimeException { ctor public ParseException(@NonNull String); ctor public ParseException(@NonNull String, @NonNull Throwable); @@ -80,6 +169,11 @@ package android.net { field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkSpecifier> CREATOR; } + public interface TransportInfo { + method public default long getApplicableRedactions(); + method @NonNull public default android.net.TransportInfo makeCopy(long); + } + public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo { ctor public VpnTransportInfo(int); method public int describeContents(); diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt index 884522582352..1ee79a425e80 100644 --- a/packages/Connectivity/framework/api/system-current.txt +++ b/packages/Connectivity/framework/api/system-current.txt @@ -52,7 +52,7 @@ package android.net { method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported(); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider); - method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull android.net.QosCallback, @NonNull java.util.concurrent.Executor); + method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull java.util.concurrent.Executor, @NonNull android.net.QosCallback); method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback); method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback); method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean); @@ -212,10 +212,14 @@ package android.net { public abstract class NetworkAgent { ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider); + ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkScore, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider); method @Nullable public android.net.Network getNetwork(); method public void markConnected(); method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData); method public void onAutomaticReconnectDisabled(); + method public void onBandwidthUpdateRequested(); + method public void onNetworkCreated(); + method public void onNetworkDisconnected(); method public void onNetworkUnwanted(); method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter); method public void onQosCallbackUnregistered(int); @@ -230,9 +234,10 @@ package android.net { method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities); method public final void sendNetworkScore(@IntRange(from=0, to=99) int); method public final void sendQosCallbackError(int, int); - method public final void sendQosSessionAvailable(int, int, @NonNull android.telephony.data.EpsBearerQosSessionAttributes); - method public final void sendQosSessionLost(int, int); + method public final void sendQosSessionAvailable(int, int, @NonNull android.net.QosSessionAttributes); + method public final void sendQosSessionLost(int, int, int); method public final void sendSocketKeepaliveEvent(int, int); + method @Deprecated public void setLegacySubtype(int, @NonNull String); method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>); method public void unregister(); field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2 @@ -253,7 +258,12 @@ package android.net { public static final class NetworkAgentConfig.Builder { ctor public NetworkAgentConfig.Builder(); method @NonNull public android.net.NetworkAgentConfig build(); + method @NonNull public android.net.NetworkAgentConfig.Builder disableNat64Detection(); + method @NonNull public android.net.NetworkAgentConfig.Builder disableProvisioningNotification(); method @NonNull public android.net.NetworkAgentConfig.Builder setExplicitlySelected(boolean); + method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyExtraInfo(@NonNull String); + method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubType(int); + method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubTypeName(@NonNull String); method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyType(int); method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyTypeName(@NonNull String); method @NonNull public android.net.NetworkAgentConfig.Builder setPartialConnectivityAcceptable(boolean); @@ -261,7 +271,6 @@ package android.net { } public final class NetworkCapabilities implements android.os.Parcelable { - ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, boolean); method @NonNull public int[] getAdministratorUids(); method @Nullable public String getSsid(); method @NonNull public int[] getTransportTypes(); @@ -317,6 +326,19 @@ package android.net { method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int); } + public final class NetworkScore implements android.os.Parcelable { + method public int describeContents(); + method public int getLegacyInt(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkScore> CREATOR; + } + + public static final class NetworkScore.Builder { + ctor public NetworkScore.Builder(); + method @NonNull public android.net.NetworkScore build(); + method @NonNull public android.net.NetworkScore.Builder setLegacyInt(int); + } + public final class OemNetworkPreferences implements android.os.Parcelable { method public int describeContents(); method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getNetworkPreferences(); @@ -364,6 +386,7 @@ package android.net { method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR; field public static final int TYPE_EPS_BEARER = 1; // 0x1 + field public static final int TYPE_NR_BEARER = 2; // 0x2 } public interface QosSessionAttributes { @@ -389,6 +412,7 @@ package android.net { } public abstract class SocketKeepalive implements java.lang.AutoCloseable { + field public static final int ERROR_NO_SUCH_SLOT = -33; // 0xffffffdf field public static final int SUCCESS = 0; // 0x0 } @@ -435,11 +459,6 @@ package android.net { field public final int tcpWindowScale; } - public interface TransportInfo { - method public default boolean hasLocationSensitiveFields(); - method @NonNull public default android.net.TransportInfo makeCopy(boolean); - } - } package android.net.apf { diff --git a/packages/Connectivity/framework/jarjar-rules-proto.txt b/packages/Connectivity/framework/jarjar-rules-proto.txt new file mode 100644 index 000000000000..37b4dec1c331 --- /dev/null +++ b/packages/Connectivity/framework/jarjar-rules-proto.txt @@ -0,0 +1,3 @@ +keep android.net.NetworkCapabilitiesProto +keep android.net.NetworkProto +keep android.net.NetworkRequestProto diff --git a/packages/Connectivity/framework/jarjar-rules.txt b/packages/Connectivity/framework/jarjar-rules.txt index 381a4ac87505..0959840f2dd2 100644 --- a/packages/Connectivity/framework/jarjar-rules.txt +++ b/packages/Connectivity/framework/jarjar-rules.txt @@ -5,3 +5,6 @@ zap android.annotation.** zap com.android.net.module.annotation.** zap com.android.internal.annotations.** +rule android.net.NetworkCapabilitiesProto* android.net.connectivity.proto.NetworkCapabilitiesProto@1 +rule android.net.NetworkProto* android.net.connectivity.proto.NetworkProto@1 +rule android.net.NetworkRequestProto* android.net.connectivity.proto.NetworkRequestProto@1 diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java index 523449497345..3598ebc70118 100644 --- a/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java +++ b/packages/Connectivity/framework/src/android/net/ConnectivityDiagnosticsManager.java @@ -28,7 +28,6 @@ import android.os.PersistableBundle; import android.os.RemoteException; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -70,8 +69,8 @@ public class ConnectivityDiagnosticsManager { /** @hide */ public ConnectivityDiagnosticsManager(Context context, IConnectivityManager service) { - mContext = Preconditions.checkNotNull(context, "missing context"); - mService = Preconditions.checkNotNull(service, "missing IConnectivityManager"); + mContext = Objects.requireNonNull(context, "missing context"); + mService = Objects.requireNonNull(service, "missing IConnectivityManager"); } /** @hide */ diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java index e32622391cda..d196c1a2d186 100644 --- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java +++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java @@ -38,7 +38,9 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.app.PendingIntent; +import android.app.admin.DevicePolicyManager; import android.compat.annotation.UnsupportedAppUsage; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -62,7 +64,6 @@ import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; -import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.os.UserHandle; import android.provider.Settings; @@ -74,9 +75,7 @@ import android.util.Log; import android.util.Range; import android.util.SparseIntArray; -import com.android.connectivity.aidl.INetworkAgent; import com.android.internal.annotations.GuardedBy; -import com.android.internal.util.Preconditions; import libcore.net.event.NetworkEventDispatcher; @@ -829,6 +828,113 @@ public class ConnectivityManager { }) public @interface PrivateDnsMode {} + /** + * Flag to indicate that an app is not subject to any restrictions that could result in its + * network access blocked. + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final int BLOCKED_REASON_NONE = 0; + + /** + * Flag to indicate that an app is subject to Battery saver restrictions that would + * result in its network access being blocked. + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final int BLOCKED_REASON_BATTERY_SAVER = 1 << 0; + + /** + * Flag to indicate that an app is subject to Doze restrictions that would + * result in its network access being blocked. + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final int BLOCKED_REASON_DOZE = 1 << 1; + + /** + * Flag to indicate that an app is subject to App Standby restrictions that would + * result in its network access being blocked. + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final int BLOCKED_REASON_APP_STANDBY = 1 << 2; + + /** + * Flag to indicate that an app is subject to Restricted mode restrictions that would + * result in its network access being blocked. + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final int BLOCKED_REASON_RESTRICTED_MODE = 1 << 3; + + /** + * Flag to indicate that an app is blocked because it is subject to an always-on VPN but the VPN + * is not currently connected. + * + * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean) + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final int BLOCKED_REASON_LOCKDOWN_VPN = 1 << 4; + + /** + * Flag to indicate that an app is subject to Data saver restrictions that would + * result in its metered network access being blocked. + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final int BLOCKED_METERED_REASON_DATA_SAVER = 1 << 16; + + /** + * Flag to indicate that an app is subject to user restrictions that would + * result in its metered network access being blocked. + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 1 << 17; + + /** + * Flag to indicate that an app is subject to Device admin restrictions that would + * result in its metered network access being blocked. + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 1 << 18; + + /** + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, prefix = {"BLOCKED_"}, value = { + BLOCKED_REASON_NONE, + BLOCKED_REASON_BATTERY_SAVER, + BLOCKED_REASON_DOZE, + BLOCKED_REASON_APP_STANDBY, + BLOCKED_REASON_RESTRICTED_MODE, + BLOCKED_METERED_REASON_DATA_SAVER, + BLOCKED_METERED_REASON_USER_RESTRICTED, + BLOCKED_METERED_REASON_ADMIN_DISABLED, + }) + public @interface BlockedReason {} + + /** + * Set of blocked reasons that are only applicable on metered networks. + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final int BLOCKED_METERED_REASON_MASK = 0xffff0000; + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) private final IConnectivityManager mService; @@ -842,7 +948,6 @@ public class ConnectivityManager { private final Context mContext; - private INetworkPolicyManager mNPManager; private final TetheringManager mTetheringManager; /** @@ -1126,12 +1231,13 @@ public class ConnectivityManager { * @param ranges the UID ranges to restrict * @param requireVpn whether the specified UID ranges must use a VPN * - * TODO: expose as @SystemApi. * @hide */ @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.NETWORK_SETTINGS}) + @SystemApi(client = MODULE_LIBRARIES) public void setRequireVpnForUids(boolean requireVpn, @NonNull Collection<Range<Integer>> ranges) { Objects.requireNonNull(ranges); @@ -1175,13 +1281,13 @@ public class ConnectivityManager { * * @param enabled whether legacy lockdown VPN is enabled or disabled * - * TODO: @SystemApi(client = MODULE_LIBRARIES) - * * @hide */ @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) + @SystemApi(client = MODULE_LIBRARIES) public void setLegacyLockdownVpnEnabled(boolean enabled) { try { mService.setLegacyLockdownVpnEnabled(enabled); @@ -1777,7 +1883,9 @@ public class ConnectivityManager { // Map from type to transports. final int NOT_FOUND = -1; final int transport = sLegacyTypeToTransport.get(type, NOT_FOUND); - Preconditions.checkArgument(transport != NOT_FOUND, "unknown legacy type: " + type); + if (transport == NOT_FOUND) { + throw new IllegalArgumentException("unknown legacy type: " + type); + } nc.addTransportType(transport); // Map from type to capabilities. @@ -1882,8 +1990,8 @@ public class ConnectivityManager { } private PacketKeepalive(Network network, PacketKeepaliveCallback callback) { - Preconditions.checkNotNull(network, "network cannot be null"); - Preconditions.checkNotNull(callback, "callback cannot be null"); + Objects.requireNonNull(network, "network cannot be null"); + Objects.requireNonNull(callback, "callback cannot be null"); mNetwork = network; mExecutor = Executors.newSingleThreadExecutor(); mCallback = new ISocketKeepaliveCallback.Stub() { @@ -2126,6 +2234,7 @@ public class ConnectivityManager { */ @Deprecated @UnsupportedAppUsage + @SystemApi(client = MODULE_LIBRARIES) public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) { checkLegacyRoutingApiAccess(); try { @@ -2258,7 +2367,9 @@ public class ConnectivityManager { */ public void removeDefaultNetworkActiveListener(@NonNull OnNetworkActiveListener l) { INetworkActivityListener rl = mNetworkActivityListeners.get(l); - Preconditions.checkArgument(rl != null, "Listener was not registered."); + if (rl == null) { + throw new IllegalArgumentException("Listener was not registered."); + } try { mService.registerNetworkActivityListener(rl); } catch (RemoteException e) { @@ -2286,8 +2397,8 @@ public class ConnectivityManager { * {@hide} */ public ConnectivityManager(Context context, IConnectivityManager service) { - mContext = Preconditions.checkNotNull(context, "missing context"); - mService = Preconditions.checkNotNull(service, "missing IConnectivityManager"); + mContext = Objects.requireNonNull(context, "missing context"); + mService = Objects.requireNonNull(service, "missing IConnectivityManager"); mTetheringManager = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE); sInstance = this; } @@ -2554,7 +2665,7 @@ public class ConnectivityManager { @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int type, boolean showProvisioningUi, final OnStartTetheringCallback callback, Handler handler) { - Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null."); + Objects.requireNonNull(callback, "OnStartTetheringCallback cannot be null."); final Executor executor = new Executor() { @Override @@ -2647,7 +2758,7 @@ public class ConnectivityManager { public void registerTetheringEventCallback( @NonNull @CallbackExecutor Executor executor, @NonNull final OnTetheringEventCallback callback) { - Preconditions.checkNotNull(callback, "OnTetheringEventCallback cannot be null."); + Objects.requireNonNull(callback, "OnTetheringEventCallback cannot be null."); final TetheringEventCallback tetherCallback = new TetheringEventCallback() { @@ -2945,7 +3056,7 @@ public class ConnectivityManager { public void getLatestTetheringEntitlementResult(int type, boolean showEntitlementUi, @NonNull @CallbackExecutor Executor executor, @NonNull final OnTetheringEntitlementResultListener listener) { - Preconditions.checkNotNull(listener, "TetheringEntitlementResultListener cannot be null."); + Objects.requireNonNull(listener, "TetheringEntitlementResultListener cannot be null."); ResultReceiver wrappedListener = new ResultReceiver(null) { @Override protected void onReceiveResult(int resultCode, Bundle resultData) { @@ -3318,7 +3429,9 @@ public class ConnectivityManager { } public NetworkCallback(@Flag int flags) { - Preconditions.checkArgument((flags & VALID_FLAGS) == flags); + if ((flags & VALID_FLAGS) != flags) { + throw new IllegalArgumentException("Invalid flags"); + } mFlags = flags; } @@ -3350,12 +3463,30 @@ public class ConnectivityManager { * @param blocked Whether access to the {@link Network} is blocked due to system policy. * @hide */ - public void onAvailable(@NonNull Network network, + public final void onAvailable(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities, - @NonNull LinkProperties linkProperties, boolean blocked) { + @NonNull LinkProperties linkProperties, @BlockedReason int blocked) { // Internally only this method is called when a new network is available, and // it calls the callback in the same way and order that older versions used // to call so as not to change the behavior. + onAvailable(network, networkCapabilities, linkProperties, blocked != 0); + onBlockedStatusChanged(network, blocked); + } + + /** + * Legacy variant of onAvailable that takes a boolean blocked reason. + * + * This method has never been public API, but it's not final, so there may be apps that + * implemented it and rely on it being called. Do our best not to break them. + * Note: such apps will also get a second call to onBlockedStatusChanged immediately after + * this method is called. There does not seem to be a way to avoid this. + * TODO: add a compat check to move apps off this method, and eventually stop calling it. + * + * @hide + */ + public void onAvailable(@NonNull Network network, + @NonNull NetworkCapabilities networkCapabilities, + @NonNull LinkProperties linkProperties, boolean blocked) { onAvailable(network); if (!networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)) { @@ -3363,7 +3494,7 @@ public class ConnectivityManager { } onCapabilitiesChanged(network, networkCapabilities); onLinkPropertiesChanged(network, linkProperties); - onBlockedStatusChanged(network, blocked); + // No call to onBlockedStatusChanged here. That is done by the caller. } /** @@ -3527,6 +3658,26 @@ public class ConnectivityManager { */ public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {} + /** + * Called when access to the specified network is blocked or unblocked. + * + * If a NetworkCallback object implements this method, + * {@link #onBlockedStatusChanged(Network, boolean)} will not be called. + * + * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or + * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in + * this callback as this is prone to race conditions : calling these methods while in a + * callback may return an outdated or even a null object. + * + * @param network The {@link Network} whose blocked status has changed. + * @param blocked The blocked status of this {@link Network}. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public void onBlockedStatusChanged(@NonNull Network network, @BlockedReason int blocked) { + onBlockedStatusChanged(network, blocked != 0); + } + private NetworkRequest networkRequest; private final int mFlags; } @@ -3604,7 +3755,7 @@ public class ConnectivityManager { } CallbackHandler(Handler handler) { - this(Preconditions.checkNotNull(handler, "Handler cannot be null.").getLooper()); + this(Objects.requireNonNull(handler, "Handler cannot be null.").getLooper()); } @Override @@ -3641,7 +3792,7 @@ public class ConnectivityManager { case CALLBACK_AVAILABLE: { NetworkCapabilities cap = getObject(message, NetworkCapabilities.class); LinkProperties lp = getObject(message, LinkProperties.class); - callback.onAvailable(network, cap, lp, message.arg1 != 0); + callback.onAvailable(network, cap, lp, message.arg1); break; } case CALLBACK_LOSING: { @@ -3675,8 +3826,7 @@ public class ConnectivityManager { break; } case CALLBACK_BLK_CHANGED: { - boolean blocked = message.arg1 != 0; - callback.onBlockedStatusChanged(network, blocked); + callback.onBlockedStatusChanged(network, message.arg1); } } } @@ -3698,13 +3848,14 @@ public class ConnectivityManager { private static final HashMap<NetworkRequest, NetworkCallback> sCallbacks = new HashMap<>(); private static CallbackHandler sCallbackHandler; - private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback, - int timeoutMs, NetworkRequest.Type reqType, int legacyType, CallbackHandler handler) { + private NetworkRequest sendRequestForNetwork(int asUid, NetworkCapabilities need, + NetworkCallback callback, int timeoutMs, NetworkRequest.Type reqType, int legacyType, + CallbackHandler handler) { printStackTrace(); checkCallbackNotNull(callback); - Preconditions.checkArgument( - reqType == TRACK_DEFAULT || reqType == TRACK_SYSTEM_DEFAULT || need != null, - "null NetworkCapabilities"); + if (reqType != TRACK_DEFAULT && reqType != TRACK_SYSTEM_DEFAULT && need == null) { + throw new IllegalArgumentException("null NetworkCapabilities"); + } final NetworkRequest request; final String callingPackageName = mContext.getOpPackageName(); try { @@ -3724,8 +3875,8 @@ public class ConnectivityManager { getAttributionTag()); } else { request = mService.requestNetwork( - need, reqType.ordinal(), messenger, timeoutMs, binder, legacyType, - callbackFlags, callingPackageName, getAttributionTag()); + asUid, need, reqType.ordinal(), messenger, timeoutMs, binder, + legacyType, callbackFlags, callingPackageName, getAttributionTag()); } if (request != null) { sCallbacks.put(request, callback); @@ -3740,6 +3891,12 @@ public class ConnectivityManager { return request; } + private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback, + int timeoutMs, NetworkRequest.Type reqType, int legacyType, CallbackHandler handler) { + return sendRequestForNetwork(Process.INVALID_UID, need, callback, timeoutMs, reqType, + legacyType, handler); + } + /** * Helper function to request a network with a particular legacy type. * @@ -4051,15 +4208,17 @@ public class ConnectivityManager { } private static void checkPendingIntentNotNull(PendingIntent intent) { - Preconditions.checkNotNull(intent, "PendingIntent cannot be null."); + Objects.requireNonNull(intent, "PendingIntent cannot be null."); } private static void checkCallbackNotNull(NetworkCallback callback) { - Preconditions.checkNotNull(callback, "null NetworkCallback"); + Objects.requireNonNull(callback, "null NetworkCallback"); } private static void checkTimeout(int timeoutMs) { - Preconditions.checkArgumentPositive(timeoutMs, "timeoutMs must be strictly positive."); + if (timeoutMs <= 0) { + throw new IllegalArgumentException("timeoutMs must be strictly positive."); + } } /** @@ -4223,8 +4382,40 @@ public class ConnectivityManager { @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback, @NonNull Handler handler) { + registerDefaultNetworkCallbackAsUid(Process.INVALID_UID, networkCallback, handler); + } + + /** + * Registers to receive notifications about changes in the default network for the specified + * UID. This may be a physical network or a virtual network, such as a VPN that applies to the + * UID. The callbacks will continue to be called until either the application exits or + * {@link #unregisterNetworkCallback(NetworkCallback)} is called. + * + * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the + * number of outstanding requests to 100 per app (identified by their UID), shared with + * all variants of this method, of {@link #requestNetwork} as well as + * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}. + * Requesting a network with this method will count toward this limit. If this limit is + * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources, + * make sure to unregister the callbacks with + * {@link #unregisterNetworkCallback(NetworkCallback)}. + * + * @param uid the UID for which to track default network changes. + * @param networkCallback The {@link NetworkCallback} that the system will call as the + * UID's default network changes. + * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. + * @throws RuntimeException if the app already has too many callbacks registered. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + @SuppressLint({"ExecutorRegistration", "PairedRegistration"}) + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_SETTINGS}) + public void registerDefaultNetworkCallbackAsUid(int uid, + @NonNull NetworkCallback networkCallback, @NonNull Handler handler) { CallbackHandler cbHandler = new CallbackHandler(handler); - sendRequestForNetwork(null /* NetworkCapabilities need */, networkCallback, 0, + sendRequestForNetwork(uid, null /* need */, networkCallback, 0 /* timeoutMs */, TRACK_DEFAULT, TYPE_NONE, cbHandler); } @@ -4339,8 +4530,9 @@ public class ConnectivityManager { // Find all requests associated to this callback and stop callback triggers immediately. // Callback is reusable immediately. http://b/20701525, http://b/35921499. synchronized (sCallbacks) { - Preconditions.checkArgument(networkCallback.networkRequest != null, - "NetworkCallback was not registered"); + if (networkCallback.networkRequest == null) { + throw new IllegalArgumentException("NetworkCallback was not registered"); + } if (networkCallback.networkRequest == ALREADY_UNREGISTERED) { Log.d(TAG, "NetworkCallback was already unregistered"); return; @@ -4794,17 +4986,6 @@ public class ConnectivityManager { public @interface RestrictBackgroundStatus { } - private INetworkPolicyManager getNetworkPolicyManager() { - synchronized (this) { - if (mNPManager != null) { - return mNPManager; - } - mNPManager = INetworkPolicyManager.Stub.asInterface(ServiceManager - .getService(Context.NETWORK_POLICY_SERVICE)); - return mNPManager; - } - } - /** * Determines if the calling application is subject to metered network restrictions while * running on background. @@ -4815,7 +4996,7 @@ public class ConnectivityManager { */ public @RestrictBackgroundStatus int getRestrictBackgroundStatus() { try { - return getNetworkPolicyManager().getRestrictBackgroundByCaller(); + return mService.getRestrictBackgroundStatusByCaller(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -4945,20 +5126,20 @@ public class ConnectivityManager { * {@link QosCallback#onError(QosCallbackException)}. see: {@link QosCallbackException}. * * @param socketInfo the socket information used to match QoS events - * @param callback receives qos events that satisfy socketInfo * @param executor The executor on which the callback will be invoked. The provided * {@link Executor} must run callback sequentially, otherwise the order of - * callbacks cannot be guaranteed. + * callbacks cannot be guaranteed.onQosCallbackRegistered + * @param callback receives qos events that satisfy socketInfo * * @hide */ @SystemApi public void registerQosCallback(@NonNull final QosSocketInfo socketInfo, - @NonNull final QosCallback callback, - @CallbackExecutor @NonNull final Executor executor) { + @CallbackExecutor @NonNull final Executor executor, + @NonNull final QosCallback callback) { Objects.requireNonNull(socketInfo, "socketInfo must be non-null"); - Objects.requireNonNull(callback, "callback must be non-null"); Objects.requireNonNull(executor, "executor must be non-null"); + Objects.requireNonNull(callback, "callback must be non-null"); try { synchronized (mQosCallbackConnections) { @@ -5248,4 +5429,23 @@ public class ConnectivityManager { if (TextUtils.isEmpty(mode)) mode = PRIVATE_DNS_MODE_OPPORTUNISTIC; return mode; } + + /** + * Set private DNS mode to settings. + * + * @param context The {@link Context} to set the private DNS mode. + * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants. + * + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static void setPrivateDnsMode(@NonNull Context context, + @NonNull @PrivateDnsMode String mode) { + if (!(mode == PRIVATE_DNS_MODE_OFF + || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC + || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) { + throw new IllegalArgumentException("Invalid private dns mode"); + } + Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE, mode); + } } diff --git a/services/core/java/com/android/server/connectivity/ConnectivityResources.java b/packages/Connectivity/framework/src/android/net/ConnectivityResources.java index 45cf21e035ca..18f0de0cc9a1 100644 --- a/services/core/java/com/android/server/connectivity/ConnectivityResources.java +++ b/packages/Connectivity/framework/src/android/net/ConnectivityResources.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.connectivity; +package android.net; import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; @@ -27,13 +27,14 @@ import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.util.Log; -import com.android.server.ConnectivityService; +import com.android.internal.annotations.VisibleForTesting; import java.util.List; /** - * Utility to obtain the {@link ConnectivityService} {@link Resources}, in the + * Utility to obtain the {@link com.android.server.ConnectivityService} {@link Resources}, in the * ServiceConnectivityResources APK. + * @hide */ public class ConnectivityResources { private static final String RESOURCES_APK_INTENT = @@ -44,18 +45,35 @@ public class ConnectivityResources { private final Context mContext; @Nullable - private Resources mResources = null; + private Context mResourcesContext = null; + + @Nullable + private static Context sTestResourcesContext = null; public ConnectivityResources(Context context) { mContext = context; } /** - * Get the {@link Resources} of the ServiceConnectivityResources APK. + * Convenience method to mock all resources for the duration of a test. + * + * Call with a null context to reset after the test. + */ + @VisibleForTesting + public static void setResourcesContextForTest(@Nullable Context testContext) { + sTestResourcesContext = testContext; + } + + /** + * Get the {@link Context} of the resources package. */ - public synchronized Resources get() { - if (mResources != null) { - return mResources; + public synchronized Context getResourcesContext() { + if (sTestResourcesContext != null) { + return sTestResourcesContext; + } + + if (mResourcesContext != null) { + return mResourcesContext; } final List<ResolveInfo> pkgs = mContext.getPackageManager() @@ -77,7 +95,14 @@ public class ConnectivityResources { throw new IllegalStateException("Resolved package not found", e); } - mResources = pkgContext.getResources(); - return mResources; + mResourcesContext = pkgContext; + return pkgContext; + } + + /** + * Get the {@link Resources} of the ServiceConnectivityResources APK. + */ + public Resources get() { + return getResourcesContext().getResources(); } } diff --git a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java index bbd83931ee0d..9a00055e0079 100644 --- a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java +++ b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java @@ -16,16 +16,38 @@ package android.net; +import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER; +import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE; +import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY; +import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; +import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; +import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; + import android.annotation.IntDef; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.content.Context; +import android.net.ConnectivityManager.MultipathPreference; +import android.net.ConnectivityManager.PrivateDnsMode; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Range; + +import com.android.net.module.util.ProxyUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.time.Duration; +import java.util.List; /** * A manager class for connectivity module settings. * * @hide */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public class ConnectivitySettingsManager { private ConnectivitySettingsManager() {} @@ -45,12 +67,16 @@ public class ConnectivitySettingsManager { * Network activity refers to transmitting or receiving data on the network interfaces. * * Tracking is disabled if set to zero or negative value. + * + * @hide */ public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile"; /** * Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE} * but for Wifi network. + * + * @hide */ public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi"; @@ -58,12 +84,16 @@ public class ConnectivitySettingsManager { /** * Sample validity in seconds to configure for the system DNS resolver. + * + * @hide */ public static final String DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS = "dns_resolver_sample_validity_seconds"; /** * Success threshold in percent for use with the system DNS resolver. + * + * @hide */ public static final String DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT = "dns_resolver_success_threshold_percent"; @@ -71,24 +101,35 @@ public class ConnectivitySettingsManager { /** * Minimum number of samples needed for statistics to be considered meaningful in the * system DNS resolver. + * + * @hide */ public static final String DNS_RESOLVER_MIN_SAMPLES = "dns_resolver_min_samples"; /** * Maximum number taken into account for statistics purposes in the system DNS resolver. + * + * @hide */ public static final String DNS_RESOLVER_MAX_SAMPLES = "dns_resolver_max_samples"; + private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8; + private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64; + /** Network switch notification settings */ /** * The maximum number of notifications shown in 24 hours when switching networks. + * + * @hide */ public static final String NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT = "network_switch_notification_daily_limit"; /** * The minimum time in milliseconds between notifications when switching networks. + * + * @hide */ public static final String NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS = "network_switch_notification_rate_limit_millis"; @@ -98,14 +139,18 @@ public class ConnectivitySettingsManager { /** * The URL used for HTTP captive portal detection upon a new connection. * A 204 response code from the server is used for validation. + * + * @hide */ public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url"; /** * What to do when connecting a network that presents a captive portal. - * Must be one of the CAPTIVE_PORTAL_MODE_* constants above. + * Must be one of the CAPTIVE_PORTAL_MODE_* constants below. * * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT. + * + * @hide */ public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode"; @@ -139,11 +184,15 @@ public class ConnectivitySettingsManager { /** * Host name for global http proxy. Set via ConnectivityManager. + * + * @hide */ public static final String GLOBAL_HTTP_PROXY_HOST = "global_http_proxy_host"; /** * Integer host port for global http proxy. Set via ConnectivityManager. + * + * @hide */ public static final String GLOBAL_HTTP_PROXY_PORT = "global_http_proxy_port"; @@ -153,12 +202,16 @@ public class ConnectivitySettingsManager { * Domains should be listed in a comma- separated list. Example of * acceptable formats: ".domain1.com,my.domain2.com" Use * ConnectivityManager to set/get. + * + * @hide */ public static final String GLOBAL_HTTP_PROXY_EXCLUSION_LIST = "global_http_proxy_exclusion_list"; /** * The location PAC File for the proxy. + * + * @hide */ public static final String GLOBAL_HTTP_PROXY_PAC = "global_proxy_pac_url"; @@ -171,11 +224,15 @@ public class ConnectivitySettingsManager { * a specific provider. It may be used to store the provider name even when the * mode changes so that temporarily disabling and re-enabling the specific * provider mode does not necessitate retyping the provider hostname. + * + * @hide */ public static final String PRIVATE_DNS_MODE = "private_dns_mode"; /** * The specific Private DNS provider name. + * + * @hide */ public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier"; @@ -185,6 +242,8 @@ public class ConnectivitySettingsManager { * all of which require explicit user action to enable/configure. See also b/79719289. * * Value is a string, suitable for assignment to PRIVATE_DNS_MODE above. + * + * @hide */ public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode"; @@ -194,6 +253,8 @@ public class ConnectivitySettingsManager { * The number of milliseconds to hold on to a PendingIntent based request. This delay gives * the receivers of the PendingIntent an opportunity to make a new network request before * the Network satisfying the request is potentially removed. + * + * @hide */ public static final String CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS = "connectivity_release_pending_intent_delay_ms"; @@ -205,6 +266,8 @@ public class ConnectivitySettingsManager { * See ConnectivityService for more info. * * (0 = disabled, 1 = enabled) + * + * @hide */ public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on"; @@ -217,6 +280,8 @@ public class ConnectivitySettingsManager { * See ConnectivityService for more info. * * (0 = disabled, 1 = enabled) + * + * @hide */ public static final String WIFI_ALWAYS_REQUESTED = "wifi_always_requested"; @@ -228,14 +293,637 @@ public class ConnectivitySettingsManager { * 0: Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013. * null: Ask the user whether to switch away from bad wifi. * 1: Avoid bad wifi. + * + * @hide */ public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi"; /** + * Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013. + */ + public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0; + + /** + * Ask the user whether to switch away from bad wifi. + */ + public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1; + + /** + * Avoid bad wifi. + */ + public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + NETWORK_AVOID_BAD_WIFI_IGNORE, + NETWORK_AVOID_BAD_WIFI_PROMPT, + NETWORK_AVOID_BAD_WIFI_AVOID, + }) + public @interface NetworkAvoidBadWifi {} + + /** * User setting for ConnectivityManager.getMeteredMultipathPreference(). This value may be * overridden by the system based on device or application state. If null, the value * specified by config_networkMeteredMultipathPreference is used. + * + * @hide */ public static final String NETWORK_METERED_MULTIPATH_PREFERENCE = "network_metered_multipath_preference"; + + /** + * A list of apps that should go on cellular networks in preference even when higher-priority + * networks are connected. + * + * @hide + */ + public static final String MOBILE_DATA_PREFERRED_APPS = "mobile_data_preferred_apps"; + + /** + * Get mobile data activity timeout from {@link Settings}. + * + * @param context The {@link Context} to query the setting. + * @param def The default timeout if no setting value. + * @return The {@link Duration} of timeout to track mobile data activity. + */ + @NonNull + public static Duration getMobileDataActivityTimeout(@NonNull Context context, + @NonNull Duration def) { + final int timeout = Settings.Global.getInt( + context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE, (int) def.getSeconds()); + return Duration.ofSeconds(timeout); + } + + /** + * Set mobile data activity timeout to {@link Settings}. + * Tracking is disabled if set to zero or negative value. + * + * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be + * ignored. + * + * @param context The {@link Context} to set the setting. + * @param timeout The mobile data activity timeout. + */ + public static void setMobileDataActivityTimeout(@NonNull Context context, + @NonNull Duration timeout) { + Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE, + (int) timeout.getSeconds()); + } + + /** + * Get wifi data activity timeout from {@link Settings}. + * + * @param context The {@link Context} to query the setting. + * @param def The default timeout if no setting value. + * @return The {@link Duration} of timeout to track wifi data activity. + */ + @NonNull + public static Duration getWifiDataActivityTimeout(@NonNull Context context, + @NonNull Duration def) { + final int timeout = Settings.Global.getInt( + context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI, (int) def.getSeconds()); + return Duration.ofSeconds(timeout); + } + + /** + * Set wifi data activity timeout to {@link Settings}. + * Tracking is disabled if set to zero or negative value. + * + * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be + * ignored. + * + * @param context The {@link Context} to set the setting. + * @param timeout The wifi data activity timeout. + */ + public static void setWifiDataActivityTimeout(@NonNull Context context, + @NonNull Duration timeout) { + Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI, + (int) timeout.getSeconds()); + } + + /** + * Get dns resolver sample validity duration from {@link Settings}. + * + * @param context The {@link Context} to query the setting. + * @param def The default duration if no setting value. + * @return The {@link Duration} of sample validity duration to configure for the system DNS + * resolver. + */ + @NonNull + public static Duration getDnsResolverSampleValidityDuration(@NonNull Context context, + @NonNull Duration def) { + final int duration = Settings.Global.getInt(context.getContentResolver(), + DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, (int) def.getSeconds()); + return Duration.ofSeconds(duration); + } + + /** + * Set dns resolver sample validity duration to {@link Settings}. The duration must be a + * positive number of seconds. + * + * @param context The {@link Context} to set the setting. + * @param duration The sample validity duration. + */ + public static void setDnsResolverSampleValidityDuration(@NonNull Context context, + @NonNull Duration duration) { + final int time = (int) duration.getSeconds(); + if (time <= 0) { + throw new IllegalArgumentException("Invalid duration"); + } + Settings.Global.putInt( + context.getContentResolver(), DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, time); + } + + /** + * Get dns resolver success threshold percent from {@link Settings}. + * + * @param context The {@link Context} to query the setting. + * @param def The default value if no setting value. + * @return The success threshold in percent for use with the system DNS resolver. + */ + public static int getDnsResolverSuccessThresholdPercent(@NonNull Context context, int def) { + return Settings.Global.getInt( + context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, def); + } + + /** + * Set dns resolver success threshold percent to {@link Settings}. The threshold percent must + * be 0~100. + * + * @param context The {@link Context} to set the setting. + * @param percent The success threshold percent. + */ + public static void setDnsResolverSuccessThresholdPercent(@NonNull Context context, + @IntRange(from = 0, to = 100) int percent) { + if (percent < 0 || percent > 100) { + throw new IllegalArgumentException("Percent must be 0~100"); + } + Settings.Global.putInt( + context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, percent); + } + + /** + * Get dns resolver samples range from {@link Settings}. + * + * @param context The {@link Context} to query the setting. + * @return The {@link Range<Integer>} of samples needed for statistics to be considered + * meaningful in the system DNS resolver. + */ + @NonNull + public static Range<Integer> getDnsResolverSampleRanges(@NonNull Context context) { + final int minSamples = Settings.Global.getInt(context.getContentResolver(), + DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES); + final int maxSamples = Settings.Global.getInt(context.getContentResolver(), + DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES); + return new Range<>(minSamples, maxSamples); + } + + /** + * Set dns resolver samples range to {@link Settings}. + * + * @param context The {@link Context} to set the setting. + * @param range The samples range. The minimum number should be more than 0 and the maximum + * number should be less that 64. + */ + public static void setDnsResolverSampleRanges(@NonNull Context context, + @NonNull Range<Integer> range) { + if (range.getLower() < 0 || range.getUpper() > 64) { + throw new IllegalArgumentException("Argument must be 0~64"); + } + Settings.Global.putInt( + context.getContentResolver(), DNS_RESOLVER_MIN_SAMPLES, range.getLower()); + Settings.Global.putInt( + context.getContentResolver(), DNS_RESOLVER_MAX_SAMPLES, range.getUpper()); + } + + /** + * Get maximum count (from {@link Settings}) of switching network notifications shown in 24 + * hours. + * + * @param context The {@link Context} to query the setting. + * @param def The default value if no setting value. + * @return The maximum count of notifications shown in 24 hours when switching networks. + */ + public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context, + int def) { + return Settings.Global.getInt( + context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, def); + } + + /** + * Set maximum count (to {@link Settings}) of switching network notifications shown in 24 hours. + * The count must be at least 0. + * + * @param context The {@link Context} to set the setting. + * @param count The maximum count of switching network notifications shown in 24 hours. + */ + public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context, + @IntRange(from = 0) int count) { + if (count < 0) { + throw new IllegalArgumentException("Count must be 0~10."); + } + Settings.Global.putInt( + context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, count); + } + + /** + * Get minimum duration (from {@link Settings}) between each switching network notifications. + * + * @param context The {@link Context} to query the setting. + * @param def The default time if no setting value. + * @return The minimum duration between notifications when switching networks. + */ + @NonNull + public static Duration getNetworkSwitchNotificationRateDuration(@NonNull Context context, + @NonNull Duration def) { + final int duration = Settings.Global.getInt(context.getContentResolver(), + NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, (int) def.toMillis()); + return Duration.ofMillis(duration); + } + + /** + * Set minimum duration (to {@link Settings}) between each switching network notifications. + * + * @param context The {@link Context} to set the setting. + * @param duration The minimum duration between notifications when switching networks. + */ + public static void setNetworkSwitchNotificationRateDuration(@NonNull Context context, + @NonNull Duration duration) { + final int time = (int) duration.toMillis(); + if (time < 0) { + throw new IllegalArgumentException("Invalid duration."); + } + Settings.Global.putInt(context.getContentResolver(), + NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, time); + } + + /** + * Get URL (from {@link Settings}) used for HTTP captive portal detection upon a new connection. + * + * @param context The {@link Context} to query the setting. + * @return The URL used for HTTP captive portal detection upon a new connection. + */ + @Nullable + public static String getCaptivePortalHttpUrl(@NonNull Context context) { + return Settings.Global.getString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL); + } + + /** + * Set URL (to {@link Settings}) used for HTTP captive portal detection upon a new connection. + * This URL should respond with a 204 response to a GET request to indicate no captive portal is + * present. And this URL must be HTTP as redirect responses are used to find captive portal + * sign-in pages. If the URL set to null or be incorrect, it will result in captive portal + * detection failed and lost the connection. + * + * @param context The {@link Context} to set the setting. + * @param url The URL used for HTTP captive portal detection upon a new connection. + */ + public static void setCaptivePortalHttpUrl(@NonNull Context context, @Nullable String url) { + Settings.Global.putString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL, url); + } + + /** + * Get mode (from {@link Settings}) when connecting a network that presents a captive portal. + * + * @param context The {@link Context} to query the setting. + * @param def The default mode if no setting value. + * @return The mode when connecting a network that presents a captive portal. + */ + @CaptivePortalMode + public static int getCaptivePortalMode(@NonNull Context context, + @CaptivePortalMode int def) { + return Settings.Global.getInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, def); + } + + /** + * Set mode (to {@link Settings}) when connecting a network that presents a captive portal. + * + * @param context The {@link Context} to set the setting. + * @param mode The mode when connecting a network that presents a captive portal. + */ + public static void setCaptivePortalMode(@NonNull Context context, @CaptivePortalMode int mode) { + if (!(mode == CAPTIVE_PORTAL_MODE_IGNORE + || mode == CAPTIVE_PORTAL_MODE_PROMPT + || mode == CAPTIVE_PORTAL_MODE_AVOID)) { + throw new IllegalArgumentException("Invalid captive portal mode"); + } + Settings.Global.putInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, mode); + } + + /** + * Get the global HTTP proxy applied to the device, or null if none. + * + * @param context The {@link Context} to query the setting. + * @return The {@link ProxyInfo} which build from global http proxy settings. + */ + @Nullable + public static ProxyInfo getGlobalProxy(@NonNull Context context) { + final String host = Settings.Global.getString( + context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST); + final int port = Settings.Global.getInt( + context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* def */); + final String exclusionList = Settings.Global.getString( + context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST); + final String pacFileUrl = Settings.Global.getString( + context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC); + + if (TextUtils.isEmpty(host) && TextUtils.isEmpty(pacFileUrl)) { + return null; // No global proxy. + } + + if (TextUtils.isEmpty(pacFileUrl)) { + return ProxyInfo.buildDirectProxy( + host, port, ProxyUtils.exclusionStringAsList(exclusionList)); + } else { + return ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl)); + } + } + + /** + * Set global http proxy settings from given {@link ProxyInfo}. + * + * @param context The {@link Context} to set the setting. + * @param proxyInfo The {@link ProxyInfo} for global http proxy settings which build from + * {@link ProxyInfo#buildPacProxy(Uri)} or + * {@link ProxyInfo#buildDirectProxy(String, int, List)} + */ + public static void setGlobalProxy(@NonNull Context context, @NonNull ProxyInfo proxyInfo) { + final String host = proxyInfo.getHost(); + final int port = proxyInfo.getPort(); + final String exclusionList = proxyInfo.getExclusionListAsString(); + final String pacFileUrl = proxyInfo.getPacFileUrl().toString(); + + if (TextUtils.isEmpty(pacFileUrl)) { + Settings.Global.putString(context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, host); + Settings.Global.putInt(context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, port); + Settings.Global.putString( + context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclusionList); + Settings.Global.putString( + context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */); + } else { + Settings.Global.putString( + context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, pacFileUrl); + Settings.Global.putString( + context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */); + Settings.Global.putInt( + context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */); + Settings.Global.putString( + context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */); + } + } + + /** + * Clear all global http proxy settings. + * + * @param context The {@link Context} to set the setting. + */ + public static void clearGlobalProxy(@NonNull Context context) { + Settings.Global.putString( + context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */); + Settings.Global.putInt( + context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */); + Settings.Global.putString( + context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */); + Settings.Global.putString( + context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */); + } + + /** + * Get specific private dns provider name from {@link Settings}. + * + * @param context The {@link Context} to query the setting. + * @return The specific private dns provider name, or null if no setting value. + */ + @Nullable + public static String getPrivateDnsHostname(@NonNull Context context) { + return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER); + } + + /** + * Set specific private dns provider name to {@link Settings}. + * + * @param context The {@link Context} to set the setting. + * @param specifier The specific private dns provider name. + */ + public static void setPrivateDnsHostname(@NonNull Context context, + @Nullable String specifier) { + Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER, specifier); + } + + /** + * Get default private dns mode from {@link Settings}. + * + * @param context The {@link Context} to query the setting. + * @return The default private dns mode. + */ + @PrivateDnsMode + @NonNull + public static String getPrivateDnsDefaultMode(@NonNull Context context) { + return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE); + } + + /** + * Set default private dns mode to {@link Settings}. + * + * @param context The {@link Context} to set the setting. + * @param mode The default private dns mode. This should be one of the PRIVATE_DNS_MODE_* + * constants. + */ + public static void setPrivateDnsDefaultMode(@NonNull Context context, + @NonNull @PrivateDnsMode String mode) { + if (!(mode == PRIVATE_DNS_MODE_OFF + || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC + || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) { + throw new IllegalArgumentException("Invalid private dns mode"); + } + Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE, mode); + } + + /** + * Get duration (from {@link Settings}) to keep a PendingIntent-based request. + * + * @param context The {@link Context} to query the setting. + * @param def The default duration if no setting value. + * @return The duration to keep a PendingIntent-based request. + */ + @NonNull + public static Duration getConnectivityKeepPendingIntentDuration(@NonNull Context context, + @NonNull Duration def) { + final int duration = Settings.Secure.getInt(context.getContentResolver(), + CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, (int) def.toMillis()); + return Duration.ofMillis(duration); + } + + /** + * Set duration (to {@link Settings}) to keep a PendingIntent-based request. + * + * @param context The {@link Context} to set the setting. + * @param duration The duration to keep a PendingIntent-based request. + */ + public static void setConnectivityKeepPendingIntentDuration(@NonNull Context context, + @NonNull Duration duration) { + final int time = (int) duration.toMillis(); + if (time < 0) { + throw new IllegalArgumentException("Invalid duration."); + } + Settings.Secure.putInt( + context.getContentResolver(), CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, time); + } + + /** + * Read from {@link Settings} whether the mobile data connection should remain active + * even when higher priority networks are active. + * + * @param context The {@link Context} to query the setting. + * @param def The default value if no setting value. + * @return Whether the mobile data connection should remain active even when higher + * priority networks are active. + */ + public static boolean getMobileDataAlwaysOn(@NonNull Context context, boolean def) { + final int enable = Settings.Global.getInt( + context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (def ? 1 : 0)); + return (enable != 0) ? true : false; + } + + /** + * Write into {@link Settings} whether the mobile data connection should remain active + * even when higher priority networks are active. + * + * @param context The {@link Context} to set the setting. + * @param enable Whether the mobile data connection should remain active even when higher + * priority networks are active. + */ + public static void setMobileDataAlwaysOn(@NonNull Context context, boolean enable) { + Settings.Global.putInt( + context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (enable ? 1 : 0)); + } + + /** + * Read from {@link Settings} whether the wifi data connection should remain active + * even when higher priority networks are active. + * + * @param context The {@link Context} to query the setting. + * @param def The default value if no setting value. + * @return Whether the wifi data connection should remain active even when higher + * priority networks are active. + */ + public static boolean getWifiAlwaysRequested(@NonNull Context context, boolean def) { + final int enable = Settings.Global.getInt( + context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (def ? 1 : 0)); + return (enable != 0) ? true : false; + } + + /** + * Write into {@link Settings} whether the wifi data connection should remain active + * even when higher priority networks are active. + * + * @param context The {@link Context} to set the setting. + * @param enable Whether the wifi data connection should remain active even when higher + * priority networks are active + */ + public static void setWifiAlwaysRequested(@NonNull Context context, boolean enable) { + Settings.Global.putInt( + context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (enable ? 1 : 0)); + } + + /** + * Get avoid bad wifi setting from {@link Settings}. + * + * @param context The {@link Context} to query the setting. + * @return The setting whether to automatically switch away from wifi networks that lose + * internet access. + */ + @NetworkAvoidBadWifi + public static int getNetworkAvoidBadWifi(@NonNull Context context) { + final String setting = + Settings.Global.getString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI); + if ("0".equals(setting)) { + return NETWORK_AVOID_BAD_WIFI_IGNORE; + } else if ("1".equals(setting)) { + return NETWORK_AVOID_BAD_WIFI_AVOID; + } else { + return NETWORK_AVOID_BAD_WIFI_PROMPT; + } + } + + /** + * Set avoid bad wifi setting to {@link Settings}. + * + * @param context The {@link Context} to set the setting. + * @param value Whether to automatically switch away from wifi networks that lose internet + * access. + */ + public static void setNetworkAvoidBadWifi(@NonNull Context context, + @NetworkAvoidBadWifi int value) { + final String setting; + if (value == NETWORK_AVOID_BAD_WIFI_IGNORE) { + setting = "0"; + } else if (value == NETWORK_AVOID_BAD_WIFI_AVOID) { + setting = "1"; + } else if (value == NETWORK_AVOID_BAD_WIFI_PROMPT) { + setting = null; + } else { + throw new IllegalArgumentException("Invalid avoid bad wifi setting"); + } + Settings.Global.putString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI, setting); + } + + /** + * Get network metered multipath preference from {@link Settings}. + * + * @param context The {@link Context} to query the setting. + * @return The network metered multipath preference which should be one of + * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value specified + * by config_networkMeteredMultipathPreference is used. + */ + @Nullable + public static String getNetworkMeteredMultipathPreference(@NonNull Context context) { + return Settings.Global.getString( + context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE); + } + + /** + * Set network metered multipath preference to {@link Settings}. + * + * @param context The {@link Context} to set the setting. + * @param preference The network metered multipath preference which should be one of + * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value + * specified by config_networkMeteredMultipathPreference is used. + */ + public static void setNetworkMeteredMultipathPreference(@NonNull Context context, + @NonNull @MultipathPreference String preference) { + if (!(Integer.valueOf(preference) == MULTIPATH_PREFERENCE_HANDOVER + || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_RELIABILITY + || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_PERFORMANCE)) { + throw new IllegalArgumentException("Invalid private dns mode"); + } + Settings.Global.putString( + context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE, preference); + } + + /** + * Get the list of apps(from {@link Settings}) that should go on cellular networks in preference + * even when higher-priority networks are connected. + * + * @param context The {@link Context} to query the setting. + * @return A list of apps that should go on cellular networks in preference even when + * higher-priority networks are connected or null if no setting value. + */ + @Nullable + public static String getMobileDataPreferredApps(@NonNull Context context) { + return Settings.Secure.getString(context.getContentResolver(), MOBILE_DATA_PREFERRED_APPS); + } + + /** + * Set the list of apps(to {@link Settings}) that should go on cellular networks in preference + * even when higher-priority networks are connected. + * + * @param context The {@link Context} to set the setting. + * @param list A list of apps that should go on cellular networks in preference even when + * higher-priority networks are connected. + */ + public static void setMobileDataPreferredApps(@NonNull Context context, @Nullable String list) { + Settings.Secure.putString(context.getContentResolver(), MOBILE_DATA_PREFERRED_APPS, list); + } } diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl index d83cc163b53f..0826922e2165 100644 --- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl +++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl @@ -20,6 +20,7 @@ import android.app.PendingIntent; import android.net.ConnectionInfo; import android.net.ConnectivityDiagnosticsManager; import android.net.IConnectivityDiagnosticsCallback; +import android.net.INetworkAgent; import android.net.IOnCompleteListener; import android.net.INetworkActivityListener; import android.net.IQosCallback; @@ -45,8 +46,6 @@ import android.os.PersistableBundle; import android.os.ResultReceiver; import android.os.UserHandle; -import com.android.connectivity.aidl.INetworkAgent; - /** * Interface that answers queries about, and allows changing, the * state of network connectivity. @@ -143,7 +142,7 @@ interface IConnectivityManager in NetworkCapabilities nc, in NetworkScore score, in NetworkAgentConfig config, in int factorySerialNumber); - NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, int reqType, + NetworkRequest requestNetwork(int uid, in NetworkCapabilities networkCapabilities, int reqType, in Messenger messenger, int timeoutSec, in IBinder binder, int legacy, int callbackFlags, String callingPackageName, String callingAttributionTag); @@ -220,4 +219,6 @@ interface IConnectivityManager void setProfileNetworkPreference(in UserHandle profile, int preference, in IOnCompleteListener listener); + + int getRestrictBackgroundStatusByCaller(); } diff --git a/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl b/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl index 64b556720cd2..f9d399459ebd 100644 --- a/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgent.aidl +++ b/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl @@ -13,13 +13,13 @@ * See the License for the specific language governing perNmissions and * limitations under the License. */ -package com.android.connectivity.aidl; +package android.net; import android.net.NattKeepalivePacketData; import android.net.QosFilterParcelable; import android.net.TcpKeepalivePacketData; -import com.android.connectivity.aidl.INetworkAgentRegistry; +import android.net.INetworkAgentRegistry; /** * Interface to notify NetworkAgent of connectivity events. @@ -46,4 +46,6 @@ oneway interface INetworkAgent { void onRemoveKeepalivePacketFilter(int slot); void onQosFilterCallbackRegistered(int qosCallbackId, in QosFilterParcelable filterParcel); void onQosCallbackUnregistered(int qosCallbackId); + void onNetworkCreated(); + void onNetworkDisconnected(); } diff --git a/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl index 18d26a7e4baf..cbd6193744b9 100644 --- a/packages/Connectivity/framework/src/com/android/connectivity/aidl/INetworkAgentRegistry.aidl +++ b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl @@ -13,7 +13,7 @@ * See the License for the specific language governing perNmissions and * limitations under the License. */ -package com.android.connectivity.aidl; +package android.net; import android.net.LinkProperties; import android.net.Network; @@ -22,6 +22,7 @@ import android.net.NetworkInfo; import android.net.NetworkScore; import android.net.QosSession; import android.telephony.data.EpsBearerQosSessionAttributes; +import android.telephony.data.NrQosSessionAttributes; /** * Interface for NetworkAgents to send network properties. @@ -37,6 +38,7 @@ oneway interface INetworkAgentRegistry { void sendSocketKeepaliveEvent(int slot, int reason); void sendUnderlyingNetworks(in @nullable List<Network> networks); void sendEpsQosSessionAvailable(int callbackId, in QosSession session, in EpsBearerQosSessionAttributes attributes); + void sendNrQosSessionAvailable(int callbackId, in QosSession session, in NrQosSessionAttributes attributes); void sendQosSessionLost(int qosCallbackId, in QosSession session); void sendQosCallbackError(int qosCallbackId, int exceptionType); } diff --git a/packages/Connectivity/framework/src/android/net/IQosCallback.aidl b/packages/Connectivity/framework/src/android/net/IQosCallback.aidl index 91c75759f85c..c9735419f7dd 100644 --- a/packages/Connectivity/framework/src/android/net/IQosCallback.aidl +++ b/packages/Connectivity/framework/src/android/net/IQosCallback.aidl @@ -19,6 +19,7 @@ package android.net; import android.os.Bundle; import android.net.QosSession; import android.telephony.data.EpsBearerQosSessionAttributes; +import android.telephony.data.NrQosSessionAttributes; /** * AIDL interface for QosCallback @@ -29,6 +30,8 @@ oneway interface IQosCallback { void onQosEpsBearerSessionAvailable(in QosSession session, in EpsBearerQosSessionAttributes attributes); + void onNrQosSessionAvailable(in QosSession session, + in NrQosSessionAttributes attributes); void onQosSessionLost(in QosSession session); void onError(in int type); } diff --git a/packages/Connectivity/framework/src/android/net/MacAddress.java b/packages/Connectivity/framework/src/android/net/MacAddress.java index c83c23a4b66e..26a504a29c1c 100644 --- a/packages/Connectivity/framework/src/android/net/MacAddress.java +++ b/packages/Connectivity/framework/src/android/net/MacAddress.java @@ -25,7 +25,6 @@ import android.os.Build; import android.os.Parcel; import android.os.Parcelable; -import com.android.internal.util.Preconditions; import com.android.net.module.util.MacAddressUtils; import java.lang.annotation.Retention; @@ -34,6 +33,7 @@ import java.net.Inet6Address; import java.net.UnknownHostException; import java.security.SecureRandom; import java.util.Arrays; +import java.util.Objects; /** * Representation of a MAC address. @@ -229,7 +229,7 @@ public final class MacAddress implements Parcelable { * @hide */ public static @NonNull byte[] byteAddrFromStringAddr(String addr) { - Preconditions.checkNotNull(addr); + Objects.requireNonNull(addr); String[] parts = addr.split(":"); if (parts.length != ETHER_ADDR_LEN) { throw new IllegalArgumentException(addr + " was not a valid MAC address"); @@ -275,7 +275,7 @@ public final class MacAddress implements Parcelable { // Internal conversion function equivalent to longAddrFromByteAddr(byteAddrFromStringAddr(addr)) // that avoids the allocation of an intermediary byte[]. private static long longAddrFromStringAddr(String addr) { - Preconditions.checkNotNull(addr); + Objects.requireNonNull(addr); String[] parts = addr.split(":"); if (parts.length != ETHER_ADDR_LEN) { throw new IllegalArgumentException(addr + " was not a valid MAC address"); @@ -364,8 +364,8 @@ public final class MacAddress implements Parcelable { * */ public boolean matches(@NonNull MacAddress baseAddress, @NonNull MacAddress mask) { - Preconditions.checkNotNull(baseAddress); - Preconditions.checkNotNull(mask); + Objects.requireNonNull(baseAddress); + Objects.requireNonNull(mask); return (mAddr & mask.mAddr) == (baseAddress.mAddr & mask.mAddr); } diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgent.java b/packages/Connectivity/framework/src/android/net/NetworkAgent.java index a127c6f6de26..6b55bb771c30 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkAgent.java +++ b/packages/Connectivity/framework/src/android/net/NetworkAgent.java @@ -32,10 +32,9 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.telephony.data.EpsBearerQosSessionAttributes; +import android.telephony.data.NrQosSessionAttributes; import android.util.Log; -import com.android.connectivity.aidl.INetworkAgent; -import com.android.connectivity.aidl.INetworkAgentRegistry; import com.android.internal.annotations.VisibleForTesting; import java.lang.annotation.Retention; @@ -363,10 +362,25 @@ public abstract class NetworkAgent { */ public static final int CMD_UNREGISTER_QOS_CALLBACK = BASE + 21; + /** + * Sent by ConnectivityService to {@link NetworkAgent} to inform the agent that its native + * network was created and the Network object is now valid. + * + * @hide + */ + public static final int CMD_NETWORK_CREATED = BASE + 22; + + /** + * Sent by ConnectivityService to {@link NetworkAgent} to inform the agent that its native + * network was destroyed. + * + * @hide + */ + public static final int CMD_NETWORK_DISCONNECTED = BASE + 23; + private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) { - // The subtype can be changed with (TODO) setLegacySubtype, but it starts - // with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description. - final NetworkInfo ni = new NetworkInfo(config.legacyType, 0, config.legacyTypeName, ""); + final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacySubType, + config.legacyTypeName, config.legacySubTypeName); ni.setIsAvailable(true); ni.setDetailedState(NetworkInfo.DetailedState.CONNECTING, null /* reason */, config.getLegacyExtraInfo()); @@ -392,7 +406,6 @@ public abstract class NetworkAgent { * @param score the initial score of this network. Update with sendNetworkScore. * @param config an immutable {@link NetworkAgentConfig} for this agent. * @param provider the {@link NetworkProvider} managing this agent. - * @hide TODO : unhide when impl is complete */ public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag, @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, @@ -436,7 +449,7 @@ public abstract class NetworkAgent { } mInitialConfiguration = new InitialConfiguration(context, - new NetworkCapabilities(nc, /* parcelLocationSensitiveFields */ true), + new NetworkCapabilities(nc, NetworkCapabilities.REDACT_NONE), new LinkProperties(lp), score, config, ni); } @@ -564,6 +577,14 @@ public abstract class NetworkAgent { msg.arg1 /* QoS callback id */); break; } + case CMD_NETWORK_CREATED: { + onNetworkCreated(); + break; + } + case CMD_NETWORK_DISCONNECTED: { + onNetworkDisconnected(); + break; + } } } } @@ -704,6 +725,16 @@ public abstract class NetworkAgent { mHandler.sendMessage(mHandler.obtainMessage( CMD_UNREGISTER_QOS_CALLBACK, qosCallbackId, 0, null)); } + + @Override + public void onNetworkCreated() { + mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_CREATED)); + } + + @Override + public void onNetworkDisconnected() { + mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_DISCONNECTED)); + } } /** @@ -831,6 +862,7 @@ public abstract class NetworkAgent { * @hide */ @Deprecated + @SystemApi public void setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName) { mNetworkInfo.setSubtype(legacySubtype, legacySubtypeName); queueOrSendNetworkInfo(mNetworkInfo); @@ -880,8 +912,7 @@ public abstract class NetworkAgent { mBandwidthUpdatePending.set(false); mLastBwRefreshTime = System.currentTimeMillis(); final NetworkCapabilities nc = - new NetworkCapabilities(networkCapabilities, - /* parcelLocationSensitiveFields */ true); + new NetworkCapabilities(networkCapabilities, NetworkCapabilities.REDACT_NONE); queueOrSendMessage(reg -> reg.sendNetworkCapabilities(nc)); } @@ -965,6 +996,7 @@ public abstract class NetworkAgent { * shall try to overwrite this method and produce a bandwidth update if capable. * @hide */ + @SystemApi public void onBandwidthUpdateRequested() { pollLceData(); } @@ -1013,6 +1045,17 @@ public abstract class NetworkAgent { } /** + * Called when ConnectivityService has successfully created this NetworkAgent's native network. + */ + public void onNetworkCreated() {} + + + /** + * Called when ConnectivityService has successfully destroy this NetworkAgent's native network. + */ + public void onNetworkDisconnected() {} + + /** * Requests that the network hardware send the specified packet at the specified interval. * * @param slot the hardware slot on which to start the keepalive. @@ -1163,29 +1206,37 @@ public abstract class NetworkAgent { /** - * Sends the attributes of Eps Bearer Qos Session back to the Application + * Sends the attributes of Qos Session back to the Application * * @param qosCallbackId the callback id that the session belongs to - * @param sessionId the unique session id across all Eps Bearer Qos Sessions - * @param attributes the attributes of the Eps Qos Session + * @param sessionId the unique session id across all Qos Sessions + * @param attributes the attributes of the Qos Session */ public final void sendQosSessionAvailable(final int qosCallbackId, final int sessionId, - @NonNull final EpsBearerQosSessionAttributes attributes) { + @NonNull final QosSessionAttributes attributes) { Objects.requireNonNull(attributes, "The attributes must be non-null"); - queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId, - new QosSession(sessionId, QosSession.TYPE_EPS_BEARER), - attributes)); + if (attributes instanceof EpsBearerQosSessionAttributes) { + queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId, + new QosSession(sessionId, QosSession.TYPE_EPS_BEARER), + (EpsBearerQosSessionAttributes)attributes)); + } else if (attributes instanceof NrQosSessionAttributes) { + queueOrSendMessage(ra -> ra.sendNrQosSessionAvailable(qosCallbackId, + new QosSession(sessionId, QosSession.TYPE_NR_BEARER), + (NrQosSessionAttributes)attributes)); + } } /** - * Sends event that the Eps Qos Session was lost. + * Sends event that the Qos Session was lost. * * @param qosCallbackId the callback id that the session belongs to - * @param sessionId the unique session id across all Eps Bearer Qos Sessions + * @param sessionId the unique session id across all Qos Sessions + * @param qosSessionType the session type {@code QosSesson#QosSessionType} */ - public final void sendQosSessionLost(final int qosCallbackId, final int sessionId) { + public final void sendQosSessionLost(final int qosCallbackId, + final int sessionId, final int qosSessionType) { queueOrSendMessage(ra -> ra.sendQosSessionLost(qosCallbackId, - new QosSession(sessionId, QosSession.TYPE_EPS_BEARER))); + new QosSession(sessionId, qosSessionType))); } /** diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java index 5e50a6404acb..3f058d8cbf12 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java +++ b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java @@ -64,6 +64,16 @@ public final class NetworkAgentConfig implements Parcelable { } /** + * @return whether this VPN connection can be bypassed by the apps. + * + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public boolean isBypassableVpn() { + return allowBypass; + } + + /** * Set if the user desires to use this network even if it is unvalidated. This field has meaning * only if {@link explicitlySelected} is true. If it is, this field must also be set to the * appropriate value based on previous user choice. @@ -165,6 +175,12 @@ public final class NetworkAgentConfig implements Parcelable { } /** + * The legacy Sub type of this network agent, or TYPE_NONE if unset. + * @hide + */ + public int legacySubType = ConnectivityManager.TYPE_NONE; + + /** * Set to true if the PRIVATE_DNS_BROKEN notification has shown for this network. * Reset this bit when private DNS mode is changed from strict mode to opportunistic/off mode. * @@ -190,6 +206,13 @@ public final class NetworkAgentConfig implements Parcelable { } /** + * The name of the legacy Sub network type. It's a free-form string. + * @hide + */ + @NonNull + public String legacySubTypeName = ""; + + /** * The legacy extra info of the agent. The extra info should only be : * <ul> * <li>For cellular agents, the APN name.</li> @@ -225,6 +248,8 @@ public final class NetworkAgentConfig implements Parcelable { skip464xlat = nac.skip464xlat; legacyType = nac.legacyType; legacyTypeName = nac.legacyTypeName; + legacySubType = nac.legacySubType; + legacySubTypeName = nac.legacySubTypeName; mLegacyExtraInfo = nac.mLegacyExtraInfo; } } @@ -290,7 +315,6 @@ public final class NetworkAgentConfig implements Parcelable { * and reduce idle traffic on networks that are known to be IPv6-only without a NAT64. * * @return this builder, to facilitate chaining. - * @hide */ @NonNull public Builder disableNat64Detection() { @@ -303,7 +327,6 @@ public final class NetworkAgentConfig implements Parcelable { * perform its own carrier-specific provisioning procedure. * * @return this builder, to facilitate chaining. - * @hide */ @NonNull public Builder disableProvisioningNotification() { @@ -324,6 +347,18 @@ public final class NetworkAgentConfig implements Parcelable { } /** + * Sets the legacy sub-type for this network. + * + * @param legacySubType the type + * @return this builder, to facilitate chaining. + */ + @NonNull + public Builder setLegacySubType(final int legacySubType) { + mConfig.legacySubType = legacySubType; + return this; + } + + /** * Sets the name of the legacy type of the agent. It's a free-form string used in logging. * @param legacyTypeName the name * @return this builder, to facilitate chaining. @@ -335,10 +370,20 @@ public final class NetworkAgentConfig implements Parcelable { } /** + * Sets the name of the legacy Sub-type of the agent. It's a free-form string. + * @param legacySubTypeName the name + * @return this builder, to facilitate chaining. + */ + @NonNull + public Builder setLegacySubTypeName(@NonNull String legacySubTypeName) { + mConfig.legacySubTypeName = legacySubTypeName; + return this; + } + + /** * Sets the legacy extra info of the agent. * @param legacyExtraInfo the legacy extra info. * @return this builder, to facilitate chaining. - * @hide */ @NonNull public Builder setLegacyExtraInfo(@NonNull String legacyExtraInfo) { @@ -347,6 +392,19 @@ public final class NetworkAgentConfig implements Parcelable { } /** + * Sets whether the apps can bypass the VPN connection. + * + * @return this builder, to facilitate chaining. + * @hide + */ + @NonNull + @SystemApi(client = MODULE_LIBRARIES) + public Builder setBypassableVpn(boolean allowBypass) { + mConfig.allowBypass = allowBypass; + return this; + } + + /** * Returns the constructed {@link NetworkAgentConfig} object. */ @NonNull @@ -412,6 +470,8 @@ public final class NetworkAgentConfig implements Parcelable { out.writeInt(skip464xlat ? 1 : 0); out.writeInt(legacyType); out.writeString(legacyTypeName); + out.writeInt(legacySubType); + out.writeString(legacySubTypeName); out.writeString(mLegacyExtraInfo); } @@ -429,6 +489,8 @@ public final class NetworkAgentConfig implements Parcelable { networkAgentConfig.skip464xlat = in.readInt() != 0; networkAgentConfig.legacyType = in.readInt(); networkAgentConfig.legacyTypeName = in.readString(); + networkAgentConfig.legacySubType = in.readInt(); + networkAgentConfig.legacySubTypeName = in.readString(); networkAgentConfig.mLegacyExtraInfo = in.readString(); return networkAgentConfig; } diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java index 5ec7aa1b23ac..881fa8c2702c 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java +++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java @@ -19,9 +19,11 @@ package android.net; import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; import android.annotation.IntDef; +import android.annotation.LongDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.net.ConnectivityManager.NetworkCallback; @@ -32,10 +34,10 @@ import android.os.Parcelable; import android.os.Process; import android.text.TextUtils; import android.util.ArraySet; +import android.util.Range; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.NetworkCapabilitiesUtils; @@ -63,6 +65,68 @@ import java.util.StringJoiner; public final class NetworkCapabilities implements Parcelable { private static final String TAG = "NetworkCapabilities"; + /** + * Mechanism to support redaction of fields in NetworkCapabilities that are guarded by specific + * app permissions. + **/ + /** + * Don't redact any fields since the receiving app holds all the necessary permissions. + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final long REDACT_NONE = 0; + + /** + * Redact any fields that need {@link android.Manifest.permission#ACCESS_FINE_LOCATION} + * permission since the receiving app does not hold this permission or the location toggle + * is off. + * + * @see android.Manifest.permission#ACCESS_FINE_LOCATION + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1 << 0; + + /** + * Redact any fields that need {@link android.Manifest.permission#LOCAL_MAC_ADDRESS} + * permission since the receiving app does not hold this permission. + * + * @see android.Manifest.permission#LOCAL_MAC_ADDRESS + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 1 << 1; + + /** + * + * Redact any fields that need {@link android.Manifest.permission#NETWORK_SETTINGS} + * permission since the receiving app does not hold this permission. + * + * @see android.Manifest.permission#NETWORK_SETTINGS + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final long REDACT_FOR_NETWORK_SETTINGS = 1 << 2; + + /** + * Redact all fields in this object that require any relevant permission. + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final long REDACT_ALL = -1L; + + /** @hide */ + @LongDef(flag = true, prefix = { "REDACT_" }, value = { + REDACT_NONE, + REDACT_FOR_ACCESS_FINE_LOCATION, + REDACT_FOR_LOCAL_MAC_ADDRESS, + REDACT_FOR_NETWORK_SETTINGS, + REDACT_ALL + }) + @Retention(RetentionPolicy.SOURCE) + public @interface RedactionType {} + // Set to true when private DNS is broken. private boolean mPrivateDnsBroken; @@ -77,32 +141,31 @@ public final class NetworkCapabilities implements Parcelable { private String mRequestorPackageName; /** - * Indicates whether parceling should preserve fields that are set based on permissions of - * the process receiving the {@link NetworkCapabilities}. + * Indicates what fields should be redacted from this instance. */ - private final boolean mParcelLocationSensitiveFields; + private final @RedactionType long mRedactions; public NetworkCapabilities() { - mParcelLocationSensitiveFields = false; + mRedactions = REDACT_ALL; clearAll(); mNetworkCapabilities = DEFAULT_CAPABILITIES; } public NetworkCapabilities(NetworkCapabilities nc) { - this(nc, false /* parcelLocationSensitiveFields */); + this(nc, REDACT_ALL); } /** * Make a copy of NetworkCapabilities. * * @param nc Original NetworkCapabilities - * @param parcelLocationSensitiveFields Whether to parcel location sensitive data or not. + * @param redactions bitmask of redactions that needs to be performed on this new instance of + * {@link NetworkCapabilities}. * @hide */ - @SystemApi - public NetworkCapabilities( - @Nullable NetworkCapabilities nc, boolean parcelLocationSensitiveFields) { - mParcelLocationSensitiveFields = parcelLocationSensitiveFields; + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public NetworkCapabilities(@Nullable NetworkCapabilities nc, @RedactionType long redactions) { + mRedactions = redactions; if (nc != null) { set(nc); } @@ -114,11 +177,13 @@ public final class NetworkCapabilities implements Parcelable { * @hide */ public void clearAll() { - // Ensures that the internal copies maintained by the connectivity stack does not set - // this bit. - if (mParcelLocationSensitiveFields) { + // Ensures that the internal copies maintained by the connectivity stack does not set it to + // anything other than |REDACT_ALL|. + if (mRedactions != REDACT_ALL) { + // This is needed because the current redaction mechanism relies on redaction while + // parceling. throw new UnsupportedOperationException( - "Cannot clear NetworkCapabilities when parcelLocationSensitiveFields is set"); + "Cannot clear NetworkCapabilities when mRedactions is set"); } mNetworkCapabilities = mTransportTypes = mUnwantedNetworkCapabilities = 0; mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED; @@ -148,12 +213,12 @@ public final class NetworkCapabilities implements Parcelable { mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps; mNetworkSpecifier = nc.mNetworkSpecifier; if (nc.getTransportInfo() != null) { - setTransportInfo(nc.getTransportInfo().makeCopy(mParcelLocationSensitiveFields)); + setTransportInfo(nc.getTransportInfo().makeCopy(mRedactions)); } else { setTransportInfo(null); } mSignalStrength = nc.mSignalStrength; - setUids(nc.mUids); // Will make the defensive copy + mUids = (nc.mUids == null) ? null : new ArraySet<>(nc.mUids); setAdministratorUids(nc.getAdministratorUids()); mOwnerUid = nc.mOwnerUid; mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities; @@ -574,19 +639,31 @@ public final class NetworkCapabilities implements Parcelable { } /** - * Removes (if found) the given capability from this {@code NetworkCapability} instance. + * Removes (if found) the given capability from this {@code NetworkCapability} + * instance that were added via addCapability(int) or setCapabilities(int[], int[]). * * @param capability the capability to be removed. * @return This NetworkCapabilities instance, to facilitate chaining. * @hide */ public @NonNull NetworkCapabilities removeCapability(@NetCapability int capability) { - // Note that this method removes capabilities that were added via addCapability(int), - // addUnwantedCapability(int) or setCapabilities(int[], int[]). checkValidCapability(capability); final long mask = ~(1 << capability); mNetworkCapabilities &= mask; - mUnwantedNetworkCapabilities &= mask; + return this; + } + + /** + * Removes (if found) the given unwanted capability from this {@code NetworkCapability} + * instance that were added via addUnwantedCapability(int) or setCapabilities(int[], int[]). + * + * @param capability the capability to be removed. + * @return This NetworkCapabilities instance, to facilitate chaining. + * @hide + */ + public @NonNull NetworkCapabilities removeUnwantedCapability(@NetCapability int capability) { + checkValidCapability(capability); + mUnwantedNetworkCapabilities &= ~(1 << capability); return this; } @@ -658,6 +735,7 @@ public final class NetworkCapabilities implements Parcelable { } /** @hide */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public boolean hasUnwantedCapability(@NetCapability int capability) { return isValidCapability(capability) && ((mUnwantedNetworkCapabilities & (1 << capability)) != 0); @@ -671,10 +749,16 @@ public final class NetworkCapabilities implements Parcelable { return ((mNetworkCapabilities & CONNECTIVITY_MANAGED_CAPABILITIES) != 0); } - /** Note this method may result in having the same capability in wanted and unwanted lists. */ private void combineNetCapabilities(@NonNull NetworkCapabilities nc) { - this.mNetworkCapabilities |= nc.mNetworkCapabilities; - this.mUnwantedNetworkCapabilities |= nc.mUnwantedNetworkCapabilities; + final long wantedCaps = this.mNetworkCapabilities | nc.mNetworkCapabilities; + final long unwantedCaps = + this.mUnwantedNetworkCapabilities | nc.mUnwantedNetworkCapabilities; + if ((wantedCaps & unwantedCaps) != 0) { + throw new IllegalArgumentException( + "Cannot have the same capability in wanted and unwanted lists."); + } + this.mNetworkCapabilities = wantedCaps; + this.mUnwantedNetworkCapabilities = unwantedCaps; } /** @@ -1456,9 +1540,8 @@ public final class NetworkCapabilities implements Parcelable { * @hide */ public @NonNull NetworkCapabilities setSingleUid(int uid) { - final ArraySet<UidRange> identity = new ArraySet<>(1); - identity.add(new UidRange(uid, uid)); - setUids(identity); + mUids = new ArraySet<>(1); + mUids.add(new UidRange(uid, uid)); return this; } @@ -1467,22 +1550,34 @@ public final class NetworkCapabilities implements Parcelable { * This makes a copy of the set so that callers can't modify it after the call. * @hide */ - public @NonNull NetworkCapabilities setUids(Set<UidRange> uids) { - if (null == uids) { - mUids = null; - } else { - mUids = new ArraySet<>(uids); - } + public @NonNull NetworkCapabilities setUids(@Nullable Set<Range<Integer>> uids) { + mUids = UidRange.fromIntRanges(uids); return this; } /** * Get the list of UIDs this network applies to. * This returns a copy of the set so that callers can't modify the original object. + * + * @return the list of UIDs this network applies to. If {@code null}, then the network applies + * to all UIDs. + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @SuppressLint("NullableCollection") + public @Nullable Set<Range<Integer>> getUids() { + return UidRange.toIntRanges(mUids); + } + + /** + * Get the list of UIDs this network applies to. + * This returns a copy of the set so that callers can't modify the original object. * @hide */ - public @Nullable Set<UidRange> getUids() { - return null == mUids ? null : new ArraySet<>(mUids); + public @Nullable Set<UidRange> getUidRanges() { + if (mUids == null) return null; + + return new ArraySet<>(mUids); } /** @@ -2097,8 +2192,9 @@ public final class NetworkCapabilities implements Parcelable { } private static void checkValidTransportType(@Transport int transport) { - Preconditions.checkArgument( - isValidTransport(transport), "Invalid TransportType " + transport); + if (!isValidTransport(transport)) { + throw new IllegalArgumentException("Invalid TransportType " + transport); + } } private static boolean isValidCapability(@NetworkCapabilities.NetCapability int capability) { @@ -2106,8 +2202,9 @@ public final class NetworkCapabilities implements Parcelable { } private static void checkValidCapability(@NetworkCapabilities.NetCapability int capability) { - Preconditions.checkArgument(isValidCapability(capability), - "NetworkCapability " + capability + "out of range"); + if (!isValidCapability(capability)) { + throw new IllegalArgumentException("NetworkCapability " + capability + "out of range"); + } } /** @@ -2336,6 +2433,23 @@ public final class NetworkCapabilities implements Parcelable { } /** + * Returns a bitmask of all the applicable redactions (based on the permissions held by the + * receiving app) to be performed on this object. + * + * @return bitmask of redactions applicable on this instance. + * @hide + */ + public @RedactionType long getApplicableRedactions() { + // Currently, there are no fields redacted in NetworkCapabilities itself, so we just + // passthrough the redactions required by the embedded TransportInfo. If this changes + // in the future, modify this method. + if (mTransportInfo == null) { + return NetworkCapabilities.REDACT_NONE; + } + return mTransportInfo.getApplicableRedactions(); + } + + /** * Builder class for NetworkCapabilities. * * This class is mainly for for {@link NetworkAgent} instances to use. Many fields in @@ -2653,6 +2767,21 @@ public final class NetworkCapabilities implements Parcelable { } /** + * Set the list of UIDs this network applies to. + * + * @param uids the list of UIDs this network applies to, or {@code null} if this network + * applies to all UIDs. + * @return this builder + * @hide + */ + @NonNull + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public Builder setUids(@Nullable Set<Range<Integer>> uids) { + mCaps.setUids(uids); + return this; + } + + /** * Builds the instance of the capabilities. * * @return the built instance of NetworkCapabilities. diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java index dbe3ecc4d775..bcbc04f72efc 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java +++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java @@ -36,6 +36,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_TEST; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.net.NetworkCapabilities.NetCapability; @@ -45,6 +46,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.Process; import android.text.TextUtils; +import android.util.Range; import android.util.proto.ProtoOutputStream; import java.util.Arrays; @@ -214,6 +216,14 @@ public class NetworkRequest implements Parcelable { } /** + * Creates a new Builder of NetworkRequest from an existing instance. + */ + public Builder(@NonNull final NetworkRequest request) { + Objects.requireNonNull(request); + mNetworkCapabilities = request.networkCapabilities; + } + + /** * Build {@link NetworkRequest} give the current set of capabilities. */ public NetworkRequest build() { @@ -277,11 +287,14 @@ public class NetworkRequest implements Parcelable { * Set the watched UIDs for this request. This will be reset and wiped out unless * the calling app holds the CHANGE_NETWORK_STATE permission. * - * @param uids The watched UIDs as a set of UidRanges, or null for everything. + * @param uids The watched UIDs as a set of {@code Range<Integer>}, or null for everything. * @return The builder to facilitate chaining. * @hide */ - public Builder setUids(Set<UidRange> uids) { + @NonNull + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @SuppressLint("MissingGetterMatchingBuilder") + public Builder setUids(@Nullable Set<Range<Integer>> uids) { mNetworkCapabilities.setUids(uids); return this; } @@ -300,12 +313,31 @@ public class NetworkRequest implements Parcelable { * * @hide */ + @NonNull + @SuppressLint("MissingGetterMatchingBuilder") + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public Builder addUnwantedCapability(@NetworkCapabilities.NetCapability int capability) { mNetworkCapabilities.addUnwantedCapability(capability); return this; } /** + * Removes (if found) the given unwanted capability from this builder instance. + * + * @param capability The unwanted capability to remove. + * @return The builder to facilitate chaining. + * + * @hide + */ + @NonNull + @SuppressLint("BuilderSetStyle") + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public Builder removeUnwantedCapability(@NetworkCapabilities.NetCapability int capability) { + mNetworkCapabilities.removeUnwantedCapability(capability); + return this; + } + + /** * Completely clears all the {@code NetworkCapabilities} from this builder instance, * removing even the capabilities that are set by default when the object is constructed. * @@ -562,6 +594,7 @@ public class NetworkRequest implements Parcelable { * * @hide */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public boolean hasUnwantedCapability(@NetCapability int capability) { return networkCapabilities.hasUnwantedCapability(capability); } diff --git a/packages/Connectivity/framework/src/android/net/NetworkScore.java b/packages/Connectivity/framework/src/android/net/NetworkScore.java index eadcb2d0a7f4..65849930fa4a 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkScore.java +++ b/packages/Connectivity/framework/src/android/net/NetworkScore.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.NonNull; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -29,7 +30,7 @@ import com.android.internal.annotations.VisibleForTesting; * network is considered for a particular use. * @hide */ -// TODO : @SystemApi when the implementation is complete +@SystemApi public final class NetworkScore implements Parcelable { // This will be removed soon. Do *NOT* depend on it for any new code that is not part of // a migration. @@ -62,6 +63,8 @@ public final class NetworkScore implements Parcelable { /** * @return whether this score has a particular policy. + * + * @hide */ @VisibleForTesting public boolean hasPolicy(final int policy) { diff --git a/packages/Connectivity/framework/src/android/net/NetworkUtils.java b/packages/Connectivity/framework/src/android/net/NetworkUtils.java index c0f262815b0c..a92fda1cde46 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkUtils.java +++ b/packages/Connectivity/framework/src/android/net/NetworkUtils.java @@ -92,7 +92,10 @@ public class NetworkUtils { * Determine if {@code uid} can access network designated by {@code netId}. * @return {@code true} if {@code uid} can access network, {@code false} otherwise. */ - public native static boolean queryUserAccess(int uid, int netId); + public static boolean queryUserAccess(int uid, int netId) { + // TODO (b/183485986): remove this method + return false; + } /** * DNS resolver series jni method. @@ -323,22 +326,7 @@ public class NetworkUtils { */ @UnsupportedAppUsage public static String trimV4AddrZeros(String addr) { - if (addr == null) return null; - String[] octets = addr.split("\\."); - if (octets.length != 4) return addr; - StringBuilder builder = new StringBuilder(16); - String result = null; - for (int i = 0; i < 4; i++) { - try { - if (octets[i].length() > 3) return addr; - builder.append(Integer.parseInt(octets[i])); - } catch (NumberFormatException e) { - return addr; - } - if (i < 3) builder.append('.'); - } - result = builder.toString(); - return result; + return Inet4AddressUtils.trimAddressZeros(addr); } /** diff --git a/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java b/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java index bdb4ad68cd7b..de0fc243b43b 100644 --- a/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java +++ b/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java @@ -19,6 +19,7 @@ package android.net; import android.annotation.NonNull; import android.annotation.Nullable; import android.telephony.data.EpsBearerQosSessionAttributes; +import android.telephony.data.NrQosSessionAttributes; import com.android.internal.annotations.VisibleForTesting; @@ -84,6 +85,25 @@ class QosCallbackConnection extends android.net.IQosCallback.Stub { } /** + * Called when either the {@link NrQosSessionAttributes} has changed or on the first time + * the attributes have become available. + * + * @param session the session that is now available + * @param attributes the corresponding attributes of session + */ + @Override + public void onNrQosSessionAvailable(@NonNull final QosSession session, + @NonNull final NrQosSessionAttributes attributes) { + + mExecutor.execute(() -> { + final QosCallback callback = mCallback; + if (callback != null) { + callback.onQosSessionAvailable(session, attributes); + } + }); + } + + /** * Called when the session is lost. * * @param session the session that was lost diff --git a/packages/Connectivity/framework/src/android/net/QosSession.java b/packages/Connectivity/framework/src/android/net/QosSession.java index 4f3bb77c5877..93f2ff2bf724 100644 --- a/packages/Connectivity/framework/src/android/net/QosSession.java +++ b/packages/Connectivity/framework/src/android/net/QosSession.java @@ -36,6 +36,11 @@ public final class QosSession implements Parcelable { */ public static final int TYPE_EPS_BEARER = 1; + /** + * The {@link QosSession} is a NR Session. + */ + public static final int TYPE_NR_BEARER = 2; + private final int mSessionId; private final int mSessionType; @@ -100,6 +105,7 @@ public final class QosSession implements Parcelable { */ @IntDef(value = { TYPE_EPS_BEARER, + TYPE_NR_BEARER, }) @interface QosSessionType {} diff --git a/packages/Connectivity/framework/src/android/net/SocketKeepalive.java b/packages/Connectivity/framework/src/android/net/SocketKeepalive.java index d007a9520cb5..f6cae7251609 100644 --- a/packages/Connectivity/framework/src/android/net/SocketKeepalive.java +++ b/packages/Connectivity/framework/src/android/net/SocketKeepalive.java @@ -55,36 +55,68 @@ public abstract class SocketKeepalive implements AutoCloseable { static final String TAG = "SocketKeepalive"; /** - * No errors. + * Success. It indicates there is no error. * @hide */ @SystemApi public static final int SUCCESS = 0; - /** @hide */ + /** + * No keepalive. This should only be internally as it indicates There is no keepalive. + * It should not propagate to applications. + * @hide + */ public static final int NO_KEEPALIVE = -1; - /** @hide */ + /** + * Data received. + * @hide + */ public static final int DATA_RECEIVED = -2; - /** @hide */ + /** + * The binder died. + * @hide + */ public static final int BINDER_DIED = -10; - /** The specified {@code Network} is not connected. */ + /** + * The invalid network. It indicates the specified {@code Network} is not connected. + */ public static final int ERROR_INVALID_NETWORK = -20; - /** The specified IP addresses are invalid. For example, the specified source IP address is - * not configured on the specified {@code Network}. */ + + /** + * The invalid IP addresses. Indicates the specified IP addresses are invalid. + * For example, the specified source IP address is not configured on the + * specified {@code Network}. + */ public static final int ERROR_INVALID_IP_ADDRESS = -21; - /** The requested port is invalid. */ + + /** + * The port is invalid. + */ public static final int ERROR_INVALID_PORT = -22; - /** The packet length is invalid (e.g., too long). */ + + /** + * The length is invalid (e.g. too long). + */ public static final int ERROR_INVALID_LENGTH = -23; - /** The packet transmission interval is invalid (e.g., too short). */ + + /** + * The interval is invalid (e.g. too short). + */ public static final int ERROR_INVALID_INTERVAL = -24; - /** The target socket is invalid. */ + + /** + * The socket is invalid. + */ public static final int ERROR_INVALID_SOCKET = -25; - /** The target socket is not idle. */ + + /** + * The socket is not idle. + */ public static final int ERROR_SOCKET_NOT_IDLE = -26; + /** * The stop reason is uninitialized. This should only be internally used as initial state * of stop reason, instead of propagating to application. @@ -92,15 +124,29 @@ public abstract class SocketKeepalive implements AutoCloseable { */ public static final int ERROR_STOP_REASON_UNINITIALIZED = -27; - /** The device does not support this request. */ + /** + * The request is unsupported. + */ public static final int ERROR_UNSUPPORTED = -30; - /** @hide TODO: delete when telephony code has been updated. */ - public static final int ERROR_HARDWARE_UNSUPPORTED = ERROR_UNSUPPORTED; - /** The hardware returned an error. */ + + /** + * There was a hardware error. + */ public static final int ERROR_HARDWARE_ERROR = -31; - /** The limitation of resource is reached. */ + + /** + * Resources are insufficient (e.g. all hardware slots are in use). + */ public static final int ERROR_INSUFFICIENT_RESOURCES = -32; + /** + * There was no such slot. This should only be internally as it indicates + * a programming error in the system server. It should not propagate to + * applications. + * @hide + */ + @SystemApi + public static final int ERROR_NO_SUCH_SLOT = -33; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -111,7 +157,8 @@ public abstract class SocketKeepalive implements AutoCloseable { ERROR_INVALID_LENGTH, ERROR_INVALID_INTERVAL, ERROR_INVALID_SOCKET, - ERROR_SOCKET_NOT_IDLE + ERROR_SOCKET_NOT_IDLE, + ERROR_NO_SUCH_SLOT }) public @interface ErrorCode {} @@ -122,7 +169,6 @@ public abstract class SocketKeepalive implements AutoCloseable { ERROR_INVALID_LENGTH, ERROR_UNSUPPORTED, ERROR_INSUFFICIENT_RESOURCES, - ERROR_HARDWARE_UNSUPPORTED }) public @interface KeepaliveEvent {} diff --git a/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java b/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java index ce545974f5cb..7904f7a4ec17 100644 --- a/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java +++ b/packages/Connectivity/framework/src/android/net/StaticIpConfiguration.java @@ -24,7 +24,6 @@ import android.os.Build; import android.os.Parcel; import android.os.Parcelable; -import com.android.internal.util.Preconditions; import com.android.net.module.util.InetAddressUtils; import java.net.InetAddress; @@ -153,7 +152,7 @@ public final class StaticIpConfiguration implements Parcelable { * @return The {@link Builder} for chaining. */ public @NonNull Builder setDnsServers(@NonNull Iterable<InetAddress> dnsServers) { - Preconditions.checkNotNull(dnsServers); + Objects.requireNonNull(dnsServers); mDnsServers = dnsServers; return this; } diff --git a/packages/Connectivity/framework/src/android/net/TestNetworkManager.java b/packages/Connectivity/framework/src/android/net/TestNetworkManager.java index a174a7be85d1..a7a62351e5be 100644 --- a/packages/Connectivity/framework/src/android/net/TestNetworkManager.java +++ b/packages/Connectivity/framework/src/android/net/TestNetworkManager.java @@ -21,10 +21,9 @@ import android.annotation.SystemApi; import android.os.IBinder; import android.os.RemoteException; -import com.android.internal.util.Preconditions; - import java.util.Arrays; import java.util.Collection; +import java.util.Objects; /** * Class that allows creation and management of per-app, test-only networks @@ -50,7 +49,7 @@ public class TestNetworkManager { /** @hide */ public TestNetworkManager(@NonNull ITestNetworkManager service) { - mService = Preconditions.checkNotNull(service, "missing ITestNetworkManager"); + mService = Objects.requireNonNull(service, "missing ITestNetworkManager"); } /** @@ -93,7 +92,7 @@ public class TestNetworkManager { */ public void setupTestNetwork( @NonNull LinkProperties lp, boolean isMetered, @NonNull IBinder binder) { - Preconditions.checkNotNull(lp, "Invalid LinkProperties"); + Objects.requireNonNull(lp, "Invalid LinkProperties"); setupTestNetwork(lp.getInterfaceName(), lp, isMetered, new int[0], binder); } diff --git a/packages/Connectivity/framework/src/android/net/TestNetworkSpecifier.java b/packages/Connectivity/framework/src/android/net/TestNetworkSpecifier.java index b7470a591d20..117457dffc9f 100644 --- a/packages/Connectivity/framework/src/android/net/TestNetworkSpecifier.java +++ b/packages/Connectivity/framework/src/android/net/TestNetworkSpecifier.java @@ -23,8 +23,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; -import com.android.internal.util.Preconditions; - import java.util.Objects; /** @@ -43,7 +41,9 @@ public final class TestNetworkSpecifier extends NetworkSpecifier implements Parc private final String mInterfaceName; public TestNetworkSpecifier(@NonNull String interfaceName) { - Preconditions.checkStringNotEmpty(interfaceName); + if (TextUtils.isEmpty(interfaceName)) { + throw new IllegalArgumentException("Empty interfaceName"); + } mInterfaceName = interfaceName; } diff --git a/packages/Connectivity/framework/src/android/net/TransportInfo.java b/packages/Connectivity/framework/src/android/net/TransportInfo.java index aa4bbb051179..fa889eabb842 100644 --- a/packages/Connectivity/framework/src/android/net/TransportInfo.java +++ b/packages/Connectivity/framework/src/android/net/TransportInfo.java @@ -29,35 +29,47 @@ import android.annotation.SystemApi; public interface TransportInfo { /** - * Create a copy of a {@link TransportInfo} that will preserve location sensitive fields that - * were set based on the permissions of the process that originally received it. + * Create a copy of a {@link TransportInfo} with some fields redacted based on the permissions + * held by the receiving app. * - * <p>By default {@link TransportInfo} does not preserve such fields during parceling, as - * they should not be shared outside of the process that receives them without appropriate - * checks. + * <p> + * Usage by connectivity stack: + * <ul> + * <li> Connectivity stack will invoke {@link #getApplicableRedactions()} to find the list + * of redactions that are required by this {@link TransportInfo} instance.</li> + * <li> Connectivity stack then loops through each bit in the bitmask returned and checks if the + * receiving app holds the corresponding permission. + * <ul> + * <li> If the app holds the corresponding permission, the bit is cleared from the + * |redactions| bitmask. </li> + * <li> If the app does not hold the corresponding permission, the bit is retained in the + * |redactions| bitmask. </li> + * </ul> + * <li> Connectivity stack then invokes {@link #makeCopy(long)} with the necessary |redactions| + * to create a copy to send to the corresponding app. </li> + * </ul> + * </p> * - * @param parcelLocationSensitiveFields Whether the location sensitive fields should be kept - * when parceling - * @return Copy of this instance. + * @param redactions bitmask of redactions that needs to be performed on this instance. + * @return Copy of this instance with the necessary redactions. * @hide */ - @SystemApi + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @NonNull - default TransportInfo makeCopy(boolean parcelLocationSensitiveFields) { + default TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) { return this; } /** - * Returns whether this TransportInfo type has location sensitive fields or not (helps - * to determine whether to perform a location permission check or not before sending to - * apps). + * Returns a bitmask of all the applicable redactions (based on the permissions held by the + * receiving app) to be performed on this TransportInfo. * - * @return {@code true} if this instance contains location sensitive info, {@code false} - * otherwise. + * @return bitmask of redactions applicable on this instance. + * @see #makeCopy(long) * @hide */ - @SystemApi - default boolean hasLocationSensitiveFields() { - return false; + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + default @NetworkCapabilities.RedactionType long getApplicableRedactions() { + return NetworkCapabilities.REDACT_NONE; } } diff --git a/packages/Connectivity/framework/src/android/net/UidRange.java b/packages/Connectivity/framework/src/android/net/UidRange.java index 26518d32edcb..bc67c745c98f 100644 --- a/packages/Connectivity/framework/src/android/net/UidRange.java +++ b/packages/Connectivity/framework/src/android/net/UidRange.java @@ -20,8 +20,11 @@ import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; +import android.util.ArraySet; +import android.util.Range; import java.util.Collection; +import java.util.Set; /** * An inclusive range of UIDs. @@ -149,4 +152,32 @@ public final class UidRange implements Parcelable { } return false; } + + /** + * Convert a set of {@code Range<Integer>} to a set of {@link UidRange}. + */ + @Nullable + public static ArraySet<UidRange> fromIntRanges(@Nullable Set<Range<Integer>> ranges) { + if (null == ranges) return null; + + final ArraySet<UidRange> uids = new ArraySet<>(); + for (Range<Integer> range : ranges) { + uids.add(new UidRange(range.getLower(), range.getUpper())); + } + return uids; + } + + /** + * Convert a set of {@link UidRange} to a set of {@code Range<Integer>}. + */ + @Nullable + public static ArraySet<Range<Integer>> toIntRanges(@Nullable Set<UidRange> ranges) { + if (null == ranges) return null; + + final ArraySet<Range<Integer>> uids = new ArraySet<>(); + for (UidRange range : ranges) { + uids.add(new Range<Integer>(range.start, range.stop)); + } + return uids; + } } diff --git a/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java b/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java index bf5b26e278f9..85b24713f256 100644 --- a/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java +++ b/packages/Connectivity/framework/src/android/net/apf/ApfCapabilities.java @@ -19,12 +19,12 @@ package android.net.apf; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.content.Context; import android.content.res.Resources; +import android.net.ConnectivityResources; import android.os.Parcel; import android.os.Parcelable; -import com.android.internal.R; - /** * APF program support capabilities. APF stands for Android Packet Filtering and it is a flexible * way to drop unwanted network packets to save power. @@ -36,6 +36,8 @@ import com.android.internal.R; */ @SystemApi public final class ApfCapabilities implements Parcelable { + private static ConnectivityResources sResources; + /** * Version of APF instruction set supported for packet filtering. 0 indicates no support for * packet filtering using APF programs. @@ -65,6 +67,14 @@ public final class ApfCapabilities implements Parcelable { apfPacketFormat = in.readInt(); } + @NonNull + private static synchronized ConnectivityResources getResources(@NonNull Context ctx) { + if (sResources == null) { + sResources = new ConnectivityResources(ctx); + } + return sResources; + } + @Override public int describeContents() { @@ -121,13 +131,43 @@ public final class ApfCapabilities implements Parcelable { * @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames. */ public static boolean getApfDrop8023Frames() { - return Resources.getSystem().getBoolean(R.bool.config_apfDrop802_3Frames); + // TODO(b/183076074): remove reading resources from system resources + final Resources systemRes = Resources.getSystem(); + final int id = systemRes.getIdentifier("config_apfDrop802_3Frames", "bool", "android"); + return systemRes.getBoolean(id); + } + + /** + * @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames. + * @hide + */ + public static boolean getApfDrop8023Frames(@NonNull Context context) { + final ConnectivityResources res = getResources(context); + // TODO(b/183076074): use R.bool.config_apfDrop802_3Frames directly + final int id = res.get().getIdentifier("config_apfDrop802_3Frames", "bool", + res.getResourcesContext().getPackageName()); + return res.get().getBoolean(id); } /** * @return An array of denylisted EtherType, packets with EtherTypes within it will be dropped. */ public static @NonNull int[] getApfEtherTypeBlackList() { - return Resources.getSystem().getIntArray(R.array.config_apfEthTypeBlackList); + // TODO(b/183076074): remove reading resources from system resources + final Resources systemRes = Resources.getSystem(); + final int id = systemRes.getIdentifier("config_apfEthTypeBlackList", "array", "android"); + return systemRes.getIntArray(id); + } + + /** + * @return An array of denylisted EtherType, packets with EtherTypes within it will be dropped. + * @hide + */ + public static @NonNull int[] getApfEtherTypeDenyList(@NonNull Context context) { + final ConnectivityResources res = getResources(context); + // TODO(b/183076074): use R.array.config_apfEthTypeDenyList directly + final int id = res.get().getIdentifier("config_apfEthTypeDenyList", "array", + res.getResourcesContext().getPackageName()); + return res.get().getIntArray(id); } } diff --git a/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java b/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java index bfc4563fbf8f..8d7a0b3d02ed 100644 --- a/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java +++ b/packages/Connectivity/framework/src/android/net/util/KeepaliveUtils.java @@ -19,12 +19,11 @@ package android.net.util; import android.annotation.NonNull; import android.content.Context; import android.content.res.Resources; +import android.net.ConnectivityResources; import android.net.NetworkCapabilities; import android.text.TextUtils; import android.util.AndroidRuntimeException; -import com.android.internal.R; - /** * Collection of utilities for socket keepalive offload. * @@ -52,8 +51,11 @@ public final class KeepaliveUtils { public static int[] getSupportedKeepalives(@NonNull Context context) { String[] res = null; try { - res = context.getResources().getStringArray( - R.array.config_networkSupportedKeepaliveCount); + final ConnectivityResources connRes = new ConnectivityResources(context); + // TODO: use R.id.config_networkSupportedKeepaliveCount directly + final int id = connRes.get().getIdentifier("config_networkSupportedKeepaliveCount", + "array", connRes.getResourcesContext().getPackageName()); + res = new ConnectivityResources(context).get().getStringArray(id); } catch (Resources.NotFoundException unused) { } if (res == null) throw new KeepaliveDeviceConfigurationException("invalid resource"); diff --git a/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java index 6a49aa2576c3..0b42a0036925 100644 --- a/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java +++ b/packages/Connectivity/framework/src/android/net/util/MultinetworkPolicyTracker.java @@ -27,6 +27,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; import android.database.ContentObserver; +import android.net.ConnectivityResources; import android.net.Uri; import android.os.Handler; import android.provider.Settings; @@ -35,7 +36,6 @@ import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; import android.util.Log; -import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import java.util.Arrays; @@ -64,6 +64,7 @@ public class MultinetworkPolicyTracker { private static String TAG = MultinetworkPolicyTracker.class.getSimpleName(); private final Context mContext; + private final ConnectivityResources mResources; private final Handler mHandler; private final Runnable mAvoidBadWifiCallback; private final List<Uri> mSettingsUris; @@ -107,6 +108,7 @@ public class MultinetworkPolicyTracker { public MultinetworkPolicyTracker(Context ctx, Handler handler, Runnable avoidBadWifiCallback) { mContext = ctx; + mResources = new ConnectivityResources(ctx); mHandler = handler; mAvoidBadWifiCallback = avoidBadWifiCallback; mSettingsUris = Arrays.asList( @@ -160,12 +162,16 @@ public class MultinetworkPolicyTracker { * Whether the device or carrier configuration disables avoiding bad wifi by default. */ public boolean configRestrictsAvoidBadWifi() { - return (getResourcesForActiveSubId().getInteger(R.integer.config_networkAvoidBadWifi) == 0); + // TODO: use R.integer.config_networkAvoidBadWifi directly + final int id = mResources.get().getIdentifier("config_networkAvoidBadWifi", + "integer", mResources.getResourcesContext().getPackageName()); + return (getResourcesForActiveSubId().getInteger(id) == 0); } @NonNull private Resources getResourcesForActiveSubId() { - return SubscriptionManager.getResourcesForSubId(mContext, mActiveSubId); + return SubscriptionManager.getResourcesForSubId( + mResources.getResourcesContext(), mActiveSubId); } /** @@ -205,8 +211,10 @@ public class MultinetworkPolicyTracker { * The default (device and carrier-dependent) value for metered multipath preference. */ public int configMeteredMultipathPreference() { - return mContext.getResources().getInteger( - R.integer.config_networkMeteredMultipathPreference); + // TODO: use R.integer.config_networkMeteredMultipathPreference directly + final int id = mResources.get().getIdentifier("config_networkMeteredMultipathPreference", + "integer", mResources.getResourcesContext().getPackageName()); + return mResources.get().getInteger(id); } public void updateMeteredMultipathPreference() { diff --git a/packages/Connectivity/service/Android.bp b/packages/Connectivity/service/Android.bp index f630ceac3662..1330e719e774 100644 --- a/packages/Connectivity/service/Android.bp +++ b/packages/Connectivity/service/Android.bp @@ -68,6 +68,7 @@ java_library { "net-utils-framework-common", "netd-client", "PlatformProperties", + "service-connectivity-protos", ], apex_available: [ "//apex_available:platform", @@ -76,6 +77,21 @@ java_library { } java_library { + name: "service-connectivity-protos", + proto: { + type: "nano", + }, + srcs: [ + ":system-messages-proto-src", + ], + libs: ["libprotobuf-java-nano"], + apex_available: [ + "//apex_available:platform", + "com.android.tethering", + ], +} + +java_library { name: "service-connectivity", installable: true, static_libs: [ diff --git a/packages/Connectivity/service/ServiceConnectivityResources/Android.bp b/packages/Connectivity/service/ServiceConnectivityResources/Android.bp index f2446b7f7eb8..fa4501ac7f29 100644 --- a/packages/Connectivity/service/ServiceConnectivityResources/Android.bp +++ b/packages/Connectivity/service/ServiceConnectivityResources/Android.bp @@ -21,7 +21,7 @@ package { android_app { name: "ServiceConnectivityResources", - sdk_version: "system_current", + sdk_version: "module_current", resource_dirs: [ "res", ], diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc204-mnc04/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc204-mnc04/config.xml new file mode 100644 index 000000000000..7e7025fb042f --- /dev/null +++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc204-mnc04/config.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<!-- Configuration values for ConnectivityService + DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources + Overlay package following the overlayable.xml configuration in the same directory: + https://source.android.com/devices/architecture/rros --> +<resources> + <!-- Whether the device should automatically switch away from Wi-Fi networks that lose + Internet access. Actual device behaviour is controlled by + Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. --> + <integer translatable="false" name="config_networkAvoidBadWifi">0</integer> +</resources>
\ No newline at end of file diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc310-mnc004/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc310-mnc004/config.xml new file mode 100644 index 000000000000..7e7025fb042f --- /dev/null +++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc310-mnc004/config.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<!-- Configuration values for ConnectivityService + DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources + Overlay package following the overlayable.xml configuration in the same directory: + https://source.android.com/devices/architecture/rros --> +<resources> + <!-- Whether the device should automatically switch away from Wi-Fi networks that lose + Internet access. Actual device behaviour is controlled by + Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. --> + <integer translatable="false" name="config_networkAvoidBadWifi">0</integer> +</resources>
\ No newline at end of file diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml new file mode 100644 index 000000000000..7e7025fb042f --- /dev/null +++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values-mcc311-mnc480/config.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<!-- Configuration values for ConnectivityService + DO NOT EDIT THIS FILE for specific device configuration; instead, use a Runtime Resources + Overlay package following the overlayable.xml configuration in the same directory: + https://source.android.com/devices/architecture/rros --> +<resources> + <!-- Whether the device should automatically switch away from Wi-Fi networks that lose + Internet access. Actual device behaviour is controlled by + Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. --> + <integer translatable="false" name="config_networkAvoidBadWifi">0</integer> +</resources>
\ No newline at end of file diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml index 06c81921fd3f..71674e4dc606 100644 --- a/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml +++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values/config.xml @@ -52,4 +52,41 @@ <item>12,60000</item><!-- mobile_cbs --> </string-array> -</resources>
\ No newline at end of file + <!-- Whether the APF Filter in the device should filter out IEEE 802.3 Frames + Those frames are identified by the field Eth-type having values + less than 0x600 --> + <bool translatable="false" name="config_apfDrop802_3Frames">true</bool> + + <!-- An array of Denylisted EtherType, packets with EtherTypes within this array + will be dropped + TODO: need to put proper values, these are for testing purposes only --> + <integer-array translatable="false" name="config_apfEthTypeDenyList"> + <item>0x88A2</item> + <item>0x88A4</item> + <item>0x88B8</item> + <item>0x88CD</item> + <item>0x88E3</item> + </integer-array> + + <!-- Default supported concurrent socket keepalive slots per transport type, used by + ConnectivityManager.createSocketKeepalive() for calculating the number of keepalive + offload slots that should be reserved for privileged access. This string array should be + overridden by the device to present the capability of creating socket keepalives. --> + <!-- An Array of "[NetworkCapabilities.TRANSPORT_*],[supported keepalives] --> + <string-array translatable="false" name="config_networkSupportedKeepaliveCount"> + <item>0,1</item> + <item>1,3</item> + </string-array> + + + <!-- Default value for ConnectivityManager.getMultipathPreference() on metered networks. Actual + device behaviour is controlled by the metered multipath preference in + ConnectivitySettingsManager. This is the default value of that setting. --> + <integer translatable="false" name="config_networkMeteredMultipathPreference">0</integer> + + <!-- Whether the device should automatically switch away from Wi-Fi networks that lose + Internet access. Actual device behaviour is controlled by + Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. --> + <integer translatable="false" name="config_networkAvoidBadWifi">1</integer> + +</resources> diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml index da8aee56276c..25e19cedbbba 100644 --- a/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml +++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values/overlayable.xml @@ -21,6 +21,11 @@ <item type="string" name="config_networkCaptivePortalServerUrl"/> <item type="integer" name="config_networkTransitionTimeout"/> <item type="array" name="config_wakeonlan_supported_interfaces"/> + <item type="bool" name="config_apfDrop802_3Frames"/> + <item type="array" name="config_apfEthTypeDenyList"/> + <item type="integer" name="config_networkMeteredMultipathPreference"/> + <item type="array" name="config_networkSupportedKeepaliveCount"/> + <item type="integer" name="config_networkAvoidBadWifi"/> </policy> </overlayable> diff --git a/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml b/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml index 7a9cf57afcd6..b2fa5f5b4129 100644 --- a/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml +++ b/packages/Connectivity/service/ServiceConnectivityResources/res/values/strings.xml @@ -68,8 +68,6 @@ <item>VPN</item> </string-array> - <!-- Network type names used in the network_switch_metered and network_switch_metered_detail strings. These must be kept in the sync with the values NetworkCapabilities.TRANSPORT_xxx values, and in the same order. --> - <!-- Network type name displayed if one of the types is not found in network_switch_type_name. --> <string name="network_switch_type_name_unknown">an unknown network type</string> diff --git a/packages/Connectivity/service/jarjar-rules.txt b/packages/Connectivity/service/jarjar-rules.txt index a7b419b020b5..5caa11b11ae4 100644 --- a/packages/Connectivity/service/jarjar-rules.txt +++ b/packages/Connectivity/service/jarjar-rules.txt @@ -12,3 +12,6 @@ rule android.util.LocalLog* com.android.connectivity.util.LocalLog@1 # the one in com.android.internal.util rule android.util.IndentingPrintWriter* android.connectivity.util.IndentingPrintWriter@1 rule com.android.internal.util.** com.android.connectivity.util.@1 + +rule com.android.internal.messages.** com.android.connectivity.messages.@1 +rule com.google.protobuf.** com.android.connectivity.protobuf.@1 diff --git a/packages/Connectivity/service/proto/connectivityproto.proto b/packages/Connectivity/service/proto/connectivityproto.proto new file mode 100644 index 000000000000..a992d7c26368 --- /dev/null +++ b/packages/Connectivity/service/proto/connectivityproto.proto @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; + +// Connectivity protos can be created in this directory. Note this file must be included before +// building system-messages-proto, otherwise it will not build by itself. diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS index f884270eaba8..835471d5cb94 100644 --- a/packages/SystemUI/OWNERS +++ b/packages/SystemUI/OWNERS @@ -9,6 +9,7 @@ asc@google.com awickham@google.com beverlyt@google.com brockman@google.com +ccassidy@google.com cinek@google.com cwren@google.com dupin@google.com @@ -19,10 +20,10 @@ hwwang@google.com hyunyoungs@google.com jaggies@google.com jamesoleary@google.com +jdemeulenaere@google.com jeffdq@google.com jjaggi@google.com jonmiranda@google.com -joshmcgrath@google.com joshtrask@google.com juliacr@google.com juliatuttle@google.com @@ -37,7 +38,6 @@ mkephart@google.com mpietal@google.com mrcasey@google.com mrenouf@google.com -nbenbernou@google.com nesciosquid@google.com ogunwale@google.com peanutbutter@google.com @@ -45,6 +45,7 @@ pinyaoting@google.com pixel@google.com roosa@google.com santie@google.com +shanh@google.com snoeberger@google.com sreyasr@google.com steell@google.com @@ -59,6 +60,7 @@ twickham@google.com vadimt@google.com victortulias@google.com winsonc@google.com +yurilin@google.com xuqiu@google.com zakcohen@google.com diff --git a/packages/VpnDialogs/res/values/strings.xml b/packages/VpnDialogs/res/values/strings.xml index 443a9bc33b90..f971a0916837 100644 --- a/packages/VpnDialogs/res/values/strings.xml +++ b/packages/VpnDialogs/res/values/strings.xml @@ -28,6 +28,17 @@ ]]> appears at the top of your screen when VPN is active. </string> + <!-- TV specific dialog message to warn about the risk of using a VPN application. [CHAR LIMIT=NONE] --> + <string name="warning" product="tv"> + <xliff:g id="app">%s</xliff:g> wants to set up a VPN connection + that allows it to monitor network traffic. Only accept if you trust the source. + <![CDATA[ + <br /> + <br /> + <img src="vpn_icon" /> + ]]> appears on your screen when VPN is active. + </string> + <!-- Dialog title for built-in VPN. [CHAR LIMIT=40] --> <string name="legacy_title">VPN is connected</string> <!-- Label for the name of the current VPN session. [CHAR LIMIT=20] --> diff --git a/services/core/Android.bp b/services/core/Android.bp index f91e69240605..0ac8f74ff831 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -209,8 +209,8 @@ 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/ConnectivityResources.java", "java/com/android/server/connectivity/DnsManager.java", + "java/com/android/server/connectivity/FullScore.java", "java/com/android/server/connectivity/KeepaliveTracker.java", "java/com/android/server/connectivity/LingerMonitor.java", "java/com/android/server/connectivity/MockableSystemProperties.java", diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index f527da582959..0c4258561f70 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -30,6 +30,9 @@ import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTI import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS_CONSECUTIVE_TIMEOUTS; import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS; import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE; +import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK; +import static android.net.ConnectivityManager.BLOCKED_REASON_LOCKDOWN_VPN; +import static android.net.ConnectivityManager.BLOCKED_REASON_NONE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.ConnectivityManager.TYPE_BLUETOOTH; @@ -69,10 +72,12 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE; import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; +import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION; +import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS; +import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.net.NetworkCapabilities.TRANSPORT_VPN; -import static android.net.NetworkPolicyManager.BLOCKED_REASON_NONE; import static android.net.NetworkPolicyManager.blockedReasonsToString; import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST; import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired; @@ -105,7 +110,10 @@ import android.net.ConnectionInfo; import android.net.ConnectivityDiagnosticsManager.ConnectivityReport; import android.net.ConnectivityDiagnosticsManager.DataStallReport; import android.net.ConnectivityManager; +import android.net.ConnectivityManager.BlockedReason; import android.net.ConnectivityManager.NetworkCallback; +import android.net.ConnectivityManager.RestrictBackgroundStatus; +import android.net.ConnectivityResources; import android.net.ConnectivitySettingsManager; import android.net.DataStallReportParcelable; import android.net.DnsResolverServiceManager; @@ -115,6 +123,7 @@ import android.net.IConnectivityManager; import android.net.IDnsResolver; import android.net.INetd; import android.net.INetworkActivityListener; +import android.net.INetworkAgent; import android.net.INetworkMonitor; import android.net.INetworkMonitorCallbacks; import android.net.IOnCompleteListener; @@ -208,7 +217,6 @@ import android.util.Pair; import android.util.SparseArray; import android.util.SparseIntArray; -import com.android.connectivity.aidl.INetworkAgent; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; @@ -222,7 +230,6 @@ import com.android.net.module.util.LocationPermissionChecker; import com.android.net.module.util.NetworkCapabilitiesUtils; import com.android.net.module.util.PermissionUtils; import com.android.server.connectivity.AutodestructReference; -import com.android.server.connectivity.ConnectivityResources; import com.android.server.connectivity.DnsManager; import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate; import com.android.server.connectivity.KeepaliveTracker; @@ -237,7 +244,6 @@ import com.android.server.connectivity.PermissionMonitor; import com.android.server.connectivity.ProfileNetworkPreferences; import com.android.server.connectivity.ProxyTracker; import com.android.server.connectivity.QosCallbackTracker; -import com.android.server.net.NetworkPolicyManagerInternal; import libcore.io.IoUtils; @@ -350,7 +356,6 @@ public class ConnectivityService extends IConnectivityManager.Stub protected INetd mNetd; private NetworkStatsManager mStatsManager; private NetworkPolicyManager mPolicyManager; - private NetworkPolicyManagerInternal mPolicyManagerInternal; private final NetdCallback mNetdCallback; /** @@ -1144,8 +1149,8 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * @see NetworkUtils#queryUserAccess(int, int) */ - public boolean queryUserAccess(int uid, int netId) { - return NetworkUtils.queryUserAccess(uid, netId); + public boolean queryUserAccess(int uid, Network network, ConnectivityService cs) { + return cs.queryUserAccess(uid, network); } /** @@ -1201,7 +1206,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mNetworkRanker = new NetworkRanker(); final NetworkRequest defaultInternetRequest = createDefaultRequest(); mDefaultRequest = new NetworkRequestInfo( - defaultInternetRequest, null, + Process.myUid(), defaultInternetRequest, null, new Binder(), NetworkCallback.FLAG_INCLUDE_LOCATION_INFO, null /* attributionTags */); mNetworkRequests.put(defaultInternetRequest, mDefaultRequest); @@ -1237,9 +1242,6 @@ public class ConnectivityService extends IConnectivityManager.Stub mStatsManager = mContext.getSystemService(NetworkStatsManager.class); mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class); - mPolicyManagerInternal = Objects.requireNonNull( - LocalServices.getService(NetworkPolicyManagerInternal.class), - "missing NetworkPolicyManagerInternal"); mDnsResolver = Objects.requireNonNull(dnsresolver, "missing IDnsResolver"); mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler); @@ -1339,7 +1341,7 @@ public class ConnectivityService extends IConnectivityManager.Stub netCap.addCapability(NET_CAPABILITY_INTERNET); netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); netCap.removeCapability(NET_CAPABILITY_NOT_VPN); - netCap.setUids(Collections.singleton(uids)); + netCap.setUids(UidRange.toIntRanges(Collections.singleton(uids))); return netCap; } @@ -1411,8 +1413,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (enable) { handleRegisterNetworkRequest(new NetworkRequestInfo( - networkRequest, null, - new Binder(), + Process.myUid(), networkRequest, null, new Binder(), NetworkCallback.FLAG_INCLUDE_LOCATION_INFO, null /* attributionTags */)); } else { @@ -1559,7 +1560,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final int requestId = nri.getActiveRequest() != null ? nri.getActiveRequest().requestId : nri.mRequests.get(0).requestId; mNetworkInfoBlockingLogs.log(String.format( - "%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId())); + "%s %d(%d) on netId %d", action, nri.mAsUid, requestId, net.getNetId())); } /** @@ -1775,7 +1776,8 @@ public class ConnectivityService extends IConnectivityManager.Stub nai.network, createWithLocationInfoSanitizedIfNecessaryWhenParceled( nc, false /* includeLocationSensitiveInfo */, - mDeps.getCallingUid(), callingPackageName, callingAttributionTag)); + getCallingPid(), mDeps.getCallingUid(), callingPackageName, + callingAttributionTag)); } } @@ -1790,7 +1792,7 @@ public class ConnectivityService extends IConnectivityManager.Stub createWithLocationInfoSanitizedIfNecessaryWhenParceled( nc, false /* includeLocationSensitiveInfo */, - mDeps.getCallingUid(), callingPackageName, + getCallingPid(), mDeps.getCallingUid(), callingPackageName, callingAttributionTag)); } } @@ -1873,7 +1875,7 @@ public class ConnectivityService extends IConnectivityManager.Stub return createWithLocationInfoSanitizedIfNecessaryWhenParceled( getNetworkCapabilitiesInternal(network), false /* includeLocationSensitiveInfo */, - mDeps.getCallingUid(), callingPackageName, callingAttributionTag); + getCallingPid(), mDeps.getCallingUid(), callingPackageName, callingAttributionTag); } @VisibleForTesting @@ -1892,40 +1894,137 @@ public class ConnectivityService extends IConnectivityManager.Stub return newNc; } - private boolean hasLocationPermission(int callerUid, @NonNull String callerPkgName, - @Nullable String callingAttributionTag) { - final long token = Binder.clearCallingIdentity(); - try { - return mLocationPermissionChecker.checkLocationPermission( - callerPkgName, callingAttributionTag, callerUid, null /* message */); - } finally { - Binder.restoreCallingIdentity(token); + /** + * Wrapper used to cache the permission check results performed for the corresponding + * app. This avoid performing multiple permission checks for different fields in + * NetworkCapabilities. + * Note: This wrapper does not support any sort of invalidation and thus must not be + * persistent or long-lived. It may only be used for the time necessary to + * compute the redactions required by one particular NetworkCallback or + * synchronous call. + */ + private class RedactionPermissionChecker { + private final int mCallingPid; + private final int mCallingUid; + @NonNull private final String mCallingPackageName; + @Nullable private final String mCallingAttributionTag; + + private Boolean mHasLocationPermission = null; + private Boolean mHasLocalMacAddressPermission = null; + private Boolean mHasSettingsPermission = null; + + RedactionPermissionChecker(int callingPid, int callingUid, + @NonNull String callingPackageName, @Nullable String callingAttributionTag) { + mCallingPid = callingPid; + mCallingUid = callingUid; + mCallingPackageName = callingPackageName; + mCallingAttributionTag = callingAttributionTag; + } + + private boolean hasLocationPermissionInternal() { + final long token = Binder.clearCallingIdentity(); + try { + return mLocationPermissionChecker.checkLocationPermission( + mCallingPackageName, mCallingAttributionTag, mCallingUid, + null /* message */); + } finally { + Binder.restoreCallingIdentity(token); + } + } + + /** + * Returns whether the app holds location permission or not (might return cached result + * if the permission was already checked before). + */ + public boolean hasLocationPermission() { + if (mHasLocationPermission == null) { + // If there is no cached result, perform the check now. + mHasLocationPermission = hasLocationPermissionInternal(); + } + return mHasLocationPermission; } + + /** + * Returns whether the app holds local mac address permission or not (might return cached + * result if the permission was already checked before). + */ + public boolean hasLocalMacAddressPermission() { + if (mHasLocalMacAddressPermission == null) { + // If there is no cached result, perform the check now. + mHasLocalMacAddressPermission = + checkLocalMacAddressPermission(mCallingPid, mCallingUid); + } + return mHasLocalMacAddressPermission; + } + + /** + * Returns whether the app holds settings permission or not (might return cached + * result if the permission was already checked before). + */ + public boolean hasSettingsPermission() { + if (mHasSettingsPermission == null) { + // If there is no cached result, perform the check now. + mHasSettingsPermission = checkSettingsPermission(mCallingPid, mCallingUid); + } + return mHasSettingsPermission; + } + } + + private static boolean shouldRedact(@NetworkCapabilities.RedactionType long redactions, + @NetworkCapabilities.NetCapability long redaction) { + return (redactions & redaction) != 0; + } + + /** + * Use the provided |applicableRedactions| to check the receiving app's + * permissions and clear/set the corresponding bit in the returned bitmask. The bitmask + * returned will be used to ensure the necessary redactions are performed by NetworkCapabilities + * before being sent to the corresponding app. + */ + private @NetworkCapabilities.RedactionType long retrieveRequiredRedactions( + @NetworkCapabilities.RedactionType long applicableRedactions, + @NonNull RedactionPermissionChecker redactionPermissionChecker, + boolean includeLocationSensitiveInfo) { + long redactions = applicableRedactions; + if (shouldRedact(redactions, REDACT_FOR_ACCESS_FINE_LOCATION)) { + if (includeLocationSensitiveInfo + && redactionPermissionChecker.hasLocationPermission()) { + redactions &= ~REDACT_FOR_ACCESS_FINE_LOCATION; + } + } + if (shouldRedact(redactions, REDACT_FOR_LOCAL_MAC_ADDRESS)) { + if (redactionPermissionChecker.hasLocalMacAddressPermission()) { + redactions &= ~REDACT_FOR_LOCAL_MAC_ADDRESS; + } + } + if (shouldRedact(redactions, REDACT_FOR_NETWORK_SETTINGS)) { + if (redactionPermissionChecker.hasSettingsPermission()) { + redactions &= ~REDACT_FOR_NETWORK_SETTINGS; + } + } + return redactions; } @VisibleForTesting @Nullable NetworkCapabilities createWithLocationInfoSanitizedIfNecessaryWhenParceled( @Nullable NetworkCapabilities nc, boolean includeLocationSensitiveInfo, - int callerUid, @NonNull String callerPkgName, @Nullable String callingAttributionTag) { + int callingPid, int callingUid, @NonNull String callingPkgName, + @Nullable String callingAttributionTag) { if (nc == null) { return null; } - Boolean hasLocationPermission = null; - final NetworkCapabilities newNc; // Avoid doing location permission check if the transport info has no location sensitive // data. - if (includeLocationSensitiveInfo - && nc.getTransportInfo() != null - && nc.getTransportInfo().hasLocationSensitiveFields()) { - hasLocationPermission = - hasLocationPermission(callerUid, callerPkgName, callingAttributionTag); - newNc = new NetworkCapabilities(nc, hasLocationPermission); - } else { - newNc = new NetworkCapabilities(nc, false /* parcelLocationSensitiveFields */); - } + final RedactionPermissionChecker redactionPermissionChecker = + new RedactionPermissionChecker(callingPid, callingUid, callingPkgName, + callingAttributionTag); + final long redactions = retrieveRequiredRedactions( + nc.getApplicableRedactions(), redactionPermissionChecker, + includeLocationSensitiveInfo); + final NetworkCapabilities newNc = new NetworkCapabilities(nc, redactions); // Reset owner uid if not destined for the owner app. - if (callerUid != nc.getOwnerUid()) { + if (callingUid != nc.getOwnerUid()) { newNc.setOwnerUid(INVALID_UID); return newNc; } @@ -1934,23 +2033,17 @@ public class ConnectivityService extends IConnectivityManager.Stub // Owner UIDs already checked above. No need to re-check. return newNc; } - // If the caller does not want location sensitive data & target SDK >= S, then mask info. - // Else include the owner UID iff the caller has location permission to provide backwards + // If the calling does not want location sensitive data & target SDK >= S, then mask info. + // Else include the owner UID iff the calling has location permission to provide backwards // compatibility for older apps. if (!includeLocationSensitiveInfo && isTargetSdkAtleast( - Build.VERSION_CODES.S, callerUid, callerPkgName)) { + Build.VERSION_CODES.S, callingUid, callingPkgName)) { newNc.setOwnerUid(INVALID_UID); return newNc; } - - if (hasLocationPermission == null) { - // Location permission not checked yet, check now for masking owner UID. - hasLocationPermission = - hasLocationPermission(callerUid, callerPkgName, callingAttributionTag); - } // Reset owner uid if the app has no location permission. - if (!hasLocationPermission) { + if (!redactionPermissionChecker.hasLocationPermission()) { newNc.setOwnerUid(INVALID_UID); } return newNc; @@ -1982,6 +2075,8 @@ public class ConnectivityService extends IConnectivityManager.Stub private void restrictRequestUidsForCallerAndSetRequestorInfo(NetworkCapabilities nc, int callerUid, String callerPackageName) { if (!checkSettingsPermission()) { + // There is no need to track the effective UID of the request here. If the caller lacks + // the settings permission, the effective UID is the same as the calling ID. nc.setSingleUid(callerUid); } nc.setRequestorUidAndPackageName(callerUid, callerPackageName); @@ -1997,6 +2092,18 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + @Override + public @RestrictBackgroundStatus int getRestrictBackgroundStatusByCaller() { + enforceAccessPermission(); + final int callerUid = Binder.getCallingUid(); + final long token = Binder.clearCallingIdentity(); + try { + return mPolicyManager.getRestrictBackgroundStatus(callerUid); + } finally { + Binder.restoreCallingIdentity(token); + } + } + // TODO: Consider delete this function or turn it into a no-op method. @Override public NetworkState[] getAllNetworkState() { @@ -2234,15 +2341,15 @@ public class ConnectivityService extends IConnectivityManager.Stub private final NetworkPolicyCallback mPolicyCallback = new NetworkPolicyCallback() { @Override - public void onUidBlockedReasonChanged(int uid, int blockedReasons) { + public void onUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) { mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_BLOCKED_REASON_CHANGED, uid, blockedReasons)); } }; - void handleUidBlockedReasonChanged(int uid, int blockedReasons) { + private void handleUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) { maybeNotifyNetworkBlockedForNewState(uid, blockedReasons); - mUidBlockedReasons.put(uid, blockedReasons); + setUidBlockedReasons(uid, blockedReasons); } private boolean checkAnyPermissionOf(String... permissions) { @@ -2429,6 +2536,11 @@ public class ConnectivityService extends IConnectivityManager.Stub mContext.enforceCallingOrSelfPermission(KeepaliveTracker.PERMISSION, "ConnectivityService"); } + private boolean checkLocalMacAddressPermission(int pid, int uid) { + return PERMISSION_GRANTED == mContext.checkPermission( + Manifest.permission.LOCAL_MAC_ADDRESS, pid, uid); + } + private void sendConnectedBroadcast(NetworkInfo info) { sendGeneralBroadcast(info, CONNECTIVITY_ACTION); } @@ -2860,7 +2972,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (0 == defaultRequest.mRequests.size()) { pw.println("none, this should never occur."); } else { - pw.println(defaultRequest.mRequests.get(0).networkCapabilities.getUids()); + pw.println(defaultRequest.mRequests.get(0).networkCapabilities.getUidRanges()); } pw.decreaseIndent(); pw.decreaseIndent(); @@ -3592,6 +3704,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mDnsManager.removeNetwork(nai.network); } mNetIdManager.releaseNetId(nai.network.getNetId()); + nai.onNetworkDisconnected(); } private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) { @@ -4407,7 +4520,13 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkPolicyManager netPolicyManager = mContext.getSystemService(NetworkPolicyManager.class); - final int networkPreference = netPolicyManager.getMultipathPreference(network); + final long token = Binder.clearCallingIdentity(); + final int networkPreference; + try { + networkPreference = netPolicyManager.getMultipathPreference(network); + } finally { + Binder.restoreCallingIdentity(token); + } if (networkPreference != 0) { return networkPreference; } @@ -4724,6 +4843,42 @@ public class ConnectivityService extends IConnectivityManager.Stub nai.networkMonitor().forceReevaluation(uid); } + // TODO: call into netd. + private boolean queryUserAccess(int uid, Network network) { + final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network); + if (nai == null) return false; + + // Any UID can use its default network. + if (nai == getDefaultNetworkForUid(uid)) return true; + + // Privileged apps can use any network. + if (mPermissionMonitor.hasRestrictedNetworksPermission(uid)) { + return true; + } + + // An unprivileged UID can use a VPN iff the VPN applies to it. + if (nai.isVPN()) { + return nai.networkCapabilities.appliesToUid(uid); + } + + // An unprivileged UID can bypass the VPN that applies to it only if it can protect its + // sockets, i.e., if it is the owner. + final NetworkAgentInfo vpn = getVpnForUid(uid); + if (vpn != null && !vpn.networkAgentConfig.allowBypass + && uid != vpn.networkCapabilities.getOwnerUid()) { + return false; + } + + // The UID's permission must be at least sufficient for the network. Since the restricted + // permission was already checked above, that just leaves background networks. + if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_FOREGROUND)) { + return mPermissionMonitor.hasUseBackgroundNetworksPermission(uid); + } + + // Unrestricted network. Anyone gets to use it. + return true; + } + /** * Returns information about the proxy a certain network is using. If given a null network, it * it will return the proxy for the bound network for the caller app or the default proxy if @@ -4744,7 +4899,7 @@ public class ConnectivityService extends IConnectivityManager.Stub return null; } return getLinkPropertiesProxyInfo(activeNetwork); - } else if (mDeps.queryUserAccess(mDeps.getCallingUid(), network.getNetId())) { + } else if (mDeps.queryUserAccess(mDeps.getCallingUid(), network, this)) { // Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which // caller may not have. return getLinkPropertiesProxyInfo(network); @@ -4971,7 +5126,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public void setRequireVpnForUids(boolean requireVpn, UidRange[] ranges) { - PermissionUtils.enforceNetworkStackPermission(mContext); + enforceNetworkStackOrSettingsPermission(); mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_REQUIRE_VPN_FOR_UIDS, encodeBool(requireVpn), 0 /* arg2 */, ranges)); } @@ -5009,7 +5164,7 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public void setLegacyLockdownVpnEnabled(boolean enabled) { - enforceSettingsPermission(); + enforceNetworkStackOrSettingsPermission(); mHandler.post(() -> mLockdownEnabled = enabled); } @@ -5249,6 +5404,8 @@ public class ConnectivityService extends IConnectivityManager.Stub boolean mPendingIntentSent; @Nullable final Messenger mMessenger; + + // Information about the caller that caused this object to be created. @Nullable private final IBinder mBinder; final int mPid; @@ -5256,6 +5413,13 @@ public class ConnectivityService extends IConnectivityManager.Stub final @NetworkCallback.Flag int mCallbackFlags; @Nullable final String mCallingAttributionTag; + + // Effective UID of this request. This is different from mUid when a privileged process + // files a request on behalf of another UID. This UID is used to determine blocked status, + // UID matching, and so on. mUid above is used for permission checks and to enforce the + // maximum limit of registered callbacks per UID. + final int mAsUid; + // In order to preserve the mapping of NetworkRequest-to-callback when apps register // callbacks using a returned NetworkRequest, the original NetworkRequest needs to be // maintained for keying off of. This is only a concern when the original nri @@ -5279,17 +5443,16 @@ public class ConnectivityService extends IConnectivityManager.Stub private Set<UidRange> getUids() { // networkCapabilities.getUids() returns a defensive copy. // multilayer requests will all have the same uids so return the first one. - final Set<UidRange> uids = null == mRequests.get(0).networkCapabilities.getUids() - ? new ArraySet<>() : mRequests.get(0).networkCapabilities.getUids(); - return uids; + final Set<UidRange> uids = mRequests.get(0).networkCapabilities.getUidRanges(); + return (null == uids) ? new ArraySet<>() : uids; } - NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final PendingIntent pi, - @Nullable String callingAttributionTag) { - this(Collections.singletonList(r), r, pi, callingAttributionTag); + NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r, + @Nullable final PendingIntent pi, @Nullable String callingAttributionTag) { + this(asUid, Collections.singletonList(r), r, pi, callingAttributionTag); } - NetworkRequestInfo(@NonNull final List<NetworkRequest> r, + NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r, @NonNull final NetworkRequest requestForCallback, @Nullable final PendingIntent pi, @Nullable String callingAttributionTag) { ensureAllNetworkRequestsHaveType(r); @@ -5300,6 +5463,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mBinder = null; mPid = getCallingPid(); mUid = mDeps.getCallingUid(); + mAsUid = asUid; mNetworkRequestCounter.incrementCountOrThrow(mUid); /** * Location sensitive data not included in pending intent. Only included in @@ -5309,14 +5473,15 @@ public class ConnectivityService extends IConnectivityManager.Stub mCallingAttributionTag = callingAttributionTag; } - NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final Messenger m, + NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r, @Nullable final Messenger m, @Nullable final IBinder binder, @NetworkCallback.Flag int callbackFlags, @Nullable String callingAttributionTag) { - this(Collections.singletonList(r), r, m, binder, callbackFlags, callingAttributionTag); + this(asUid, Collections.singletonList(r), r, m, binder, callbackFlags, + callingAttributionTag); } - NetworkRequestInfo(@NonNull final List<NetworkRequest> r, + NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r, @NonNull final NetworkRequest requestForCallback, @Nullable final Messenger m, @Nullable final IBinder binder, @NetworkCallback.Flag int callbackFlags, @@ -5329,6 +5494,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mBinder = binder; mPid = getCallingPid(); mUid = mDeps.getCallingUid(); + mAsUid = asUid; mPendingIntent = null; mNetworkRequestCounter.incrementCountOrThrow(mUid); mCallbackFlags = callbackFlags; @@ -5371,18 +5537,19 @@ public class ConnectivityService extends IConnectivityManager.Stub mBinder = nri.mBinder; mPid = nri.mPid; mUid = nri.mUid; + mAsUid = nri.mAsUid; mPendingIntent = nri.mPendingIntent; mNetworkRequestCounter.incrementCountOrThrow(mUid); mCallbackFlags = nri.mCallbackFlags; mCallingAttributionTag = nri.mCallingAttributionTag; } - NetworkRequestInfo(@NonNull final NetworkRequest r) { - this(Collections.singletonList(r)); + NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r) { + this(asUid, Collections.singletonList(r)); } - NetworkRequestInfo(@NonNull final List<NetworkRequest> r) { - this(r, r.get(0), null /* pi */, null /* callingAttributionTag */); + NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r) { + this(asUid, r, r.get(0), null /* pi */, null /* callingAttributionTag */); } // True if this NRI is being satisfied. It also accounts for if the nri has its satisifer @@ -5418,9 +5585,10 @@ public class ConnectivityService extends IConnectivityManager.Stub @Override public String toString() { - return "uid/pid:" + mUid + "/" + mPid + " active request Id: " + final String asUidString = (mAsUid == mUid) ? "" : " asUid: " + mAsUid; + return "uid/pid:" + mUid + "/" + mPid + asUidString + " activeRequest: " + (mActiveRequest == null ? null : mActiveRequest.requestId) - + " callback request Id: " + + " callbackRequest: " + mNetworkRequestForCallback.requestId + " " + mRequests + (mPendingIntent == null ? "" : " to trigger " + mPendingIntent) @@ -5521,7 +5689,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities, + public NetworkRequest requestNetwork(int asUid, NetworkCapabilities networkCapabilities, int reqTypeInt, Messenger messenger, int timeoutMs, IBinder binder, int legacyType, int callbackFlags, @NonNull String callingPackageName, @Nullable String callingAttributionTag) { @@ -5533,6 +5701,12 @@ public class ConnectivityService extends IConnectivityManager.Stub } final NetworkCapabilities defaultNc = mDefaultRequest.mRequests.get(0).networkCapabilities; final int callingUid = mDeps.getCallingUid(); + // Privileged callers can track the default network of another UID by passing in a UID. + if (asUid != Process.INVALID_UID) { + enforceSettingsPermission(); + } else { + asUid = callingUid; + } final NetworkRequest.Type reqType; try { reqType = NetworkRequest.Type.values()[reqTypeInt]; @@ -5542,10 +5716,10 @@ public class ConnectivityService extends IConnectivityManager.Stub switch (reqType) { case TRACK_DEFAULT: // If the request type is TRACK_DEFAULT, the passed {@code networkCapabilities} - // is unused and will be replaced by ones appropriate for the caller. - // This allows callers to keep track of the default network for their app. + // is unused and will be replaced by ones appropriate for the UID (usually, the + // calling app). This allows callers to keep track of the default network. networkCapabilities = copyDefaultNetworkCapabilitiesForUid( - defaultNc, callingUid, callingPackageName); + defaultNc, asUid, callingUid, callingPackageName); enforceAccessPermission(); break; case TRACK_SYSTEM_DEFAULT: @@ -5597,7 +5771,8 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType, nextNetworkRequestId(), reqType); final NetworkRequestInfo nri = getNriToRegister( - networkRequest, messenger, binder, callbackFlags, callingAttributionTag); + asUid, networkRequest, messenger, binder, callbackFlags, + callingAttributionTag); if (DBG) log("requestNetwork for " + nri); // For TRACK_SYSTEM_DEFAULT callbacks, the capabilities have been modified since they were @@ -5624,25 +5799,27 @@ public class ConnectivityService extends IConnectivityManager.Stub * requests registered to track the default request. If there is currently a per-app default * tracking the app requestor, then we need to create a version of this nri that mirrors that of * the tracking per-app default so that callbacks are sent to the app requestor appropriately. + * @param asUid the uid on behalf of which to file the request. Different from requestorUid + * when a privileged caller is tracking the default network for another uid. * @param nr the network request for the nri. * @param msgr the messenger for the nri. * @param binder the binder for the nri. * @param callingAttributionTag the calling attribution tag for the nri. * @return the nri to register. */ - private NetworkRequestInfo getNriToRegister(@NonNull final NetworkRequest nr, + private NetworkRequestInfo getNriToRegister(final int asUid, @NonNull final NetworkRequest nr, @Nullable final Messenger msgr, @Nullable final IBinder binder, @NetworkCallback.Flag int callbackFlags, @Nullable String callingAttributionTag) { final List<NetworkRequest> requests; if (NetworkRequest.Type.TRACK_DEFAULT == nr.type) { requests = copyDefaultNetworkRequestsForUid( - nr.getRequestorUid(), nr.getRequestorPackageName()); + asUid, nr.getRequestorUid(), nr.getRequestorPackageName()); } else { requests = Collections.singletonList(nr); } return new NetworkRequestInfo( - requests, nr, msgr, binder, callbackFlags, callingAttributionTag); + asUid, requests, nr, msgr, binder, callbackFlags, callingAttributionTag); } private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities, @@ -5723,8 +5900,8 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.REQUEST); - NetworkRequestInfo nri = - new NetworkRequestInfo(networkRequest, operation, callingAttributionTag); + NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, networkRequest, operation, + callingAttributionTag); if (DBG) log("pendingRequest for " + nri); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT, nri)); @@ -5791,7 +5968,7 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.LISTEN); NetworkRequestInfo nri = - new NetworkRequestInfo(networkRequest, messenger, binder, callbackFlags, + new NetworkRequestInfo(callingUid, networkRequest, messenger, binder, callbackFlags, callingAttributionTag); if (VDBG) log("listenForNetwork for " + nri); @@ -5816,8 +5993,8 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.LISTEN); - NetworkRequestInfo nri = - new NetworkRequestInfo(networkRequest, operation, callingAttributionTag); + NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, networkRequest, operation, + callingAttributionTag); if (VDBG) log("pendingListenForNetwork for " + nri); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri)); @@ -5967,33 +6144,37 @@ public class ConnectivityService extends IConnectivityManager.Stub /** * Get a copy of the network requests of the default request that is currently tracking the * given uid. + * @param asUid the uid on behalf of which to file the request. Different from requestorUid + * when a privileged caller is tracking the default network for another uid. * @param requestorUid the uid to check the default for. * @param requestorPackageName the requestor's package name. * @return a copy of the default's NetworkRequest that is tracking the given uid. */ @NonNull private List<NetworkRequest> copyDefaultNetworkRequestsForUid( - @NonNull final int requestorUid, @NonNull final String requestorPackageName) { + final int asUid, final int requestorUid, @NonNull final String requestorPackageName) { return copyNetworkRequestsForUid( - getDefaultRequestTrackingUid(requestorUid).mRequests, - requestorUid, requestorPackageName); + getDefaultRequestTrackingUid(asUid).mRequests, + asUid, requestorUid, requestorPackageName); } /** * Copy the given nri's NetworkRequest collection. * @param requestsToCopy the NetworkRequest collection to be copied. + * @param asUid the uid on behalf of which to file the request. Different from requestorUid + * when a privileged caller is tracking the default network for another uid. * @param requestorUid the uid to set on the copied collection. * @param requestorPackageName the package name to set on the copied collection. * @return the copied NetworkRequest collection. */ @NonNull private List<NetworkRequest> copyNetworkRequestsForUid( - @NonNull final List<NetworkRequest> requestsToCopy, @NonNull final int requestorUid, - @NonNull final String requestorPackageName) { + @NonNull final List<NetworkRequest> requestsToCopy, final int asUid, + final int requestorUid, @NonNull final String requestorPackageName) { final List<NetworkRequest> requests = new ArrayList<>(); for (final NetworkRequest nr : requestsToCopy) { requests.add(new NetworkRequest(copyDefaultNetworkCapabilitiesForUid( - nr.networkCapabilities, requestorUid, requestorPackageName), + nr.networkCapabilities, asUid, requestorUid, requestorPackageName), nr.legacyType, nextNetworkRequestId(), nr.type)); } return requests; @@ -6001,12 +6182,17 @@ public class ConnectivityService extends IConnectivityManager.Stub @NonNull private NetworkCapabilities copyDefaultNetworkCapabilitiesForUid( - @NonNull final NetworkCapabilities netCapToCopy, @NonNull final int requestorUid, - @NonNull final String requestorPackageName) { + @NonNull final NetworkCapabilities netCapToCopy, final int asUid, + final int requestorUid, @NonNull final String requestorPackageName) { + // These capabilities are for a TRACK_DEFAULT callback, so: + // 1. Remove NET_CAPABILITY_VPN, because it's (currently!) the only difference between + // mDefaultRequest and a per-UID default request. + // TODO: stop depending on the fact that these two unrelated things happen to be the same + // 2. Always set the UIDs to asUid. restrictRequestUidsForCallerAndSetRequestorInfo will + // not do this in the case of a privileged application. final NetworkCapabilities netCap = new NetworkCapabilities(netCapToCopy); netCap.removeCapability(NET_CAPABILITY_NOT_VPN); - netCap.setSingleUid(requestorUid); - netCap.setUids(new ArraySet<>()); + netCap.setSingleUid(asUid); restrictRequestUidsForCallerAndSetRequestorInfo( netCap, requestorUid, requestorPackageName); return netCap; @@ -6087,7 +6273,7 @@ public class ConnectivityService extends IConnectivityManager.Stub for (final NetworkRequestInfo nri : mDefaultNetworkRequests) { // Currently, all network requests will have the same uids therefore checking the first // one is sufficient. If/when uids are tracked at the nri level, this can change. - final Set<UidRange> uids = nri.mRequests.get(0).networkCapabilities.getUids(); + final Set<UidRange> uids = nri.mRequests.get(0).networkCapabilities.getUidRanges(); if (null == uids) { continue; } @@ -6528,7 +6714,7 @@ public class ConnectivityService extends IConnectivityManager.Stub return; } - final Set<UidRange> ranges = nai.networkCapabilities.getUids(); + final Set<UidRange> ranges = nai.networkCapabilities.getUidRanges(); final int vpnAppUid = nai.networkCapabilities.getOwnerUid(); // TODO: this create a window of opportunity for apps to receive traffic between the time // when the old rules are removed and the time when new rules are added. To fix this, @@ -6893,8 +7079,8 @@ public class ConnectivityService extends IConnectivityManager.Stub private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc, NetworkCapabilities newNc) { - Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUids(); - Set<UidRange> newRanges = null == newNc ? null : newNc.getUids(); + Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUidRanges(); + Set<UidRange> newRanges = null == newNc ? null : newNc.getUidRanges(); if (null == prevRanges) prevRanges = new ArraySet<>(); if (null == newRanges) newRanges = new ArraySet<>(); final Set<UidRange> prevRangesCopy = new ArraySet<>(prevRanges); @@ -7130,7 +7316,7 @@ public class ConnectivityService extends IConnectivityManager.Stub putParcelable( bundle, createWithLocationInfoSanitizedIfNecessaryWhenParceled( - nc, includeLocationSensitiveInfo, nri.mUid, + nc, includeLocationSensitiveInfo, nri.mPid, nri.mUid, nrForCallback.getRequestorPackageName(), nri.mCallingAttributionTag)); putParcelable(bundle, linkPropertiesRestrictedForCallerPermissions( @@ -7151,7 +7337,7 @@ public class ConnectivityService extends IConnectivityManager.Stub putParcelable( bundle, createWithLocationInfoSanitizedIfNecessaryWhenParceled( - netCap, includeLocationSensitiveInfo, nri.mUid, + netCap, includeLocationSensitiveInfo, nri.mPid, nri.mUid, nrForCallback.getRequestorPackageName(), nri.mCallingAttributionTag)); break; @@ -7818,6 +8004,7 @@ public class ConnectivityService extends IConnectivityManager.Stub updateCapabilitiesForNetwork(networkAgent); } networkAgent.created = true; + networkAgent.onNetworkCreated(); } if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) { @@ -7905,12 +8092,11 @@ public class ConnectivityService extends IConnectivityManager.Stub return; } + final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE); final boolean metered = nai.networkCapabilities.isMetered(); - boolean blocked; - blocked = isUidBlockedByVpn(nri.mUid, mVpnBlockedUidRanges); - blocked |= NetworkPolicyManager.isUidBlocked( - mUidBlockedReasons.get(nri.mUid, BLOCKED_REASON_NONE), metered); - callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, blocked ? 1 : 0); + final boolean vpnBlocked = isUidBlockedByVpn(nri.mAsUid, mVpnBlockedUidRanges); + callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, + getBlockedState(blockedReasons, metered, vpnBlocked)); } // Notify the requests on this NAI that the network is now lingered. @@ -7919,6 +8105,21 @@ public class ConnectivityService extends IConnectivityManager.Stub notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime); } + private static int getBlockedState(int reasons, boolean metered, boolean vpnBlocked) { + if (!metered) reasons &= ~BLOCKED_METERED_REASON_MASK; + return vpnBlocked + ? reasons | BLOCKED_REASON_LOCKDOWN_VPN + : reasons & ~BLOCKED_REASON_LOCKDOWN_VPN; + } + + private void setUidBlockedReasons(int uid, @BlockedReason int blockedReasons) { + if (blockedReasons == BLOCKED_REASON_NONE) { + mUidBlockedReasons.delete(uid); + } else { + mUidBlockedReasons.put(uid, blockedReasons); + } + } + /** * Notify of the blocked state apps with a registered callback matching a given NAI. * @@ -7926,7 +8127,10 @@ public class ConnectivityService extends IConnectivityManager.Stub * any given nai, all requests need to be considered according to the uid who filed it. * * @param nai The target NetworkAgentInfo. - * @param oldMetered True if the previous network capabilities is metered. + * @param oldMetered True if the previous network capabilities were metered. + * @param newMetered True if the current network capabilities are metered. + * @param oldBlockedUidRanges list of UID ranges previously blocked by lockdown VPN. + * @param newBlockedUidRanges list of UID ranges blocked by lockdown VPN. */ private void maybeNotifyNetworkBlocked(NetworkAgentInfo nai, boolean oldMetered, boolean newMetered, List<UidRange> oldBlockedUidRanges, @@ -7935,22 +8139,18 @@ public class ConnectivityService extends IConnectivityManager.Stub for (int i = 0; i < nai.numNetworkRequests(); i++) { NetworkRequest nr = nai.requestAt(i); NetworkRequestInfo nri = mNetworkRequests.get(nr); - final boolean oldBlocked, newBlocked, oldVpnBlocked, newVpnBlocked; - oldVpnBlocked = isUidBlockedByVpn(nri.mUid, oldBlockedUidRanges); - newVpnBlocked = (oldBlockedUidRanges != newBlockedUidRanges) - ? isUidBlockedByVpn(nri.mUid, newBlockedUidRanges) + final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE); + final boolean oldVpnBlocked = isUidBlockedByVpn(nri.mAsUid, oldBlockedUidRanges); + final boolean newVpnBlocked = (oldBlockedUidRanges != newBlockedUidRanges) + ? isUidBlockedByVpn(nri.mAsUid, newBlockedUidRanges) : oldVpnBlocked; - final int blockedReasons = mUidBlockedReasons.get(nri.mUid, BLOCKED_REASON_NONE); - oldBlocked = oldVpnBlocked || NetworkPolicyManager.isUidBlocked( - blockedReasons, oldMetered); - newBlocked = newVpnBlocked || NetworkPolicyManager.isUidBlocked( - blockedReasons, newMetered); - - if (oldBlocked != newBlocked) { + final int oldBlockedState = getBlockedState(blockedReasons, oldMetered, oldVpnBlocked); + final int newBlockedState = getBlockedState(blockedReasons, newMetered, newVpnBlocked); + if (oldBlockedState != newBlockedState) { callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED, - encodeBool(newBlocked)); + newBlockedState); } } } @@ -7960,25 +8160,23 @@ public class ConnectivityService extends IConnectivityManager.Stub * @param uid The uid for which the rules changed. * @param blockedReasons The reasons for why an uid is blocked. */ - private void maybeNotifyNetworkBlockedForNewState(int uid, int blockedReasons) { + private void maybeNotifyNetworkBlockedForNewState(int uid, @BlockedReason int blockedReasons) { for (final NetworkAgentInfo nai : mNetworkAgentInfos) { final boolean metered = nai.networkCapabilities.isMetered(); final boolean vpnBlocked = isUidBlockedByVpn(uid, mVpnBlockedUidRanges); - final boolean oldBlocked, newBlocked; - oldBlocked = vpnBlocked || NetworkPolicyManager.isUidBlocked( - mUidBlockedReasons.get(uid, BLOCKED_REASON_NONE), metered); - newBlocked = vpnBlocked || NetworkPolicyManager.isUidBlocked( - blockedReasons, metered); - if (oldBlocked == newBlocked) { + final int oldBlockedState = getBlockedState( + mUidBlockedReasons.get(uid, BLOCKED_REASON_NONE), metered, vpnBlocked); + final int newBlockedState = getBlockedState(blockedReasons, metered, vpnBlocked); + if (oldBlockedState == newBlockedState) { continue; } - final int arg = encodeBool(newBlocked); for (int i = 0; i < nai.numNetworkRequests(); i++) { NetworkRequest nr = nai.requestAt(i); NetworkRequestInfo nri = mNetworkRequests.get(nr); - if (nri != null && nri.mUid == uid) { - callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED, arg); + if (nri != null && nri.mAsUid == uid) { + callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED, + newBlockedState); } } } @@ -8742,7 +8940,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // nri is not bound to the death of callback. Instead, callback.bindToDeath() is set in // handleRegisterConnectivityDiagnosticsCallback(). nri will be cleaned up as part of the // callback's binder death. - final NetworkRequestInfo nri = new NetworkRequestInfo(requestWithId); + final NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, requestWithId); final ConnectivityDiagnosticsCallbackInfo cbInfo = new ConnectivityDiagnosticsCallbackInfo(callback, nri, callingPackageName); @@ -9225,8 +9423,8 @@ public class ConnectivityService extends IConnectivityManager.Stub final ArrayList<NetworkRequest> nrs = new ArrayList<>(); nrs.add(createNetworkRequest(NetworkRequest.Type.REQUEST, pref.capabilities)); nrs.add(createDefaultRequest()); - setNetworkRequestUids(nrs, pref.capabilities.getUids()); - final NetworkRequestInfo nri = new NetworkRequestInfo(nrs); + setNetworkRequestUids(nrs, UidRange.fromIntRanges(pref.capabilities.getUids())); + final NetworkRequestInfo nri = new NetworkRequestInfo(Process.myUid(), nrs); result.add(nri); } return result; @@ -9397,7 +9595,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } // Include this nri if it will be tracked by the new per-app default requests. final boolean isNriGoingToBeTracked = - getDefaultRequestTrackingUid(nri.mUid) != mDefaultRequest; + getDefaultRequestTrackingUid(nri.mAsUid) != mDefaultRequest; if (isNriGoingToBeTracked) { defaultCallbackRequests.add(nri); } @@ -9419,7 +9617,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final ArraySet<NetworkRequestInfo> callbackRequestsToRegister = new ArraySet<>(); for (final NetworkRequestInfo callbackRequest : perAppCallbackRequestsForUpdate) { final NetworkRequestInfo trackingNri = - getDefaultRequestTrackingUid(callbackRequest.mUid); + getDefaultRequestTrackingUid(callbackRequest.mAsUid); // If this nri is not being tracked, the change it back to an untracked nri. if (trackingNri == mDefaultRequest) { @@ -9429,21 +9627,20 @@ public class ConnectivityService extends IConnectivityManager.Stub continue; } - final String requestorPackageName = - callbackRequest.mRequests.get(0).getRequestorPackageName(); + final NetworkRequest request = callbackRequest.mRequests.get(0); callbackRequestsToRegister.add(new NetworkRequestInfo( callbackRequest, copyNetworkRequestsForUid( - trackingNri.mRequests, callbackRequest.mUid, requestorPackageName))); + trackingNri.mRequests, callbackRequest.mAsUid, + callbackRequest.mUid, request.getRequestorPackageName()))); } 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); + req.networkCapabilities.setUids(UidRange.toIntRanges(uids)); } } @@ -9539,7 +9736,7 @@ public class ConnectivityService extends IConnectivityManager.Stub ranges.add(new UidRange(uid, uid)); } setNetworkRequestUids(requests, ranges); - return new NetworkRequestInfo(requests); + return new NetworkRequestInfo(Process.myUid(), requests); } private NetworkRequest createUnmeteredNetworkRequest() { diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 4c3c6ef21fc5..794cb9301d69 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1651,7 +1651,7 @@ public class IpSecService extends IIpSecService.Stub { c.getMode(), c.getSourceAddress(), c.getDestinationAddress(), - (c.getNetwork() != null) ? c.getNetwork().netId : 0, + (c.getNetwork() != null) ? c.getNetwork().getNetId() : 0, spiRecord.getSpi(), c.getMarkValue(), c.getMarkMask(), diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java index 3148a6205871..1241b77798ff 100644 --- a/services/core/java/com/android/server/PinnerService.java +++ b/services/core/java/com/android/server/PinnerService.java @@ -270,18 +270,9 @@ public final class PinnerService extends SystemService { * Handler for on start pinning message */ private void handlePinOnStart() { - final String bootImage = SystemProperties.get("dalvik.vm.boot-image", ""); - String[] filesToPin = null; - if (bootImage.endsWith("boot-image.prof")) { - // Use the files listed for that specific boot image. - // TODO: find a better way to know we're using the JIT zygote configuration. - filesToPin = mContext.getResources().getStringArray( - com.android.internal.R.array.config_jitzygoteBootImagePinnerServiceFiles); - } else { - // Files to pin come from the overlay and can be specified per-device config - filesToPin = mContext.getResources().getStringArray( - com.android.internal.R.array.config_defaultPinnerServiceFiles); - } + // Files to pin come from the overlay and can be specified per-device config + String[] filesToPin = mContext.getResources().getStringArray( + com.android.internal.R.array.config_defaultPinnerServiceFiles); // Continue trying to pin each file even if we fail to pin some of them for (String fileToPin : filesToPin) { PinnedFile pf = pinFile(fileToPin, @@ -291,10 +282,32 @@ public final class PinnerService extends SystemService { Slog.e(TAG, "Failed to pin file = " + fileToPin); continue; } - synchronized (this) { mPinnedFiles.add(pf); } + if (fileToPin.endsWith(".jar") | fileToPin.endsWith(".apk")) { + // Check whether the runtime has compilation artifacts to pin. + String arch = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); + String[] files = null; + try { + files = DexFile.getDexFileOutputPaths(fileToPin, arch); + } catch (IOException ioe) { } + if (files == null) { + continue; + } + for (String file : files) { + PinnedFile df = pinFile(file, + Integer.MAX_VALUE, + /*attemptPinIntrospection=*/false); + if (df == null) { + Slog.i(TAG, "Failed to pin ART file = " + file); + continue; + } + synchronized (this) { + mPinnedFiles.add(df); + } + } + } } } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index e8ef7e2c5a2c..a95589b5ace3 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -319,7 +319,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private int[] mDataEnabledReason; - private Map<Integer, Long> mAllowedNetworkTypesList; + private int[] mAllowedNetworkTypeReason; + private long[] mAllowedNetworkTypeValue; private List<List<LinkCapacityEstimate>> mLinkCapacityEstimateLists; @@ -388,7 +389,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { private boolean isPrivilegedPhoneStatePermissionRequired(Set<Integer> events) { return events.contains(TelephonyCallback.EVENT_SRVCC_STATE_CHANGED) || events.contains(TelephonyCallback.EVENT_VOICE_ACTIVATION_STATE_CHANGED) - || events.contains(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED); + || events.contains(TelephonyCallback.EVENT_RADIO_POWER_STATE_CHANGED) + || events.contains(TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED); } private static final int MSG_USER_SWITCHED = 1; @@ -532,6 +534,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mTelephonyDisplayInfos = copyOf(mTelephonyDisplayInfos, mNumPhones); mIsDataEnabled= copyOf(mIsDataEnabled, mNumPhones); mDataEnabledReason = copyOf(mDataEnabledReason, mNumPhones); + mAllowedNetworkTypeReason = copyOf(mAllowedNetworkTypeReason, mNumPhones); + mAllowedNetworkTypeValue = copyOf(mAllowedNetworkTypeValue, mNumPhones); // ds -> ss switch. if (mNumPhones < oldNumPhones) { @@ -577,6 +581,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build()); mIsDataEnabled[i] = false; mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER; + mAllowedNetworkTypeReason[i] = -1; + mAllowedNetworkTypeValue[i] = -1; mLinkCapacityEstimateLists.add(i, new ArrayList<>()); } } @@ -637,10 +643,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mBarringInfo = new ArrayList<>(); mTelephonyDisplayInfos = new TelephonyDisplayInfo[numPhones]; mPhysicalChannelConfigs = new ArrayList<>(); + mAllowedNetworkTypeReason = new int[numPhones]; + mAllowedNetworkTypeValue = new long[numPhones]; mIsDataEnabled = new boolean[numPhones]; mDataEnabledReason = new int[numPhones]; - mAllowedNetworkTypesList = new HashMap<>(); mLinkCapacityEstimateLists = new ArrayList<>(); + for (int i = 0; i < numPhones; i++) { mCallState[i] = TelephonyManager.CALL_STATE_IDLE; mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE; @@ -673,6 +681,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mPhysicalChannelConfigs.add(i, new PhysicalChannelConfig.Builder().build()); mIsDataEnabled[i] = false; mDataEnabledReason[i] = TelephonyManager.DATA_ENABLED_REASON_USER; + mAllowedNetworkTypeReason[i] = -1; + mAllowedNetworkTypeValue[i] = -1; mLinkCapacityEstimateLists.add(i, new ArrayList<>()); } @@ -1160,7 +1170,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyCallback.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)) { try { r.callback.onPhysicalChannelConfigChanged( - mPhysicalChannelConfigs); + shouldSanitizeLocationForPhysicalChannelConfig(r) + ? getLocationSanitizedConfigs(mPhysicalChannelConfigs) + : mPhysicalChannelConfigs); } catch (RemoteException ex) { remove(r.binder); } @@ -1175,14 +1187,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } if (events.contains( - TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED)) { - try { - r.callback.onAllowedNetworkTypesChanged(mAllowedNetworkTypesList); - } catch (RemoteException ex) { - remove(r.binder); - } - } - if (events.contains( TelephonyCallback.EVENT_LINK_CAPACITY_ESTIMATE_CHANGED)) { try { if (mLinkCapacityEstimateLists.get(phoneId) != null) { @@ -2369,8 +2373,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { return; } + List<PhysicalChannelConfig> sanitizedConfigs = getLocationSanitizedConfigs(configs); if (VDBG) { - log("notifyPhysicalChannelConfig: subId=" + subId + " configs=" + configs); + log("notifyPhysicalChannelConfig: subId=" + subId + " configs=" + configs + + " sanitizedConfigs=" + sanitizedConfigs); } synchronized (mRecords) { @@ -2383,11 +2389,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { && idMatch(r.subId, subId, phoneId)) { try { if (DBG_LOC) { - log("notifyPhysicalChannelConfig: " - + "mPhysicalChannelConfigs=" - + configs + " r=" + r); + log("notifyPhysicalChannelConfig: mPhysicalChannelConfigs=" + + (shouldSanitizeLocationForPhysicalChannelConfig(r) + ? sanitizedConfigs : configs) + + " r=" + r); } - r.callback.onPhysicalChannelConfigChanged(configs); + r.callback.onPhysicalChannelConfigChanged( + shouldSanitizeLocationForPhysicalChannelConfig(r) + ? sanitizedConfigs : configs); } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -2398,6 +2407,25 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } + private static boolean shouldSanitizeLocationForPhysicalChannelConfig(Record record) { + // Always redact location info from PhysicalChannelConfig if the registrant is from neither + // PHONE nor SYSTEM process. There is no user case that the registrant needs the location + // info (e.g. physicalCellId). This also remove the need for the location permissions check. + return record.callerUid != Process.PHONE_UID && record.callerUid != Process.SYSTEM_UID; + } + + /** + * Return a copy of the PhysicalChannelConfig list but with location info removed. + */ + private static List<PhysicalChannelConfig> getLocationSanitizedConfigs( + List<PhysicalChannelConfig> configs) { + List<PhysicalChannelConfig> sanitizedConfigs = new ArrayList<>(configs.size()); + for (PhysicalChannelConfig config : configs) { + sanitizedConfigs.add(config.createLocationInfoSanitizedCopy()); + } + return sanitizedConfigs; + } + /** * Notify that the data enabled has changed. * @@ -2443,18 +2471,19 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { * * @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. + * @param reason the allowed network type reason. + * @param allowedNetworkType the allowed network type value. */ - public void notifyAllowedNetworkTypesChanged(int phoneId, int subId, - Map allowedNetworkTypesList) { + public void notifyAllowedNetworkTypesChanged(int phoneId, int subId, int reason, + long allowedNetworkType) { if (!checkNotifyPermission("notifyAllowedNetworkTypesChanged()")) { return; } synchronized (mRecords) { if (validatePhoneId(phoneId)) { - mAllowedNetworkTypesList = allowedNetworkTypesList; + mAllowedNetworkTypeReason[phoneId] = reason; + mAllowedNetworkTypeValue[phoneId] = allowedNetworkType; for (Record r : mRecords) { if (r.matchTelephonyCallbackEvent( @@ -2462,10 +2491,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { && idMatch(r.subId, subId, phoneId)) { try { if (VDBG) { - log("notifyAllowedNetworkTypesChanged: AllowedNetworkTypesList= " - + mAllowedNetworkTypesList.toString()); + log("notifyAllowedNetworkTypesChanged: reason= " + reason + + ", allowed network type:" + + TelephonyManager.convertNetworkTypeBitmaskToString( + allowedNetworkType)); } - r.callback.onAllowedNetworkTypesChanged(mAllowedNetworkTypesList); + r.callback.onAllowedNetworkTypesChanged(reason, allowedNetworkType); } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -2556,6 +2587,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { pw.println("mTelephonyDisplayInfo=" + mTelephonyDisplayInfos[i]); pw.println("mIsDataEnabled=" + mIsDataEnabled); pw.println("mDataEnabledReason=" + mDataEnabledReason); + pw.println("mAllowedNetworkTypeReason=" + mAllowedNetworkTypeReason[i]); + pw.println("mAllowedNetworkTypeValue=" + mAllowedNetworkTypeValue[i]); pw.println("mLinkCapacityEstimateList=" + mLinkCapacityEstimateLists.get(i)); pw.decreaseIndent(); } diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java index 6c18cdea51fa..4622e98bbbb2 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -29,7 +29,10 @@ import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AppOpsManager; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.NetworkCapabilities; @@ -158,6 +161,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { @NonNull private final TelephonySubscriptionTrackerCallback mTelephonySubscriptionTrackerCb; @NonNull private final TelephonySubscriptionTracker mTelephonySubscriptionTracker; @NonNull private final VcnContext mVcnContext; + @NonNull private final BroadcastReceiver mPkgChangeReceiver; /** Can only be assigned when {@link #systemReady()} is called, since it uses AppOpsManager. */ @Nullable private LocationPermissionChecker mLocationPermissionChecker; @@ -203,6 +207,29 @@ public class VcnManagementService extends IVcnManagementService.Stub { mConfigDiskRwHelper = mDeps.newPersistableBundleLockingReadWriteHelper(VCN_CONFIG_FILE); mVcnContext = mDeps.newVcnContext(mContext, mLooper, mNetworkProvider); + mPkgChangeReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + + if (Intent.ACTION_PACKAGE_ADDED.equals(action) + || Intent.ACTION_PACKAGE_REPLACED.equals(action) + || Intent.ACTION_PACKAGE_REMOVED.equals(action)) { + mTelephonySubscriptionTracker.handleSubscriptionsChanged(); + } else { + Log.wtf(TAG, "received unexpected intent: " + action); + } + } + }; + + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); + intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED); + intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); + intentFilter.addDataScheme("package"); + mContext.registerReceiver( + mPkgChangeReceiver, intentFilter, null /* broadcastPermission */, mHandler); + // Run on handler to ensure I/O does not block system server startup mHandler.post(() -> { PersistableBundle configBundle = null; @@ -349,7 +376,8 @@ public class VcnManagementService extends IVcnManagementService.Stub { } } - private void enforceCallingUserAndCarrierPrivilege(ParcelUuid subscriptionGroup) { + private void enforceCallingUserAndCarrierPrivilege( + ParcelUuid subscriptionGroup, String pkgName) { // Only apps running in the primary (system) user are allowed to configure the VCN. This is // in line with Telephony's behavior with regards to binding to a Carrier App provided // CarrierConfigService. @@ -363,12 +391,15 @@ public class VcnManagementService extends IVcnManagementService.Stub { subscriptionInfos.addAll(subMgr.getSubscriptionsInGroup(subscriptionGroup)); }); - final TelephonyManager telMgr = mContext.getSystemService(TelephonyManager.class); for (SubscriptionInfo info : subscriptionInfos) { + final TelephonyManager telMgr = mContext.getSystemService(TelephonyManager.class) + .createForSubscriptionId(info.getSubscriptionId()); + // Check subscription is active first; much cheaper/faster check, and an app (currently) // cannot be carrier privileged for inactive subscriptions. if (subMgr.isValidSlotIndex(info.getSimSlotIndex()) - && telMgr.hasCarrierPrivileges(info.getSubscriptionId())) { + && telMgr.checkCarrierPrivilegesForPackage(pkgName) + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { // TODO (b/173717728): Allow configuration for inactive, but manageable // subscriptions. // TODO (b/173718661): Check for whole subscription groups at a time. @@ -536,7 +567,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { mContext.getSystemService(AppOpsManager.class) .checkPackage(mDeps.getBinderCallingUid(), config.getProvisioningPackageName()); - enforceCallingUserAndCarrierPrivilege(subscriptionGroup); + enforceCallingUserAndCarrierPrivilege(subscriptionGroup, opPkgName); Binder.withCleanCallingIdentity(() -> { synchronized (mLock) { @@ -554,11 +585,14 @@ public class VcnManagementService extends IVcnManagementService.Stub { * <p>Implements the IVcnManagementService Binder interface. */ @Override - public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) { + public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull String opPkgName) { requireNonNull(subscriptionGroup, "subscriptionGroup was null"); + requireNonNull(opPkgName, "opPkgName was null"); Slog.v(TAG, "VCN config cleared for subGrp: " + subscriptionGroup); - enforceCallingUserAndCarrierPrivilege(subscriptionGroup); + mContext.getSystemService(AppOpsManager.class) + .checkPackage(mDeps.getBinderCallingUid(), opPkgName); + enforceCallingUserAndCarrierPrivilege(subscriptionGroup, opPkgName); Binder.withCleanCallingIdentity(() -> { synchronized (mLock) { @@ -821,8 +855,7 @@ public class VcnManagementService extends IVcnManagementService.Stub { final IBinder cbBinder = callback.asBinder(); final VcnStatusCallbackInfo cbInfo = - new VcnStatusCallbackInfo( - subGroup, callback, opPkgName, mDeps.getBinderCallingUid()); + new VcnStatusCallbackInfo(subGroup, callback, opPkgName, callingUid); try { cbBinder.linkToDeath(cbInfo, 0 /* flags */); diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java index 56aabc208027..d756c1ffd00f 100644 --- a/services/core/java/com/android/server/VpnManagerService.java +++ b/services/core/java/com/android/server/VpnManagerService.java @@ -352,7 +352,10 @@ public class VpnManagerService extends IVpnManager.Stub { @Override public void startLegacyVpn(VpnProfile profile) { int user = UserHandle.getUserId(mDeps.getCallingUid()); - final LinkProperties egress = mCm.getActiveLinkProperties(); + // Note that if the caller is not system (uid >= Process.FIRST_APPLICATION_UID), + // the code might not work well since getActiveNetwork might return null if the uid is + // blocked by NetworkPolicyManagerService. + final LinkProperties egress = mCm.getLinkProperties(mCm.getActiveNetwork()); if (egress == null) { throw new IllegalStateException("Missing active network connection"); } diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java index b3373d0bb536..351231f34c4b 100644 --- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java +++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java @@ -69,6 +69,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -101,6 +102,7 @@ public final class AppHibernationService extends SystemService { private final Map<String, GlobalLevelState> mGlobalHibernationStates = new ArrayMap<>(); private final HibernationStateDiskStore<GlobalLevelState> mGlobalLevelHibernationDiskStore; private final Injector mInjector; + private final Executor mBackgroundExecutor; @VisibleForTesting boolean mIsServiceEnabled; @@ -126,6 +128,7 @@ public final class AppHibernationService extends SystemService { mIActivityManager = injector.getActivityManager(); mUserManager = injector.getUserManager(); mGlobalLevelHibernationDiskStore = injector.getGlobalLevelDiskStore(); + mBackgroundExecutor = injector.getBackgroundExecutor(); mInjector = injector; final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */); @@ -147,11 +150,13 @@ public final class AppHibernationService extends SystemService { @Override public void onBootPhase(int phase) { if (phase == PHASE_BOOT_COMPLETED) { - List<GlobalLevelState> states = - mGlobalLevelHibernationDiskStore.readHibernationStates(); - synchronized (mLock) { - initializeGlobalHibernationStates(states); - } + mBackgroundExecutor.execute(() -> { + List<GlobalLevelState> states = + mGlobalLevelHibernationDiskStore.readHibernationStates(); + synchronized (mLock) { + initializeGlobalHibernationStates(states); + } + }); } if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { mIsServiceEnabled = isAppHibernationEnabled(); @@ -170,16 +175,15 @@ public final class AppHibernationService extends SystemService { * @return true if package is hibernating for the user */ boolean isHibernatingForUser(String packageName, int userId) { - if (!checkHibernationEnabled("isHibernatingForUser")) { + String methodName = "isHibernatingForUser"; + if (!checkHibernationEnabled(methodName)) { return false; } getContext().enforceCallingOrSelfPermission( android.Manifest.permission.MANAGE_APP_HIBERNATION, "Caller does not have MANAGE_APP_HIBERNATION permission."); - userId = handleIncomingUser(userId, "isHibernating"); - if (!mUserManager.isUserUnlockingOrUnlocked(userId)) { - Slog.e(TAG, "Attempt to get hibernation state of stopped or nonexistent user " - + userId); + userId = handleIncomingUser(userId, methodName); + if (!checkUserStatesExist(userId, methodName)) { return false; } synchronized (mLock) { @@ -225,16 +229,15 @@ public final class AppHibernationService extends SystemService { * @param isHibernating new hibernation state */ void setHibernatingForUser(String packageName, int userId, boolean isHibernating) { - if (!checkHibernationEnabled("setHibernatingForUser")) { + String methodName = "setHibernatingForUser"; + if (!checkHibernationEnabled(methodName)) { return; } getContext().enforceCallingOrSelfPermission( android.Manifest.permission.MANAGE_APP_HIBERNATION, "Caller does not have MANAGE_APP_HIBERNATION permission."); - userId = handleIncomingUser(userId, "setHibernating"); - if (!mUserManager.isUserUnlockingOrUnlocked(userId)) { - Slog.w(TAG, "Attempt to set hibernation state for a stopped or nonexistent user " - + userId); + userId = handleIncomingUser(userId, methodName); + if (!checkUserStatesExist(userId, methodName)) { return; } synchronized (mLock) { @@ -298,16 +301,15 @@ public final class AppHibernationService extends SystemService { */ @NonNull List<String> getHibernatingPackagesForUser(int userId) { ArrayList<String> hibernatingPackages = new ArrayList<>(); - if (!checkHibernationEnabled("getHibernatingPackagesForUser")) { + String methodName = "getHibernatingPackagesForUser"; + if (!checkHibernationEnabled(methodName)) { return hibernatingPackages; } getContext().enforceCallingOrSelfPermission( android.Manifest.permission.MANAGE_APP_HIBERNATION, "Caller does not have MANAGE_APP_HIBERNATION permission."); - userId = handleIncomingUser(userId, "getHibernatingPackagesForUser"); - if (!mUserManager.isUserUnlockingOrUnlocked(userId)) { - Slog.w(TAG, "Attempt to get hibernating packages for a stopped or nonexistent user " - + userId); + userId = handleIncomingUser(userId, methodName); + if (!checkUserStatesExist(userId, methodName)) { return hibernatingPackages; } synchronized (mLock) { @@ -477,10 +479,15 @@ public final class AppHibernationService extends SystemService { HibernationStateDiskStore<UserLevelState> diskStore = mInjector.getUserLevelDiskStore(userId); mUserDiskStores.put(userId, diskStore); - List<UserLevelState> storedStates = diskStore.readHibernationStates(); - synchronized (mLock) { - initializeUserHibernationStates(userId, storedStates); - } + mBackgroundExecutor.execute(() -> { + List<UserLevelState> storedStates = diskStore.readHibernationStates(); + synchronized (mLock) { + // Ensure user hasn't stopped in the time to execute. + if (mUserManager.isUserUnlockingOrUnlocked(userId)) { + initializeUserHibernationStates(userId, storedStates); + } + } + }); } @Override @@ -550,6 +557,20 @@ public final class AppHibernationService extends SystemService { } } + private boolean checkUserStatesExist(int userId, String methodName) { + if (!mUserManager.isUserUnlockingOrUnlocked(userId)) { + Slog.e(TAG, String.format( + "Attempt to call %s on stopped or nonexistent user %d", methodName, userId)); + return false; + } + if (!mUserStates.contains(userId)) { + Slog.w(TAG, String.format( + "Attempt to call %s before states have been read from disk", methodName)); + return false; + } + return true; + } + private boolean checkHibernationEnabled(String methodName) { if (!mIsServiceEnabled) { Slog.w(TAG, String.format("Attempted to call %s on unsupported device.", methodName)); @@ -720,6 +741,8 @@ public final class AppHibernationService extends SystemService { UserManager getUserManager(); + Executor getBackgroundExecutor(); + HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore(); HibernationStateDiskStore<UserLevelState> getUserLevelDiskStore(int userId); @@ -758,6 +781,11 @@ public final class AppHibernationService extends SystemService { } @Override + public Executor getBackgroundExecutor() { + return mScheduledExecutorService; + } + + @Override public HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore() { File dir = new File(Environment.getDataSystemDirectory(), HIBERNATION_DIR_NAME); return new HibernationStateDiskStore<>( diff --git a/services/core/java/com/android/server/apphibernation/HibernationStateDiskStore.java b/services/core/java/com/android/server/apphibernation/HibernationStateDiskStore.java index c83659d2ff56..24cf43339847 100644 --- a/services/core/java/com/android/server/apphibernation/HibernationStateDiskStore.java +++ b/services/core/java/com/android/server/apphibernation/HibernationStateDiskStore.java @@ -109,6 +109,7 @@ class HibernationStateDiskStore<T> { * @return the parsed list of hibernation states, null if file does not exist */ @Nullable + @WorkerThread List<T> readHibernationStates() { synchronized (this) { if (!mHibernationFile.exists()) { diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index b355730c6450..6aec9fcf9a24 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -91,18 +91,44 @@ class HostClipboardMonitor implements Runnable { return bits; } - private void openPipe() { + private boolean openPipe() { try { - mPipe = new RandomAccessFile(PIPE_DEVICE, "rw"); - mPipe.write(createOpenHandshake()); - } catch (IOException e) { + final RandomAccessFile pipe = new RandomAccessFile(PIPE_DEVICE, "rw"); try { - if (mPipe != null) mPipe.close(); - } catch (IOException ee) {} + pipe.write(createOpenHandshake()); + mPipe = pipe; + return true; + } catch (IOException ignore) { + pipe.close(); + } + } catch (IOException ignore) { + } + return false; + } + + private void closePipe() { + try { + final RandomAccessFile pipe = mPipe; mPipe = null; + if (pipe != null) { + pipe.close(); + } + } catch (IOException ignore) { } } + private byte[] receiveMessage() throws IOException { + final int size = Integer.reverseBytes(mPipe.readInt()); + final byte[] receivedData = new byte[size]; + mPipe.readFully(receivedData); + return receivedData; + } + + private void sendMessage(byte[] message) throws IOException { + mPipe.writeInt(Integer.reverseBytes(message.length)); + mPipe.write(message); + } + public HostClipboardMonitor(HostClipboardCallback cb) { mHostClipboardCallback = cb; } @@ -114,21 +140,15 @@ class HostClipboardMonitor implements Runnable { // There's no guarantee that QEMU pipes will be ready at the moment // this method is invoked. We simply try to get the pipe open and // retry on failure indefinitely. - while (mPipe == null) { - openPipe(); + while ((mPipe == null) && !openPipe()) { Thread.sleep(100); } - int size = mPipe.readInt(); - size = Integer.reverseBytes(size); - byte[] receivedData = new byte[size]; - mPipe.readFully(receivedData); + + final byte[] receivedData = receiveMessage(); mHostClipboardCallback.onHostClipboardUpdated( new String(receivedData)); } catch (IOException e) { - try { - mPipe.close(); - } catch (IOException ee) {} - mPipe = null; + closePipe(); } catch (InterruptedException e) {} } } @@ -136,8 +156,7 @@ class HostClipboardMonitor implements Runnable { public void setHostClipboard(String content) { try { if (mPipe != null) { - mPipe.writeInt(Integer.reverseBytes(content.getBytes().length)); - mPipe.write(content.getBytes()); + sendMessage(content.getBytes()); } } catch(IOException e) { Slog.e("HostClipboardMonitor", diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java index ae9b0015de43..d29a0c715e95 100644 --- a/services/core/java/com/android/server/compat/CompatChange.java +++ b/services/core/java/com/android/server/compat/CompatChange.java @@ -23,7 +23,9 @@ import static android.app.compat.PackageOverride.VALUE_UNDEFINED; import android.annotation.Nullable; import android.app.compat.PackageOverride; import android.compat.annotation.ChangeId; +import android.compat.annotation.Disabled; import android.compat.annotation.EnabledSince; +import android.compat.annotation.Overridable; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -60,6 +62,15 @@ public final class CompatChange extends CompatibilityChangeInfo { static final long CTS_SYSTEM_API_CHANGEID = 149391281; // This is a bug id. /** + * An overridable change ID to be used only in the CTS test for this SystemApi + */ + @ChangeId + @Disabled + @Overridable + static final long CTS_SYSTEM_API_OVERRIDABLE_CHANGEID = 174043039; // This is a bug id. + + + /** * Callback listener for when compat changes are updated for a package. * See {@link #registerListener(ChangeListener)} for more details. */ @@ -211,6 +222,7 @@ public final class CompatChange extends CompatibilityChangeInfo { boolean hasPackageOverride(String pname) { return mRawOverrides.containsKey(pname); } + /** * Remove any package override for the given package name, restoring the default behaviour. * @@ -355,7 +367,7 @@ public final class CompatChange extends CompatibilityChangeInfo { override.setPackageName(entry.getKey()); override.setMinVersionCode(entry.getValue().getMinVersionCode()); override.setMaxVersionCode(entry.getValue().getMaxVersionCode()); - override.setEnabled(entry.getValue().getEnabled()); + override.setEnabled(entry.getValue().isEnabled()); rawList.add(override); } changeOverrides.setRaw(rawOverrides); diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java index ef86f42d6c3c..55e269630093 100644 --- a/services/core/java/com/android/server/compat/CompatConfig.java +++ b/services/core/java/com/android/server/compat/CompatConfig.java @@ -304,6 +304,16 @@ final class CompatConfig { } /** + * Returns whether the change is overridable. + */ + boolean isOverridable(long changeId) { + synchronized (mChanges) { + CompatChange c = mChanges.get(changeId); + return c != null && c.getOverridable(); + } + } + + /** * Removes an override previously added via {@link #addOverride(long, String, boolean)}. * * <p>This restores the default behaviour for the given change and app, once any app processes @@ -343,7 +353,7 @@ final class CompatConfig { /** * Removes all overrides previously added via {@link #addOverride(long, String, boolean)} or - * {@link #addOverrides(CompatibilityChangeConfig, String)} for a certain package. + * {@link #addOverrides(CompatibilityOverrideConfig, String)} for a certain package. * * <p>This restores the default behaviour for the given app. * @@ -632,8 +642,11 @@ final class CompatConfig { } boolean shouldInvalidateCache = false; for (CompatChange c: changes) { + if (!c.hasPackageOverride(packageName)) { + continue; + } OverrideAllowedState allowedState = - mOverrideValidator.getOverrideAllowedState(c.getId(), packageName); + mOverrideValidator.getOverrideAllowedStateForRecheck(c.getId(), packageName); shouldInvalidateCache |= c.recheckOverride(packageName, allowedState, mContext); } if (shouldInvalidateCache) { diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java index aa66a1a8b01f..b5006913af35 100644 --- a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java +++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java @@ -16,6 +16,9 @@ package com.android.server.compat; +import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; + import static com.android.internal.compat.OverrideAllowedState.ALLOWED; import static com.android.internal.compat.OverrideAllowedState.DEFERRED_VERIFICATION; import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK; @@ -24,6 +27,7 @@ import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_S import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE; import static com.android.internal.compat.OverrideAllowedState.PLATFORM_TOO_OLD; +import android.annotation.NonNull; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -69,8 +73,25 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub { mForceNonDebuggableFinalBuild = false; } + /** + * Check the allowed state for the given changeId and packageName on a recheck. + * + * <p>Recheck happens when the given app is getting updated. In this case we cannot do a + * permission check on the caller, so we're using the fact that the override was present as + * proof that the original caller was allowed to set this override. + */ + OverrideAllowedState getOverrideAllowedStateForRecheck(long changeId, + @NonNull String packageName) { + return getOverrideAllowedStateInternal(changeId, packageName, true); + } + @Override public OverrideAllowedState getOverrideAllowedState(long changeId, String packageName) { + return getOverrideAllowedStateInternal(changeId, packageName, false); + } + + private OverrideAllowedState getOverrideAllowedStateInternal(long changeId, String packageName, + boolean isRecheck) { if (mCompatConfig.isLoggingOnly(changeId)) { return new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1); } @@ -99,6 +120,16 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub { } catch (NameNotFoundException e) { return new OverrideAllowedState(DEFERRED_VERIFICATION, -1, -1); } + // If the change is annotated as @Overridable, apps with the specific permission can + // set the override even on production builds. When rechecking the override, e.g. during an + // app update we can bypass this check, as it wouldn't have been here in the first place. + if (mCompatConfig.isOverridable(changeId) + && (isRecheck + || mContext.checkCallingOrSelfPermission( + OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) + == PERMISSION_GRANTED)) { + return new OverrideAllowedState(ALLOWED, -1, -1); + } int appTargetSdk = applicationInfo.targetSdkVersion; // Only allow overriding debuggable apps. if ((applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) { @@ -130,5 +161,4 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub { void forceNonDebuggableFinalForTest(boolean value) { mForceNonDebuggableFinalBuild = value; } - } diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index 40e386359a40..20469a21db0c 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -18,6 +18,7 @@ package com.android.server.compat; import static android.Manifest.permission.LOG_COMPAT_CHANGE; import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG; +import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD; import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Process.SYSTEM_UID; @@ -182,11 +183,12 @@ public class PlatformCompat extends IPlatformCompat.Stub { } @Override - public void setOverridesFromInstaller(CompatibilityOverrideConfig overrides, + public void setOverridesOnReleaseBuilds(CompatibilityOverrideConfig overrides, String packageName) { - checkCompatChangeOverridePermission(); + // TODO(b/183630314): Unify the permission enforcement with the other setOverrides* methods. + checkCompatChangeOverrideOverridablePermission(); + checkAllCompatOverridesAreOverridable(overrides); mCompatConfig.addOverrides(overrides, packageName); - killPackage(packageName); } @Override @@ -383,6 +385,26 @@ public class PlatformCompat extends IPlatformCompat.Stub { } } + private void checkCompatChangeOverrideOverridablePermission() { + // Don't check for permissions within the system process + if (Binder.getCallingUid() == SYSTEM_UID) { + return; + } + if (mContext.checkCallingOrSelfPermission(OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) + != PERMISSION_GRANTED) { + throw new SecurityException("Cannot override compat change"); + } + } + + private void checkAllCompatOverridesAreOverridable(CompatibilityOverrideConfig overrides) { + for (Long changeId : overrides.overrides.keySet()) { + if (!mCompatConfig.isOverridable(changeId)) { + throw new SecurityException("Only change ids marked as Overridable can be " + + "overridden."); + } + } + } + private void checkCompatChangeReadAndLogPermission() { checkCompatChangeReadPermission(); checkCompatChangeLogPermission(); diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java index 7b20ded19205..058dac882225 100644 --- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java +++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java @@ -26,6 +26,7 @@ import static android.net.SocketKeepalive.ERROR_INVALID_INTERVAL; import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS; import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK; import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET; +import static android.net.SocketKeepalive.ERROR_NO_SUCH_SLOT; import static android.net.SocketKeepalive.ERROR_STOP_REASON_UNINITIALIZED; import static android.net.SocketKeepalive.ERROR_UNSUPPORTED; import static android.net.SocketKeepalive.MAX_INTERVAL_SEC; @@ -518,6 +519,8 @@ public class KeepaliveTracker { } } else if (reason == ERROR_STOP_REASON_UNINITIALIZED) { throw new IllegalStateException("Unexpected stop reason: " + reason); + } else if (reason == ERROR_NO_SUCH_SLOT) { + throw new IllegalStateException("No such slot: " + reason); } else { notifyErrorCallback(ki.mCallback, reason); } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index fde4f5d87e8c..97df5bff4946 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -25,6 +25,8 @@ import android.content.Context; import android.net.CaptivePortalData; import android.net.IDnsResolver; import android.net.INetd; +import android.net.INetworkAgent; +import android.net.INetworkAgentRegistry; import android.net.INetworkMonitor; import android.net.LinkProperties; import android.net.NattKeepalivePacketData; @@ -47,12 +49,11 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.SystemClock; import android.telephony.data.EpsBearerQosSessionAttributes; +import android.telephony.data.NrQosSessionAttributes; import android.util.Log; import android.util.Pair; import android.util.SparseArray; -import com.android.connectivity.aidl.INetworkAgent; -import com.android.connectivity.aidl.INetworkAgentRegistry; import com.android.internal.util.WakeupMessage; import com.android.server.ConnectivityService; @@ -576,6 +577,28 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { } } + /** + * Notify the NetworkAgent that the network is successfully connected. + */ + public void onNetworkCreated() { + try { + networkAgent.onNetworkCreated(); + } catch (RemoteException e) { + Log.e(TAG, "Error sending network created event", e); + } + } + + /** + * Notify the NetworkAgent that the network is disconnected and destroyed. + */ + public void onNetworkDisconnected() { + try { + networkAgent.onNetworkDisconnected(); + } catch (RemoteException e) { + Log.e(TAG, "Error sending network disconnected event", e); + } + } + // TODO: consider moving out of NetworkAgentInfo into its own class private class NetworkAgentMessageHandler extends INetworkAgentRegistry.Stub { private final Handler mHandler; @@ -633,7 +656,13 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { @Override public void sendEpsQosSessionAvailable(final int qosCallbackId, final QosSession session, final EpsBearerQosSessionAttributes attributes) { - mQosCallbackTracker.sendEventQosSessionAvailable(qosCallbackId, session, attributes); + mQosCallbackTracker.sendEventEpsQosSessionAvailable(qosCallbackId, session, attributes); + } + + @Override + public void sendNrQosSessionAvailable(final int qosCallbackId, final QosSession session, + final NrQosSessionAttributes attributes) { + mQosCallbackTracker.sendEventNrQosSessionAvailable(qosCallbackId, session, attributes); } @Override diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java index 181a10d2a63e..0c0d45995a2b 100644 --- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java +++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java @@ -28,6 +28,8 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.res.Resources; +import android.graphics.drawable.Icon; +import android.net.ConnectivityResources; import android.net.NetworkSpecifier; import android.net.TelephonyNetworkSpecifier; import android.net.wifi.WifiInfo; @@ -40,7 +42,7 @@ import android.util.SparseArray; import android.util.SparseIntArray; import android.widget.Toast; -import com.android.internal.R; +import com.android.connectivity.resources.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; @@ -82,6 +84,7 @@ public class NetworkNotificationManager { // The context is for the current user (system server) private final Context mContext; + private final Resources mResources; private final TelephonyManager mTelephonyManager; // The notification manager is created from a context for User.ALL, so notifications // will be sent to all users. @@ -96,6 +99,7 @@ public class NetworkNotificationManager { (NotificationManager) c.createContextAsUser(UserHandle.ALL, 0 /* flags */) .getSystemService(Context.NOTIFICATION_SERVICE); mNotificationTypeMap = new SparseIntArray(); + mResources = new ConnectivityResources(mContext).get(); } @VisibleForTesting @@ -113,20 +117,19 @@ public class NetworkNotificationManager { return -1; } - private static String getTransportName(final int transportType) { - Resources r = Resources.getSystem(); - String[] networkTypes = r.getStringArray(R.array.network_switch_type_name); + private String getTransportName(final int transportType) { + String[] networkTypes = mResources.getStringArray(R.array.network_switch_type_name); try { return networkTypes[transportType]; } catch (IndexOutOfBoundsException e) { - return r.getString(R.string.network_switch_type_name_unknown); + return mResources.getString(R.string.network_switch_type_name_unknown); } } private static int getIcon(int transportType) { return (transportType == TRANSPORT_WIFI) - ? R.drawable.stat_notify_wifi_in_range : // TODO: Distinguish ! from ?. - R.drawable.stat_notify_rssi_in_range; + ? R.drawable.stat_notify_wifi_in_range // TODO: Distinguish ! from ?. + : R.drawable.stat_notify_rssi_in_range; } /** @@ -194,10 +197,10 @@ public class NetworkNotificationManager { tag, nameOf(eventId), getTransportName(transportType), name, highPriority)); } - Resources r = mContext.getResources(); + final Resources r = mResources; final CharSequence title; final CharSequence details; - int icon = getIcon(transportType); + Icon icon = Icon.createWithResource(r, getIcon(transportType)); if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) { title = r.getString(R.string.wifi_no_internet, name); details = r.getString(R.string.wifi_no_internet_detailed); @@ -272,8 +275,7 @@ public class NetworkNotificationManager { .setSmallIcon(icon) .setAutoCancel(true) .setTicker(title) - .setColor(mContext.getColor( - com.android.internal.R.color.system_notification_accent_color)) + .setColor(mContext.getColor(android.R.color.system_notification_accent_color)) .setContentTitle(title) .setContentIntent(intent) .setLocalOnly(true) @@ -353,7 +355,7 @@ public class NetworkNotificationManager { public void showToast(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) { String fromTransport = getTransportName(approximateTransportType(fromNai)); String toTransport = getTransportName(approximateTransportType(toNai)); - String text = mContext.getResources().getString( + String text = mResources.getString( R.string.network_switch_metered_toast, fromTransport, toTransport); Toast.makeText(mContext, text, Toast.LENGTH_LONG).show(); } diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index 488677ac1b59..37116797d8d7 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -271,6 +271,13 @@ public class PermissionMonitor { return mApps.containsKey(uid); } + /** + * Returns whether the given uid has permission to use restricted networks. + */ + public synchronized boolean hasRestrictedNetworksPermission(int uid) { + return Boolean.TRUE.equals(mApps.get(uid)); + } + private void update(Set<UserHandle> users, Map<Integer, Boolean> apps, boolean add) { List<Integer> network = new ArrayList<>(); List<Integer> system = new ArrayList<>(); diff --git a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java index 0f5400d0f8e6..534dbe7699a7 100644 --- a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java +++ b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java @@ -27,6 +27,7 @@ import android.net.QosSession; import android.os.IBinder; import android.os.RemoteException; import android.telephony.data.EpsBearerQosSessionAttributes; +import android.telephony.data.NrQosSessionAttributes; import android.util.Log; import java.util.Objects; @@ -146,13 +147,23 @@ class QosCallbackAgentConnection implements IBinder.DeathRecipient { mNetworkAgentInfo.onQosCallbackUnregistered(mAgentCallbackId); } - void sendEventQosSessionAvailable(final QosSession session, + void sendEventEpsQosSessionAvailable(final QosSession session, final EpsBearerQosSessionAttributes attributes) { try { - if (DBG) log("sendEventQosSessionAvailable: sending..."); + if (DBG) log("sendEventEpsQosSessionAvailable: sending..."); mCallback.onQosEpsBearerSessionAvailable(session, attributes); } catch (final RemoteException e) { - loge("sendEventQosSessionAvailable: remote exception", e); + loge("sendEventEpsQosSessionAvailable: remote exception", e); + } + } + + void sendEventNrQosSessionAvailable(final QosSession session, + final NrQosSessionAttributes attributes) { + try { + if (DBG) log("sendEventNrQosSessionAvailable: sending..."); + mCallback.onNrQosSessionAvailable(session, attributes); + } catch (final RemoteException e) { + loge("sendEventNrQosSessionAvailable: remote exception", e); } } diff --git a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java index 8bda5323e4f8..b6ab47b276e3 100644 --- a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java +++ b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java @@ -27,6 +27,7 @@ import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.telephony.data.EpsBearerQosSessionAttributes; +import android.telephony.data.NrQosSessionAttributes; import android.util.Log; import com.android.net.module.util.CollectionUtils; @@ -179,17 +180,31 @@ public class QosCallbackTracker { } /** - * Called when the NetworkAgent sends the qos session available event + * Called when the NetworkAgent sends the qos session available event for EPS * * @param qosCallbackId the callback id that the qos session is now available to * @param session the qos session that is now available * @param attributes the qos attributes that are now available on the qos session */ - public void sendEventQosSessionAvailable(final int qosCallbackId, + public void sendEventEpsQosSessionAvailable(final int qosCallbackId, final QosSession session, final EpsBearerQosSessionAttributes attributes) { - runOnAgentConnection(qosCallbackId, "sendEventQosSessionAvailable: ", - ac -> ac.sendEventQosSessionAvailable(session, attributes)); + runOnAgentConnection(qosCallbackId, "sendEventEpsQosSessionAvailable: ", + ac -> ac.sendEventEpsQosSessionAvailable(session, attributes)); + } + + /** + * Called when the NetworkAgent sends the qos session available event for NR + * + * @param qosCallbackId the callback id that the qos session is now available to + * @param session the qos session that is now available + * @param attributes the qos attributes that are now available on the qos session + */ + public void sendEventNrQosSessionAvailable(final int qosCallbackId, + final QosSession session, + final NrQosSessionAttributes attributes) { + runOnAgentConnection(qosCallbackId, "sendEventNrQosSessionAvailable: ", + ac -> ac.sendEventNrQosSessionAvailable(session, attributes)); } /** diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index e35a1ab71492..e5ce4f062973 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -17,11 +17,11 @@ package com.android.server.connectivity; import static android.Manifest.permission.BIND_VPN_SERVICE; -import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.RouteInfo.RTN_THROW; import static android.net.RouteInfo.RTN_UNREACHABLE; import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN; +import static android.os.UserHandle.PER_USER_RANGE; import static com.android.internal.util.Preconditions.checkArgument; import static com.android.internal.util.Preconditions.checkNotNull; @@ -70,7 +70,6 @@ import android.net.NetworkProvider; import android.net.NetworkRequest; import android.net.NetworkScore; import android.net.RouteInfo; -import android.net.UidRange; import android.net.UidRangeParcel; import android.net.UnderlyingNetworkInfo; import android.net.VpnManager; @@ -223,7 +222,7 @@ public class Vpn { protected NetworkAgent mNetworkAgent; private final Looper mLooper; @VisibleForTesting - protected final NetworkCapabilities mNetworkCapabilities; + protected NetworkCapabilities mNetworkCapabilities; private final SystemServices mSystemServices; private final Ikev2SessionCreator mIkev2SessionCreator; private final UserManager mUserManager; @@ -460,11 +459,12 @@ public class Vpn { mLegacyState = LegacyVpnInfo.STATE_DISCONNECTED; mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0 /* subtype */, NETWORKTYPE, "" /* subtypeName */); - mNetworkCapabilities = new NetworkCapabilities(); - mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN); - mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); - mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); - mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE)); + mNetworkCapabilities = new NetworkCapabilities.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_VPN) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) + .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE)) + .build(); loadAlwaysOnPackage(); } @@ -525,8 +525,10 @@ public class Vpn { } private void resetNetworkCapabilities() { - mNetworkCapabilities.setUids(null); - mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE)); + mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities) + .setUids(null) + .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE)) + .build(); } /** @@ -1124,17 +1126,19 @@ public class Vpn { } /** - * Return netId of current running VPN network. + * Return Network of current running VPN network. * - * @return a netId if there is a running VPN network or NETID_UNSET if there is no running VPN + * @return a Network if there is a running VPN network or null if there is no running VPN * network or network is null. */ - public synchronized int getNetId() { + @VisibleForTesting + @Nullable + public synchronized Network getNetwork() { final NetworkAgent agent = mNetworkAgent; - if (null == agent) return NETID_UNSET; + if (null == agent) return null; final Network network = agent.getNetwork(); - if (null == network) return NETID_UNSET; - return network.getNetId(); + if (null == network) return null; + return network; } private LinkProperties makeLinkProperties() { @@ -1237,29 +1241,33 @@ public class Vpn { // registered with registerDefaultNetworkCallback. This in turn protects the invariant // that an app calling ConnectivityManager#bindProcessToNetwork(getDefaultNetwork()) // behaves the same as when it uses the default network. - mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + final NetworkCapabilities.Builder capsBuilder = + new NetworkCapabilities.Builder(mNetworkCapabilities); + capsBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); mLegacyState = LegacyVpnInfo.STATE_CONNECTING; updateState(DetailedState.CONNECTING, "agentConnect"); - NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig.Builder().build(); - networkAgentConfig.allowBypass = mConfig.allowBypass && !mLockdown; + final NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig.Builder() + .setBypassableVpn(mConfig.allowBypass && !mLockdown) + .build(); - mNetworkCapabilities.setOwnerUid(mOwnerUID); - mNetworkCapabilities.setAdministratorUids(new int[] {mOwnerUID}); - mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserId, + capsBuilder.setOwnerUid(mOwnerUID); + capsBuilder.setAdministratorUids(new int[] {mOwnerUID}); + capsBuilder.setUids(createUserAndRestrictedProfilesRanges(mUserId, mConfig.allowedApplications, mConfig.disallowedApplications)); - mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType())); + capsBuilder.setTransportInfo(new VpnTransportInfo(getActiveVpnType())); // Only apps targeting Q and above can explicitly declare themselves as metered. // These VPNs are assumed metered unless they state otherwise. if (mIsPackageTargetingAtLeastQ && mConfig.isMetered) { - mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_METERED); + capsBuilder.removeCapability(NET_CAPABILITY_NOT_METERED); } else { - mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED); + capsBuilder.addCapability(NET_CAPABILITY_NOT_METERED); } + mNetworkCapabilities = capsBuilder.build(); mNetworkAgent = new NetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */, mNetworkCapabilities, lp, new NetworkScore.Builder().setLegacyInt(VPN_DEFAULT_SCORE).build(), @@ -1280,7 +1288,6 @@ public class Vpn { }); mNetworkAgent.setUnderlyingNetworks((mConfig.underlyingNetworks != null) ? Arrays.asList(mConfig.underlyingNetworks) : null); - mNetworkInfo.setIsAvailable(true); updateState(DetailedState.CONNECTED, "agentConnect"); } @@ -1351,7 +1358,7 @@ public class Vpn { String oldInterface = mInterface; Connection oldConnection = mConnection; NetworkAgent oldNetworkAgent = mNetworkAgent; - Set<UidRange> oldUsers = mNetworkCapabilities.getUids(); + Set<Range<Integer>> oldUsers = mNetworkCapabilities.getUids(); // Configure the interface. Abort if any of these steps fails. ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu)); @@ -1426,7 +1433,8 @@ public class Vpn { // restore old state mConfig = oldConfig; mConnection = oldConnection; - mNetworkCapabilities.setUids(oldUsers); + mNetworkCapabilities = + new NetworkCapabilities.Builder(mNetworkCapabilities).setUids(oldUsers).build(); mNetworkAgent = oldNetworkAgent; mInterface = oldInterface; throw e; @@ -1457,7 +1465,7 @@ public class Vpn { } /** - * Creates a {@link Set} of non-intersecting {@link UidRange} objects including all UIDs + * Creates a {@link Set} of non-intersecting {@code Range<Integer>} objects including all UIDs * associated with one user, and any restricted profiles attached to that user. * * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided, @@ -1470,10 +1478,10 @@ public class Vpn { * @param disallowedApplications (optional) List of applications to deny. */ @VisibleForTesting - Set<UidRange> createUserAndRestrictedProfilesRanges(@UserIdInt int userId, + Set<Range<Integer>> createUserAndRestrictedProfilesRanges(@UserIdInt int userId, @Nullable List<String> allowedApplications, @Nullable List<String> disallowedApplications) { - final Set<UidRange> ranges = new ArraySet<>(); + final Set<Range<Integer>> ranges = new ArraySet<>(); // Assign the top-level user to the set of ranges addUserToRanges(ranges, userId, allowedApplications, disallowedApplications); @@ -1497,20 +1505,20 @@ public class Vpn { } /** - * Updates a {@link Set} of non-intersecting {@link UidRange} objects to include all UIDs + * Updates a {@link Set} of non-intersecting {@code Range<Integer>} objects to include all UIDs * associated with one user. * * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided, * the UID ranges will match the app allowlist or denylist specified there. Otherwise, all UIDs * in the user will be included. * - * @param ranges {@link Set} of {@link UidRange}s to which to add. + * @param ranges {@link Set} of {@code Range<Integer>}s to which to add. * @param userId The userId to add to {@param ranges}. * @param allowedApplications (optional) allowlist of applications to include. * @param disallowedApplications (optional) denylist of applications to exclude. */ @VisibleForTesting - void addUserToRanges(@NonNull Set<UidRange> ranges, @UserIdInt int userId, + void addUserToRanges(@NonNull Set<Range<Integer>> ranges, @UserIdInt int userId, @Nullable List<String> allowedApplications, @Nullable List<String> disallowedApplications) { if (allowedApplications != null) { @@ -1520,40 +1528,41 @@ public class Vpn { if (start == -1) { start = uid; } else if (uid != stop + 1) { - ranges.add(new UidRange(start, stop)); + ranges.add(new Range<Integer>(start, stop)); start = uid; } stop = uid; } - if (start != -1) ranges.add(new UidRange(start, stop)); + if (start != -1) ranges.add(new Range<Integer>(start, stop)); } else if (disallowedApplications != null) { // Add all ranges for user skipping UIDs for disallowedApplications. - final UidRange userRange = UidRange.createForUser(UserHandle.of(userId)); - int start = userRange.start; + final Range<Integer> userRange = createUidRangeForUser(userId); + int start = userRange.getLower(); for (int uid : getAppsUids(disallowedApplications, userId)) { if (uid == start) { start++; } else { - ranges.add(new UidRange(start, uid - 1)); + ranges.add(new Range<Integer>(start, uid - 1)); start = uid + 1; } } - if (start <= userRange.stop) ranges.add(new UidRange(start, userRange.stop)); + if (start <= userRange.getUpper()) { + ranges.add(new Range<Integer>(start, userRange.getUpper())); + } } else { // Add all UIDs for the user. - ranges.add(UidRange.createForUser(UserHandle.of(userId))); + ranges.add(createUidRangeForUser(userId)); } } // Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that // apply to userId. - private static List<UidRange> uidRangesForUser(int userId, Set<UidRange> existingRanges) { - // UidRange#createForUser returns the entire range of UIDs available to a macro-user. - // This is something like 0-99999 ; {@see UserHandle#PER_USER_RANGE} - final UidRange userRange = UidRange.createForUser(UserHandle.of(userId)); - final List<UidRange> ranges = new ArrayList<>(); - for (UidRange range : existingRanges) { - if (userRange.containsRange(range)) { + private static List<Range<Integer>> uidRangesForUser(int userId, + Set<Range<Integer>> existingRanges) { + final Range<Integer> userRange = createUidRangeForUser(userId); + final List<Range<Integer>> ranges = new ArrayList<>(); + for (Range<Integer> range : existingRanges) { + if (userRange.contains(range)) { ranges.add(range); } } @@ -1570,12 +1579,13 @@ public class Vpn { UserInfo user = mUserManager.getUserInfo(userId); if (user.isRestricted() && user.restrictedProfileParentId == mUserId) { synchronized(Vpn.this) { - final Set<UidRange> existingRanges = mNetworkCapabilities.getUids(); + final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids(); if (existingRanges != null) { try { addUserToRanges(existingRanges, userId, mConfig.allowedApplications, mConfig.disallowedApplications); - mNetworkCapabilities.setUids(existingRanges); + mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities) + .setUids(existingRanges).build(); } catch (Exception e) { Log.wtf(TAG, "Failed to add restricted user to owner", e); } @@ -1598,13 +1608,14 @@ public class Vpn { UserInfo user = mUserManager.getUserInfo(userId); if (user.isRestricted() && user.restrictedProfileParentId == mUserId) { synchronized(Vpn.this) { - final Set<UidRange> existingRanges = mNetworkCapabilities.getUids(); + final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids(); if (existingRanges != null) { try { - final List<UidRange> removedRanges = + final List<Range<Integer>> removedRanges = uidRangesForUser(userId, existingRanges); existingRanges.removeAll(removedRanges); - mNetworkCapabilities.setUids(existingRanges); + mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities) + .setUids(existingRanges).build(); } catch (Exception e) { Log.wtf(TAG, "Failed to remove restricted user to owner", e); } @@ -1662,7 +1673,7 @@ public class Vpn { final Set<UidRangeParcel> rangesToRemove = new ArraySet<>(mBlockedUidsAsToldToConnectivity); final Set<UidRangeParcel> rangesToAdd; if (enforce) { - final Set<UidRange> restrictedProfilesRanges = + final Set<Range<Integer>> restrictedProfilesRanges = createUserAndRestrictedProfilesRanges(mUserId, /* allowedApplications */ null, /* disallowedApplications */ exemptedPackages); @@ -1671,11 +1682,12 @@ public class Vpn { // The UID range of the first user (0-99999) would block the IPSec traffic, which comes // directly from the kernel and is marked as uid=0. So we adjust the range to allow // it through (b/69873852). - for (UidRange range : restrictedProfilesRanges) { - if (range.start == 0 && range.stop != 0) { - rangesThatShouldBeBlocked.add(new UidRangeParcel(1, range.stop)); - } else if (range.start != 0) { - rangesThatShouldBeBlocked.add(new UidRangeParcel(range.start, range.stop)); + for (Range<Integer> range : restrictedProfilesRanges) { + if (range.getLower() == 0 && range.getUpper() != 0) { + rangesThatShouldBeBlocked.add(new UidRangeParcel(1, range.getUpper())); + } else if (range.getLower() != 0) { + rangesThatShouldBeBlocked.add( + new UidRangeParcel(range.getLower(), range.getUpper())); } } @@ -1697,12 +1709,12 @@ public class Vpn { } /** - * Tell ConnectivityService to add or remove a list of {@link UidRange}s to the list of UIDs - * that are only allowed to make connections through sockets that have had {@code protect()} - * called on them. + * Tell ConnectivityService to add or remove a list of {@link UidRangeParcel}s to the list of + * UIDs that are only allowed to make connections through sockets that have had + * {@code protect()} called on them. * * @param enforce {@code true} to add to the denylist, {@code false} to remove. - * @param ranges {@link Collection} of {@link UidRange}s to add (if {@param enforce} is + * @param ranges {@link Collection} of {@link UidRangeParcel}s to add (if {@param enforce} is * {@code true}) or to remove. * @return {@code true} if all of the UIDs were added/removed. {@code false} otherwise, * including added ranges that already existed or removed ones that didn't. @@ -1847,22 +1859,13 @@ public class Vpn { /** * Updates underlying network set. */ - public synchronized boolean setUnderlyingNetworks(Network[] networks) { + public synchronized boolean setUnderlyingNetworks(@Nullable Network[] networks) { if (!isCallerEstablishedOwnerLocked()) { return false; } - if (networks == null) { - mConfig.underlyingNetworks = null; - } else { - mConfig.underlyingNetworks = new Network[networks.length]; - for (int i = 0; i < networks.length; ++i) { - if (networks[i] == null) { - mConfig.underlyingNetworks[i] = null; - } else { - mConfig.underlyingNetworks[i] = new Network(networks[i].getNetId()); - } - } - } + // Make defensive copy since the content of array might be altered by the caller. + mConfig.underlyingNetworks = + (networks != null) ? Arrays.copyOf(networks, networks.length) : null; mNetworkAgent.setUnderlyingNetworks((mConfig.underlyingNetworks != null) ? Arrays.asList(mConfig.underlyingNetworks) : null); return true; @@ -1884,7 +1887,12 @@ public class Vpn { if (!isRunningLocked()) { return false; } - return mNetworkCapabilities.appliesToUid(uid); + final Set<Range<Integer>> uids = mNetworkCapabilities.getUids(); + if (uids == null) return true; + for (final Range<Integer> range : uids) { + if (range.contains(uid)) return true; + } + return false; } /** @@ -3346,4 +3354,12 @@ public class Vpn { firstChildSessionCallback); } } + + /** + * Returns the entire range of UIDs available to a macro-user. This is something like 0-99999. + */ + @VisibleForTesting + static Range<Integer> createUidRangeForUser(int userId) { + return new Range<Integer>(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1); + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index f658e33e0530..58a702527e5f 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -619,8 +619,10 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } } - addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress, - activeSource.physicalAddress, deviceType)); + if (!mService.isPowerStandbyOrTransient()) { + addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress, + activeSource.physicalAddress, deviceType)); + } } private boolean handleNewDeviceAtTheTailOfActivePath(int path) { @@ -796,10 +798,12 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { @ServiceThreadOnly void onNewAvrAdded(HdmiDeviceInfo avr) { assertRunOnServiceThread(); - addAndStartAction(new SystemAudioAutoInitiationAction(this, avr.getLogicalAddress())); - if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId()) - && !hasAction(SetArcTransmissionStateAction.class)) { - startArcAction(true); + if (!mService.isPowerStandbyOrTransient()) { + addAndStartAction(new SystemAudioAutoInitiationAction(this, avr.getLogicalAddress())); + if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId()) + && !hasAction(SetArcTransmissionStateAction.class)) { + startArcAction(true); + } } } @@ -1656,6 +1660,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { // Remove recording actions. removeAction(OneTouchRecordAction.class); removeAction(TimerRecordingAction.class); + removeAction(NewDeviceAction.class); disableSystemAudioIfExist(); disableArcIfExist(); @@ -1696,12 +1701,20 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { setArcStatus(false); // Seq #44. - removeAction(RequestArcInitiationAction.class); + removeAllRunningArcAction(); if (!hasAction(RequestArcTerminationAction.class) && isArcEstablished()) { addAndStartAction(new RequestArcTerminationAction(this, avr.getLogicalAddress())); } } + @ServiceThreadOnly + private void removeAllRunningArcAction() { + // Running or pending actions make TV fail to broadcast <Standby> to connected devices + removeAction(RequestArcTerminationAction.class); + removeAction(RequestArcInitiationAction.class); + removeAction(SetArcTransmissionStateAction.class); + } + @Override @ServiceThreadOnly protected void onStandby(boolean initiatedByCec, int standbyAction) { diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java index 6e99cba6ea91..76ecc1acc7ac 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java @@ -15,14 +15,17 @@ */ package com.android.server.locksettings; + import static android.os.UserHandle.USER_SYSTEM; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.Context; import android.content.pm.UserInfo; import android.os.Handler; import android.os.SystemClock; +import android.os.SystemProperties; import android.os.UserManager; import android.provider.DeviceConfig; import android.provider.Settings; @@ -35,6 +38,8 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.widget.RebootEscrowListener; import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; @@ -65,6 +70,22 @@ class RebootEscrowManager { public static final String REBOOT_ESCROW_ARMED_KEY = "reboot_escrow_armed_count"; static final String REBOOT_ESCROW_KEY_ARMED_TIMESTAMP = "reboot_escrow_key_stored_timestamp"; + static final String REBOOT_ESCROW_KEY_PROVIDER = "reboot_escrow_key_provider"; + + /** + * The verified boot 2.0 vbmeta digest of the current slot, the property value is always + * available after boot. + */ + static final String VBMETA_DIGEST_PROP_NAME = "ro.boot.vbmeta.digest"; + /** + * The system prop contains vbmeta digest of the inactive slot. The build property is set after + * an OTA update. RebootEscrowManager will store it in disk before the OTA reboot, so the value + * is available for vbmeta digest verification after the device reboots. + */ + static final String OTHER_VBMETA_DIGEST_PROP_NAME = "ota.other.vbmeta_digest"; + static final String REBOOT_ESCROW_KEY_VBMETA_DIGEST = "reboot_escrow_key_vbmeta_digest"; + static final String REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST = + "reboot_escrow_key_other_vbmeta_digest"; /** * Number of boots until we consider the escrow data to be stale for the purposes of metrics. @@ -86,6 +107,31 @@ class RebootEscrowManager { private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT = 3; private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS = 30; + @IntDef(prefix = {"ERROR_"}, value = { + ERROR_NONE, + ERROR_UNKNOWN, + ERROR_NO_PROVIDER, + ERROR_LOAD_ESCROW_KEY, + ERROR_RETRY_COUNT_EXHAUSTED, + ERROR_UNLOCK_ALL_USERS, + ERROR_PROVIDER_MISMATCH, + ERROR_KEYSTORE_FAILURE, + }) + @Retention(RetentionPolicy.SOURCE) + @interface RebootEscrowErrorCode { + } + + static final int ERROR_NONE = 0; + static final int ERROR_UNKNOWN = 1; + static final int ERROR_NO_PROVIDER = 2; + static final int ERROR_LOAD_ESCROW_KEY = 3; + static final int ERROR_RETRY_COUNT_EXHAUSTED = 4; + static final int ERROR_UNLOCK_ALL_USERS = 5; + static final int ERROR_PROVIDER_MISMATCH = 6; + static final int ERROR_KEYSTORE_FAILURE = 7; + + private @RebootEscrowErrorCode int mLoadEscrowDataErrorCode = ERROR_NONE; + /** * Logs events for later debugging in bugreports. */ @@ -199,6 +245,10 @@ class RebootEscrowManager { 0); } + public long getCurrentTimeMillis() { + return System.currentTimeMillis(); + } + public int getLoadEscrowDataRetryLimit() { return DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA, "load_escrow_data_retry_count", DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT); @@ -221,6 +271,11 @@ class RebootEscrowManager { public RebootEscrowEventLog getEventLog() { return new RebootEscrowEventLog(); } + + public String getVbmetaDigest(boolean other) { + return other ? SystemProperties.get(OTHER_VBMETA_DIGEST_PROP_NAME) + : SystemProperties.get(VBMETA_DIGEST_PROP_NAME); + } } RebootEscrowManager(Context context, Callbacks callbacks, LockSettingsStorage storage) { @@ -261,6 +316,7 @@ class RebootEscrowManager { if (rebootEscrowUsers.isEmpty()) { Slog.i(TAG, "No reboot escrow data found for users," + " skipping loading escrow data"); + clearMetricsStorage(); return; } @@ -284,6 +340,7 @@ class RebootEscrowManager { } Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts"); + mLoadEscrowDataErrorCode = ERROR_RETRY_COUNT_EXHAUSTED; onGetRebootEscrowKeyFailed(users, attemptNumber); } @@ -307,6 +364,17 @@ class RebootEscrowManager { } if (escrowKey == null) { + if (mLoadEscrowDataErrorCode == ERROR_NONE) { + // Specifically check if the RoR provider has changed after reboot. + int providerType = mInjector.serverBasedResumeOnReboot() + ? RebootEscrowProviderInterface.TYPE_SERVER_BASED + : RebootEscrowProviderInterface.TYPE_HAL; + if (providerType != mStorage.getInt(REBOOT_ESCROW_KEY_PROVIDER, -1, USER_SYSTEM)) { + mLoadEscrowDataErrorCode = ERROR_PROVIDER_MISMATCH; + } else { + mLoadEscrowDataErrorCode = ERROR_LOAD_ESCROW_KEY; + } + } onGetRebootEscrowKeyFailed(users, attemptNumber + 1); return; } @@ -321,9 +389,49 @@ class RebootEscrowManager { // Clear the old key in keystore. A new key will be generated by new RoR requests. mKeyStoreManager.clearKeyStoreEncryptionKey(); + if (!allUsersUnlocked && mLoadEscrowDataErrorCode == ERROR_NONE) { + mLoadEscrowDataErrorCode = ERROR_UNLOCK_ALL_USERS; + } onEscrowRestoreComplete(allUsersUnlocked, attemptNumber + 1); } + private void clearMetricsStorage() { + mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM); + mStorage.removeKey(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, USER_SYSTEM); + mStorage.removeKey(REBOOT_ESCROW_KEY_VBMETA_DIGEST, USER_SYSTEM); + mStorage.removeKey(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST, USER_SYSTEM); + mStorage.removeKey(REBOOT_ESCROW_KEY_PROVIDER, USER_SYSTEM); + } + + private int getVbmetaDigestStatusOnRestoreComplete() { + String currentVbmetaDigest = mInjector.getVbmetaDigest(false); + String vbmetaDigestStored = mStorage.getString(REBOOT_ESCROW_KEY_VBMETA_DIGEST, + "", USER_SYSTEM); + String vbmetaDigestOtherStored = mStorage.getString(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST, + "", USER_SYSTEM); + + // The other vbmeta digest is never set, assume no slot switch is attempted. + if (vbmetaDigestOtherStored.isEmpty()) { + if (currentVbmetaDigest.equals(vbmetaDigestStored)) { + return FrameworkStatsLog + .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_EXPECTED_SLOT; + } + return FrameworkStatsLog + .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MISMATCH; + } + + // The other vbmeta digest is set, we expect to boot into the new slot. + if (currentVbmetaDigest.equals(vbmetaDigestOtherStored)) { + return FrameworkStatsLog + .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_EXPECTED_SLOT; + } else if (currentVbmetaDigest.equals(vbmetaDigestStored)) { + return FrameworkStatsLog + .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_FALLBACK_SLOT; + } + return FrameworkStatsLog + .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MISMATCH; + } + private void reportMetricOnRestoreComplete(boolean success, int attemptCount) { int serviceType = mInjector.serverBasedResumeOnReboot() ? FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED__TYPE__SERVER_BASED @@ -331,26 +439,32 @@ class RebootEscrowManager { long armedTimestamp = mStorage.getLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, -1, USER_SYSTEM); - mStorage.removeKey(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, USER_SYSTEM); - int escrowDurationInSeconds = armedTimestamp != -1 - ? (int) (System.currentTimeMillis() - armedTimestamp) / 1000 : -1; + int escrowDurationInSeconds = -1; + long currentTimeStamp = mInjector.getCurrentTimeMillis(); + if (armedTimestamp != -1 && currentTimeStamp > armedTimestamp) { + escrowDurationInSeconds = (int) (currentTimeStamp - armedTimestamp) / 1000; + } - // TODO(b/179105110) design error code; and report the true value for other fields. - int vbmetaDigestStatus = FrameworkStatsLog - .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_EXPECTED_SLOT; + int vbmetaDigestStatus = getVbmetaDigestStatusOnRestoreComplete(); + if (!success && mLoadEscrowDataErrorCode == ERROR_NONE) { + mLoadEscrowDataErrorCode = ERROR_UNKNOWN; + } - mInjector.reportMetric(success, 0 /* error code */, serviceType, attemptCount, + // TODO(179105110) report the duration since boot complete. + mInjector.reportMetric(success, mLoadEscrowDataErrorCode, serviceType, attemptCount, escrowDurationInSeconds, vbmetaDigestStatus, -1); + + mLoadEscrowDataErrorCode = ERROR_NONE; } private void onEscrowRestoreComplete(boolean success, int attemptCount) { int previousBootCount = mStorage.getInt(REBOOT_ESCROW_ARMED_KEY, -1, USER_SYSTEM); - mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM); int bootCountDelta = mInjector.getBootCount() - previousBootCount; if (success || (previousBootCount != -1 && bootCountDelta <= BOOT_COUNT_TOLERANCE)) { reportMetricOnRestoreComplete(success, attemptCount); } + clearMetricsStorage(); } private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) throws IOException { @@ -358,6 +472,14 @@ class RebootEscrowManager { if (rebootEscrowProvider == null) { Slog.w(TAG, "Had reboot escrow data for users, but RebootEscrowProvider is unavailable"); + mLoadEscrowDataErrorCode = ERROR_NO_PROVIDER; + return null; + } + + // Server based RoR always need the decryption key from keystore. + if (rebootEscrowProvider.getType() == RebootEscrowProviderInterface.TYPE_SERVER_BASED + && kk == null) { + mLoadEscrowDataErrorCode = ERROR_KEYSTORE_FAILURE; return null; } @@ -463,7 +585,7 @@ class RebootEscrowManager { return; } - mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM); + clearMetricsStorage(); rebootEscrowProvider.clearRebootEscrowKey(); List<UserInfo> users = mUserManager.getUsers(); @@ -486,6 +608,9 @@ class RebootEscrowManager { return false; } + int actualProviderType = rebootEscrowProvider.getType(); + // TODO(b/183140900) Fail the reboot if provider type mismatches. + RebootEscrowKey escrowKey; synchronized (mKeyGenerationLock) { escrowKey = mPendingRebootEscrowKey; @@ -505,8 +630,14 @@ class RebootEscrowManager { boolean armedRebootEscrow = rebootEscrowProvider.storeRebootEscrowKey(escrowKey, kk); if (armedRebootEscrow) { mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM); - mStorage.setLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, System.currentTimeMillis(), + mStorage.setLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, mInjector.getCurrentTimeMillis(), + USER_SYSTEM); + // Store the vbmeta digest of both slots. + mStorage.setString(REBOOT_ESCROW_KEY_VBMETA_DIGEST, mInjector.getVbmetaDigest(false), USER_SYSTEM); + mStorage.setString(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST, + mInjector.getVbmetaDigest(true), USER_SYSTEM); + mStorage.setInt(REBOOT_ESCROW_KEY_PROVIDER, actualProviderType, USER_SYSTEM); mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS); } diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java index 4b00772088f2..e8f6f4abd030 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java @@ -60,6 +60,11 @@ class RebootEscrowProviderHalImpl implements RebootEscrowProviderInterface { } @Override + public int getType() { + return TYPE_HAL; + } + + @Override public boolean hasRebootEscrowSupport() { return mInjector.getRebootEscrow() != null; } diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java index af6faad3c76e..e106d817c533 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java @@ -16,7 +16,11 @@ package com.android.server.locksettings; +import android.annotation.IntDef; + import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import javax.crypto.SecretKey; @@ -28,6 +32,21 @@ import javax.crypto.SecretKey; * @hide */ public interface RebootEscrowProviderInterface { + @IntDef(prefix = {"TYPE_"}, value = { + TYPE_HAL, + TYPE_SERVER_BASED, + }) + @Retention(RetentionPolicy.SOURCE) + @interface RebootEscrowProviderType { + } + int TYPE_HAL = 0; + int TYPE_SERVER_BASED = 1; + + /** + * Returns the reboot escrow provider type. + */ + @RebootEscrowProviderType int getType(); + /** * Returns true if the secure store/discard of reboot escrow key is supported. */ diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java index 697bf08a232e..28669875f1cd 100644 --- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java +++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java @@ -95,6 +95,11 @@ class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterfa } @Override + public int getType() { + return TYPE_SERVER_BASED; + } + + @Override public boolean hasRebootEscrowSupport() { return mInjector.getServiceConnection() != null; } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java index 39ed7e8b1e1a..2e4d41c7d364 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java @@ -96,9 +96,10 @@ public abstract class NetworkPolicyManagerInternal { /** * Notifies that the specified {@link NetworkStatsProvider} has reached its quota - * which was set through {@link NetworkStatsProvider#onSetLimit(String, long)}. + * which was set through {@link NetworkStatsProvider#onSetLimit(String, long)} or + * {@link NetworkStatsProvider#onSetWarningAndLimit(String, long, long)}. * * @param tag the human readable identifier of the custom network stats provider. */ - public abstract void onStatsProviderLimitReached(@NonNull String tag); + public abstract void onStatsProviderWarningOrLimitReached(@NonNull String tag); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index b7367e5170c6..e9d5fe6d537c 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -38,6 +38,15 @@ import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS; import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_ADMIN_DISABLED; +import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER; +import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK; +import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED; +import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY; +import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER; +import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE; +import static android.net.ConnectivityManager.BLOCKED_REASON_NONE; +import static android.net.ConnectivityManager.BLOCKED_REASON_RESTRICTED_MODE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; @@ -56,7 +65,9 @@ import static android.net.NetworkIdentity.OEM_NONE; import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.SNOOZE_NEVER; import static android.net.NetworkPolicy.WARNING_DISABLED; +import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_FOREGROUND; import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_MASK; +import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_SYSTEM; import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_USER_EXEMPTED; import static android.net.NetworkPolicyManager.ALLOWED_REASON_FOREGROUND; import static android.net.NetworkPolicyManager.ALLOWED_REASON_NONE; @@ -64,15 +75,6 @@ import static android.net.NetworkPolicyManager.ALLOWED_REASON_POWER_SAVE_ALLOWLI import static android.net.NetworkPolicyManager.ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST; import static android.net.NetworkPolicyManager.ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS; import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM; -import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_ADMIN_DISABLED; -import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_DATA_SAVER; -import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_MASK; -import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_USER_RESTRICTED; -import static android.net.NetworkPolicyManager.BLOCKED_REASON_APP_STANDBY; -import static android.net.NetworkPolicyManager.BLOCKED_REASON_BATTERY_SAVER; -import static android.net.NetworkPolicyManager.BLOCKED_REASON_DOZE; -import static android.net.NetworkPolicyManager.BLOCKED_REASON_NONE; -import static android.net.NetworkPolicyManager.BLOCKED_REASON_RESTRICTED_MODE; import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE; import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT; import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS; @@ -172,12 +174,10 @@ import android.content.res.Resources; import android.database.ContentObserver; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; -import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkPolicyListener; import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; -import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkIdentity; @@ -261,6 +261,7 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.StatLogger; import com.android.internal.util.XmlUtils; import com.android.net.module.util.NetworkIdentityUtils; +import com.android.net.module.util.PermissionUtils; import com.android.server.EventLogTags; import com.android.server.LocalServices; import com.android.server.ServiceThread; @@ -430,7 +431,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int MSG_METERED_RESTRICTED_PACKAGES_CHANGED = 17; private static final int MSG_SET_NETWORK_TEMPLATE_ENABLED = 18; private static final int MSG_SUBSCRIPTION_PLANS_CHANGED = 19; - private static final int MSG_STATS_PROVIDER_LIMIT_REACHED = 20; + private static final int MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED = 20; // TODO: Add similar docs for other messages. /** * Message to indicate that reasons for why an uid is blocked changed. @@ -1217,10 +1218,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static boolean updateCapabilityChange(SparseBooleanArray lastValues, boolean newValue, Network network) { - final boolean lastValue = lastValues.get(network.netId, false); - final boolean changed = (lastValue != newValue) || lastValues.indexOfKey(network.netId) < 0; + final boolean lastValue = lastValues.get(network.getNetId(), false); + final boolean changed = (lastValue != newValue) + || lastValues.indexOfKey(network.getNetId()) < 0; if (changed) { - lastValues.put(network.netId, newValue); + lastValues.put(network.getNetId(), newValue); } return changed; } @@ -1243,7 +1245,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mNetworkRoaming, newRoaming, network); if (meteredChanged || roamingChanged) { - mLogger.meterednessChanged(network.netId, newMetered); + mLogger.meterednessChanged(network.getNetId(), newMetered); updateNetworkRulesNL(); } } @@ -1919,16 +1921,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * Collect all ifaces from a {@link NetworkStateSnapshot} into the given set. */ private static void collectIfaces(ArraySet<String> ifaces, NetworkStateSnapshot snapshot) { - final String baseIface = snapshot.linkProperties.getInterfaceName(); - if (baseIface != null) { - ifaces.add(baseIface); - } - for (LinkProperties stackedLink : snapshot.linkProperties.getStackedLinks()) { - final String stackedIface = stackedLink.getInterfaceName(); - if (stackedIface != null) { - ifaces.add(stackedIface); - } - } + ifaces.addAll(snapshot.linkProperties.getAllInterfaceNames()); } /** @@ -2009,7 +2002,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mNetIdToSubId.clear(); final ArrayMap<NetworkStateSnapshot, NetworkIdentity> identified = new ArrayMap<>(); for (final NetworkStateSnapshot snapshot : snapshots) { - mNetIdToSubId.put(snapshot.network.netId, parseSubId(snapshot)); + mNetIdToSubId.put(snapshot.network.getNetId(), parseSubId(snapshot)); // Policies matched by NPMS only match by subscriber ID or by ssid. Thus subtype // in the object created here is never used and its value doesn't matter, so use @@ -2042,39 +2035,34 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final boolean hasWarning = policy.warningBytes != LIMIT_DISABLED; final boolean hasLimit = policy.limitBytes != LIMIT_DISABLED; - if (hasLimit || policy.metered) { - final long quotaBytes; - if (hasLimit && policy.hasCycle()) { - final Pair<ZonedDateTime, ZonedDateTime> cycle = NetworkPolicyManager - .cycleIterator(policy).next(); - final long start = cycle.first.toInstant().toEpochMilli(); - final long end = cycle.second.toInstant().toEpochMilli(); - final long totalBytes = getTotalBytes(policy.template, start, end); - - if (policy.lastLimitSnooze >= start) { - // snoozing past quota, but we still need to restrict apps, - // so push really high quota. - quotaBytes = Long.MAX_VALUE; - } else { - // remaining "quota" bytes are based on total usage in - // current cycle. kernel doesn't like 0-byte rules, so we - // set 1-byte quota and disable the radio later. - quotaBytes = Math.max(1, policy.limitBytes - totalBytes); - } - } else { - // metered network, but no policy limit; we still need to - // restrict apps, so push really high quota. - quotaBytes = Long.MAX_VALUE; + long limitBytes = Long.MAX_VALUE; + if (hasLimit && policy.hasCycle()) { + final Pair<ZonedDateTime, ZonedDateTime> cycle = NetworkPolicyManager + .cycleIterator(policy).next(); + final long start = cycle.first.toInstant().toEpochMilli(); + final long end = cycle.second.toInstant().toEpochMilli(); + final long totalBytes = getTotalBytes(policy.template, start, end); + + if (policy.lastLimitSnooze < start) { + // remaining "quota" bytes are based on total usage in + // current cycle. kernel doesn't like 0-byte rules, so we + // set 1-byte quota and disable the radio later. + limitBytes = Math.max(1, policy.limitBytes - totalBytes); } + } + if (hasLimit || policy.metered) { if (matchingIfaces.size() > 1) { // TODO: switch to shared quota once NMS supports Slog.w(TAG, "shared quota unsupported; generating rule for each iface"); } + // Set the interface limit. For interfaces which has no cycle, or metered with + // no policy limit, or snoozed limit notification; we still need to put iptables + // rule hooks to restrict apps for data saver, so push really high quota. for (int j = matchingIfaces.size() - 1; j >= 0; j--) { final String iface = matchingIfaces.valueAt(j); - setInterfaceQuotaAsync(iface, quotaBytes); + setInterfaceQuotaAsync(iface, limitBytes); newMeteredIfaces.add(iface); } } @@ -3112,8 +3100,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @Override public int getRestrictBackgroundByCaller() { mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG); - final int uid = Binder.getCallingUid(); + return getRestrictBackgroundStatusInternal(Binder.getCallingUid()); + } + @Override + public int getRestrictBackgroundStatus(int uid) { + PermissionUtils.enforceNetworkStackPermission(mContext); + return getRestrictBackgroundStatusInternal(uid); + } + + private int getRestrictBackgroundStatusInternal(int uid) { synchronized (mUidRulesFirstLock) { // Must clear identity because getUidPolicy() is restricted to system. final long token = Binder.clearCallingIdentity(); @@ -3582,6 +3578,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * Get multipath preference value for the given network. */ public int getMultipathPreference(Network network) { + PermissionUtils.enforceNetworkStackPermission(mContext); final Integer preference = mMultipathPolicyTracker.getMultipathPreference(network); if (preference != null) { return preference; @@ -4626,8 +4623,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { newBlockedReasons |= (mRestrictBackground ? BLOCKED_METERED_REASON_DATA_SAVER : 0); newBlockedReasons |= (isDenied ? BLOCKED_METERED_REASON_USER_RESTRICTED : 0); - newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0); - newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0); + newAllowedReasons |= (isSystem(uid) ? ALLOWED_METERED_REASON_SYSTEM : 0); + newAllowedReasons |= (isForeground ? ALLOWED_METERED_REASON_FOREGROUND : 0); newAllowedReasons |= (isAllowed ? ALLOWED_METERED_REASON_USER_EXEMPTED : 0); if (LOGV) { @@ -4701,18 +4698,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // Dispatch changed rule to existing listeners. mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRules).sendToTarget(); + } - final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons; - uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons - & ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons; - uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons - & ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons; - uidBlockedState.updateEffectiveBlockedReasons(); - if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) { - mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid, - uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons) - .sendToTarget(); - } + final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons; + uidBlockedState.blockedReasons = (uidBlockedState.blockedReasons + & ~BLOCKED_METERED_REASON_MASK) | newBlockedReasons; + uidBlockedState.allowedReasons = (uidBlockedState.allowedReasons + & ~ALLOWED_METERED_REASON_MASK) | newAllowedReasons; + uidBlockedState.updateEffectiveBlockedReasons(); + if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) { + mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid, + uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons) + .sendToTarget(); } } @@ -4970,7 +4967,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mListeners.finishBroadcast(); return true; } - case MSG_STATS_PROVIDER_LIMIT_REACHED: { + case MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED: { mNetworkStats.forceUpdate(); synchronized (mNetworkPoliciesSecondLock) { @@ -5726,9 +5723,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @Override - public void onStatsProviderLimitReached(@NonNull String tag) { - Log.v(TAG, "onStatsProviderLimitReached: " + tag); - mHandler.obtainMessage(MSG_STATS_PROVIDER_LIMIT_REACHED).sendToTarget(); + public void onStatsProviderWarningOrLimitReached(@NonNull String tag) { + Log.v(TAG, "onStatsProviderWarningOrLimitReached: " + tag); + mHandler.obtainMessage(MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED).sendToTarget(); } } @@ -5770,7 +5767,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @GuardedBy("mNetworkPoliciesSecondLock") private int getSubIdLocked(Network network) { - return mNetIdToSubId.get(network.netId, INVALID_SUBSCRIPTION_ID); + return mNetIdToSubId.get(network.getNetId(), INVALID_SUBSCRIPTION_ID); } @GuardedBy("mNetworkPoliciesSecondLock") @@ -5860,12 +5857,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return; } if ((allowedReasons & ALLOWED_REASON_SYSTEM) != 0) { - effectiveBlockedReasons = BLOCKED_REASON_NONE; + effectiveBlockedReasons = (blockedReasons & ALLOWED_METERED_REASON_MASK); + } + if ((allowedReasons & ALLOWED_METERED_REASON_SYSTEM) != 0) { + effectiveBlockedReasons = (blockedReasons & ~ALLOWED_METERED_REASON_MASK); } if ((allowedReasons & ALLOWED_REASON_FOREGROUND) != 0) { effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER; effectiveBlockedReasons &= ~BLOCKED_REASON_DOZE; effectiveBlockedReasons &= ~BLOCKED_REASON_APP_STANDBY; + } + if ((allowedReasons & ALLOWED_METERED_REASON_FOREGROUND) != 0) { effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_DATA_SAVER; effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_USER_RESTRICTED; } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 7b376847fd44..445a425854ea 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -24,6 +24,7 @@ import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkIdentity.SUBTYPE_COMBINED; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; @@ -65,6 +66,7 @@ import static android.provider.Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES; import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; @@ -92,7 +94,6 @@ import android.net.DataUsageRequest; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; -import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkIdentity; @@ -101,7 +102,9 @@ import android.net.NetworkStateSnapshot; import android.net.NetworkStats; import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; +import android.net.NetworkSpecifier; import android.net.NetworkTemplate; +import android.net.TelephonyNetworkSpecifier; import android.net.TrafficStats; import android.net.UnderlyingNetworkInfo; import android.net.Uri; @@ -131,6 +134,7 @@ import android.service.NetworkInterfaceProto; import android.service.NetworkStatsServiceDumpProto; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionPlan; +import android.text.TextUtils; import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -1320,8 +1324,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(), ident.getRoaming(), true /* metered */, true /* onDefaultNetwork */, ident.getOemManaged()); - findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent); + final String ifaceVt = IFACE_VT + getSubIdForMobile(snapshot); + findOrCreateNetworkIdentitySet(mActiveIfaces, ifaceVt).add(vtIdent); + findOrCreateNetworkIdentitySet(mActiveUidIfaces, ifaceVt).add(vtIdent); } if (isMobile) { @@ -1358,17 +1363,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // (or non eBPF offloaded) TX they would appear on both, however egress interface // accounting is explicitly bypassed for traffic from the clat uid. // - final List<LinkProperties> stackedLinks = snapshot.linkProperties.getStackedLinks(); - for (LinkProperties stackedLink : stackedLinks) { - final String stackedIface = stackedLink.getInterfaceName(); - if (stackedIface != null) { - findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident); + // TODO: This code might be combined to above code. + for (String iface : snapshot.linkProperties.getAllInterfaceNames()) { + // baseIface has been handled, so ignore it. + if (TextUtils.equals(baseIface, iface)) continue; + if (iface != null) { + findOrCreateNetworkIdentitySet(mActiveIfaces, iface).add(ident); + findOrCreateNetworkIdentitySet(mActiveUidIfaces, iface).add(ident); if (isMobile) { - mobileIfaces.add(stackedIface); + mobileIfaces.add(iface); } - mStatsFactory.noteStackedIface(stackedIface, baseIface); + mStatsFactory.noteStackedIface(iface, baseIface); } } } @@ -1376,6 +1382,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]); } + private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) { + if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + throw new IllegalArgumentException("Mobile state need capability TRANSPORT_CELLULAR"); + } + + final NetworkSpecifier spec = state.networkCapabilities.getNetworkSpecifier(); + if (spec instanceof TelephonyNetworkSpecifier) { + return ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); + } else { + Slog.wtf(TAG, "getSubIdForState invalid NetworkSpecifier"); + return INVALID_SUBSCRIPTION_ID; + } + } + /** * For networks with {@code TRANSPORT_CELLULAR}, get subType that was obtained through * {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different @@ -1675,7 +1695,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void setStatsProviderLimitAsync(@NonNull String iface, long quota) { if (LOGV) Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota)); + // TODO: Set warning accordingly. + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface, + NetworkStatsProvider.QUOTA_UNLIMITED, quota)); } } @@ -2070,10 +2092,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void notifyLimitReached() { - Log.d(TAG, mTag + ": onLimitReached"); + public void notifyWarningOrLimitReached() { + Log.d(TAG, mTag + ": notifyWarningOrLimitReached"); LocalServices.getService(NetworkPolicyManagerInternal.class) - .onStatsProviderLimitReached(mTag); + .onStatsProviderWarningOrLimitReached(mTag); } @Override diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 7d1827d1b6e2..0c1ba962323f 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -32,6 +32,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; +import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.Notification; import android.app.NotificationChannel; @@ -177,6 +178,8 @@ public class PreferencesHelper implements RankingConfig { private Map<String, List<String>> mOemLockedApps = new HashMap(); + private int mCurrentUserId = UserHandle.USER_NULL; + public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler, ZenModeHelper zenHelper, NotificationChannelLogger notificationChannelLogger, AppOpsManager appOpsManager, @@ -191,7 +194,8 @@ public class PreferencesHelper implements RankingConfig { updateBadgingEnabled(); updateBubblesEnabled(); - syncChannelsBypassingDnd(mContext.getUserId()); + mCurrentUserId = ActivityManager.getCurrentUser(); + syncChannelsBypassingDnd(); } public void readXml(XmlPullParser parser, boolean forRestore, int userId) @@ -790,7 +794,7 @@ public class PreferencesHelper implements RankingConfig { // but the system can if (group.isBlocked() != oldGroup.isBlocked()) { group.lockFields(NotificationChannelGroup.USER_LOCKED_BLOCKED_STATE); - updateChannelsBypassingDnd(mContext.getUserId()); + updateChannelsBypassingDnd(); } } } @@ -871,13 +875,13 @@ public class PreferencesHelper implements RankingConfig { // fields on the channel yet if (existing.getUserLockedFields() == 0 && hasDndAccess) { boolean bypassDnd = channel.canBypassDnd(); - if (bypassDnd != existing.canBypassDnd()) { + if (bypassDnd != existing.canBypassDnd() || wasUndeleted) { existing.setBypassDnd(bypassDnd); needsPolicyFileChange = true; if (bypassDnd != mAreChannelsBypassingDnd || previousExistingImportance != existing.getImportance()) { - updateChannelsBypassingDnd(mContext.getUserId()); + updateChannelsBypassingDnd(); } } } @@ -941,7 +945,7 @@ public class PreferencesHelper implements RankingConfig { r.channels.put(channel.getId(), channel); if (channel.canBypassDnd() != mAreChannelsBypassingDnd) { - updateChannelsBypassingDnd(mContext.getUserId()); + updateChannelsBypassingDnd(); } MetricsLogger.action(getChannelLog(channel, pkg).setType( com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN)); @@ -1013,7 +1017,7 @@ public class PreferencesHelper implements RankingConfig { if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd || channel.getImportance() != updatedChannel.getImportance()) { - updateChannelsBypassingDnd(mContext.getUserId()); + updateChannelsBypassingDnd(); } } updateConfig(); @@ -1110,7 +1114,7 @@ public class PreferencesHelper implements RankingConfig { mNotificationChannelLogger.logNotificationChannelDeleted(channel, uid, pkg); if (mAreChannelsBypassingDnd && channel.canBypassDnd()) { - updateChannelsBypassingDnd(mContext.getUserId()); + updateChannelsBypassingDnd(); } } } @@ -1454,7 +1458,7 @@ public class PreferencesHelper implements RankingConfig { } } if (!deletedChannelIds.isEmpty() && mAreChannelsBypassingDnd) { - updateChannelsBypassingDnd(mContext.getUserId()); + updateChannelsBypassingDnd(); } return deletedChannelIds; } @@ -1600,29 +1604,29 @@ public class PreferencesHelper implements RankingConfig { } /** - * Syncs {@link #mAreChannelsBypassingDnd} with the user's notification policy before + * Syncs {@link #mAreChannelsBypassingDnd} with the current user's notification policy before * updating - * @param userId */ - private void syncChannelsBypassingDnd(int userId) { + private void syncChannelsBypassingDnd() { mAreChannelsBypassingDnd = (mZenModeHelper.getNotificationPolicy().state & NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND) == 1; - updateChannelsBypassingDnd(userId); + updateChannelsBypassingDnd(); } /** - * Updates the user's NotificationPolicy based on whether the given userId + * Updates the user's NotificationPolicy based on whether the current userId * has channels bypassing DND * @param userId */ - private void updateChannelsBypassingDnd(int userId) { + private void updateChannelsBypassingDnd() { synchronized (mPackagePreferences) { final int numPackagePreferences = mPackagePreferences.size(); for (int i = 0; i < numPackagePreferences; i++) { final PackagePreferences r = mPackagePreferences.valueAt(i); - // Package isn't associated with this userId or notifications from this package are - // blocked - if (userId != UserHandle.getUserId(r.uid) || r.importance == IMPORTANCE_NONE) { + // Package isn't associated with the current userId or notifications from this + // package are blocked + if (mCurrentUserId != UserHandle.getUserId(r.uid) + || r.importance == IMPORTANCE_NONE) { continue; } @@ -2168,14 +2172,16 @@ public class PreferencesHelper implements RankingConfig { * Called when user switches */ public void onUserSwitched(int userId) { - syncChannelsBypassingDnd(userId); + mCurrentUserId = userId; + syncChannelsBypassingDnd(); } /** * Called when user is unlocked */ public void onUserUnlocked(int userId) { - syncChannelsBypassingDnd(userId); + mCurrentUserId = userId; + syncChannelsBypassingDnd(); } public void onUserRemoved(int userId) { diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 5d8b75d2af4e..6ad43ce6c6ae 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -51,8 +51,8 @@ import android.os.FileUtils; import android.os.PowerManager; import android.os.SystemClock; import android.os.SystemProperties; -import android.os.UserHandle; import android.os.Trace; +import android.os.UserHandle; import android.os.WorkSource; import android.os.storage.StorageManager; import android.util.Log; @@ -260,7 +260,8 @@ public class PackageDexOptimizer { // Only report metrics for base apk for now. // TODO: add ISA and APK type to metrics. - if (pkg.getBaseCodePath().equals(path)) { + // OTAPreopt doesn't have stats so don't report in that case. + if (pkg.getBaseCodePath().equals(path) && packageStats != null) { Trace.traceBegin(Trace.TRACE_TAG_PACKAGE_MANAGER, "dex2oat-metrics"); try { long sessionId = Math.randomLongInternal(); diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java index beebb3145018..fe21201f5cb7 100644 --- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java +++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java @@ -21,11 +21,13 @@ import static android.os.UserHandle.USER_SYSTEM; import android.annotation.IntDef; import android.content.Context; import android.content.IntentSender; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.hardware.boot.V1_0.IBootControl; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.os.Binder; +import android.os.Environment; import android.os.IRecoverySystem; import android.os.IRecoverySystemProgressListener; import android.os.PowerManager; @@ -52,6 +54,7 @@ import libcore.io.IoUtils; import java.io.DataInputStream; import java.io.DataOutputStream; +import java.io.File; import java.io.FileDescriptor; import java.io.FileWriter; import java.io.IOException; @@ -87,6 +90,12 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo private static final int SOCKET_CONNECTION_MAX_RETRY = 30; + static final String REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX = "_request_lskf_timestamp"; + static final String REQUEST_LSKF_COUNT_PREF_SUFFIX = "_request_lskf_count"; + + static final String LSKF_CAPTURED_TIMESTAMP_PREF = "lskf_captured_timestamp"; + static final String LSKF_CAPTURED_COUNT_PREF = "lskf_captured_count"; + private final Injector mInjector; private final Context mContext; @@ -127,7 +136,7 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo */ @IntDef({ ROR_NEED_PREPARATION, ROR_SKIP_PREPARATION_AND_NOTIFY, - ROR_SKIP_PREPARATION_NOT_NOTIFY }) + ROR_SKIP_PREPARATION_NOT_NOTIFY}) private @interface ResumeOnRebootActionsOnRequest {} /** @@ -139,7 +148,7 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo private @interface ResumeOnRebootActionsOnClear {} /** - * The error code for reboots initiated by resume on reboot clients. + * The error codes for reboots initiated by resume on reboot clients. */ private static final int REBOOT_ERROR_NONE = 0; private static final int REBOOT_ERROR_UNKNOWN = 1; @@ -156,11 +165,64 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE}) private @interface ResumeOnRebootRebootErrorCode {} + /** + * Manages shared preference, i.e. the storage used for metrics reporting. + */ + public static class PreferencesManager { + private static final String METRICS_DIR = "recovery_system"; + private static final String METRICS_PREFS_FILE = "RecoverySystemMetricsPrefs.xml"; + + protected final SharedPreferences mSharedPreferences; + private final File mMetricsPrefsFile; + + PreferencesManager(Context context) { + File prefsDir = new File(Environment.getDataSystemCeDirectory(USER_SYSTEM), + METRICS_DIR); + mMetricsPrefsFile = new File(prefsDir, METRICS_PREFS_FILE); + mSharedPreferences = context.getSharedPreferences(mMetricsPrefsFile, 0); + } + + /** Reads the value of a given key with type long. **/ + public long getLong(String key, long defaultValue) { + return mSharedPreferences.getLong(key, defaultValue); + } + + /** Reads the value of a given key with type int. **/ + public int getInt(String key, int defaultValue) { + return mSharedPreferences.getInt(key, defaultValue); + } + + /** Stores the value of a given key with type long. **/ + public void putLong(String key, long value) { + mSharedPreferences.edit().putLong(key, value).commit(); + } + + /** Stores the value of a given key with type int. **/ + public void putInt(String key, int value) { + mSharedPreferences.edit().putInt(key, value).commit(); + } + + /** Increments the value of a given key with type int. **/ + public synchronized void incrementIntKey(String key, int defaultInitialValue) { + int oldValue = getInt(key, defaultInitialValue); + putInt(key, oldValue + 1); + } + + /** Delete the preference file and cleanup all metrics storage. **/ + public void deletePrefsFile() { + if (!mMetricsPrefsFile.delete()) { + Slog.w(TAG, "Failed to delete metrics prefs"); + } + } + } + static class Injector { protected final Context mContext; + protected final PreferencesManager mPrefs; Injector(Context context) { mContext = context; + mPrefs = new PreferencesManager(context); } public Context getContext() { @@ -236,6 +298,14 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo return -1; } + public PreferencesManager getMetricsPrefs() { + return mPrefs; + } + + public long getCurrentTimeMillis() { + return System.currentTimeMillis(); + } + public void reportRebootEscrowPreparationMetrics(int uid, @ResumeOnRebootActionsOnRequest int requestResult, int requestedClientCount) { FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_PREPARATION_REPORTED, uid, @@ -414,7 +484,7 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.RECOVERY) != PackageManager.PERMISSION_GRANTED && mContext.checkCallingOrSelfPermission(android.Manifest.permission.REBOOT) - != PackageManager.PERMISSION_GRANTED) { + != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Caller must have " + android.Manifest.permission.RECOVERY + " or " + android.Manifest.permission.REBOOT + " for resume on reboot."); } @@ -427,6 +497,12 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo pendingRequestCount = mCallerPendingRequest.size(); } + // Save the timestamp and request count for new ror request + PreferencesManager prefs = mInjector.getMetricsPrefs(); + prefs.putLong(packageName + REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX, + mInjector.getCurrentTimeMillis()); + prefs.incrementIntKey(packageName + REQUEST_LSKF_COUNT_PREF_SUFFIX, 0); + mInjector.reportRebootEscrowPreparationMetrics(uid, requestResult, pendingRequestCount); } @@ -486,15 +562,31 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo } private void reportMetricsOnPreparedForReboot() { + long currentTimestamp = mInjector.getCurrentTimeMillis(); + List<String> preparedClients; synchronized (this) { preparedClients = new ArrayList<>(mCallerPreparedForReboot); } + // Save the timestamp & lskf capture count for lskf capture + PreferencesManager prefs = mInjector.getMetricsPrefs(); + prefs.putLong(LSKF_CAPTURED_TIMESTAMP_PREF, currentTimestamp); + prefs.incrementIntKey(LSKF_CAPTURED_COUNT_PREF, 0); + for (String packageName : preparedClients) { int uid = mInjector.getUidFromPackageName(packageName); + + int durationSeconds = -1; + long requestLskfTimestamp = prefs.getLong( + packageName + REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX, -1); + if (requestLskfTimestamp != -1 && currentTimestamp > requestLskfTimestamp) { + durationSeconds = (int) (currentTimestamp - requestLskfTimestamp) / 1000; + } + Slog.i(TAG, String.format("Reporting lskf captured, lskf capture takes %d seconds for" + + " package %s", durationSeconds, packageName)); mInjector.reportRebootEscrowLskfCapturedMetrics(uid, preparedClients.size(), - -1 /* duration */); + durationSeconds); } } @@ -541,6 +633,7 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo Slog.w(TAG, "Missing packageName when clearing lskf."); return false; } + // TODO(179105110) Clear the RoR metrics for the given packageName. @ResumeOnRebootActionsOnClear int action = updateRoRPreparationStateOnClear(packageName); switch (action) { @@ -641,7 +734,15 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo return REBOOT_ERROR_SLOT_MISMATCH; } - if (!mInjector.getLockSettingsService().armRebootEscrow()) { + final long origId = Binder.clearCallingIdentity(); + boolean result; + try { + result = mInjector.getLockSettingsService().armRebootEscrow(); + } finally { + Binder.restoreCallingIdentity(origId); + } + + if (!result) { Slog.w(TAG, "Failure to escrow key for reboot"); return REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE; } @@ -649,20 +750,42 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo return REBOOT_ERROR_NONE; } + private boolean useServerBasedRoR() { + final long origId = Binder.clearCallingIdentity(); + try { + return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA, + "server_based_ror_enabled", false); + } finally { + Binder.restoreCallingIdentity(origId); + } + } + private void reportMetricsOnRebootWithLskf(String packageName, boolean slotSwitch, @ResumeOnRebootRebootErrorCode int errorCode) { int uid = mInjector.getUidFromPackageName(packageName); - boolean serverBased = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA, - "server_based_ror_enabled", false); + boolean serverBased = useServerBasedRoR(); int preparedClientCount; synchronized (this) { preparedClientCount = mCallerPreparedForReboot.size(); } - // TODO(b/179105110) report the true value of duration and counts + long currentTimestamp = mInjector.getCurrentTimeMillis(); + int durationSeconds = -1; + PreferencesManager prefs = mInjector.getMetricsPrefs(); + long lskfCapturedTimestamp = prefs.getLong(LSKF_CAPTURED_TIMESTAMP_PREF, -1); + if (lskfCapturedTimestamp != -1 && currentTimestamp > lskfCapturedTimestamp) { + durationSeconds = (int) (currentTimestamp - lskfCapturedTimestamp) / 1000; + } + + int requestCount = prefs.getInt(packageName + REQUEST_LSKF_COUNT_PREF_SUFFIX, -1); + int lskfCapturedCount = prefs.getInt(LSKF_CAPTURED_COUNT_PREF, -1); + + Slog.i(TAG, String.format("Reporting reboot with lskf, package name %s, client count %d," + + " request count %d, lskf captured count %d, duration since lskf captured" + + " %d seconds.", packageName, preparedClientCount, requestCount, + lskfCapturedCount, durationSeconds)); mInjector.reportRebootEscrowRebootMetrics(errorCode, uid, preparedClientCount, - 1 /* request count */, slotSwitch, serverBased, - -1 /* duration */, 1 /* lskf capture count */); + requestCount, slotSwitch, serverBased, durationSeconds, lskfCapturedCount); } private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) { @@ -673,6 +796,9 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo return false; } + // Clear the metrics prefs after a successful RoR reboot. + mInjector.getMetricsPrefs().deletePrefsFile(); + PowerManager pm = mInjector.getPowerManager(); pm.reboot(reason); return true; diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java index 35194658a48f..85d2d39d7a1d 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java @@ -20,7 +20,7 @@ import android.annotation.Nullable; import android.app.AlarmManager; import android.content.ContentResolver; import android.content.Context; -import android.net.ConnectivityManager; +import android.content.pm.PackageManager; import android.os.SystemProperties; import android.provider.Settings; @@ -52,9 +52,7 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat } private boolean deviceHasTelephonyNetwork() { - // TODO b/150583524 Avoid the use of a deprecated API. - return mContext.getSystemService(ConnectivityManager.class) - .isNetworkSupported(ConnectivityManager.TYPE_MOBILE); + return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY); } @Override diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java index 3f74938005a7..89ed956b3aef 100644 --- a/services/core/java/com/android/server/vcn/Vcn.java +++ b/services/core/java/com/android/server/vcn/Vcn.java @@ -41,6 +41,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; @@ -110,6 +111,24 @@ public class Vcn extends Handler { @NonNull private final VcnNetworkRequestListener mRequestListener; @NonNull private final VcnCallback mVcnCallback; + /** + * Map containing all VcnGatewayConnections and their VcnGatewayConnectionConfigs. + * + * <p>Due to potential for race conditions, VcnGatewayConnections MUST only be created and added + * to this map in {@link #handleNetworkRequested(NetworkRequest, int, int)}, when a VCN receives + * a NetworkRequest that matches a VcnGatewayConnectionConfig for this VCN's VcnConfig. + * + * <p>A VcnGatewayConnection instance MUST NEVER overwrite an existing instance - otherwise + * there is potential for a orphaned VcnGatewayConnection instance that does not get properly + * shut down. + * + * <p>Due to potential for race conditions, VcnGatewayConnections MUST only be removed from this + * map once they have finished tearing down, which is reported to this VCN via {@link + * VcnGatewayStatusCallback#onQuit()}. Once this is done, all NetworkRequests are retrieved from + * the NetworkProvider so that another VcnGatewayConnectionConfig can match the + * previously-matched request. + */ + // TODO(b/182533200): remove the invariant on VcnGatewayConnection lifecycles @NonNull private final Map<VcnGatewayConnectionConfig, VcnGatewayConnection> mVcnGatewayConnections = new HashMap<>(); @@ -191,6 +210,19 @@ public class Vcn extends Handler { return Collections.unmodifiableSet(new HashSet<>(mVcnGatewayConnections.values())); } + /** Get current Configs and Gateways for testing purposes */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public Map<VcnGatewayConnectionConfig, VcnGatewayConnection> + getVcnGatewayConnectionConfigMap() { + return Collections.unmodifiableMap(new HashMap<>(mVcnGatewayConnections)); + } + + /** Set whether this Vcn is active for testing purposes */ + @VisibleForTesting(visibility = Visibility.PRIVATE) + public void setIsActive(boolean isActive) { + mIsActive.set(isActive); + } + private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener { @Override public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) { @@ -202,11 +234,6 @@ public class Vcn extends Handler { @Override public void handleMessage(@NonNull Message msg) { - // Ignore if this Vcn is not active and we're not receiving new configs - if (!isActive() && msg.what != MSG_EVENT_CONFIG_UPDATED) { - return; - } - switch (msg.what) { case MSG_EVENT_CONFIG_UPDATED: handleConfigUpdated((VcnConfig) msg.obj); @@ -237,9 +264,31 @@ public class Vcn extends Handler { mConfig = config; - // TODO(b/181815405): Reevaluate active VcnGatewayConnection(s) + if (mIsActive.getAndSet(true)) { + // VCN is already active - teardown any GatewayConnections whose configs have been + // removed and get all current requests + for (final Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry : + mVcnGatewayConnections.entrySet()) { + final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey(); + final VcnGatewayConnection gatewayConnection = entry.getValue(); + + // GatewayConnectionConfigs must match exactly (otherwise authentication or + // connection details may have changed). + if (!mConfig.getGatewayConnectionConfigs().contains(gatewayConnectionConfig)) { + if (gatewayConnection == null) { + Slog.wtf( + getLogTag(), + "Found gatewayConnectionConfig without GatewayConnection"); + } else { + gatewayConnection.teardownAsynchronously(); + } + } + } - if (!mIsActive.getAndSet(true)) { + // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be + // satisfied start a new GatewayConnection) + mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); + } else { // If this VCN was not previously active, it is exiting Safe Mode. Re-register the // request listener to get NetworkRequests again (and all cached requests). mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener); @@ -259,13 +308,16 @@ public class Vcn extends Handler { private void handleEnterSafeMode() { handleTeardown(); - mVcnGatewayConnections.clear(); - mVcnCallback.onEnteredSafeMode(); } private void handleNetworkRequested( @NonNull NetworkRequest request, int score, int providerId) { + if (!isActive()) { + Slog.v(getLogTag(), "Received NetworkRequest while inactive. Ignore for now"); + return; + } + if (score > getNetworkScore()) { if (VDBG) { Slog.v( @@ -318,8 +370,10 @@ public class Vcn extends Handler { mVcnGatewayConnections.remove(config); // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied - // start a new GatewayConnection) - mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); + // start a new GatewayConnection), but only if the Vcn is still active + if (isActive()) { + mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener); + } } private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) { diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java index a262939c0ef9..29aedcea0cd2 100644 --- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java +++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java @@ -295,10 +295,30 @@ public final class ProfcollectForwardingService extends SystemService { return; } - try { - mIProfcollect.report(); - } catch (RemoteException e) { - Log.e(LOG_TAG, e.getMessage()); - } + final boolean uploadReport = + DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT, + "upload_report", false); + + new Thread(() -> { + try { + String reportPath = mIProfcollect.report(); + if (!uploadReport) { + return; + } + Intent uploadIntent = + new Intent("com.google.android.apps.betterbug.intent.action.UPLOAD_PROFILE") + .setPackage("com.google.android.apps.internal.betterbug") + .putExtra("EXTRA_DESTINATION", "PROFCOLLECT") + .putExtra("EXTRA_PACKAGE_NAME", getContext().getPackageName()) + .putExtra("EXTRA_PROFILE_PATH", reportPath) + .addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + Context context = getContext(); + if (context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0) != null) { + context.sendBroadcast(uploadIntent); + } + } catch (RemoteException e) { + Log.e(LOG_TAG, e.getMessage()); + } + }).start(); } } diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java index 1b8ab2175458..2f0d71a2a579 100644 --- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java @@ -58,6 +58,7 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executor; /** * Tests for {@link com.android.server.apphibernation.AppHibernationService} @@ -116,8 +117,8 @@ public final class AppHibernationServiceTest { mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); UserInfo userInfo = addUser(USER_ID_1); - mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo)); doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_1); + mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo)); mAppHibernationService.mIsServiceEnabled = true; } @@ -150,8 +151,8 @@ public final class AppHibernationServiceTest { throws RemoteException { // WHEN a new user is added and a package from the user is hibernated UserInfo user2 = addUser(USER_ID_2); - mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(user2)); doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2); + mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(user2)); mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true); // THEN the new user's package is hibernated @@ -188,8 +189,8 @@ public final class AppHibernationServiceTest { // GIVEN an unlocked user with all packages installed UserInfo userInfo = addUser(USER_ID_2, new String[]{PACKAGE_NAME_1, PACKAGE_NAME_2, PACKAGE_NAME_3}); - mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo)); doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2); + mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo)); // WHEN packages are hibernated for the user mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true); @@ -259,6 +260,12 @@ public final class AppHibernationServiceTest { } @Override + public Executor getBackgroundExecutor() { + // Just execute immediately in tests. + return r -> r.run(); + } + + @Override public HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore() { return Mockito.mock(HibernationStateDiskStore.class); } diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java index fcd6b842426a..7bdc87ef6bd7 100644 --- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java @@ -116,7 +116,7 @@ class CompatConfigBuilder { } CompatConfigBuilder addOverridableChangeWithId(long id) { - mChanges.add(new CompatChange(id, "", -1, -1, false, true, "", true)); + mChanges.add(new CompatChange(id, "", -1, -1, true, false, "", true)); return this; } diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java index bd774056aef8..a866363f46e6 100644 --- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java @@ -260,6 +260,36 @@ public class CompatConfigTest { } @Test + public void testInstallerCanSetOverrides() throws Exception { + final long changeId = 1234L; + final int installerUid = 23; + CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext) + .addOverridableChangeWithId(1234L) + .build(); + ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() + .withPackageName("com.some.package") + .build(); + PackageManager packageManager = mock(PackageManager.class); + when(mContext.getPackageManager()).thenReturn(packageManager); + when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt())) + .thenReturn(applicationInfo); + + // Force the validator to prevent overriding the change by using a user build. + when(mBuildClassifier.isDebuggableBuild()).thenReturn(false); + when(mBuildClassifier.isFinalBuild()).thenReturn(true); + + CompatibilityOverrideConfig config = new CompatibilityOverrideConfig( + Collections.singletonMap(1234L, + new PackageOverride.Builder() + .setMaxVersionCode(99L) + .setEnabled(true) + .build())); + + compatConfig.addOverrides(config, "com.some.package"); + assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue(); + } + + @Test public void testApplyDeferredOverridesAfterInstallingApp() throws Exception { ApplicationInfo applicationInfo = ApplicationInfoBuilder.create() .withPackageName("com.notinstalled.foo") @@ -639,9 +669,18 @@ public class CompatConfigTest { .build()); when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt())) .thenThrow(new NameNotFoundException()); - - compatConfig.addOverride(1L, "foo.bar", true); - compatConfig.addOverride(2L, "bar.baz", false); + compatConfig.addOverrides( + new CompatibilityOverrideConfig( + Collections.singletonMap( + 1L, + new PackageOverride.Builder().setEnabled(true).build())), + "foo.bar"); + compatConfig.addOverrides( + new CompatibilityOverrideConfig( + Collections.singletonMap( + 2L, + new PackageOverride.Builder().setEnabled(false).build())), + "bar.baz"); assertThat(readFile(overridesFile)).isEqualTo("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<overrides>\n" diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java index 3fc6e9918382..a2664e5f3b0a 100644 --- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java @@ -113,7 +113,7 @@ public class PlatformCompatTest { new CompatibilityChangeInfo( 6L, "", Build.VERSION_CODES.R, -1, false, false, "", false), new CompatibilityChangeInfo(7L, "", -1, -1, false, true, "", false), - new CompatibilityChangeInfo(8L, "", -1, -1, false, true, "", true)); + new CompatibilityChangeInfo(8L, "", -1, -1, true, false, "", true)); } @Test diff --git a/services/tests/servicestests/src/com/android/server/content/OWNERS b/services/tests/servicestests/src/com/android/server/content/OWNERS new file mode 100644 index 000000000000..6264a1427c7f --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/content/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/content/OWNERS 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 91342ce925f6..8c08226201a8 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java @@ -21,6 +21,7 @@ import static android.content.pm.UserInfo.FLAG_PRIMARY; import static android.content.pm.UserInfo.FLAG_PROFILE; import static android.os.UserHandle.USER_SYSTEM; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -110,6 +111,10 @@ public class RebootEscrowManagerTests { public interface MockableRebootEscrowInjected { int getBootCount(); + long getCurrentTimeMillis(); + + boolean forceServerBased(); + void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount, int escrowDurationInSeconds, int vbmetaDigestStatus, int durationSinceBootComplete); } @@ -174,6 +179,9 @@ public class RebootEscrowManagerTests { @Override public boolean serverBasedResumeOnReboot() { + if (mInjected.forceServerBased()) { + return true; + } return mServerBased; } @@ -205,9 +213,20 @@ public class RebootEscrowManagerTests { } @Override + public String getVbmetaDigest(boolean other) { + return other ? "" : "fake digest"; + } + + @Override + public long getCurrentTimeMillis() { + return mInjected.getCurrentTimeMillis(); + } + + @Override public void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount, int escrowDurationInSeconds, int vbmetaDigestStatus, int durationSinceBootComplete) { + mInjected.reportMetric(success, errorCode, serviceType, attemptCount, escrowDurationInSeconds, vbmetaDigestStatus, durationSinceBootComplete); } @@ -430,16 +449,21 @@ public class RebootEscrowManagerTests { // pretend reboot happens here when(mInjected.getBootCount()).thenReturn(1); + when(mInjected.getCurrentTimeMillis()).thenReturn(30000L); + mStorage.setLong(RebootEscrowManager.REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, 10000L, + USER_SYSTEM); ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class); doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(), eq(0) /* error code */, eq(1) /* HAL based */, eq(1) /* attempt count */, - anyInt(), anyInt(), anyInt()); + eq(20), eq(0) /* vbmeta status */, anyInt()); when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue()); mService.loadRebootEscrowDataIfAvailable(null); verify(mRebootEscrow).retrieveKey(); assertTrue(metricsSuccessCaptor.getValue()); verify(mKeyStoreManager).clearKeyStoreEncryptionKey(); + assertEquals(mStorage.getLong(RebootEscrowManager.REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, + -1, USER_SYSTEM), -1); } @Test @@ -468,7 +492,7 @@ public class RebootEscrowManagerTests { ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class); doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(), eq(0) /* error code */, eq(2) /* Server based */, eq(1) /* attempt count */, - anyInt(), anyInt(), anyInt()); + anyInt(), eq(0) /* vbmeta status */, anyInt()); when(mServiceConnection.unwrap(any(), anyLong())) .thenAnswer(invocation -> invocation.getArgument(0)); @@ -479,6 +503,84 @@ public class RebootEscrowManagerTests { } @Test + public void loadRebootEscrowDataIfAvailable_ServerBasedRemoteException_Failure() + 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); + ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class); + doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(), + metricsErrorCodeCaptor.capture(), eq(2) /* Server based */, + eq(1) /* attempt count */, anyInt(), eq(0) /* vbmeta status */, anyInt()); + + when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(RemoteException.class); + mService.loadRebootEscrowDataIfAvailable(null); + verify(mServiceConnection).unwrap(any(), anyLong()); + assertFalse(metricsSuccessCaptor.getValue()); + assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_LOAD_ESCROW_KEY), + metricsErrorCodeCaptor.getValue()); + } + + @Test + public void loadRebootEscrowDataIfAvailable_ServerBasedIoError_RetryFailure() 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); + ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class); + doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(), + metricsErrorCodeCaptor.capture(), eq(2) /* Server based */, + eq(2) /* attempt count */, anyInt(), eq(0) /* vbmeta status */, anyInt()); + when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(IOException.class); + + HandlerThread thread = new HandlerThread("RebootEscrowManagerTest"); + thread.start(); + mService.loadRebootEscrowDataIfAvailable(new Handler(thread.getLooper())); + // Sleep 5s for the retry to complete + Thread.sleep(5 * 1000); + assertFalse(metricsSuccessCaptor.getValue()); + assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_RETRY_COUNT_EXHAUSTED), + metricsErrorCodeCaptor.getValue()); + } + + @Test public void loadRebootEscrowDataIfAvailable_ServerBased_RetrySuccess() throws Exception { setServerBasedRebootEscrowProvider(); @@ -607,9 +709,14 @@ public class RebootEscrowManagerTests { when(mInjected.getBootCount()).thenReturn(10); when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue()); + // Trigger a vbmeta digest mismatch + mStorage.setString(RebootEscrowManager.REBOOT_ESCROW_KEY_VBMETA_DIGEST, + "non sense value", USER_SYSTEM); mService.loadRebootEscrowDataIfAvailable(null); verify(mInjected).reportMetric(eq(true), eq(0) /* error code */, eq(1) /* HAL based */, - eq(1) /* attempt count */, anyInt(), anyInt(), anyInt()); + eq(1) /* attempt count */, anyInt(), eq(2) /* vbmeta status */, anyInt()); + assertEquals(mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_KEY_VBMETA_DIGEST, + "", USER_SYSTEM), ""); } @Test @@ -636,12 +743,17 @@ public class RebootEscrowManagerTests { when(mInjected.getBootCount()).thenReturn(1); ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class); + ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class); + // Return a null escrow key doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(), - anyInt() /* error code */, eq(1) /* HAL based */, eq(1) /* attempt count */, - anyInt(), anyInt(), anyInt()); - when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> new byte[32]); + metricsErrorCodeCaptor.capture(), eq(1) /* HAL based */, + eq(1) /* attempt count */, anyInt(), anyInt(), anyInt()); + + when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> null); mService.loadRebootEscrowDataIfAvailable(null); verify(mRebootEscrow).retrieveKey(); assertFalse(metricsSuccessCaptor.getValue()); + assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_LOAD_ESCROW_KEY), + metricsErrorCodeCaptor.getValue()); } } 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 fb01ff6e16c6..d405113d064c 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -1817,7 +1817,7 @@ public class NetworkPolicyManagerServiceTest { // yet reached. final NetworkPolicyManagerInternal npmi = LocalServices .getService(NetworkPolicyManagerInternal.class); - npmi.onStatsProviderLimitReached("TEST"); + npmi.onStatsProviderWarningOrLimitReached("TEST"); // Verifies that the limit reached leads to a force update and new limit should be set. postMsgAndWaitForCompletion(); diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java index 324e5929f77f..7903a90979fb 100644 --- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java @@ -22,6 +22,7 @@ import static org.mockito.AdditionalMatchers.not; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doNothing; @@ -72,6 +73,7 @@ public class RecoverySystemServiceTest { private LockSettingsInternal mLockSettingsInternal; private IBootControl mIBootControl; private RecoverySystemServiceTestable.IMetricsReporter mMetricsReporter; + private RecoverySystemService.PreferencesManager mSharedPreferences; private static final String FAKE_OTA_PACKAGE_NAME = "fake.ota.package"; private static final String FAKE_OTHER_PACKAGE_NAME = "fake.other.package"; @@ -97,10 +99,11 @@ public class RecoverySystemServiceTest { when(mIBootControl.getActiveBootSlot()).thenReturn(1); mMetricsReporter = mock(RecoverySystemServiceTestable.IMetricsReporter.class); + mSharedPreferences = mock(RecoverySystemService.PreferencesManager.class); mRecoverySystemService = new RecoverySystemServiceTestable(mContext, mSystemProperties, powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal, - mIBootControl, mMetricsReporter); + mIBootControl, mMetricsReporter, mSharedPreferences); } @Test @@ -237,6 +240,8 @@ public class RecoverySystemServiceTest { is(true)); verify(mMetricsReporter).reportRebootEscrowPreparationMetrics( eq(1000), eq(0) /* need preparation */, eq(1) /* client count */); + verify(mSharedPreferences).putLong(eq(FAKE_OTA_PACKAGE_NAME + + RecoverySystemService.REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX), eq(100_000L)); } @@ -245,10 +250,19 @@ public class RecoverySystemServiceTest { IntentSender intentSender = mock(IntentSender.class); assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender), is(true)); + + when(mSharedPreferences.getLong(eq(FAKE_OTA_PACKAGE_NAME + + RecoverySystemService.REQUEST_LSKF_TIMESTAMP_PREF_SUFFIX), anyLong())) + .thenReturn(200_000L).thenReturn(5000L); + mRecoverySystemService.onPreparedForReboot(true); + verify(mMetricsReporter).reportRebootEscrowLskfCapturedMetrics( + eq(1000), eq(1) /* client count */, + eq(-1) /* invalid duration */); + mRecoverySystemService.onPreparedForReboot(true); verify(intentSender).sendIntent(any(), anyInt(), any(), any(), any()); verify(mMetricsReporter).reportRebootEscrowLskfCapturedMetrics( - eq(1000), eq(1) /* client count */, anyInt() /* duration */); + eq(1000), eq(1) /* client count */, eq(95) /* duration */); } @Test @@ -352,12 +366,19 @@ public class RecoverySystemServiceTest { public void rebootWithLskf_Success() throws Exception { assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true)); mRecoverySystemService.onPreparedForReboot(true); + + when(mSharedPreferences.getInt(eq(FAKE_OTA_PACKAGE_NAME + + RecoverySystemService.REQUEST_LSKF_COUNT_PREF_SUFFIX), anyInt())).thenReturn(2); + when(mSharedPreferences.getInt(eq(RecoverySystemService.LSKF_CAPTURED_COUNT_PREF), + anyInt())).thenReturn(3); + when(mSharedPreferences.getLong(eq(RecoverySystemService.LSKF_CAPTURED_TIMESTAMP_PREF), + anyLong())).thenReturn(40_000L); assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", true), is(true)); verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean()); verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(0), eq(1000), - eq(1) /* client count */, eq(1) /* request count */, eq(true) /* slot switch */, - anyBoolean(), anyInt(), eq(1) /* lskf capture count */); + eq(1) /* client count */, eq(2) /* request count */, eq(true) /* slot switch */, + anyBoolean(), eq(60) /* duration */, eq(3) /* lskf capture count */); } @@ -400,13 +421,19 @@ public class RecoverySystemServiceTest { assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true)); mRecoverySystemService.onPreparedForReboot(true); - // Client B's clear won't affect client A's preparation. + when(mSharedPreferences.getInt(eq(FAKE_OTA_PACKAGE_NAME + + RecoverySystemService.REQUEST_LSKF_COUNT_PREF_SUFFIX), anyInt())).thenReturn(2); + when(mSharedPreferences.getInt(eq(RecoverySystemService.LSKF_CAPTURED_COUNT_PREF), + anyInt())).thenReturn(1); + when(mSharedPreferences.getLong(eq(RecoverySystemService.LSKF_CAPTURED_TIMESTAMP_PREF), + anyLong())).thenReturn(60_000L); + assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", true), is(true)); verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean()); verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(0), eq(1000), - eq(2) /* client count */, eq(1) /* request count */, eq(true) /* slot switch */, - anyBoolean(), anyInt(), eq(1) /* lskf capture count */); + eq(2) /* client count */, eq(2) /* request count */, eq(true) /* slot switch */, + anyBoolean(), eq(40), eq(1) /* lskf capture count */); } @Test @@ -415,22 +442,30 @@ public class RecoverySystemServiceTest { mRecoverySystemService.onPreparedForReboot(true); assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true)); + when(mSharedPreferences.getInt(eq(FAKE_OTHER_PACKAGE_NAME + + RecoverySystemService.REQUEST_LSKF_COUNT_PREF_SUFFIX), anyInt())).thenReturn(2); + when(mSharedPreferences.getInt(eq(RecoverySystemService.LSKF_CAPTURED_COUNT_PREF), + anyInt())).thenReturn(1); + when(mSharedPreferences.getLong(eq(RecoverySystemService.LSKF_CAPTURED_TIMESTAMP_PREF), + anyLong())).thenReturn(60_000L); + assertThat(mRecoverySystemService.clearLskf(FAKE_OTA_PACKAGE_NAME), is(true)); assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, null, true), is(false)); verifyNoMoreInteractions(mIPowerManager); verify(mMetricsReporter).reportRebootEscrowRebootMetrics(not(eq(0)), eq(1000), - eq(1) /* client count */, eq(1) /* request count */, eq(true) /* slot switch */, - anyBoolean(), anyInt(), eq(1) /* lskf capture count */); + eq(1) /* client count */, anyInt() /* request count */, eq(true) /* slot switch */, + anyBoolean(), eq(40), eq(1)/* lskf capture count */); assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true)); assertThat( mRecoverySystemService.rebootWithLskf(FAKE_OTHER_PACKAGE_NAME, "ab-update", true), is(true)); verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean()); - verify(mMetricsReporter).reportRebootEscrowRebootMetrics(eq(0), eq(2000), - eq(1) /* client count */, eq(1) /* request count */, eq(true) /* slot switch */, - anyBoolean(), anyInt(), eq(1) /* lskf capture count */); + + verify(mMetricsReporter).reportRebootEscrowRebootMetrics((eq(0)), eq(2000), + eq(1) /* client count */, eq(2) /* request count */, eq(true) /* slot switch */, + anyBoolean(), eq(40), eq(1) /* lskf capture count */); } @Test diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java index a894178fca06..27e953f30fa0 100644 --- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java @@ -33,11 +33,13 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { private final LockSettingsInternal mLockSettingsInternal; private final IBootControl mIBootControl; private final IMetricsReporter mIMetricsReporter; + private final RecoverySystemService.PreferencesManager mSharedPreferences; MockInjector(Context context, FakeSystemProperties systemProperties, PowerManager powerManager, FileWriter uncryptPackageFileWriter, UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal, - IBootControl bootControl, IMetricsReporter metricsReporter) { + IBootControl bootControl, IMetricsReporter metricsReporter, + RecoverySystemService.PreferencesManager preferences) { super(context); mSystemProperties = systemProperties; mPowerManager = powerManager; @@ -46,6 +48,7 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { mLockSettingsInternal = lockSettingsInternal; mIBootControl = bootControl; mIMetricsReporter = metricsReporter; + mSharedPreferences = preferences; } @Override @@ -114,12 +117,14 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { requestedClientCount); } + @Override public void reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount, int requestedToLskfCapturedDurationInSeconds) { mIMetricsReporter.reportRebootEscrowLskfCapturedMetrics(uid, requestedClientCount, requestedToLskfCapturedDurationInSeconds); } + @Override public void reportRebootEscrowRebootMetrics(int errorCode, int uid, int preparedClientCount, int requestCount, boolean slotSwitch, boolean serverBased, int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts) { @@ -127,14 +132,25 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { requestCount, slotSwitch, serverBased, lskfCapturedToRebootDurationInSeconds, lskfCapturedCounts); } + + @Override + public long getCurrentTimeMillis() { + return 100_000; + } + + @Override + public RecoverySystemService.PreferencesManager getMetricsPrefs() { + return mSharedPreferences; + } } RecoverySystemServiceTestable(Context context, FakeSystemProperties systemProperties, PowerManager powerManager, FileWriter uncryptPackageFileWriter, UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal, - IBootControl bootControl, IMetricsReporter metricsReporter) { + IBootControl bootControl, IMetricsReporter metricsReporter, + RecoverySystemService.PreferencesManager preferences) { super(new MockInjector(context, systemProperties, powerManager, uncryptPackageFileWriter, - uncryptSocket, lockSettingsInternal, bootControl, metricsReporter)); + uncryptSocket, lockSettingsInternal, bootControl, metricsReporter, preferences)); } public static class FakeSystemProperties { @@ -176,5 +192,4 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { int requestCount, boolean slotSwitch, boolean serverBased, int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts); } - } diff --git a/services/tests/servicestests/utils-mockito/com/android/server/testutils/OWNERS b/services/tests/servicestests/utils-mockito/com/android/server/testutils/OWNERS new file mode 100644 index 000000000000..d825dfd7cf00 --- /dev/null +++ b/services/tests/servicestests/utils-mockito/com/android/server/testutils/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/pm/OWNERS diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 4259831c15f8..ee89e1c840d6 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -833,10 +833,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testDefaultAssistant_overrideDefault() { - final int userId = 0; + final int userId = mContext.getUserId(); final String testComponent = "package/class"; final List<UserInfo> userInfos = new ArrayList<>(); - userInfos.add(new UserInfo(0, "", 0)); + userInfos.add(new UserInfo(userId, "", 0)); final ArraySet<ComponentName> validAssistants = new ArraySet<>(); validAssistants.add(ComponentName.unflattenFromString(testComponent)); when(mActivityManager.isLowRamDevice()).thenReturn(false); @@ -2393,7 +2393,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { .thenReturn(mTestNotificationChannel); reset(mListeners); - mBinderService.updateNotificationChannelForPackage(PKG, 0, mTestNotificationChannel); + mBinderService.updateNotificationChannelForPackage(PKG, mUid, mTestNotificationChannel); verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(PKG), eq(Process.myUserHandle()), eq(mTestNotificationChannel), eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); @@ -2929,7 +2929,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testSetListenerAccessForUser() throws Exception { - UserHandle user = UserHandle.of(10); + UserHandle user = UserHandle.of(mContext.getUserId() + 10); ComponentName c = ComponentName.unflattenFromString("package/Component"); mBinderService.setNotificationListenerAccessGrantedForUser(c, user.getIdentifier(), true); @@ -2945,20 +2945,20 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testSetAssistantAccessForUser() throws Exception { - UserHandle user = UserHandle.of(10); - List<UserInfo> uis = new ArrayList<>(); UserInfo ui = new UserInfo(); - ui.id = 10; + ui.id = mContext.getUserId() + 10; + UserHandle user = UserHandle.of(ui.id); + List<UserInfo> uis = new ArrayList<>(); uis.add(ui); ComponentName c = ComponentName.unflattenFromString("package/Component"); - when(mUm.getEnabledProfiles(10)).thenReturn(uis); + when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); mBinderService.setNotificationAssistantAccessGrantedForUser(c, user.getIdentifier(), true); verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any()); verify(mAssistants, times(1)).setPackageOrComponentEnabled( c.flattenToString(), user.getIdentifier(), true, true); - verify(mAssistants).setUserSet(10, true); + verify(mAssistants).setUserSet(ui.id, true); verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( c.flattenToString(), user.getIdentifier(), false, true); verify(mListeners, never()).setPackageOrComponentEnabled( @@ -2967,7 +2967,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { @Test public void testGetAssistantAllowedForUser() throws Exception { - UserHandle user = UserHandle.of(10); + UserHandle user = UserHandle.of(mContext.getUserId() + 10); try { mBinderService.getAllowedNotificationAssistantForUser(user.getIdentifier()); } catch (IllegalStateException e) { @@ -2987,12 +2987,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { throw e; } } - verify(mAssistants, times(1)).getAllowedComponents(0); + verify(mAssistants, times(1)).getAllowedComponents(mContext.getUserId()); } @Test public void testSetDndAccessForUser() throws Exception { - UserHandle user = UserHandle.of(10); + UserHandle user = UserHandle.of(mContext.getUserId() + 10); ComponentName c = ComponentName.unflattenFromString("package/Component"); mBinderService.setNotificationPolicyAccessGrantedForUser( c.getPackageName(), user.getIdentifier(), true); @@ -3012,9 +3012,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mBinderService.setNotificationListenerAccessGranted(c, true); verify(mListeners, times(1)).setPackageOrComponentEnabled( - c.flattenToString(), 0, true, true); + c.flattenToString(), mContext.getUserId(), true, true); verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( - c.flattenToString(), 0, false, true); + c.flattenToString(), mContext.getUserId(), false, true); verify(mAssistants, never()).setPackageOrComponentEnabled( any(), anyInt(), anyBoolean(), anyBoolean()); } @@ -3023,7 +3023,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testSetAssistantAccess() throws Exception { List<UserInfo> uis = new ArrayList<>(); UserInfo ui = new UserInfo(); - ui.id = 0; + ui.id = mContext.getUserId(); uis.add(ui); when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); ComponentName c = ComponentName.unflattenFromString("package/Component"); @@ -3031,9 +3031,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mBinderService.setNotificationAssistantAccessGranted(c, true); verify(mAssistants, times(1)).setPackageOrComponentEnabled( - c.flattenToString(), 0, true, true); + c.flattenToString(), ui.id, true, true); verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( - c.flattenToString(), 0, false, true); + c.flattenToString(), ui.id, false, true); verify(mListeners, never()).setPackageOrComponentEnabled( any(), anyInt(), anyBoolean(), anyBoolean()); } @@ -3042,10 +3042,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testSetAssistantAccess_multiProfile() throws Exception { List<UserInfo> uis = new ArrayList<>(); UserInfo ui = new UserInfo(); - ui.id = 0; + ui.id = mContext.getUserId(); uis.add(ui); UserInfo ui10 = new UserInfo(); - ui10.id = 10; + ui10.id = mContext.getUserId() + 10; uis.add(ui10); when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); ComponentName c = ComponentName.unflattenFromString("package/Component"); @@ -3053,13 +3053,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mBinderService.setNotificationAssistantAccessGranted(c, true); verify(mAssistants, times(1)).setPackageOrComponentEnabled( - c.flattenToString(), 0, true, true); + c.flattenToString(), ui.id, true, true); verify(mAssistants, times(1)).setPackageOrComponentEnabled( - c.flattenToString(), 10, true, true); + c.flattenToString(), ui10.id, true, true); verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( - c.flattenToString(), 0, false, true); + c.flattenToString(), ui.id, false, true); verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( - c.flattenToString(), 10, false, true); + c.flattenToString(), ui10.id, false, true); verify(mListeners, never()).setPackageOrComponentEnabled( any(), anyInt(), anyBoolean(), anyBoolean()); } @@ -3072,16 +3072,16 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList); List<UserInfo> uis = new ArrayList<>(); UserInfo ui = new UserInfo(); - ui.id = 0; + ui.id = mContext.getUserId(); uis.add(ui); when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); mBinderService.setNotificationAssistantAccessGranted(null, true); verify(mAssistants, times(1)).setPackageOrComponentEnabled( - c.flattenToString(), 0, true, false); + c.flattenToString(), ui.id, true, false); verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( - c.flattenToString(), 0, false, false); + c.flattenToString(), ui.id, false, false); verify(mListeners, never()).setPackageOrComponentEnabled( any(), anyInt(), anyBoolean(), anyBoolean()); } @@ -3090,21 +3090,21 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void testSetAssistantAccessForUser_nullWithAllowedAssistant() throws Exception { List<UserInfo> uis = new ArrayList<>(); UserInfo ui = new UserInfo(); - ui.id = 10; + ui.id = mContext.getUserId() + 10; uis.add(ui); UserHandle user = ui.getUserHandle(); ArrayList<ComponentName> componentList = new ArrayList<>(); ComponentName c = ComponentName.unflattenFromString("package/Component"); componentList.add(c); when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList); - when(mUm.getEnabledProfiles(10)).thenReturn(uis); + when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); mBinderService.setNotificationAssistantAccessGrantedForUser( null, user.getIdentifier(), true); verify(mAssistants, times(1)).setPackageOrComponentEnabled( c.flattenToString(), user.getIdentifier(), true, false); - verify(mAssistants).setUserSet(10, true); + verify(mAssistants).setUserSet(ui.id, true); verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( c.flattenToString(), user.getIdentifier(), false, false); verify(mListeners, never()).setPackageOrComponentEnabled( @@ -3116,10 +3116,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { throws Exception { List<UserInfo> uis = new ArrayList<>(); UserInfo ui = new UserInfo(); - ui.id = 0; + ui.id = mContext.getUserId(); uis.add(ui); UserInfo ui10 = new UserInfo(); - ui10.id = 10; + ui10.id = mContext.getUserId() + 10; uis.add(ui10); UserHandle user = ui.getUserHandle(); ArrayList<ComponentName> componentList = new ArrayList<>(); @@ -3135,8 +3135,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { c.flattenToString(), user.getIdentifier(), true, false); verify(mAssistants, times(1)).setPackageOrComponentEnabled( c.flattenToString(), ui10.id, true, false); - verify(mAssistants).setUserSet(0, true); - verify(mAssistants).setUserSet(10, true); + verify(mAssistants).setUserSet(ui.id, true); + verify(mAssistants).setUserSet(ui10.id, true); verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( c.flattenToString(), user.getIdentifier(), false, false); verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( @@ -3152,7 +3152,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true); verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( - c.getPackageName(), 0, true, true); + c.getPackageName(), mContext.getUserId(), true, true); verify(mAssistants, never()).setPackageOrComponentEnabled( any(), anyInt(), anyBoolean(), anyBoolean()); verify(mListeners, never()).setPackageOrComponentEnabled( @@ -3179,7 +3179,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { ComponentName c = ComponentName.unflattenFromString("package/Component"); List<UserInfo> uis = new ArrayList<>(); UserInfo ui = new UserInfo(); - ui.id = 0; + ui.id = mContext.getUserId(); uis.add(ui); when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); @@ -3214,9 +3214,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { mBinderService.setNotificationListenerAccessGranted(c, true); verify(mListeners, times(1)).setPackageOrComponentEnabled( - c.flattenToString(), 0, true, true); + c.flattenToString(), mContext.getUserId(), true, true); verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( - c.flattenToString(), 0, false, true); + c.flattenToString(), mContext.getUserId(), false, true); verify(mAssistants, never()).setPackageOrComponentEnabled( any(), anyInt(), anyBoolean(), anyBoolean()); } @@ -3228,7 +3228,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { ComponentName c = ComponentName.unflattenFromString("package/Component"); List<UserInfo> uis = new ArrayList<>(); UserInfo ui = new UserInfo(); - ui.id = 0; + ui.id = mContext.getUserId(); uis.add(ui); when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); @@ -3237,9 +3237,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { verify(mListeners, never()).setPackageOrComponentEnabled( anyString(), anyInt(), anyBoolean(), anyBoolean()); verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( - c.flattenToString(), 0, false, true); + c.flattenToString(), ui.id, false, true); verify(mAssistants, times(1)).setPackageOrComponentEnabled( - c.flattenToString(), 0, true, true); + c.flattenToString(), ui.id, true, true); } @Test @@ -3253,7 +3253,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { verify(mListeners, never()).setPackageOrComponentEnabled( anyString(), anyInt(), anyBoolean(), anyBoolean()); verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( - c.getPackageName(), 0, true, true); + c.getPackageName(), mContext.getUserId(), true, true); verify(mAssistants, never()).setPackageOrComponentEnabled( any(), anyInt(), anyBoolean(), anyBoolean()); } diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 477592ba4129..26cea2ca7a6c 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -837,20 +837,31 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser boolean prevHostConnected = mHostConnected; UsbPort port = (UsbPort) args.arg1; UsbPortStatus status = (UsbPortStatus) args.arg2; - mHostConnected = status.getCurrentDataRole() == DATA_ROLE_HOST; - mSourcePower = status.getCurrentPowerRole() == POWER_ROLE_SOURCE; - mSinkPower = status.getCurrentPowerRole() == POWER_ROLE_SINK; - mAudioAccessoryConnected = (status.getCurrentMode() == MODE_AUDIO_ACCESSORY); + + if (status != null) { + mHostConnected = status.getCurrentDataRole() == DATA_ROLE_HOST; + mSourcePower = status.getCurrentPowerRole() == POWER_ROLE_SOURCE; + mSinkPower = status.getCurrentPowerRole() == POWER_ROLE_SINK; + mAudioAccessoryConnected = (status.getCurrentMode() == MODE_AUDIO_ACCESSORY); + + // Ideally we want to see if PR_SWAP and DR_SWAP is supported. + // But, this should be suffice, since, all four combinations are only supported + // when PR_SWAP and DR_SWAP are supported. + mSupportsAllCombinations = status.isRoleCombinationSupported( + POWER_ROLE_SOURCE, DATA_ROLE_HOST) + && status.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_HOST) + && status.isRoleCombinationSupported(POWER_ROLE_SOURCE, + DATA_ROLE_DEVICE) + && status.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_DEVICE); + } else { + mHostConnected = false; + mSourcePower = false; + mSinkPower = false; + mAudioAccessoryConnected = false; + mSupportsAllCombinations = false; + } + mAudioAccessorySupported = port.isModeSupported(MODE_AUDIO_ACCESSORY); - // Ideally we want to see if PR_SWAP and DR_SWAP is supported. - // But, this should be suffice, since, all four combinations are only supported - // when PR_SWAP and DR_SWAP are supported. - mSupportsAllCombinations = status.isRoleCombinationSupported( - POWER_ROLE_SOURCE, DATA_ROLE_HOST) - && status.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_HOST) - && status.isRoleCombinationSupported(POWER_ROLE_SOURCE, - DATA_ROLE_DEVICE) - && status.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_DEVICE); args.recycle(); updateUsbNotification(false); diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 464d37510034..0ba96a947a73 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -42,8 +42,6 @@ import android.telephony.ims.feature.RcsFeature; 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; /** @@ -110,31 +108,17 @@ 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; + public static final int CARRIER_NR_AVAILABILITY_NSA = 1; /** * 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; + public static final int CARRIER_NR_AVAILABILITY_SA = 2; private final Context mContext; @@ -1807,23 +1791,20 @@ public class CarrierConfigManager { "show_precise_failed_cause_bool"; /** - * Bit-field integer to determine whether the carrier enable the non-standalone (NSA) mode of - * 5G NR, standalone (SA) mode of 5G NR + * A list of carrier nr availability is used 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> The value of list is + * {@link #CARRIER_NR_AVAILABILITY_NSA}, or {@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. + * <p> For example, if both NSA and SA are used, the list value is { + * {@link #CARRIER_NR_AVAILABILITY_NSA},{@link #CARRIER_NR_AVAILABILITY_SA}}. + * If the carrier doesn't support 5G NR, the value is the empty array. + * If the key is invalid or not configured, the default value { + * {@link #CARRIER_NR_AVAILABILITY_NSA},{@link #CARRIER_NR_AVAILABILITY_SA}} will apply. */ - public static final String KEY_CARRIER_NR_AVAILABILITY_INT = "carrier_nr_availability_int"; + public static final String KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY = + "carrier_nr_availabilities_int_array"; /** * Boolean to decide whether LTE is enabled. @@ -4045,6 +4026,14 @@ public class CarrierConfigManager { public static final String KEY_NON_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC_INT = KEY_PREFIX + "non_rcs_capabilities_cache_expiration_sec_int"; + /** + * Specifies the RCS feature tag allowed for the carrier. + * + * <p>The values refer to RCC.07 2.4.4. + */ + public static final String KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY = + KEY_PREFIX + "rcs_feature_tag_allowed_string_array"; + private Ims() {} private static PersistableBundle getDefaults() { @@ -4058,6 +4047,27 @@ public class CarrierConfigManager { defaults.putBoolean(KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL, false); defaults.putBoolean(KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL, true); defaults.putInt(KEY_NON_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC_INT, 30 * 24 * 60 * 60); + defaults.putStringArray(KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY, new String[]{ + "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.msg\"", + "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.largemsg\"", + "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.deferred\"", + "+g.gsma.rcs.cpm.pager-large", + "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session\"", + "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session\"", + "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.fthttp\"", + "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.ftsms\"", + "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.gsma.callcomposer\"", + "+g.gsma.callcomposer", + "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.gsma.callunanswered\"", + "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.gsma.sharedmap\"", + "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.gsma.sharedsketch\"", + "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.geopush\"", + "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.geosms\"", + "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.chatbot\"", + "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.chatbot.sa\"", + "+g.gsma.rcs.botversion=\"#=1,#=2\"", + "+g.gsma.rcs.cpimext"}); + return defaults; } } @@ -4653,8 +4663,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.putInt(KEY_CARRIER_NR_AVAILABILITY_INT, - CARRIER_NR_AVAILABILITY_NSA | CARRIER_NR_AVAILABILITY_SA); + sDefaults.putIntArray(KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY, + new 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/DataSpecificRegistrationInfo.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java index 597fe8f85cfa..957f683292f7 100644 --- a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java +++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java @@ -68,22 +68,22 @@ public final class DataSpecificRegistrationInfo implements Parcelable { public final boolean isEnDcAvailable; /** - * Provides network support info for LTE VoPS and LTE Emergency bearer support + * Provides network support info for VoPS and Emergency bearer support */ @Nullable - private final LteVopsSupportInfo mLteVopsSupportInfo; + private final VopsSupportInfo mVopsSupportInfo; /** * @hide */ DataSpecificRegistrationInfo( int maxDataCalls, boolean isDcNrRestricted, boolean isNrAvailable, - boolean isEnDcAvailable, @Nullable LteVopsSupportInfo lteVops) { + boolean isEnDcAvailable, @Nullable VopsSupportInfo vops) { this.maxDataCalls = maxDataCalls; this.isDcNrRestricted = isDcNrRestricted; this.isNrAvailable = isNrAvailable; this.isEnDcAvailable = isEnDcAvailable; - this.mLteVopsSupportInfo = lteVops; + this.mVopsSupportInfo = vops; } /** @@ -97,7 +97,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable { isDcNrRestricted = dsri.isDcNrRestricted; isNrAvailable = dsri.isNrAvailable; isEnDcAvailable = dsri.isEnDcAvailable; - mLteVopsSupportInfo = dsri.mLteVopsSupportInfo; + mVopsSupportInfo = dsri.mVopsSupportInfo; } private DataSpecificRegistrationInfo(/* @NonNull */ Parcel source) { @@ -105,7 +105,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable { isDcNrRestricted = source.readBoolean(); isNrAvailable = source.readBoolean(); isEnDcAvailable = source.readBoolean(); - mLteVopsSupportInfo = LteVopsSupportInfo.CREATOR.createFromParcel(source); + mVopsSupportInfo = source.readParcelable(VopsSupportInfo.class.getClassLoader()); } @Override @@ -114,7 +114,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable { dest.writeBoolean(isDcNrRestricted); dest.writeBoolean(isNrAvailable); dest.writeBoolean(isEnDcAvailable); - mLteVopsSupportInfo.writeToParcel(dest, flags); + dest.writeParcelable(mVopsSupportInfo, flags); } @Override @@ -131,15 +131,15 @@ public final class DataSpecificRegistrationInfo implements Parcelable { .append(" isDcNrRestricted = " + isDcNrRestricted) .append(" isNrAvailable = " + isNrAvailable) .append(" isEnDcAvailable = " + isEnDcAvailable) - .append(" " + mLteVopsSupportInfo) + .append(" " + mVopsSupportInfo) .append(" }") .toString(); } @Override public int hashCode() { - return Objects.hash(maxDataCalls, isDcNrRestricted, isNrAvailable, isEnDcAvailable, - mLteVopsSupportInfo); + return Objects.hash(maxDataCalls, isDcNrRestricted, isNrAvailable, + isEnDcAvailable, mVopsSupportInfo); } @Override @@ -153,7 +153,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable { && this.isDcNrRestricted == other.isDcNrRestricted && this.isNrAvailable == other.isNrAvailable && this.isEnDcAvailable == other.isEnDcAvailable - && Objects.equals(mLteVopsSupportInfo, other.mLteVopsSupportInfo); + && Objects.equals(mVopsSupportInfo, other.mVopsSupportInfo); } public static final @NonNull Parcelable.Creator<DataSpecificRegistrationInfo> CREATOR = @@ -171,10 +171,26 @@ public final class DataSpecificRegistrationInfo implements Parcelable { /** * @return The LTE VOPS (Voice over Packet Switched) support information + * + * @deprecated use {@link #getVopsSupportInfo()} */ + @Deprecated @NonNull public LteVopsSupportInfo getLteVopsSupportInfo() { - return mLteVopsSupportInfo; + return mVopsSupportInfo instanceof LteVopsSupportInfo + ? (LteVopsSupportInfo) mVopsSupportInfo + : new LteVopsSupportInfo(LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE, + LteVopsSupportInfo.LTE_STATUS_NOT_AVAILABLE); } + /** + * @return The VOPS (Voice over Packet Switched) support information. + * + * The instance of {@link LTEVopsSupportInfo}, or {@link NrVopsSupportInfo}, + * null if there is there is no VOPS support information available. + */ + @Nullable + public VopsSupportInfo getVopsSupportInfo() { + return mVopsSupportInfo; + } } diff --git a/telephony/java/android/telephony/DataThrottlingRequest.java b/telephony/java/android/telephony/DataThrottlingRequest.java index f50bb58c4b2e..2827e8dc8539 100644 --- a/telephony/java/android/telephony/DataThrottlingRequest.java +++ b/telephony/java/android/telephony/DataThrottlingRequest.java @@ -17,6 +17,7 @@ package android.telephony; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.RequiresFeature; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -52,6 +53,9 @@ public final class DataThrottlingRequest implements Parcelable { * @hide */ @SystemApi + @RequiresFeature( + enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported", + value = TelephonyManager.CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING) public static final int DATA_THROTTLING_ACTION_THROTTLE_SECONDARY_CARRIER = 1; /** @@ -63,6 +67,9 @@ public final class DataThrottlingRequest implements Parcelable { * @hide */ @SystemApi + @RequiresFeature( + enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported", + value = TelephonyManager.CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING) public static final int DATA_THROTTLING_ACTION_THROTTLE_PRIMARY_CARRIER = 2; /** @@ -76,6 +83,9 @@ public final class DataThrottlingRequest implements Parcelable { * @hide */ @SystemApi + @RequiresFeature( + enforcement = "android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported", + value = TelephonyManager.CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING) public static final int DATA_THROTTLING_ACTION_HOLD = 3; /** diff --git a/telephony/java/android/telephony/LteVopsSupportInfo.java b/telephony/java/android/telephony/LteVopsSupportInfo.java index 83e41bf3df3b..87761e21350b 100644 --- a/telephony/java/android/telephony/LteVopsSupportInfo.java +++ b/telephony/java/android/telephony/LteVopsSupportInfo.java @@ -21,7 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.os.Parcel; -import android.os.Parcelable; +import android.telephony.AccessNetworkConstants.AccessNetworkType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -32,7 +32,7 @@ import java.util.Objects; * @hide */ @SystemApi -public final class LteVopsSupportInfo implements Parcelable { +public final class LteVopsSupportInfo extends VopsSupportInfo { /**@hide*/ @Retention(RetentionPolicy.SOURCE) @@ -42,7 +42,10 @@ public final class LteVopsSupportInfo implements Parcelable { public @interface LteVopsStatus {} /** * Indicates information not available from modem. + * + * @deprecated as no instance will be created in this case */ + @Deprecated public static final int LTE_STATUS_NOT_AVAILABLE = 1; /** @@ -82,13 +85,38 @@ public final class LteVopsSupportInfo implements Parcelable { return mEmcBearerSupport; } + /** + * Returns whether VoPS is supported by the network + */ + @Override + public boolean isVopsSupported() { + return mVopsSupport == LTE_STATUS_SUPPORTED; + } + + /** + * Returns whether emergency service is supported by the network + */ + @Override + public boolean isEmergencyServiceSupported() { + return mEmcBearerSupport == LTE_STATUS_SUPPORTED; + } + + /** + * Returns whether emergency service fallback is supported by the network + */ + @Override + public boolean isEmergencyServiceFallbackSupported() { + return false; + } + @Override public int describeContents() { return 0; } @Override - public void writeToParcel(Parcel out, int flags) { + public void writeToParcel(@NonNull Parcel out, int flags) { + super.writeToParcel(out, flags, AccessNetworkType.EUTRAN); out.writeInt(mVopsSupport); out.writeInt(mEmcBearerSupport); } @@ -124,6 +152,8 @@ public final class LteVopsSupportInfo implements Parcelable { new Creator<LteVopsSupportInfo>() { @Override public LteVopsSupportInfo createFromParcel(Parcel in) { + // Skip the type info. + in.readInt(); return new LteVopsSupportInfo(in); } @@ -133,6 +163,11 @@ public final class LteVopsSupportInfo implements Parcelable { } }; + /** @hide */ + protected static LteVopsSupportInfo createFromParcelBody(Parcel in) { + return new LteVopsSupportInfo(in); + } + private LteVopsSupportInfo(Parcel in) { mVopsSupport = in.readInt(); mEmcBearerSupport = in.readInt(); diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java index a78f81331c8c..5fb60d7599ea 100644 --- a/telephony/java/android/telephony/NetworkRegistrationInfo.java +++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java @@ -293,11 +293,12 @@ public final class NetworkRegistrationInfo implements Parcelable { @Nullable CellIdentity cellIdentity, @Nullable String rplmn, int maxDataCalls, boolean isDcNrRestricted, boolean isNrAvailable, boolean isEndcAvailable, - LteVopsSupportInfo lteVopsSupportInfo) { + @Nullable VopsSupportInfo vopsSupportInfo) { this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause, emergencyOnly, availableServices, cellIdentity, rplmn); mDataSpecificInfo = new DataSpecificRegistrationInfo( - maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo); + maxDataCalls, isDcNrRestricted, isNrAvailable, + isEndcAvailable, vopsSupportInfo); updateNrState(); } diff --git a/telephony/java/android/telephony/NrVopsSupportInfo.aidl b/telephony/java/android/telephony/NrVopsSupportInfo.aidl new file mode 100644 index 000000000000..460a58971837 --- /dev/null +++ b/telephony/java/android/telephony/NrVopsSupportInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +parcelable NrVopsSupportInfo; diff --git a/telephony/java/android/telephony/NrVopsSupportInfo.java b/telephony/java/android/telephony/NrVopsSupportInfo.java new file mode 100644 index 000000000000..155ee384b5b0 --- /dev/null +++ b/telephony/java/android/telephony/NrVopsSupportInfo.java @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.telephony.AccessNetworkConstants.AccessNetworkType; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * Class stores information related to NR network VoPS support + * @hide + */ +@SystemApi +public final class NrVopsSupportInfo extends VopsSupportInfo { + + /** + * Indicates network does not support vops + */ + public static final int NR_STATUS_VOPS_NOT_SUPPORTED = 0; + + /** + * Indicates network supports vops over 3gpp access. + */ + public static final int NR_STATUS_VOPS_3GPP_SUPPORTED = 1; + + /** + * Indicates network supports vops over non 3gpp access + */ + public static final int NR_STATUS_VOPS_NON_3GPP_SUPPORTED = 2; + + /**@hide*/ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = {"NR_STATUS_VOPS_"}, + value = { + NR_STATUS_VOPS_NOT_SUPPORTED, + NR_STATUS_VOPS_3GPP_SUPPORTED, + NR_STATUS_VOPS_NON_3GPP_SUPPORTED + }) + public @interface NrVopsStatus {} + + /** + * Indicates network does not support emergency service + */ + public static final int NR_STATUS_EMC_NOT_SUPPORTED = 0; + + /** + * Indicates network supports emergency service in NR connected to 5GCN only + */ + public static final int NR_STATUS_EMC_5GCN_ONLY = 1; + + /** + * Indicates network supports emergency service in E-UTRA connected to 5GCN only + */ + public static final int NR_STATUS_EMC_EUTRA_5GCN_ONLY = 2; + + /** + * Indicates network supports emergency service in NR connected to 5GCN and + * E-UTRA connected to 5GCN + */ + public static final int NR_STATUS_EMC_NR_EUTRA_5GCN = 3; + + /**@hide*/ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = {"NR_STATUS_EMC_"}, + value = { + NR_STATUS_EMC_NOT_SUPPORTED, + NR_STATUS_EMC_5GCN_ONLY, + NR_STATUS_EMC_EUTRA_5GCN_ONLY, + NR_STATUS_EMC_NR_EUTRA_5GCN + }) + public @interface NrEmcStatus {} + + /** + * Indicates network does not support emergency service + */ + public static final int NR_STATUS_EMF_NOT_SUPPORTED = 0; + + /** + * Indicates network supports emergency service fallback in NR connected to 5GCN only + */ + public static final int NR_STATUS_EMF_5GCN_ONLY = 1; + + /** + * Indicates network supports emergency service fallback in E-UTRA connected to 5GCN only + */ + public static final int NR_STATUS_EMF_EUTRA_5GCN_ONLY = 2; + + /** + * Indicates network supports emergency service fallback in NR connected to 5GCN + * and E-UTRA connected to 5GCN + */ + public static final int NR_STATUS_EMF_NR_EUTRA_5GCN = 3; + + /**@hide*/ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = {"NR_STATUS_EMF_"}, + value = { + NR_STATUS_EMF_NOT_SUPPORTED, + NR_STATUS_EMF_5GCN_ONLY, + NR_STATUS_EMF_EUTRA_5GCN_ONLY, + NR_STATUS_EMF_NR_EUTRA_5GCN + }) + public @interface NrEmfStatus {} + + @NrVopsStatus + private final int mVopsSupport; + @NrEmcStatus + private final int mEmcSupport; + @NrEmfStatus + private final int mEmfSupport; + + public NrVopsSupportInfo(@NrVopsStatus int vops, @NrEmcStatus int emc, @NrEmcStatus int emf) { + mVopsSupport = vops; + mEmcSupport = emc; + mEmfSupport = emf; + } + + /** + * Provides the NR VoPS support capability as described in: + * 3GPP 24.501 EPS network feature support -> IMS VoPS + */ + public @NrVopsStatus int getVopsSupport() { + return mVopsSupport; + } + + /** + * Provides the NR Emergency bearer support capability as described in: + * 3GPP 24.501 EPS network feature support -> EMC, and + * 38.331 SIB1 : ims-EmergencySupport + */ + public @NrEmcStatus int getEmcSupport() { + return mEmcSupport; + } + + /** + * Provides the NR emergency service fallback support capability as + * described in 3GPP 24.501 EPS network feature support -> EMF + */ + public @NrEmfStatus int getEmfSupport() { + return mEmfSupport; + } + + /** + * Returns whether VoPS is supported by the network + */ + @Override + public boolean isVopsSupported() { + return mVopsSupport != NR_STATUS_VOPS_NOT_SUPPORTED; + } + + /** + * Returns whether emergency service is supported by the network + */ + @Override + public boolean isEmergencyServiceSupported() { + return mEmcSupport != NR_STATUS_EMC_NOT_SUPPORTED; + } + + /** + * Returns whether emergency service fallback is supported by the network + */ + public boolean isEmergencyServiceFallbackSupported() { + return mEmfSupport != NR_STATUS_EMF_NOT_SUPPORTED; + } + + /** + * Implement the Parcelable interface + */ + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + super.writeToParcel(out, flags, AccessNetworkType.NGRAN); + out.writeInt(mVopsSupport); + out.writeInt(mEmcSupport); + out.writeInt(mEmfSupport); + } + + @Override + public boolean equals(@Nullable Object o) { + if (o == null || !(o instanceof NrVopsSupportInfo)) { + return false; + } + if (this == o) return true; + NrVopsSupportInfo other = (NrVopsSupportInfo) o; + return mVopsSupport == other.mVopsSupport + && mEmcSupport == other.mEmcSupport + && mEmfSupport == other.mEmfSupport; + } + + @Override + public int hashCode() { + return Objects.hash(mVopsSupport, mEmcSupport, mEmfSupport); + } + + /** + * @return string representation. + */ + @NonNull + @Override + public String toString() { + return ("NrVopsSupportInfo : " + + " mVopsSupport = " + mVopsSupport + + " mEmcSupport = " + mEmcSupport + + " mEmfSupport = " + mEmfSupport); + } + + public static final @android.annotation.NonNull Creator<NrVopsSupportInfo> CREATOR = + new Creator<NrVopsSupportInfo>() { + @Override + public NrVopsSupportInfo createFromParcel(Parcel in) { + // Skip the type info. + in.readInt(); + return new NrVopsSupportInfo(in); + } + + @Override + public NrVopsSupportInfo[] newArray(int size) { + return new NrVopsSupportInfo[size]; + } + }; + + /** @hide */ + protected static NrVopsSupportInfo createFromParcelBody(Parcel in) { + return new NrVopsSupportInfo(in); + } + + private NrVopsSupportInfo(Parcel in) { + mVopsSupport = in.readInt(); + mEmcSupport = in.readInt(); + mEmfSupport = in.readInt(); + } +} diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java index dfe269cbb0d9..1c9cd94b245d 100644 --- a/telephony/java/android/telephony/PhysicalChannelConfig.java +++ b/telephony/java/android/telephony/PhysicalChannelConfig.java @@ -292,6 +292,14 @@ public final class PhysicalChannelConfig implements Parcelable { } /** + * Return a copy of this PhysicalChannelConfig object but redact all the location info. + * @hide + */ + public PhysicalChannelConfig createLocationInfoSanitizedCopy() { + return new Builder(this).setPhysicalCellId(PHYSICAL_CELL_ID_UNKNOWN).build(); + } + + /** * @return String representation of the connection status * @hide */ @@ -540,6 +548,23 @@ public final class PhysicalChannelConfig implements Parcelable { mBand = BAND_UNKNOWN; } + /** + * Builder object constructed from existing PhysicalChannelConfig object. + * @hide + */ + public Builder(PhysicalChannelConfig config) { + mNetworkType = config.getNetworkType(); + mFrequencyRange = config.getFrequencyRange(); + mDownlinkChannelNumber = config.getDownlinkChannelNumber(); + mUplinkChannelNumber = config.getUplinkChannelNumber(); + mCellBandwidthDownlinkKhz = config.getCellBandwidthDownlinkKhz(); + mCellBandwidthUplinkKhz = config.getCellBandwidthUplinkKhz(); + mCellConnectionStatus = config.getConnectionStatus(); + mContextIds = Arrays.copyOf(config.getContextIds(), config.getContextIds().length); + mPhysicalCellId = config.getPhysicalCellId(); + mBand = config.getBand(); + } + public PhysicalChannelConfig build() { return new PhysicalChannelConfig(this); } diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index f110daecd952..2d06062cfa44 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -564,6 +564,7 @@ public class ServiceState implements Parcelable { * @hide */ @UnsupportedAppUsage + @TestApi public int getDataRegState() { return mDataRegState; } diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java index cfb29f124b43..5a12865fb2a0 100644 --- a/telephony/java/android/telephony/SmsMessage.java +++ b/telephony/java/android/telephony/SmsMessage.java @@ -300,9 +300,12 @@ public class SmsMessage { * @param data Message data. * @param isCdma Indicates weather the type of the SMS is CDMA. * @return An SmsMessage representing the message. + * + * @hide */ + @SystemApi @Nullable - public static SmsMessage createSmsSubmitPdu(@NonNull byte[] data, boolean isCdma) { + public static SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[] data, boolean isCdma) { SmsMessageBase wrappedMessage; if (isCdma) { @@ -318,23 +321,6 @@ public class SmsMessage { } /** - * Create an SmsMessage from a native SMS-Submit PDU, specified by Bluetooth Message Access - * Profile Specification v1.4.2 5.8. - * This is used by Bluetooth MAP profile to decode message when sending non UTF-8 SMS messages. - * - * @param data Message data. - * @param isCdma Indicates weather the type of the SMS is CDMA. - * @return An SmsMessage representing the message. - * - * @hide - */ - @SystemApi - @Nullable - public static SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[] data, boolean isCdma) { - return null; - } - - /** * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the * length in bytes (not hex chars) less the SMSC header * diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 26fcf5e08508..7c39cf0b47a6 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -129,6 +129,8 @@ import java.util.Objects; import java.util.UUID; import java.util.concurrent.Executor; import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.IntStream; /** * Provides access to information about the telephony services on @@ -3116,6 +3118,10 @@ public class TelephonyManager { return NETWORK_TYPE_BITMASK_LTE_CA; case NETWORK_TYPE_NR: return NETWORK_TYPE_BITMASK_NR; + case NETWORK_TYPE_IWLAN: + return NETWORK_TYPE_BITMASK_IWLAN; + case NETWORK_TYPE_IDEN: + return (1 << (NETWORK_TYPE_IDEN - 1)); default: return NETWORK_TYPE_BITMASK_UNKNOWN; } @@ -8270,8 +8276,8 @@ public class TelephonyManager { public static final int ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G = 3; /** - * Set the allowed network types of the device and - * provide the reason triggering the allowed network change. + * 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} @@ -8283,10 +8289,15 @@ public class TelephonyManager { * </ol> * This API will result in allowing an intersection of allowed network types for all reasons, * including the configuration done through other reasons. + * + * The functionality of this API with the parameter + * {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER} is the same as the API + * {@link TelephonyManager#setAllowedNetworkTypes}. Use this API instead of + * {@link TelephonyManager#setAllowedNetworkTypes}. * <p> * If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported} * ({@link TelephonyManager#CAPABILITY_ALLOWED_NETWORK_TYPES_USED}) returns true, then - * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise, + * setAllowedNetworkTypesBitmap is used on the radio interface. Otherwise, * setPreferredNetworkTypesBitmap is used instead. * * @param reason the reason the allowed network type change is taking place @@ -8326,21 +8337,17 @@ public class TelephonyManager { * {@link #getAllowedNetworkTypesForReason} returns allowed network type for a * 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}). - * * @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 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) + @SystemApi public @NetworkTypeBitMask long getAllowedNetworkTypesForReason( @AllowedNetworkTypesReason int reason) { if (!isValidAllowedNetworkTypesReason(reason)) { @@ -8385,6 +8392,25 @@ public class TelephonyManager { } /** + * Returns a string representation of the allowed network types{@link NetworkTypeBitMask}. + * + * @param networkTypeBitmask The bitmask of allowed network types. + * @return the name of the allowed network types + * @hide + */ + public static String convertNetworkTypeBitmaskToString( + @NetworkTypeBitMask long networkTypeBitmask) { + String networkTypeName = IntStream.rangeClosed(NETWORK_TYPE_GPRS, NETWORK_TYPE_NR) + .filter(x -> { + return (networkTypeBitmask & getBitMaskForNetworkType(x)) + == getBitMaskForNetworkType(x); + }) + .mapToObj(x -> getNetworkTypeName(x)) + .collect(Collectors.joining("|")); + return TextUtils.isEmpty(networkTypeName) ? "UNKNOWN" : networkTypeName; + } + + /** * Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA. * * <p>Requires that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). @@ -11871,12 +11897,6 @@ public class TelephonyManager { * "Data capable" means that this device supports packet-switched * data connections over the telephony network. * <p> - * Note: the meaning of this flag is subtly different from the - * PackageManager.FEATURE_TELEPHONY system feature, which is available - * on any device with a telephony radio, even if the device is - * voice-only. - * - * @hide */ public boolean isDataCapable() { if (mContext == null) return true; @@ -12091,6 +12111,7 @@ public class TelephonyManager { NETWORK_TYPE_BITMASK_LTE, NETWORK_TYPE_BITMASK_LTE_CA, NETWORK_TYPE_BITMASK_NR, + NETWORK_TYPE_BITMASK_IWLAN }) public @interface NetworkTypeBitMask {} @@ -14413,12 +14434,23 @@ public class TelephonyManager { public static final String CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE = "CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE"; + /** + * Indicates whether a data throttling request sent with {@link #sendThermalMitigationRequest} + * is supported. See comments on {@link #sendThermalMitigationRequest} for more information. + * + * @hide + */ + @SystemApi + public static final String CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING = + "CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING"; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @StringDef(prefix = "CAPABILITY_", value = { CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE, CAPABILITY_ALLOWED_NETWORK_TYPES_USED, - CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE + CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE, + CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING, }) public @interface RadioInterfaceCapability {} @@ -14528,11 +14560,29 @@ public class TelephonyManager { * and can be used at any time during data throttling to hold onto the current level of data * throttling. * + * <p> If {@link android.telephony.TelephonyManager#isRadioInterfaceCapabilitySupported}({@link + * #CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING}) returns false, then sending a {@link + * DataThrottlingRequest#DATA_THROTTLING_ACTION_HOLD}, {@link + * DataThrottlingRequest#DATA_THROTTLING_ACTION_THROTTLE_SECONDARY_CARRIER}, or {@link + * DataThrottlingRequest#DATA_THROTTLING_ACTION_THROTTLE_PRIMARY_CARRIER} will result in {@link + * IllegalArgumentException} being thrown. However, on devices that do not + * support data throttling, {@link + * DataThrottlingRequest#DATA_THROTTLING_ACTION_NO_DATA_THROTTLING} can still be requested in + * order to undo the mitigations above it (i.e {@link + * ThermalMitigationRequest#THERMAL_MITIGATION_ACTION_VOICE_ONLY} and/or {@link + * ThermalMitigationRequest#THERMAL_MITIGATION_ACTION_RADIO_OFF}). </p> + * + * <p> In addition to the {@link Manifest.permission#MODIFY_PHONE_STATE} permission, callers of + * this API must also be listed in the device configuration as an authorized app in + * {@code packages/services/Telephony/res/values/config.xml} under the + * {@code thermal_mitigation_allowlisted_packages} key. </p> + * * @param thermalMitigationRequest Thermal mitigation request. See {@link * ThermalMitigationRequest} for details. * * @throws IllegalStateException if the Telephony process is not currently available. - * @throws IllegalArgumentException if the thermalMitigationRequest had invalid parameters. + * @throws IllegalArgumentException if the thermalMitigationRequest had invalid parameters or + * if the device's modem does not support data throttling. * * @hide */ @@ -14544,7 +14594,8 @@ public class TelephonyManager { try { ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.sendThermalMitigationRequest(getSubId(), thermalMitigationRequest); + return telephony.sendThermalMitigationRequest(getSubId(), thermalMitigationRequest, + getOpPackageName()); } throw new IllegalStateException("telephony service is null."); } catch (RemoteException ex) { diff --git a/telephony/java/android/telephony/VopsSupportInfo.aidl b/telephony/java/android/telephony/VopsSupportInfo.aidl new file mode 100644 index 000000000000..31c608fe9546 --- /dev/null +++ b/telephony/java/android/telephony/VopsSupportInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +parcelable VopsSupportInfo; diff --git a/telephony/java/android/telephony/VopsSupportInfo.java b/telephony/java/android/telephony/VopsSupportInfo.java new file mode 100644 index 000000000000..f89bfa9b60b4 --- /dev/null +++ b/telephony/java/android/telephony/VopsSupportInfo.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony; + +import android.annotation.NonNull; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.AccessNetworkConstants.AccessNetworkType; + +/** + * Abstract base class for the information related to network VoPS support. + * This is the base class for XxVopsSupportInfo which represent VoPS support + * information for specific network access techonology. + * @hide + */ +@SuppressLint("ParcelNotFinal") +@SystemApi +public abstract class VopsSupportInfo implements Parcelable { + + /** + * @hide + */ + public VopsSupportInfo() {} + + /** + * Returns whether VoPS is supported by the network + */ + public abstract boolean isVopsSupported(); + + /** + * Returns whether emergency service is supported by the network + */ + public abstract boolean isEmergencyServiceSupported(); + + /** + * Returns whether emergency service fallback is supported by the network + */ + public abstract boolean isEmergencyServiceFallbackSupported(); + + /** + * Implement the Parcelable interface + */ + @Override + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface */ + @Override + public abstract void writeToParcel(@NonNull Parcel dest, int flags); + + /** + * Used by child classes for parceling. + * + * @hide + */ + protected void writeToParcel(@NonNull Parcel dest, int flags, int type) { + dest.writeInt(type); + } + + /** Implement the Parcelable interface */ + public static final @android.annotation.NonNull Creator<VopsSupportInfo> CREATOR = + new Creator<VopsSupportInfo>() { + @Override + public VopsSupportInfo createFromParcel(Parcel in) { + int type = in.readInt(); + switch (type) { + case AccessNetworkType.EUTRAN: + return LteVopsSupportInfo.createFromParcelBody(in); + case AccessNetworkType.NGRAN: + return NrVopsSupportInfo.createFromParcelBody(in); + default: throw new RuntimeException("Bad VopsSupportInfo Parcel"); + } + } + + @Override + public VopsSupportInfo[] newArray(int size) { + return new VopsSupportInfo[size]; + } + }; + + @Override + public abstract int hashCode(); + + @Override + public abstract boolean equals(Object o); +} diff --git a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java index 406c38bf60ef..9bc7a5c6cf96 100644 --- a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java +++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java @@ -53,7 +53,7 @@ public final class EpsBearerQosSessionAttributes implements Parcelable, QosSessi * * @return the qci of the session */ - public int getQci() { + public int getQosIdentifier() { return mQci; } @@ -66,7 +66,7 @@ public final class EpsBearerQosSessionAttributes implements Parcelable, QosSessi * * @return the guaranteed bit rate in kbps */ - public long getGuaranteedUplinkBitRate() { + public long getGuaranteedUplinkBitRateKbps() { return mGuaranteedUplinkBitRate; } @@ -79,7 +79,7 @@ public final class EpsBearerQosSessionAttributes implements Parcelable, QosSessi * * @return the guaranteed bit rate in kbps */ - public long getGuaranteedDownlinkBitRate() { + public long getGuaranteedDownlinkBitRateKbps() { return mGuaranteedDownlinkBitRate; } @@ -92,7 +92,7 @@ public final class EpsBearerQosSessionAttributes implements Parcelable, QosSessi * * @return the max uplink bit rate in kbps */ - public long getMaxUplinkBitRate() { + public long getMaxUplinkBitRateKbps() { return mMaxUplinkBitRate; } @@ -105,7 +105,7 @@ public final class EpsBearerQosSessionAttributes implements Parcelable, QosSessi * * @return the max downlink bit rate in kbps */ - public long getMaxDownlinkBitRate() { + public long getMaxDownlinkBitRateKbps() { return mMaxDownlinkBitRate; } diff --git a/telephony/java/android/telephony/data/NrQos.java b/telephony/java/android/telephony/data/NrQos.java index 2011eed26977..fe124ac15393 100644 --- a/telephony/java/android/telephony/data/NrQos.java +++ b/telephony/java/android/telephony/data/NrQos.java @@ -50,6 +50,18 @@ public final class NrQos extends Qos implements Parcelable { return new NrQos(in); } + public int get5Qi() { + return fiveQi; + } + + public int getQfi() { + return qosFlowId; + } + + public int getAveragingWindow() { + return averagingWindowMs; + } + @Override public void writeToParcel(@NonNull Parcel dest, int flags) { super.writeToParcel(Qos.QOS_TYPE_NR, dest, flags); diff --git a/telephony/java/android/telephony/data/NrQosSessionAttributes.aidl b/telephony/java/android/telephony/data/NrQosSessionAttributes.aidl new file mode 100644 index 000000000000..fd3bbb0865cb --- /dev/null +++ b/telephony/java/android/telephony/data/NrQosSessionAttributes.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package android.telephony.data; + + parcelable NrQosSessionAttributes; diff --git a/telephony/java/android/telephony/data/NrQosSessionAttributes.java b/telephony/java/android/telephony/data/NrQosSessionAttributes.java new file mode 100644 index 000000000000..4c37687910a1 --- /dev/null +++ b/telephony/java/android/telephony/data/NrQosSessionAttributes.java @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telephony.data; + +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.net.QosSessionAttributes; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * Provides Qos attributes of an NR bearer. + * + * {@hide} + */ +@SystemApi +public final class NrQosSessionAttributes implements Parcelable, QosSessionAttributes { + private static final String TAG = NrQosSessionAttributes.class.getSimpleName(); + private final int m5Qi; + private final @IntRange(from=1, to=63) int mQfi; + private final long mMaxUplinkBitRate; + private final long mMaxDownlinkBitRate; + private final long mGuaranteedUplinkBitRate; + private final long mGuaranteedDownlinkBitRate; + private final long mAveragingWindow; + @NonNull private final List<InetSocketAddress> mRemoteAddresses; + + /** + * 5G QOS Identifier (5QI), see 3GPP TS 24.501 and 23.501. + * The allowed values are standard values(1-9, 65-68, 69-70, 75, 79-80, 82-85) + * defined in the spec and operator specific values in the range 128-254. + * + * @return the 5QI of the QOS flow + */ + public int getQosIdentifier() { + return m5Qi; + } + + /** + * QOS flow identifier of the QOS flow description in the + * range of 1 to 63. see 3GPP TS 24.501 and 23.501. + * + * @return the QOS flow identifier of the session + */ + public @IntRange(from=1, to=63) int getQosFlowIdentifier() { + return mQfi; + } + + /** + * Minimum bit rate in kbps that is guaranteed to be provided by the network on the uplink. + * + * see 3GPP TS 24.501 section 6.2.5 + * + * Note: The Qos Session may be shared with OTHER applications besides yours. + * + * @return the guaranteed bit rate in kbps + */ + public long getGuaranteedUplinkBitRateKbps() { + return mGuaranteedUplinkBitRate; + } + + /** + * Minimum bit rate in kbps that is guaranteed to be provided by the network on the downlink. + * + * see 3GPP TS 24.501 section 6.2.5 + * + * Note: The Qos Session may be shared with OTHER applications besides yours. + * + * @return the guaranteed bit rate in kbps + */ + public long getGuaranteedDownlinkBitRateKbps() { + return mGuaranteedDownlinkBitRate; + } + + /** + * The maximum uplink kbps that the network will accept. + * + * see 3GPP TS 24.501 section 6.2.5 + * + * Note: The Qos Session may be shared with OTHER applications besides yours. + * + * @return the max uplink bit rate in kbps + */ + public long getMaxUplinkBitRateKbps() { + return mMaxUplinkBitRate; + } + + /** + * The maximum downlink kbps that the network can provide. + * + * see 3GPP TS 24.501 section 6.2.5 + * + * Note: The Qos Session may be shared with OTHER applications besides yours. + * + * @return the max downlink bit rate in kbps + */ + public long getMaxDownlinkBitRateKbps() { + return mMaxDownlinkBitRate; + } + + /** + * The duration in milliseconds over which the maximum bit rates and guaranteed bit rates + * are calculated + * + * see 3GPP TS 24.501 section 6.2.5 + * + * @return the averaging window duration in milliseconds + */ + @NonNull + public Duration getBitRateWindowDuration() { + return Duration.ofMillis(mAveragingWindow); + } + + /** + * List of remote addresses associated with the Qos Session. The given uplink bit rates apply + * to this given list of remote addresses. + * + * Note: In the event that the list is empty, it is assumed that the uplink bit rates apply to + * all remote addresses that are not contained in a different set of attributes. + * + * @return list of remote socket addresses that the attributes apply to + */ + @NonNull + public List<InetSocketAddress> getRemoteAddresses() { + return mRemoteAddresses; + } + + /** + * ..ctor for attributes + * + * @param fiveQi 5G quality class indicator + * @param qfi QOS flow identifier + * @param maxDownlinkBitRate the max downlink bit rate in kbps + * @param maxUplinkBitRate the max uplink bit rate in kbps + * @param guaranteedDownlinkBitRate the guaranteed downlink bit rate in kbps + * @param guaranteedUplinkBitRate the guaranteed uplink bit rate in kbps + * @param averagingWindow the averaging window duration in milliseconds + * @param remoteAddresses the remote addresses that the uplink bit rates apply to + * + * @hide + */ + public NrQosSessionAttributes(final int fiveQi, final int qfi, + final long maxDownlinkBitRate, final long maxUplinkBitRate, + final long guaranteedDownlinkBitRate, final long guaranteedUplinkBitRate, + final long averagingWindow, @NonNull final List<InetSocketAddress> remoteAddresses) { + Objects.requireNonNull(remoteAddresses, "remoteAddress must be non-null"); + m5Qi = fiveQi; + mQfi = qfi; + mMaxDownlinkBitRate = maxDownlinkBitRate; + mMaxUplinkBitRate = maxUplinkBitRate; + mGuaranteedDownlinkBitRate = guaranteedDownlinkBitRate; + mGuaranteedUplinkBitRate = guaranteedUplinkBitRate; + mAveragingWindow = averagingWindow; + + final List<InetSocketAddress> remoteAddressesTemp = copySocketAddresses(remoteAddresses); + mRemoteAddresses = Collections.unmodifiableList(remoteAddressesTemp); + } + + private static List<InetSocketAddress> copySocketAddresses( + @NonNull final List<InetSocketAddress> remoteAddresses) { + final List<InetSocketAddress> remoteAddressesTemp = new ArrayList<>(); + for (final InetSocketAddress socketAddress : remoteAddresses) { + if (socketAddress != null && socketAddress.getAddress() != null) { + remoteAddressesTemp.add(socketAddress); + } + } + return remoteAddressesTemp; + } + + private NrQosSessionAttributes(@NonNull final Parcel in) { + m5Qi = in.readInt(); + mQfi = in.readInt(); + mMaxDownlinkBitRate = in.readLong(); + mMaxUplinkBitRate = in.readLong(); + mGuaranteedDownlinkBitRate = in.readLong(); + mGuaranteedUplinkBitRate = in.readLong(); + mAveragingWindow = in.readLong(); + + final int size = in.readInt(); + final List<InetSocketAddress> remoteAddresses = new ArrayList<>(size); + for (int i = 0; i < size; i++) { + final byte[] addressBytes = in.createByteArray(); + final int port = in.readInt(); + try { + remoteAddresses.add( + new InetSocketAddress(InetAddress.getByAddress(addressBytes), port)); + } catch (final UnknownHostException e) { + // Impossible case since its filtered out the null values in the ..ctor + Log.e(TAG, "unable to unparcel remote address at index: " + i, e); + } + } + mRemoteAddresses = Collections.unmodifiableList(remoteAddresses); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull final Parcel dest, final int flags) { + dest.writeInt(m5Qi); + dest.writeInt(mQfi); + dest.writeLong(mMaxDownlinkBitRate); + dest.writeLong(mMaxUplinkBitRate); + dest.writeLong(mGuaranteedDownlinkBitRate); + dest.writeLong(mGuaranteedUplinkBitRate); + dest.writeLong(mAveragingWindow); + + final int size = mRemoteAddresses.size(); + dest.writeInt(size); + for (int i = 0; i < size; i++) { + final InetSocketAddress address = mRemoteAddresses.get(i); + dest.writeByteArray(address.getAddress().getAddress()); + dest.writeInt(address.getPort()); + } + } + + @NonNull + public static final Creator<NrQosSessionAttributes> CREATOR = + new Creator<NrQosSessionAttributes>() { + @NonNull + @Override + public NrQosSessionAttributes createFromParcel(@NonNull final Parcel in) { + return new NrQosSessionAttributes(in); + } + + @NonNull + @Override + public NrQosSessionAttributes[] newArray(final int size) { + return new NrQosSessionAttributes[size]; + } + }; +} diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java index 52d0f036788c..a133eadb3517 100644 --- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java +++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java @@ -29,7 +29,9 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; /** * Contains the User Capability Exchange capabilities corresponding to a contact's URI. @@ -110,7 +112,6 @@ public final class RcsContactUceCapability implements Parcelable { /** * Builder to help construct {@link RcsContactUceCapability} instances when capabilities were * queried through SIP OPTIONS. - * @hide */ public static final class OptionsBuilder { @@ -151,7 +152,7 @@ public final class RcsContactUceCapability implements Parcelable { * @param tags the list of the supported feature tags * @return this OptionBuilder */ - public @NonNull OptionsBuilder addFeatureTags(@NonNull List<String> tags) { + public @NonNull OptionsBuilder addFeatureTags(@NonNull Set<String> tags) { mCapabilities.mFeatureTags.addAll(tags); return this; } @@ -220,7 +221,7 @@ public final class RcsContactUceCapability implements Parcelable { private @CapabilityMechanism int mCapabilityMechanism; private @RequestResult int mRequestResult; - private final List<String> mFeatureTags = new ArrayList<>(); + private final Set<String> mFeatureTags = new HashSet<>(); private final List<RcsContactPresenceTuple> mPresenceTuples = new ArrayList<>(); private RcsContactUceCapability(@NonNull Uri contactUri, @CapabilityMechanism int mechanism, @@ -235,7 +236,9 @@ public final class RcsContactUceCapability implements Parcelable { mCapabilityMechanism = in.readInt(); mSourceType = in.readInt(); mRequestResult = in.readInt(); - in.readStringList(mFeatureTags); + List<String> featureTagList = new ArrayList<>(); + in.readStringList(featureTagList); + mFeatureTags.addAll(featureTagList); in.readParcelableList(mPresenceTuples, RcsContactPresenceTuple.class.getClassLoader()); } @@ -245,7 +248,7 @@ public final class RcsContactUceCapability implements Parcelable { out.writeInt(mCapabilityMechanism); out.writeInt(mSourceType); out.writeInt(mRequestResult); - out.writeStringList(mFeatureTags); + out.writeStringList(new ArrayList<>(mFeatureTags)); out.writeParcelableList(mPresenceTuples, flags); } @@ -285,7 +288,20 @@ public final class RcsContactUceCapability implements Parcelable { if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) { return Collections.emptyList(); } - return Collections.unmodifiableList(mFeatureTags); + return Collections.unmodifiableList(new ArrayList<>(mFeatureTags)); + } + + /** + * @return The feature tags present in the OPTIONS response from the network. + * <p> + * Note: this is only populated if {@link #getCapabilityMechanism} is + * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_OPTIONS} + */ + public @NonNull Set<String> getFeatureTags() { + if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) { + return Collections.emptySet(); + } + return Collections.unmodifiableSet(mFeatureTags); } /** diff --git a/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java index a217d1321342..c3d7325f2e0a 100644 --- a/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java +++ b/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java @@ -26,7 +26,8 @@ import android.telephony.ims.RcsContactUceCapability; import android.telephony.ims.stub.CapabilityExchangeEventListener; import android.util.Log; -import java.util.List; +import java.util.ArrayList; +import java.util.Set; /** * The ICapabilityExchangeEventListener wrapper class to store the listener which is registered by @@ -84,7 +85,7 @@ public class CapabilityExchangeAidlWrapper implements CapabilityExchangeEventLis * request to the framework. */ public void onRemoteCapabilityRequest(@NonNull Uri contactUri, - @NonNull List<String> remoteCapabilities, @NonNull OptionsRequestCallback callback) + @NonNull Set<String> remoteCapabilities, @NonNull OptionsRequestCallback callback) throws ImsException { ICapabilityExchangeEventListener listener = mListenerBinder; if (listener == null) { @@ -114,7 +115,8 @@ public class CapabilityExchangeAidlWrapper implements CapabilityExchangeEventLis }; try { - listener.onRemoteCapabilityRequest(contactUri, remoteCapabilities, internalCallback); + listener.onRemoteCapabilityRequest(contactUri, new ArrayList<>(remoteCapabilities), + internalCallback); } catch (RemoteException e) { Log.w(LOG_TAG, "Remote capability request exception: " + e); throw new ImsException("Remote is not available", diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java index 85703f8de5e5..6315b242184a 100644 --- a/telephony/java/android/telephony/ims/feature/RcsFeature.java +++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java @@ -47,6 +47,7 @@ import com.android.internal.telephony.util.TelephonyUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.HashSet; import java.util.List; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; @@ -145,8 +146,8 @@ public class RcsFeature extends ImsFeature { throws RemoteException { OptionsResponseCallback callbackWrapper = new RcsOptionsResponseAidlWrapper(callback); executeMethodAsync(() -> mReference.getCapabilityExchangeImplBaseInternal() - .sendOptionsCapabilityRequest(contactUri, myCapabilities, callbackWrapper), - "sendOptionsCapabilityRequest"); + .sendOptionsCapabilityRequest(contactUri, new HashSet<>(myCapabilities), + callbackWrapper), "sendOptionsCapabilityRequest"); } // Call the methods with a clean calling identity on the executor and wait indefinitely for diff --git a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java index 62955487897f..a3be8dab2891 100644 --- a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java +++ b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java @@ -26,7 +26,7 @@ import android.telephony.ims.RcsUceAdapter; import android.telephony.ims.feature.ImsFeature; import android.telephony.ims.feature.RcsFeature; -import java.util.List; +import java.util.Set; /** * The interface that is used by the framework to listen to events from the vendor RCS stack @@ -98,7 +98,8 @@ public interface CapabilityExchangeEventListener { * {@link OptionsRequestCallback#onRespondToCapabilityRequestWithError}. * @param contactUri The URI associated with the remote contact that is * requesting capabilities. - * @param remoteCapabilities The remote contact's capability information. + * @param remoteCapabilities The remote contact's capability information. The capability + * information is in the format defined in RCC.07 section 2.6.1.3. * @param callback The callback of this request which is sent from the remote user. * @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is not * currently connected to the framework. This can happen if the {@link RcsFeature} is not @@ -107,6 +108,6 @@ public interface CapabilityExchangeEventListener { * cases when the Telephony stack has crashed. */ void onRemoteCapabilityRequest(@NonNull Uri contactUri, - @NonNull List<String> remoteCapabilities, + @NonNull Set<String> remoteCapabilities, @NonNull OptionsRequestCallback callback) throws ImsException; } diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java index 03e17fbc2c0d..25b9446152ac 100644 --- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java +++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java @@ -33,6 +33,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Collection; import java.util.List; +import java.util.Set; import java.util.concurrent.Executor; /** @@ -433,6 +434,7 @@ public class RcsCapabilityExchangeImplBase { * @param contactUri The URI of the remote user that we wish to get the capabilities of. * @param myCapabilities The capabilities of this device to send to the remote user. * @param callback The callback of this request which is sent from the remote user. + * @hide */ // executor used is defined in the constructor. @SuppressLint("ExecutorRegistration") @@ -446,4 +448,27 @@ public class RcsCapabilityExchangeImplBase { // Do not do anything, this is a stub implementation. } } + + /** + * Push one's own capabilities to a remote user via the SIP OPTIONS presence exchange mechanism + * in order to receive the capabilities of the remote user in response. + * <p> + * The implementer must use {@link OptionsResponseCallback} to send the response of + * this query from the network back to the framework. + * @param contactUri The URI of the remote user that we wish to get the capabilities of. + * @param myCapabilities The capabilities of this device to send to the remote user. + * @param callback The callback of this request which is sent from the remote user. + */ + // executor used is defined in the constructor. + @SuppressLint("ExecutorRegistration") + public void sendOptionsCapabilityRequest(@NonNull Uri contactUri, + @NonNull Set<String> myCapabilities, @NonNull OptionsResponseCallback callback) { + // Stub - to be implemented by service + Log.w(LOG_TAG, "sendOptionsCapabilityRequest called with no implementation."); + try { + callback.onCommandError(COMMAND_CODE_NOT_SUPPORTED); + } catch (ImsException e) { + // Do not do anything, this is a stub implementation. + } + } } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 45702c311ff3..97078c3dd76e 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -2231,10 +2231,12 @@ interface ITelephony { * * @param subId the id of the subscription * @param thermalMitigationRequest holds the parameters necessary for the request. + * @param callingPackage the package name of the calling package. * @throws InvalidThermalMitigationRequestException if the parametes are invalid. */ int sendThermalMitigationRequest(int subId, - in ThermalMitigationRequest thermalMitigationRequest); + in ThermalMitigationRequest thermalMitigationRequest, + String callingPackage); /** * Get the Generic Bootstrapping Architecture authentication keys @@ -2325,6 +2327,16 @@ interface ITelephony { boolean getCarrierSingleRegistrationEnabled(int subId); /** + * Overrides the ims feature validation result + */ + boolean setImsFeatureValidationOverride(int subId, String enabled); + + /** + * Gets the ims feature validation override value + */ + boolean getImsFeatureValidationOverride(int subId); + + /** * Return the mobile provisioning url that is used to launch a browser to allow users to manage * their mobile plan. */ diff --git a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt index a4d8353d1253..1e54093bf111 100644 --- a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt +++ b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt @@ -19,6 +19,7 @@ package android.net import android.os.Build import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 +import com.android.modules.utils.build.SdkLevel.isAtLeastS import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo import com.android.testutils.assertParcelSane @@ -44,7 +45,13 @@ class NetworkAgentConfigTest { setPartialConnectivityAcceptable(false) setUnvalidatedConnectivityAcceptable(true) }.build() - assertParcelSane(config, 10) + if (isAtLeastS()) { + // From S, the config will have 12 items + assertParcelSane(config, 12) + } else { + // For R or below, the config will have 10 items + assertParcelSane(config, 10) + } } @Test @IgnoreUpTo(Build.VERSION_CODES.Q) diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java index 0dfec7592274..1f50e31cf243 100644 --- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java +++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java @@ -35,6 +35,9 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE; import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P; +import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION; +import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS; +import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES; import static android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; @@ -51,7 +54,6 @@ import static com.android.testutils.MiscAsserts.assertEmpty; import static com.android.testutils.MiscAsserts.assertThrows; import static com.android.testutils.ParcelUtils.assertParcelSane; import static com.android.testutils.ParcelUtils.assertParcelingIsLossless; -import static com.android.testutils.ParcelUtils.parcelingRoundTrip; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -62,13 +64,13 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; -import android.net.wifi.WifiInfo; import android.net.wifi.aware.DiscoverySession; import android.net.wifi.aware.PeerHandle; import android.net.wifi.aware.WifiAwareNetworkSpecifier; import android.os.Build; import android.test.suitebuilder.annotation.SmallTest; import android.util.ArraySet; +import android.util.Range; import androidx.test.runner.AndroidJUnit4; @@ -240,73 +242,95 @@ public class NetworkCapabilitiesTest { @Test public void testSetUids() { final NetworkCapabilities netCap = new NetworkCapabilities(); - final Set<UidRange> uids = new ArraySet<>(); - uids.add(new UidRange(50, 100)); - uids.add(new UidRange(3000, 4000)); - netCap.setUids(uids); - assertTrue(netCap.appliesToUid(50)); - assertTrue(netCap.appliesToUid(80)); - assertTrue(netCap.appliesToUid(100)); + // Null uids match all UIDs + netCap.setUids(null); + assertTrue(netCap.appliesToUid(10)); + assertTrue(netCap.appliesToUid(200)); assertTrue(netCap.appliesToUid(3000)); - assertTrue(netCap.appliesToUid(3001)); - assertFalse(netCap.appliesToUid(10)); - assertFalse(netCap.appliesToUid(25)); - assertFalse(netCap.appliesToUid(49)); - assertFalse(netCap.appliesToUid(101)); - assertFalse(netCap.appliesToUid(2000)); - assertFalse(netCap.appliesToUid(100000)); - + assertTrue(netCap.appliesToUid(10010)); assertTrue(netCap.appliesToUidRange(new UidRange(50, 100))); assertTrue(netCap.appliesToUidRange(new UidRange(70, 72))); assertTrue(netCap.appliesToUidRange(new UidRange(3500, 3912))); - assertFalse(netCap.appliesToUidRange(new UidRange(1, 100))); - assertFalse(netCap.appliesToUidRange(new UidRange(49, 100))); - assertFalse(netCap.appliesToUidRange(new UidRange(1, 10))); - assertFalse(netCap.appliesToUidRange(new UidRange(60, 101))); - assertFalse(netCap.appliesToUidRange(new UidRange(60, 3400))); - - NetworkCapabilities netCap2 = new NetworkCapabilities(); - // A new netcap object has null UIDs, so anything will satisfy it. - assertTrue(netCap2.satisfiedByUids(netCap)); - // Still not equal though. - assertFalse(netCap2.equalsUids(netCap)); - netCap2.setUids(uids); - assertTrue(netCap2.satisfiedByUids(netCap)); - assertTrue(netCap.equalsUids(netCap2)); - assertTrue(netCap2.equalsUids(netCap)); - - uids.add(new UidRange(600, 700)); - netCap2.setUids(uids); - assertFalse(netCap2.satisfiedByUids(netCap)); - assertFalse(netCap.appliesToUid(650)); - assertTrue(netCap2.appliesToUid(650)); - netCap.combineCapabilities(netCap2); - assertTrue(netCap2.satisfiedByUids(netCap)); - assertTrue(netCap.appliesToUid(650)); - assertFalse(netCap.appliesToUid(500)); - - assertTrue(new NetworkCapabilities().satisfiedByUids(netCap)); - netCap.combineCapabilities(new NetworkCapabilities()); - assertTrue(netCap.appliesToUid(500)); assertTrue(netCap.appliesToUidRange(new UidRange(1, 100000))); - assertFalse(netCap2.appliesToUid(500)); - assertFalse(netCap2.appliesToUidRange(new UidRange(1, 100000))); - assertTrue(new NetworkCapabilities().satisfiedByUids(netCap)); + + if (isAtLeastS()) { + final Set<Range<Integer>> uids = new ArraySet<>(); + uids.add(uidRange(50, 100)); + uids.add(uidRange(3000, 4000)); + netCap.setUids(uids); + assertTrue(netCap.appliesToUid(50)); + assertTrue(netCap.appliesToUid(80)); + assertTrue(netCap.appliesToUid(100)); + assertTrue(netCap.appliesToUid(3000)); + assertTrue(netCap.appliesToUid(3001)); + assertFalse(netCap.appliesToUid(10)); + assertFalse(netCap.appliesToUid(25)); + assertFalse(netCap.appliesToUid(49)); + assertFalse(netCap.appliesToUid(101)); + assertFalse(netCap.appliesToUid(2000)); + assertFalse(netCap.appliesToUid(100000)); + + assertTrue(netCap.appliesToUidRange(new UidRange(50, 100))); + assertTrue(netCap.appliesToUidRange(new UidRange(70, 72))); + assertTrue(netCap.appliesToUidRange(new UidRange(3500, 3912))); + assertFalse(netCap.appliesToUidRange(new UidRange(1, 100))); + assertFalse(netCap.appliesToUidRange(new UidRange(49, 100))); + assertFalse(netCap.appliesToUidRange(new UidRange(1, 10))); + assertFalse(netCap.appliesToUidRange(new UidRange(60, 101))); + assertFalse(netCap.appliesToUidRange(new UidRange(60, 3400))); + + NetworkCapabilities netCap2 = new NetworkCapabilities(); + // A new netcap object has null UIDs, so anything will satisfy it. + assertTrue(netCap2.satisfiedByUids(netCap)); + // Still not equal though. + assertFalse(netCap2.equalsUids(netCap)); + netCap2.setUids(uids); + assertTrue(netCap2.satisfiedByUids(netCap)); + assertTrue(netCap.equalsUids(netCap2)); + assertTrue(netCap2.equalsUids(netCap)); + + uids.add(uidRange(600, 700)); + netCap2.setUids(uids); + assertFalse(netCap2.satisfiedByUids(netCap)); + assertFalse(netCap.appliesToUid(650)); + assertTrue(netCap2.appliesToUid(650)); + netCap.combineCapabilities(netCap2); + assertTrue(netCap2.satisfiedByUids(netCap)); + assertTrue(netCap.appliesToUid(650)); + assertFalse(netCap.appliesToUid(500)); + + assertTrue(new NetworkCapabilities().satisfiedByUids(netCap)); + netCap.combineCapabilities(new NetworkCapabilities()); + assertTrue(netCap.appliesToUid(500)); + assertTrue(netCap.appliesToUidRange(new UidRange(1, 100000))); + assertFalse(netCap2.appliesToUid(500)); + assertFalse(netCap2.appliesToUidRange(new UidRange(1, 100000))); + assertTrue(new NetworkCapabilities().satisfiedByUids(netCap)); + + // Null uids satisfies everything. + netCap.setUids(null); + assertTrue(netCap2.satisfiedByUids(netCap)); + assertTrue(netCap.satisfiedByUids(netCap2)); + netCap2.setUids(null); + assertTrue(netCap2.satisfiedByUids(netCap)); + assertTrue(netCap.satisfiedByUids(netCap2)); + } } @Test public void testParcelNetworkCapabilities() { - final Set<UidRange> uids = new ArraySet<>(); - uids.add(new UidRange(50, 100)); - uids.add(new UidRange(3000, 4000)); + final Set<Range<Integer>> uids = new ArraySet<>(); + uids.add(uidRange(50, 100)); + uids.add(uidRange(3000, 4000)); final NetworkCapabilities netCap = new NetworkCapabilities() .addCapability(NET_CAPABILITY_INTERNET) - .setUids(uids) .addCapability(NET_CAPABILITY_EIMS) .addCapability(NET_CAPABILITY_NOT_METERED); if (isAtLeastS()) { netCap.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2)); - } else if (isAtLeastR()) { + netCap.setUids(uids); + } + if (isAtLeastR()) { netCap.setOwnerUid(123); netCap.setAdministratorUids(new int[] {5, 11}); } @@ -330,63 +354,53 @@ public class NetworkCapabilitiesTest { testParcelSane(netCap); } - private NetworkCapabilities createNetworkCapabilitiesWithWifiInfo() { - // uses a real WifiInfo to test parceling of sensitive data. - final WifiInfo wifiInfo = new WifiInfo.Builder() - .setSsid("sssid1234".getBytes()) - .setBssid("00:11:22:33:44:55") - .build(); + private void testParcelSane(NetworkCapabilities cap) { + if (isAtLeastS()) { + assertParcelSane(cap, 17); + } else if (isAtLeastR()) { + assertParcelSane(cap, 15); + } else { + assertParcelSane(cap, 11); + } + } + + private static NetworkCapabilities createNetworkCapabilitiesWithTransportInfo() { return new NetworkCapabilities() .addCapability(NET_CAPABILITY_INTERNET) .addCapability(NET_CAPABILITY_EIMS) .addCapability(NET_CAPABILITY_NOT_METERED) .setSSID(TEST_SSID) - .setTransportInfo(wifiInfo) + .setTransportInfo(new TestTransportInfo()) .setRequestorPackageName("com.android.test") .setRequestorUid(9304); } @Test - public void testParcelNetworkCapabilitiesWithLocationSensitiveFields() { + public void testNetworkCapabilitiesCopyWithNoRedactions() { assumeTrue(isAtLeastS()); - final NetworkCapabilities netCap = createNetworkCapabilitiesWithWifiInfo(); - final NetworkCapabilities netCapWithLocationSensitiveFields = - new NetworkCapabilities(netCap, true); - - assertParcelingIsLossless(netCapWithLocationSensitiveFields); - testParcelSane(netCapWithLocationSensitiveFields); - - assertEquals(netCapWithLocationSensitiveFields, - parcelingRoundTrip(netCapWithLocationSensitiveFields)); + final NetworkCapabilities netCap = createNetworkCapabilitiesWithTransportInfo(); + final NetworkCapabilities netCapWithNoRedactions = + new NetworkCapabilities(netCap, NetworkCapabilities.REDACT_NONE); + TestTransportInfo testTransportInfo = + (TestTransportInfo) netCapWithNoRedactions.getTransportInfo(); + assertFalse(testTransportInfo.locationRedacted); + assertFalse(testTransportInfo.localMacAddressRedacted); + assertFalse(testTransportInfo.settingsRedacted); } @Test - public void testParcelNetworkCapabilitiesWithoutLocationSensitiveFields() { + public void testNetworkCapabilitiesCopyWithoutLocationSensitiveFields() { assumeTrue(isAtLeastS()); - final NetworkCapabilities netCap = createNetworkCapabilitiesWithWifiInfo(); - final NetworkCapabilities netCapWithoutLocationSensitiveFields = - new NetworkCapabilities(netCap, false); - - final NetworkCapabilities sanitizedNetCap = - new NetworkCapabilities(netCapWithoutLocationSensitiveFields); - final WifiInfo sanitizedWifiInfo = new WifiInfo.Builder() - .setSsid(new byte[0]) - .setBssid(WifiInfo.DEFAULT_MAC_ADDRESS) - .build(); - sanitizedNetCap.setTransportInfo(sanitizedWifiInfo); - assertEquals(sanitizedNetCap, parcelingRoundTrip(netCapWithoutLocationSensitiveFields)); - } - - private void testParcelSane(NetworkCapabilities cap) { - if (isAtLeastS()) { - assertParcelSane(cap, 17); - } else if (isAtLeastR()) { - assertParcelSane(cap, 15); - } else { - assertParcelSane(cap, 11); - } + final NetworkCapabilities netCap = createNetworkCapabilitiesWithTransportInfo(); + final NetworkCapabilities netCapWithNoRedactions = + new NetworkCapabilities(netCap, REDACT_FOR_ACCESS_FINE_LOCATION); + TestTransportInfo testTransportInfo = + (TestTransportInfo) netCapWithNoRedactions.getTransportInfo(); + assertTrue(testTransportInfo.locationRedacted); + assertFalse(testTransportInfo.localMacAddressRedacted); + assertFalse(testTransportInfo.settingsRedacted); } @Test @@ -518,11 +532,22 @@ public class NetworkCapabilitiesTest { assertFalse(nc1.equalsNetCapabilities(nc2)); nc2.addUnwantedCapability(NET_CAPABILITY_INTERNET); assertTrue(nc1.equalsNetCapabilities(nc2)); - - nc1.removeCapability(NET_CAPABILITY_INTERNET); - assertFalse(nc1.equalsNetCapabilities(nc2)); - nc2.removeCapability(NET_CAPABILITY_INTERNET); - assertTrue(nc1.equalsNetCapabilities(nc2)); + if (isAtLeastS()) { + // Remove a required capability doesn't affect unwanted capabilities. + // This is a behaviour change from S. + nc1.removeCapability(NET_CAPABILITY_INTERNET); + assertTrue(nc1.equalsNetCapabilities(nc2)); + + nc1.removeUnwantedCapability(NET_CAPABILITY_INTERNET); + assertFalse(nc1.equalsNetCapabilities(nc2)); + nc2.removeUnwantedCapability(NET_CAPABILITY_INTERNET); + assertTrue(nc1.equalsNetCapabilities(nc2)); + } else { + nc1.removeCapability(NET_CAPABILITY_INTERNET); + assertFalse(nc1.equalsNetCapabilities(nc2)); + nc2.removeCapability(NET_CAPABILITY_INTERNET); + assertTrue(nc1.equalsNetCapabilities(nc2)); + } } @Test @@ -540,12 +565,16 @@ public class NetworkCapabilitiesTest { assertFalse(nc1.satisfiedByNetworkCapabilities(nc2)); } - private ArraySet<UidRange> uidRange(int from, int to) { - final ArraySet<UidRange> range = new ArraySet<>(1); - range.add(new UidRange(from, to)); + private ArraySet<Range<Integer>> uidRanges(int from, int to) { + final ArraySet<Range<Integer>> range = new ArraySet<>(1); + range.add(uidRange(from, to)); return range; } + private Range<Integer> uidRange(int from, int to) { + return new Range<Integer>(from, to); + } + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) public void testSetAdministratorUids() { NetworkCapabilities nc = @@ -579,11 +608,21 @@ public class NetworkCapabilitiesTest { // This will effectively move NOT_ROAMING capability from required to unwanted for nc1. nc1.addUnwantedCapability(NET_CAPABILITY_NOT_ROAMING); - nc2.combineCapabilities(nc1); - // We will get this capability in both requested and unwanted lists thus this request - // will never be satisfied. - assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING)); - assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING)); + if (isAtLeastS()) { + // From S, it is not allowed to have the same capability in both wanted and + // unwanted list. + assertThrows(IllegalArgumentException.class, () -> nc2.combineCapabilities(nc1)); + // Remove unwanted capability to continue other tests. + nc1.removeUnwantedCapability(NET_CAPABILITY_NOT_ROAMING); + } else { + nc2.combineCapabilities(nc1); + // We will get this capability in both requested and unwanted lists thus this request + // will never be satisfied. + assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING)); + assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING)); + // For R or below, remove unwanted capability via removeCapability. + nc1.removeCapability(NET_CAPABILITY_NOT_ROAMING); + } nc1.setSSID(TEST_SSID); nc2.combineCapabilities(nc1); @@ -601,23 +640,23 @@ public class NetworkCapabilitiesTest { } catch (IllegalStateException expected) {} nc1.setSSID(TEST_SSID); - nc1.setUids(uidRange(10, 13)); - assertNotEquals(nc1, nc2); - nc2.combineCapabilities(nc1); // Everything + 10~13 is still everything. - assertNotEquals(nc1, nc2); - nc1.combineCapabilities(nc2); // 10~13 + everything is everything. - assertEquals(nc1, nc2); - nc1.setUids(uidRange(10, 13)); - nc2.setUids(uidRange(20, 23)); - assertNotEquals(nc1, nc2); - nc1.combineCapabilities(nc2); - assertTrue(nc1.appliesToUid(12)); - assertFalse(nc2.appliesToUid(12)); - assertTrue(nc1.appliesToUid(22)); - assertTrue(nc2.appliesToUid(22)); - - // Verify the subscription id list can be combined only when they are equal. if (isAtLeastS()) { + nc1.setUids(uidRanges(10, 13)); + assertNotEquals(nc1, nc2); + nc2.combineCapabilities(nc1); // Everything + 10~13 is still everything. + assertNotEquals(nc1, nc2); + nc1.combineCapabilities(nc2); // 10~13 + everything is everything. + assertEquals(nc1, nc2); + nc1.setUids(uidRanges(10, 13)); + nc2.setUids(uidRanges(20, 23)); + assertNotEquals(nc1, nc2); + nc1.combineCapabilities(nc2); + assertTrue(nc1.appliesToUid(12)); + assertFalse(nc2.appliesToUid(12)); + assertTrue(nc1.appliesToUid(22)); + assertTrue(nc2.appliesToUid(22)); + + // Verify the subscription id list can be combined only when they are equal. nc1.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2)); nc2.setSubIds(Set.of(TEST_SUBID2)); assertThrows(IllegalStateException.class, () -> nc2.combineCapabilities(nc1)); @@ -773,8 +812,11 @@ public class NetworkCapabilitiesTest { if (isAtLeastR()) { assertTrue(DIFFERENT_TEST_SSID.equals(nc2.getSsid())); } - - nc1.setUids(uidRange(10, 13)); + if (isAtLeastS()) { + nc1.setUids(uidRanges(10, 13)); + } else { + nc1.setUids(null); + } nc2.set(nc1); // Overwrites, as opposed to combineCapabilities assertEquals(nc1, nc2); @@ -1033,18 +1075,42 @@ public class NetworkCapabilitiesTest { } catch (IllegalArgumentException e) { } } - private class TestTransportInfo implements TransportInfo { + /** + * Test TransportInfo to verify redaction mechanism. + */ + private static class TestTransportInfo implements TransportInfo { + public final boolean locationRedacted; + public final boolean localMacAddressRedacted; + public final boolean settingsRedacted; + TestTransportInfo() { + locationRedacted = false; + localMacAddressRedacted = false; + settingsRedacted = false; + } + + TestTransportInfo(boolean locationRedacted, + boolean localMacAddressRedacted, + boolean settingsRedacted) { + this.locationRedacted = locationRedacted; + this.localMacAddressRedacted = + localMacAddressRedacted; + this.settingsRedacted = settingsRedacted; } @Override - public TransportInfo makeCopy(boolean parcelLocationSensitiveFields) { - return this; + public TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) { + return new TestTransportInfo( + (redactions & NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION) != 0, + (redactions & REDACT_FOR_LOCAL_MAC_ADDRESS) != 0, + (redactions & REDACT_FOR_NETWORK_SETTINGS) != 0 + ); } @Override - public boolean hasLocationSensitiveFields() { - return false; + public @NetworkCapabilities.RedactionType long getApplicableRedactions() { + return REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS + | REDACT_FOR_NETWORK_SETTINGS; } } @@ -1055,7 +1121,7 @@ public class NetworkCapabilitiesTest { final int requestUid = 10100; final int[] administratorUids = {ownerUid, 10001}; final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier(1); - final TestTransportInfo transportInfo = new TestTransportInfo(); + final TransportInfo transportInfo = new TransportInfo() {}; final String ssid = "TEST_SSID"; final String packageName = "com.google.test.networkcapabilities"; final NetworkCapabilities nc = new NetworkCapabilities.Builder() diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt index 2a2dc5628ecd..b6e42743e2a3 100644 --- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt +++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt @@ -44,12 +44,10 @@ import android.util.Log import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import com.android.server.ConnectivityService -import com.android.server.LocalServices import com.android.server.NetworkAgentWrapper import com.android.server.TestNetIdManager import com.android.server.connectivity.MockableSystemProperties import com.android.server.connectivity.ProxyTracker -import com.android.server.net.NetworkPolicyManagerInternal import com.android.testutils.TestableNetworkCallback import org.junit.After import org.junit.Before @@ -75,7 +73,7 @@ import kotlin.test.assertTrue import kotlin.test.fail const val SERVICE_BIND_TIMEOUT_MS = 5_000L -const val TEST_TIMEOUT_MS = 1_000L +const val TEST_TIMEOUT_MS = 10_000L /** * Test that exercises an instrumented version of ConnectivityService against an instrumented @@ -162,10 +160,6 @@ class ConnectivityServiceIntegrationTest { networkStackClient.init() networkStackClient.start() - LocalServices.removeServiceForTest(NetworkPolicyManagerInternal::class.java) - LocalServices.addService(NetworkPolicyManagerInternal::class.java, - mock(NetworkPolicyManagerInternal::class.java)) - service = TestConnectivityService(makeDependencies()) cm = ConnectivityManager(context, service) context.addMockSystemService(Context.CONNECTIVITY_SERVICE, cm) diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java index 01d8186c7d1b..e2d43cbb8efd 100644 --- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java +++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java @@ -44,11 +44,11 @@ import android.net.NetworkProvider; import android.net.NetworkSpecifier; import android.net.QosFilter; import android.net.SocketKeepalive; -import android.net.UidRange; import android.os.ConditionVariable; import android.os.HandlerThread; import android.os.Message; import android.util.Log; +import android.util.Range; import com.android.net.module.util.ArrayTrackRecord; import com.android.server.connectivity.ConnectivityConstants; @@ -222,7 +222,7 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); } - public void setUids(Set<UidRange> uids) { + public void setUids(Set<Range<Integer>> uids) { mNetworkCapabilities.setUids(uids); mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); } diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java index 6fc605e269fe..6cbdd258c00a 100644 --- a/tests/net/java/android/net/ConnectivityManagerTest.java +++ b/tests/net/java/android/net/ConnectivityManagerTest.java @@ -41,10 +41,10 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -64,6 +64,7 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.Messenger; +import android.os.Process; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -219,8 +220,8 @@ public class ConnectivityManagerTest { ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class); // register callback - when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(), - anyInt(), any(), nullable(String.class))).thenReturn(request); + when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(), + anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(request); manager.requestNetwork(request, callback, handler); // callback triggers @@ -247,8 +248,8 @@ public class ConnectivityManagerTest { ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class); // register callback - when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(), - anyInt(), any(), nullable(String.class))).thenReturn(req1); + when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(), + anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req1); manager.requestNetwork(req1, callback, handler); // callback triggers @@ -265,8 +266,8 @@ public class ConnectivityManagerTest { verify(callback, timeout(100).times(0)).onLosing(any(), anyInt()); // callback can be registered again - when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(), - anyInt(), any(), nullable(String.class))).thenReturn(req2); + when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(), + anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req2); manager.requestNetwork(req2, callback, handler); // callback triggers @@ -289,8 +290,8 @@ public class ConnectivityManagerTest { info.targetSdkVersion = VERSION_CODES.N_MR1 + 1; when(mCtx.getApplicationInfo()).thenReturn(info); - when(mService.requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(), anyInt(), - any(), nullable(String.class))).thenReturn(request); + when(mService.requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(), anyInt(), + anyInt(), any(), nullable(String.class))).thenReturn(request); Handler handler = new Handler(Looper.getMainLooper()); manager.requestNetwork(request, callback, handler); @@ -357,34 +358,40 @@ public class ConnectivityManagerTest { final NetworkCallback callback = new ConnectivityManager.NetworkCallback(); manager.requestNetwork(request, callback); - verify(mService).requestNetwork(eq(request.networkCapabilities), + verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities), eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), eq(testPkgName), eq(testAttributionTag)); reset(mService); // Verify that register network callback does not calls requestNetwork at all. manager.registerNetworkCallback(request, callback); - verify(mService, never()).requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(), - anyInt(), any(), any()); + verify(mService, never()).requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(), + anyInt(), anyInt(), any(), any()); verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(), anyInt(), eq(testPkgName), eq(testAttributionTag)); reset(mService); + Handler handler = new Handler(ConnectivityThread.getInstanceLooper()); + manager.registerDefaultNetworkCallback(callback); - verify(mService).requestNetwork(eq(null), + verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null), eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), eq(testPkgName), eq(testAttributionTag)); reset(mService); - Handler handler = new Handler(ConnectivityThread.getInstanceLooper()); + manager.registerDefaultNetworkCallbackAsUid(42, callback, handler); + verify(mService).requestNetwork(eq(42), eq(null), + eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), + eq(testPkgName), eq(testAttributionTag)); + manager.requestBackgroundNetwork(request, handler, callback); - verify(mService).requestNetwork(eq(request.networkCapabilities), + verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities), eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), eq(testPkgName), eq(testAttributionTag)); reset(mService); manager.registerSystemDefaultNetworkCallback(callback, handler); - verify(mService).requestNetwork(eq(null), + verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null), eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(), eq(testPkgName), eq(testAttributionTag)); reset(mService); diff --git a/tests/net/java/android/net/util/KeepaliveUtilsTest.kt b/tests/net/java/android/net/util/KeepaliveUtilsTest.kt index 8ea226db938e..b62bdbcfb5eb 100644 --- a/tests/net/java/android/net/util/KeepaliveUtilsTest.kt +++ b/tests/net/java/android/net/util/KeepaliveUtilsTest.kt @@ -18,6 +18,7 @@ package android.net.util import android.content.Context import android.content.res.Resources +import android.net.ConnectivityResources import android.net.NetworkCapabilities import android.net.NetworkCapabilities.MAX_TRANSPORT import android.net.NetworkCapabilities.TRANSPORT_CELLULAR @@ -26,13 +27,15 @@ import android.net.NetworkCapabilities.TRANSPORT_VPN import android.net.NetworkCapabilities.TRANSPORT_WIFI import androidx.test.filters.SmallTest import com.android.internal.R +import org.junit.After import org.junit.Assert.assertArrayEquals import org.junit.Assert.assertEquals import org.junit.Assert.fail import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 -import org.mockito.ArgumentMatchers +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mockito.any import org.mockito.Mockito.doReturn import org.mockito.Mockito.mock @@ -47,21 +50,33 @@ import org.mockito.Mockito.mock class KeepaliveUtilsTest { // Prepare mocked context with given resource strings. - private fun getMockedContextWithStringArrayRes(id: Int, res: Array<out String?>?): Context { + private fun getMockedContextWithStringArrayRes( + id: Int, + name: String, + res: Array<out String?>? + ): Context { val mockRes = mock(Resources::class.java) - doReturn(res).`when`(mockRes).getStringArray(ArgumentMatchers.eq(id)) + doReturn(res).`when`(mockRes).getStringArray(eq(id)) + doReturn(id).`when`(mockRes).getIdentifier(eq(name), any(), any()) return mock(Context::class.java).apply { doReturn(mockRes).`when`(this).getResources() + ConnectivityResources.setResourcesContextForTest(this) } } + @After + fun tearDown() { + ConnectivityResources.setResourcesContextForTest(null) + } + @Test fun testGetSupportedKeepalives() { fun assertRunWithException(res: Array<out String?>?) { try { val mockContext = getMockedContextWithStringArrayRes( - R.array.config_networkSupportedKeepaliveCount, res) + R.array.config_networkSupportedKeepaliveCount, + "config_networkSupportedKeepaliveCount", res) KeepaliveUtils.getSupportedKeepalives(mockContext) fail("Expected KeepaliveDeviceConfigurationException") } catch (expected: KeepaliveUtils.KeepaliveDeviceConfigurationException) { @@ -89,7 +104,8 @@ class KeepaliveUtilsTest { val expectedValidRes = intArrayOf(3, 0, 0, 0, 4, 0, 0, 0) val mockContext = getMockedContextWithStringArrayRes( - R.array.config_networkSupportedKeepaliveCount, validRes) + R.array.config_networkSupportedKeepaliveCount, + "config_networkSupportedKeepaliveCount", validRes) val actual = KeepaliveUtils.getSupportedKeepalives(mockContext) assertArrayEquals(expectedValidRes, actual) } diff --git a/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt index 1945ce7ba90d..25aa6266577e 100644 --- a/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt +++ b/tests/net/java/android/net/util/MultinetworkPolicyTrackerTest.kt @@ -21,6 +21,7 @@ import android.content.res.Resources import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE import android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY +import android.net.ConnectivityResources import android.net.ConnectivitySettingsManager.NETWORK_AVOID_BAD_WIFI import android.net.ConnectivitySettingsManager.NETWORK_METERED_MULTIPATH_PREFERENCE import android.net.util.MultinetworkPolicyTracker.ActiveDataSubscriptionIdListener @@ -31,8 +32,9 @@ import android.telephony.TelephonyManager import android.test.mock.MockContentResolver import androidx.test.filters.SmallTest import androidx.test.runner.AndroidJUnit4 -import com.android.internal.R +import com.android.connectivity.resources.R import com.android.internal.util.test.FakeSettingsProvider +import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue @@ -41,6 +43,7 @@ import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.argThat +import org.mockito.ArgumentMatchers.eq import org.mockito.Mockito.any import org.mockito.Mockito.doReturn import org.mockito.Mockito.mock @@ -57,6 +60,8 @@ import org.mockito.Mockito.verify @SmallTest class MultinetworkPolicyTrackerTest { private val resources = mock(Resources::class.java).also { + doReturn(R.integer.config_networkAvoidBadWifi).`when`(it).getIdentifier( + eq("config_networkAvoidBadWifi"), eq("integer"), any()) doReturn(0).`when`(it).getInteger(R.integer.config_networkAvoidBadWifi) } private val telephonyManager = mock(TelephonyManager::class.java) @@ -75,6 +80,7 @@ class MultinetworkPolicyTrackerTest { doReturn(resources).`when`(it).resources doReturn(it).`when`(it).createConfigurationContext(any()) Settings.Global.putString(resolver, NETWORK_AVOID_BAD_WIFI, "1") + ConnectivityResources.setResourcesContextForTest(it) } private val tracker = MultinetworkPolicyTracker(context, null /* handler */) @@ -85,6 +91,11 @@ class MultinetworkPolicyTrackerTest { assertEquals(preference, tracker.meteredMultipathPreference) } + @After + fun tearDown() { + ConnectivityResources.setResourcesContextForTest(null) + } + @Test fun testUpdateMeteredMultipathPreference() { assertMultipathPreference(MULTIPATH_PREFERENCE_HANDOVER) diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index c4f3fea770ed..4c0c1198a6f5 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -30,10 +30,14 @@ import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN; +import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER; +import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK; +import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED; +import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER; +import static android.net.ConnectivityManager.BLOCKED_REASON_NONE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO; import static android.net.ConnectivityManager.EXTRA_NETWORK_TYPE; -import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; @@ -82,15 +86,15 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P; import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP; +import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION; +import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS; +import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; +import static android.net.NetworkCapabilities.REDACT_NONE; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; -import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_DATA_SAVER; -import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_USER_RESTRICTED; -import static android.net.NetworkPolicyManager.BLOCKED_REASON_BATTERY_SAVER; -import static android.net.NetworkPolicyManager.BLOCKED_REASON_NONE; import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID; import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK; import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY; @@ -179,6 +183,7 @@ import android.net.ConnectivityManager.NetworkCallback; import android.net.ConnectivityManager.PacketKeepalive; import android.net.ConnectivityManager.PacketKeepaliveCallback; import android.net.ConnectivityManager.TooManyRequestsException; +import android.net.ConnectivityResources; import android.net.ConnectivitySettingsManager; import android.net.ConnectivityThread; import android.net.DataStallReportParcelable; @@ -236,7 +241,6 @@ import android.net.resolv.aidl.PrivateDnsValidationEventParcel; import android.net.shared.NetworkMonitorUtils; import android.net.shared.PrivateDnsConfig; import android.net.util.MultinetworkPolicyTracker; -import android.net.wifi.WifiInfo; import android.os.BadParcelableException; import android.os.Binder; import android.os.Build; @@ -262,17 +266,20 @@ import android.security.Credentials; import android.system.Os; import android.telephony.TelephonyManager; import android.telephony.data.EpsBearerQosSessionAttributes; +import android.telephony.data.NrQosSessionAttributes; import android.test.mock.MockContentResolver; import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; import android.util.Pair; +import android.util.Range; import android.util.SparseArray; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.connectivity.resources.R; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnProfile; import com.android.internal.util.ArrayUtils; @@ -282,7 +289,6 @@ import com.android.internal.util.test.FakeSettingsProvider; import com.android.net.module.util.ArrayTrackRecord; import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo; import com.android.server.connectivity.ConnectivityConstants; -import com.android.server.connectivity.ConnectivityResources; import com.android.server.connectivity.MockableSystemProperties; import com.android.server.connectivity.Nat464Xlat; import com.android.server.connectivity.NetworkAgentInfo; @@ -292,7 +298,6 @@ 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; import com.android.testutils.HandlerUtils; import com.android.testutils.RecorderCallback.CallbackEntry; @@ -1158,7 +1163,7 @@ public class ConnectivityServiceTest { } public void setUids(Set<UidRange> uids) { - mNetworkCapabilities.setUids(uids); + mNetworkCapabilities.setUids(UidRange.toIntRanges(uids)); if (mAgentRegistered) { mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities, true); } @@ -1174,11 +1179,6 @@ public class ConnectivityServiceTest { } @Override - public int getNetId() { - return (mMockNetworkAgent == null) ? NETID_UNSET : mMockNetworkAgent.getNetwork().netId; - } - - @Override public int getActiveVpnType() { return mVpnType; } @@ -1202,10 +1202,10 @@ public class ConnectivityServiceTest { mNetworkCapabilities); mMockNetworkAgent.waitForIdle(TIMEOUT_MS); - verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetId()), + verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetwork().getNetId()), eq(toUidRangeStableParcels(uids))); verify(mMockNetd, never()) - .networkRemoveUidRanges(eq(mMockVpn.getNetId()), any()); + .networkRemoveUidRanges(eq(mMockVpn.getNetwork().getNetId()), any()); mAgentRegistered = true; updateState(NetworkInfo.DetailedState.CONNECTED, "registerAgent"); mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities()); @@ -1374,10 +1374,21 @@ public class ConnectivityServiceTest { } private void mockUidNetworkingBlocked() { - doAnswer(i -> NetworkPolicyManager.isUidBlocked(mBlockedReasons, i.getArgument(1)) + doAnswer(i -> isUidBlocked(mBlockedReasons, i.getArgument(1)) ).when(mNetworkPolicyManager).isUidNetworkingBlocked(anyInt(), anyBoolean()); } + private boolean isUidBlocked(int blockedReasons, boolean meteredNetwork) { + final int blockedOnAllNetworksReason = (blockedReasons & ~BLOCKED_METERED_REASON_MASK); + if (blockedOnAllNetworksReason != BLOCKED_REASON_NONE) { + return true; + } + if (meteredNetwork) { + return blockedReasons != BLOCKED_REASON_NONE; + } + return false; + } + private void setBlockedReasonChanged(int blockedReasons) { mBlockedReasons = blockedReasons; mPolicyCallback.onUidBlockedReasonChanged(Process.myUid(), blockedReasons); @@ -1447,7 +1458,26 @@ public class ConnectivityServiceTest { }); } + private interface ExceptionalRunnable { + void run() throws Exception; + } + + private void withPermission(String permission, ExceptionalRunnable r) throws Exception { + if (mServiceContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) { + r.run(); + return; + } + try { + mServiceContext.setPermission(permission, PERMISSION_GRANTED); + r.run(); + } finally { + mServiceContext.setPermission(permission, PERMISSION_DENIED); + } + } + private static final int PRIMARY_USER = 0; + private static final UidRange PRIMARY_UIDRANGE = + UidRange.createForUser(UserHandle.of(PRIMARY_USER)); private static final int APP1_UID = UserHandle.getUid(PRIMARY_USER, 10100); private static final int APP2_UID = UserHandle.getUid(PRIMARY_USER, 10101); private static final int VPN_UID = UserHandle.getUid(PRIMARY_USER, 10043); @@ -1501,9 +1531,6 @@ public class ConnectivityServiceTest { mServiceContext = new MockContext(InstrumentationRegistry.getContext(), new FakeSettingsProvider()); mServiceContext.setUseRegisteredHandlers(true); - LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class); - LocalServices.addService( - NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class)); mAlarmManagerThread = new HandlerThread("TestAlarmManager"); mAlarmManagerThread.start(); @@ -1556,7 +1583,7 @@ public class ConnectivityServiceTest { doReturn(mNetworkStack).when(deps).getNetworkStack(); doReturn(mSystemProperties).when(deps).getSystemProperties(); doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any()); - doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt()); + doReturn(true).when(deps).queryUserAccess(anyInt(), any(), any()); doAnswer(inv -> { mPolicyTracker = new WrappedMultinetworkPolicyTracker( inv.getArgument(0), inv.getArgument(1), inv.getArgument(2)); @@ -1570,11 +1597,27 @@ public class ConnectivityServiceTest { com.android.connectivity.resources.R.string.config_networkCaptivePortalServerUrl); doReturn(new String[]{ WIFI_WOL_IFNAME }).when(mResources).getStringArray( com.android.connectivity.resources.R.array.config_wakeonlan_supported_interfaces); - final com.android.server.connectivity.ConnectivityResources connRes = mock( - ConnectivityResources.class); + doReturn(new String[] { "0,1", "1,3" }).when(mResources).getStringArray( + com.android.connectivity.resources.R.array.config_networkSupportedKeepaliveCount); + doReturn(com.android.connectivity.resources.R.array.config_networkSupportedKeepaliveCount) + .when(mResources).getIdentifier(eq("config_networkSupportedKeepaliveCount"), + eq("array"), any()); + doReturn(com.android.connectivity.resources.R.array.network_switch_type_name) + .when(mResources).getIdentifier(eq("network_switch_type_name"), + eq("array"), any()); + + // We don't test the actual notification value strings, so just return an empty array. + // It doesn't matter what the values are as long as it's not null. + doReturn(new String[0]).when(mResources).getStringArray(R.array.network_switch_type_name); + + final ConnectivityResources connRes = mock(ConnectivityResources.class); doReturn(mResources).when(connRes).get(); doReturn(connRes).when(deps).getResources(any()); + final Context mockResContext = mock(Context.class); + doReturn(mResources).when(mockResContext).getResources(); + ConnectivityResources.setResourcesContextForTest(mockResContext); + return deps; } @@ -1630,6 +1673,7 @@ public class ConnectivityServiceTest { waitForIdle(); FakeSettingsProvider.clearSettingsProvider(); + ConnectivityResources.setResourcesContextForTest(null); mCsHandlerThread.quitSafely(); mAlarmManagerThread.quitSafely(); @@ -3793,8 +3837,9 @@ public class ConnectivityServiceTest { NetworkCapabilities networkCapabilities = new NetworkCapabilities(); networkCapabilities.addTransportType(TRANSPORT_WIFI) .setNetworkSpecifier(new MatchAllNetworkSpecifier()); - mService.requestNetwork(networkCapabilities, NetworkRequest.Type.REQUEST.ordinal(), - null, 0, null, ConnectivityManager.TYPE_WIFI, NetworkCallback.FLAG_NONE, + mService.requestNetwork(Process.INVALID_UID, networkCapabilities, + NetworkRequest.Type.REQUEST.ordinal(), null, 0, null, + ConnectivityManager.TYPE_WIFI, NetworkCallback.FLAG_NONE, mContext.getPackageName(), getAttributionTag()); }); @@ -4023,7 +4068,7 @@ public class ConnectivityServiceTest { } @Test - public void testRegisterSystemDefaultCallbackRequiresNetworkSettings() throws Exception { + public void testRegisterPrivilegedDefaultCallbacksRequireNetworkSettings() throws Exception { mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(false /* validated */); @@ -4032,12 +4077,19 @@ public class ConnectivityServiceTest { assertThrows(SecurityException.class, () -> mCm.registerSystemDefaultNetworkCallback(callback, handler)); callback.assertNoCallback(); + assertThrows(SecurityException.class, + () -> mCm.registerDefaultNetworkCallbackAsUid(APP1_UID, callback, handler)); + callback.assertNoCallback(); mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED); mCm.registerSystemDefaultNetworkCallback(callback, handler); callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); mCm.unregisterNetworkCallback(callback); + + mCm.registerDefaultNetworkCallbackAsUid(APP1_UID, callback, handler); + callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); + mCm.unregisterNetworkCallback(callback); } private void setCaptivePortalMode(int mode) { @@ -6932,7 +6984,7 @@ public class ConnectivityServiceTest { final int uid = Process.myUid(); NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork()); assertNotNull("nc=" + nc, nc.getUids()); - assertEquals(nc.getUids(), uidRangesForUids(uid)); + assertEquals(nc.getUids(), UidRange.toIntRanges(uidRangesForUids(uid))); assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE); // Set an underlying network and expect to see the VPN transports change. @@ -6957,10 +7009,13 @@ public class ConnectivityServiceTest { // Expect that the VPN UID ranges contain both |uid| and the UID range for the newly-added // restricted user. + final UidRange rRange = UidRange.createForUser(UserHandle.of(RESTRICTED_USER)); + final Range<Integer> restrictUidRange = new Range<Integer>(rRange.start, rRange.stop); + final Range<Integer> singleUidRange = new Range<Integer>(uid, uid); callback.expectCapabilitiesThat(mMockVpn, (caps) -> caps.getUids().size() == 2 - && caps.getUids().contains(new UidRange(uid, uid)) - && caps.getUids().contains(createUidRange(RESTRICTED_USER)) + && caps.getUids().contains(singleUidRange) + && caps.getUids().contains(restrictUidRange) && caps.hasTransport(TRANSPORT_VPN) && caps.hasTransport(TRANSPORT_WIFI)); @@ -6969,8 +7024,8 @@ public class ConnectivityServiceTest { callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent); callback.expectCapabilitiesThat(mMockVpn, (caps) -> caps.getUids().size() == 2 - && caps.getUids().contains(new UidRange(uid, uid)) - && caps.getUids().contains(createUidRange(RESTRICTED_USER)) + && caps.getUids().contains(singleUidRange) + && caps.getUids().contains(restrictUidRange) && caps.hasTransport(TRANSPORT_VPN) && !caps.hasTransport(TRANSPORT_WIFI)); @@ -6984,7 +7039,7 @@ public class ConnectivityServiceTest { // change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved. callback.expectCapabilitiesThat(mMockVpn, (caps) -> caps.getUids().size() == 1 - && caps.getUids().contains(new UidRange(uid, uid)) + && caps.getUids().contains(singleUidRange) && caps.hasTransport(TRANSPORT_VPN) && !caps.hasTransport(TRANSPORT_WIFI)); } @@ -7234,6 +7289,20 @@ public class ConnectivityServiceTest { mMockVpn.disconnect(); } + private class DetailedBlockedStatusCallback extends TestNetworkCallback { + public void expectAvailableThenValidatedCallbacks(HasNetwork n, int blockedStatus) { + super.expectAvailableThenValidatedCallbacks(n.getNetwork(), blockedStatus, TIMEOUT_MS); + } + public void expectBlockedStatusCallback(HasNetwork n, int blockedStatus) { + // This doesn't work: + // super.expectBlockedStatusCallback(blockedStatus, n.getNetwork()); + super.expectBlockedStatusCallback(blockedStatus, n.getNetwork(), TIMEOUT_MS); + } + public void onBlockedStatusChanged(Network network, int blockedReasons) { + getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons)); + } + } + @Test public void testNetworkBlockedStatus() throws Exception { final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback(); @@ -7241,11 +7310,16 @@ public class ConnectivityServiceTest { .addTransportType(TRANSPORT_CELLULAR) .build(); mCm.registerNetworkCallback(cellRequest, cellNetworkCallback); + final DetailedBlockedStatusCallback detailedCallback = new DetailedBlockedStatusCallback(); + mCm.registerNetworkCallback(cellRequest, detailedCallback); + mockUidNetworkingBlocked(); mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); mCellNetworkAgent.connect(true); cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + detailedCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent, + BLOCKED_REASON_NONE); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); @@ -7253,17 +7327,23 @@ public class ConnectivityServiceTest { setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER); cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); + detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, + BLOCKED_REASON_BATTERY_SAVER); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertExtraInfoFromCmBlocked(mCellNetworkAgent); - // ConnectivityService should cache it not to invoke the callback again. + // If blocked state does not change but blocked reason does, the boolean callback is called. + // TODO: investigate de-duplicating. setBlockedReasonChanged(BLOCKED_METERED_REASON_USER_RESTRICTED); - cellNetworkCallback.assertNoCallback(); + cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); + detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, + BLOCKED_METERED_REASON_USER_RESTRICTED); setBlockedReasonChanged(BLOCKED_REASON_NONE); cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); + detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); @@ -7271,6 +7351,8 @@ public class ConnectivityServiceTest { setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER); cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); + detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, + BLOCKED_METERED_REASON_DATA_SAVER); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); @@ -7280,6 +7362,8 @@ public class ConnectivityServiceTest { mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent); cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); + detailedCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent); + detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); @@ -7289,6 +7373,10 @@ public class ConnectivityServiceTest { cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent); cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); + detailedCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, + mCellNetworkAgent); + detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, + BLOCKED_METERED_REASON_DATA_SAVER); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); @@ -7296,6 +7384,7 @@ public class ConnectivityServiceTest { setBlockedReasonChanged(BLOCKED_REASON_NONE); cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); + detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); @@ -7303,10 +7392,13 @@ public class ConnectivityServiceTest { setBlockedReasonChanged(BLOCKED_REASON_NONE); cellNetworkCallback.assertNoCallback(); + detailedCallback.assertNoCallback(); // Restrict background data. Networking is not blocked because the network is unmetered. setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER); cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); + detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, + BLOCKED_METERED_REASON_DATA_SAVER); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); @@ -7316,12 +7408,14 @@ public class ConnectivityServiceTest { setBlockedReasonChanged(BLOCKED_REASON_NONE); cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); + detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertExtraInfoFromCmPresent(mCellNetworkAgent); setBlockedReasonChanged(BLOCKED_REASON_NONE); cellNetworkCallback.assertNoCallback(); + detailedCallback.assertNoCallback(); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); @@ -7464,6 +7558,13 @@ public class ConnectivityServiceTest { final NetworkRequest vpnUidRequest = new NetworkRequest.Builder().build(); registerNetworkCallbackAsUid(vpnUidRequest, vpnUidCallback, VPN_UID); + final TestNetworkCallback vpnUidDefaultCallback = new TestNetworkCallback(); + registerDefaultNetworkCallbackAsUid(vpnUidDefaultCallback, VPN_UID); + + final TestNetworkCallback vpnDefaultCallbackAsUid = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallbackAsUid(VPN_UID, vpnDefaultCallbackAsUid, + new Handler(ConnectivityThread.getInstanceLooper())); + final int uid = Process.myUid(); final int userId = UserHandle.getUserId(uid); final ArrayList<String> allowList = new ArrayList<>(); @@ -7482,6 +7583,8 @@ public class ConnectivityServiceTest { callback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent); defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent); vpnUidCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + vpnUidDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + vpnDefaultCallbackAsUid.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED); @@ -7494,6 +7597,8 @@ public class ConnectivityServiceTest { callback.expectBlockedStatusCallback(false, mWiFiNetworkAgent); defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent); vpnUidCallback.assertNoCallback(); + vpnUidDefaultCallback.assertNoCallback(); + vpnDefaultCallbackAsUid.assertNoCallback(); expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); @@ -7508,6 +7613,8 @@ public class ConnectivityServiceTest { callback.assertNoCallback(); defaultCallback.assertNoCallback(); vpnUidCallback.assertNoCallback(); + vpnUidDefaultCallback.assertNoCallback(); + vpnDefaultCallbackAsUid.assertNoCallback(); // The following requires that the UID of this test package is greater than VPN_UID. This // is always true in practice because a plain AOSP build with no apps installed has almost @@ -7528,6 +7635,8 @@ public class ConnectivityServiceTest { callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); defaultCallback.assertNoCallback(); vpnUidCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent); + vpnUidDefaultCallback.assertNoCallback(); + vpnDefaultCallbackAsUid.assertNoCallback(); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); @@ -7548,6 +7657,8 @@ public class ConnectivityServiceTest { defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent); assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent); vpnUidCallback.assertNoCallback(); + vpnUidDefaultCallback.assertNoCallback(); + vpnDefaultCallbackAsUid.assertNoCallback(); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED); @@ -7559,6 +7670,8 @@ public class ConnectivityServiceTest { defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent); assertBlockedCallbackInAnyOrder(callback, false, mWiFiNetworkAgent, mCellNetworkAgent); vpnUidCallback.assertNoCallback(); + vpnUidDefaultCallback.assertNoCallback(); + vpnDefaultCallbackAsUid.assertNoCallback(); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); @@ -7573,6 +7686,8 @@ public class ConnectivityServiceTest { callback.assertNoCallback(); defaultCallback.assertNoCallback(); vpnUidCallback.assertNoCallback(); + vpnUidDefaultCallback.assertNoCallback(); + vpnDefaultCallbackAsUid.assertNoCallback(); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); @@ -7584,6 +7699,8 @@ public class ConnectivityServiceTest { callback.assertNoCallback(); defaultCallback.assertNoCallback(); vpnUidCallback.assertNoCallback(); + vpnUidDefaultCallback.assertNoCallback(); + vpnDefaultCallbackAsUid.assertNoCallback(); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); @@ -7596,6 +7713,8 @@ public class ConnectivityServiceTest { defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent); assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent); vpnUidCallback.assertNoCallback(); + vpnUidDefaultCallback.assertNoCallback(); + vpnDefaultCallbackAsUid.assertNoCallback(); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED); @@ -7606,6 +7725,8 @@ public class ConnectivityServiceTest { assertUidRangesUpdatedForMyUid(true); defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn); vpnUidCallback.assertNoCallback(); // vpnUidCallback has NOT_VPN capability. + vpnUidDefaultCallback.assertNoCallback(); // VPN does not apply to VPN_UID + vpnDefaultCallbackAsUid.assertNoCallback(); assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork()); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); @@ -7616,11 +7737,16 @@ public class ConnectivityServiceTest { mMockVpn.disconnect(); defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn); defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent); + vpnUidCallback.assertNoCallback(); + vpnUidDefaultCallback.assertNoCallback(); + vpnDefaultCallbackAsUid.assertNoCallback(); assertNull(mCm.getActiveNetwork()); mCm.unregisterNetworkCallback(callback); mCm.unregisterNetworkCallback(defaultCallback); mCm.unregisterNetworkCallback(vpnUidCallback); + mCm.unregisterNetworkCallback(vpnUidDefaultCallback); + mCm.unregisterNetworkCallback(vpnDefaultCallbackAsUid); } private void setupLegacyLockdownVpn() { @@ -7642,7 +7768,7 @@ public class ConnectivityServiceTest { assertNotNull(underlying); mMockVpn.setVpnType(VpnManager.TYPE_VPN_LEGACY); // The legacy lockdown VPN only supports userId 0. - final Set<UidRange> ranges = Collections.singleton(createUidRange(PRIMARY_USER)); + final Set<UidRange> ranges = Collections.singleton(PRIMARY_UIDRANGE); mMockVpn.registerAgent(ranges); mMockVpn.setUnderlyingNetworks(new Network[]{underlying}); mMockVpn.connect(true); @@ -8604,7 +8730,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); + final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE); mMockVpn.establish(lp, VPN_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, VPN_UID); @@ -8632,7 +8758,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); + final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE); mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID); @@ -8648,7 +8774,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0")); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); + final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE); mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID); @@ -8663,7 +8789,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); + final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE); mMockVpn.establish(lp, VPN_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, VPN_UID); @@ -8715,7 +8841,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. - final UidRange vpnRange = createUidRange(PRIMARY_USER); + final UidRange vpnRange = PRIMARY_UIDRANGE; final Set<UidRange> vpnRanges = Collections.singleton(vpnRange); mMockVpn.establish(lp, VPN_UID, vpnRanges); assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID); @@ -8820,29 +8946,34 @@ public class ConnectivityServiceTest { final NetworkCapabilities netCap = new NetworkCapabilities().setOwnerUid(ownerUid); return mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled( - netCap, includeLocationSensitiveInfo, callerUid, + netCap, includeLocationSensitiveInfo, Process.myUid(), callerUid, mContext.getPackageName(), getAttributionTag()) .getOwnerUid(); } - private void verifyWifiInfoCopyNetCapsPermission( + private void verifyTransportInfoCopyNetCapsPermission( int callerUid, boolean includeLocationSensitiveInfo, boolean shouldMakeCopyWithLocationSensitiveFieldsParcelable) { - final WifiInfo wifiInfo = mock(WifiInfo.class); - when(wifiInfo.hasLocationSensitiveFields()).thenReturn(true); - final NetworkCapabilities netCap = new NetworkCapabilities().setTransportInfo(wifiInfo); + final TransportInfo transportInfo = mock(TransportInfo.class); + when(transportInfo.getApplicableRedactions()).thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION); + final NetworkCapabilities netCap = + new NetworkCapabilities().setTransportInfo(transportInfo); mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled( - netCap, includeLocationSensitiveInfo, callerUid, + netCap, includeLocationSensitiveInfo, Process.myPid(), callerUid, mContext.getPackageName(), getAttributionTag()); - verify(wifiInfo).makeCopy(eq(shouldMakeCopyWithLocationSensitiveFieldsParcelable)); + if (shouldMakeCopyWithLocationSensitiveFieldsParcelable) { + verify(transportInfo).makeCopy(REDACT_NONE); + } else { + verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION); + } } - private void verifyOwnerUidAndWifiInfoNetCapsPermission( + private void verifyOwnerUidAndTransportInfoNetCapsPermission( boolean shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag, boolean shouldInclLocationSensitiveOwnerUidWithIncludeFlag, - boolean shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag, - boolean shouldInclLocationSensitiveWifiInfoWithIncludeFlag) { + boolean shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag, + boolean shouldInclLocationSensitiveTransportInfoWithIncludeFlag) { final int myUid = Process.myUid(); final int expectedOwnerUidWithoutIncludeFlag = @@ -8856,13 +8987,13 @@ public class ConnectivityServiceTest { assertEquals(expectedOwnerUidWithIncludeFlag, getOwnerUidNetCapsPermission( myUid, myUid, true /* includeLocationSensitiveInfo */)); - verifyWifiInfoCopyNetCapsPermission(myUid, + verifyTransportInfoCopyNetCapsPermission(myUid, false, /* includeLocationSensitiveInfo */ - shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag); + shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag); - verifyWifiInfoCopyNetCapsPermission(myUid, + verifyTransportInfoCopyNetCapsPermission(myUid, true, /* includeLocationSensitiveInfo */ - shouldInclLocationSensitiveWifiInfoWithIncludeFlag); + shouldInclLocationSensitiveTransportInfoWithIncludeFlag); } @@ -8872,15 +9003,15 @@ public class ConnectivityServiceTest { setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); - verifyOwnerUidAndWifiInfoNetCapsPermission( + verifyOwnerUidAndTransportInfoNetCapsPermission( // Ensure that we include owner uid even if the request asks to remove it since the // app has necessary permissions and targetSdk < S. true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */ - false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */ + false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */ // Ensure that we remove location info if the request asks to remove it even if the // app has necessary permissions. - true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */ + true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */ ); } @@ -8890,15 +9021,15 @@ public class ConnectivityServiceTest { setupLocationPermissions(Build.VERSION_CODES.R, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); - verifyOwnerUidAndWifiInfoNetCapsPermission( + verifyOwnerUidAndTransportInfoNetCapsPermission( // Ensure that we include owner uid even if the request asks to remove it since the // app has necessary permissions and targetSdk < S. true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */ - false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */ + false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */ // Ensure that we remove location info if the request asks to remove it even if the // app has necessary permissions. - true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */ + true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */ ); } @@ -8909,15 +9040,15 @@ public class ConnectivityServiceTest { setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); - verifyOwnerUidAndWifiInfoNetCapsPermission( + verifyOwnerUidAndTransportInfoNetCapsPermission( // Ensure that we owner UID if the request asks us to remove it even if the app // has necessary permissions since targetSdk >= S. false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */ - false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */ + false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */ // Ensure that we remove location info if the request asks to remove it even if the // app has necessary permissions. - true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */ + true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */ ); } @@ -8927,15 +9058,15 @@ public class ConnectivityServiceTest { setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION); - verifyOwnerUidAndWifiInfoNetCapsPermission( + verifyOwnerUidAndTransportInfoNetCapsPermission( // Ensure that we owner UID if the request asks us to remove it even if the app // has necessary permissions since targetSdk >= S. true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */ - false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */ + false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */ // Ensure that we remove location info if the request asks to remove it even if the // app has necessary permissions. - true /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */ + true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */ ); } @@ -8945,11 +9076,11 @@ public class ConnectivityServiceTest { setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); - verifyOwnerUidAndWifiInfoNetCapsPermission( + verifyOwnerUidAndTransportInfoNetCapsPermission( false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */ false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */ - false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */ - false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */ + false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */ + false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */ ); } @@ -8972,11 +9103,11 @@ public class ConnectivityServiceTest { setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION); - verifyOwnerUidAndWifiInfoNetCapsPermission( + verifyOwnerUidAndTransportInfoNetCapsPermission( false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */ false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */ - false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */ - false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */ + false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */ + false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */ ); } @@ -8986,17 +9117,196 @@ public class ConnectivityServiceTest { // Test that not having fine location permission leads to sanitization. setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */); - verifyOwnerUidAndWifiInfoNetCapsPermission( + verifyOwnerUidAndTransportInfoNetCapsPermission( false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */ false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */ - false, /* shouldInclLocationSensitiveWifiInfoWithoutIncludeFlag */ - false /* shouldInclLocationSensitiveWifiInfoWithIncludeFlag */ + false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */ + false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */ ); } + @Test + public void testCreateForCallerWithLocalMacAddressSanitizedWithLocalMacAddressPermission() + throws Exception { + mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_GRANTED); + + final TransportInfo transportInfo = mock(TransportInfo.class); + when(transportInfo.getApplicableRedactions()) + .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS); + final NetworkCapabilities netCap = + new NetworkCapabilities().setTransportInfo(transportInfo); + + mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled( + netCap, false /* includeLocationSensitiveInfoInTransportInfo */, + Process.myPid(), Process.myUid(), + mContext.getPackageName(), getAttributionTag()); + // don't redact MAC_ADDRESS fields, only location sensitive fields. + verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION); + } + + @Test + public void testCreateForCallerWithLocalMacAddressSanitizedWithoutLocalMacAddressPermission() + throws Exception { + mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_DENIED); + + final TransportInfo transportInfo = mock(TransportInfo.class); + when(transportInfo.getApplicableRedactions()) + .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS); + final NetworkCapabilities netCap = + new NetworkCapabilities().setTransportInfo(transportInfo); + + mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled( + netCap, false /* includeLocationSensitiveInfoInTransportInfo */, + Process.myPid(), Process.myUid(), + mContext.getPackageName(), getAttributionTag()); + // redact both MAC_ADDRESS & location sensitive fields. + verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION + | REDACT_FOR_LOCAL_MAC_ADDRESS); + } + + @Test + public void testCreateForCallerWithLocalMacAddressSanitizedWithSettingsPermission() + throws Exception { + mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED); + + final TransportInfo transportInfo = mock(TransportInfo.class); + when(transportInfo.getApplicableRedactions()) + .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS); + final NetworkCapabilities netCap = + new NetworkCapabilities().setTransportInfo(transportInfo); + + mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled( + netCap, false /* includeLocationSensitiveInfoInTransportInfo */, + Process.myPid(), Process.myUid(), + mContext.getPackageName(), getAttributionTag()); + // don't redact NETWORK_SETTINGS fields, only location sensitive fields. + verify(transportInfo).makeCopy(REDACT_FOR_ACCESS_FINE_LOCATION); + } + + @Test + public void testCreateForCallerWithLocalMacAddressSanitizedWithoutSettingsPermission() + throws Exception { + mServiceContext.setPermission(Manifest.permission.LOCAL_MAC_ADDRESS, PERMISSION_DENIED); + + final TransportInfo transportInfo = mock(TransportInfo.class); + when(transportInfo.getApplicableRedactions()) + .thenReturn(REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS); + final NetworkCapabilities netCap = + new NetworkCapabilities().setTransportInfo(transportInfo); + + mService.createWithLocationInfoSanitizedIfNecessaryWhenParceled( + netCap, false /* includeLocationSensitiveInfoInTransportInfo */, + Process.myPid(), Process.myUid(), + mContext.getPackageName(), getAttributionTag()); + // redact both NETWORK_SETTINGS & location sensitive fields. + verify(transportInfo).makeCopy( + REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_NETWORK_SETTINGS); + } + + /** + * Test TransportInfo to verify redaction mechanism. + */ + private static class TestTransportInfo implements TransportInfo { + public final boolean locationRedacted; + public final boolean localMacAddressRedacted; + public final boolean settingsRedacted; + + TestTransportInfo() { + locationRedacted = false; + localMacAddressRedacted = false; + settingsRedacted = false; + } + + TestTransportInfo(boolean locationRedacted, boolean localMacAddressRedacted, + boolean settingsRedacted) { + this.locationRedacted = locationRedacted; + this.localMacAddressRedacted = + localMacAddressRedacted; + this.settingsRedacted = settingsRedacted; + } + + @Override + public TransportInfo makeCopy(@NetworkCapabilities.RedactionType long redactions) { + return new TestTransportInfo( + (redactions & REDACT_FOR_ACCESS_FINE_LOCATION) != 0, + (redactions & REDACT_FOR_LOCAL_MAC_ADDRESS) != 0, + (redactions & REDACT_FOR_NETWORK_SETTINGS) != 0 + ); + } + + @Override + public @NetworkCapabilities.RedactionType long getApplicableRedactions() { + return REDACT_FOR_ACCESS_FINE_LOCATION | REDACT_FOR_LOCAL_MAC_ADDRESS + | REDACT_FOR_NETWORK_SETTINGS; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof TestTransportInfo)) return false; + TestTransportInfo that = (TestTransportInfo) other; + return that.locationRedacted == this.locationRedacted + && that.localMacAddressRedacted == this.localMacAddressRedacted + && that.settingsRedacted == this.settingsRedacted; + } + + @Override + public int hashCode() { + return Objects.hash(locationRedacted, localMacAddressRedacted, settingsRedacted); + } + } + + private void verifyNetworkCallbackLocationDataInclusionUsingTransportInfoAndOwnerUidInNetCaps( + @NonNull TestNetworkCallback wifiNetworkCallback, int actualOwnerUid, + @NonNull TransportInfo actualTransportInfo, int expectedOwnerUid, + @NonNull TransportInfo expectedTransportInfo) throws Exception { + when(mPackageManager.getTargetSdkVersion(anyString())).thenReturn(Build.VERSION_CODES.S); + final NetworkCapabilities ncTemplate = + new NetworkCapabilities() + .addTransportType(TRANSPORT_WIFI) + .setOwnerUid(actualOwnerUid); + + final NetworkRequest wifiRequest = new NetworkRequest.Builder() + .addTransportType(TRANSPORT_WIFI).build(); + mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback); + + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(), + ncTemplate); + mWiFiNetworkAgent.connect(false); + + wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + + // Send network capabilities update with TransportInfo to trigger capabilities changed + // callback. + mWiFiNetworkAgent.setNetworkCapabilities( + ncTemplate.setTransportInfo(actualTransportInfo), true); + + wifiNetworkCallback.expectCapabilitiesThat(mWiFiNetworkAgent, + nc -> Objects.equals(expectedOwnerUid, nc.getOwnerUid()) + && Objects.equals(expectedTransportInfo, nc.getTransportInfo())); + + } + + @Test + public void testVerifyLocationDataIsNotIncludedWhenInclFlagNotSet() throws Exception { + final TestNetworkCallback wifiNetworkCallack = new TestNetworkCallback(); + final int ownerUid = Process.myUid(); + final TransportInfo transportInfo = new TestTransportInfo(); + // Even though the test uid holds privileged permissions, mask location fields since + // the callback did not explicitly opt-in to get location data. + final TransportInfo sanitizedTransportInfo = new TestTransportInfo( + true, /* locationRedacted */ + true, /* localMacAddressRedacted */ + true /* settingsRedacted */ + ); + // Should not expect location data since the callback does not set the flag for including + // location data. + verifyNetworkCallbackLocationDataInclusionUsingTransportInfoAndOwnerUidInNetCaps( + wifiNetworkCallack, ownerUid, transportInfo, INVALID_UID, sanitizedTransportInfo); + } + private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType) throws Exception { - final Set<UidRange> vpnRange = Collections.singleton(createUidRange(PRIMARY_USER)); + final Set<UidRange> vpnRange = Collections.singleton(PRIMARY_UIDRANGE); mMockVpn.setVpnType(vpnType); mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid); @@ -9538,10 +9848,12 @@ public class ConnectivityServiceTest { assertContainsExactly(exemptUidCaptor.getValue(), Process.VPN_UID, exemptUid); if (add) { - inOrder.verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetId()), + inOrder.verify(mMockNetd, times(1)) + .networkAddUidRanges(eq(mMockVpn.getNetwork().getNetId()), eq(toUidRangeStableParcels(vpnRanges))); } else { - inOrder.verify(mMockNetd, times(1)).networkRemoveUidRanges(eq(mMockVpn.getNetId()), + inOrder.verify(mMockNetd, times(1)) + .networkRemoveUidRanges(eq(mMockVpn.getNetwork().getNetId()), eq(toUidRangeStableParcels(vpnRanges))); } @@ -9556,7 +9868,7 @@ public class ConnectivityServiceTest { lp.setInterfaceName("tun0"); lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); - final UidRange vpnRange = createUidRange(PRIMARY_USER); + final UidRange vpnRange = PRIMARY_UIDRANGE; Set<UidRange> vpnRanges = Collections.singleton(vpnRange); mMockVpn.establish(lp, VPN_UID, vpnRanges); assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID); @@ -9582,8 +9894,8 @@ public class ConnectivityServiceTest { for (int reqTypeInt : invalidReqTypeInts) { assertThrows("Expect throws for invalid request type " + reqTypeInt, IllegalArgumentException.class, - () -> mService.requestNetwork(nc, reqTypeInt, null, 0, null, - ConnectivityManager.TYPE_NONE, NetworkCallback.FLAG_NONE, + () -> mService.requestNetwork(Process.INVALID_UID, nc, reqTypeInt, null, 0, + null, ConnectivityManager.TYPE_NONE, NetworkCallback.FLAG_NONE, mContext.getPackageName(), getAttributionTag()) ); } @@ -9702,7 +10014,7 @@ public class ConnectivityServiceTest { && session.getSessionType() == QosSession.TYPE_EPS_BEARER), eq(attributes)); mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent() - .sendQosSessionLost(qosCallbackId, sessionId); + .sendQosSessionLost(qosCallbackId, sessionId, QosSession.TYPE_EPS_BEARER); waitForIdle(); verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session -> session.getSessionId() == sessionId @@ -9710,6 +10022,36 @@ public class ConnectivityServiceTest { } @Test + public void testNrQosCallbackAvailableAndLost() throws Exception { + mQosCallbackMockHelper = new QosCallbackMockHelper(); + final int sessionId = 10; + final int qosCallbackId = 1; + + when(mQosCallbackMockHelper.mFilter.validate()) + .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE); + mQosCallbackMockHelper.registerQosCallback( + mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback); + waitForIdle(); + + final NrQosSessionAttributes attributes = new NrQosSessionAttributes( + 1, 2, 3, 4, 5, 6, 7, new ArrayList<>()); + mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent() + .sendQosSessionAvailable(qosCallbackId, sessionId, attributes); + waitForIdle(); + + verify(mQosCallbackMockHelper.mCallback).onNrQosSessionAvailable(argThat(session -> + session.getSessionId() == sessionId + && session.getSessionType() == QosSession.TYPE_NR_BEARER), eq(attributes)); + + mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent() + .sendQosSessionLost(qosCallbackId, sessionId, QosSession.TYPE_NR_BEARER); + waitForIdle(); + verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session -> + session.getSessionId() == sessionId + && session.getSessionType() == QosSession.TYPE_NR_BEARER)); + } + + @Test public void testQosCallbackTooManyRequests() throws Exception { mQosCallbackMockHelper = new QosCallbackMockHelper(); @@ -9754,7 +10096,7 @@ public class ConnectivityServiceTest { .thenReturn(hasFeature); } - private UidRange getNriFirstUidRange( + private Range<Integer> getNriFirstUidRange( @NonNull final ConnectivityService.NetworkRequestInfo nri) { return nri.mRequests.get(0).networkCapabilities.getUids().iterator().next(); } @@ -9937,11 +10279,11 @@ public class ConnectivityServiceTest { pref)); // Sort by uid to access nris by index - nris.sort(Comparator.comparingInt(nri -> getNriFirstUidRange(nri).start)); - assertEquals(TEST_PACKAGE_UID, getNriFirstUidRange(nris.get(0)).start); - assertEquals(TEST_PACKAGE_UID, getNriFirstUidRange(nris.get(0)).stop); - assertEquals(testPackageNameUid2, getNriFirstUidRange(nris.get(1)).start); - assertEquals(testPackageNameUid2, getNriFirstUidRange(nris.get(1)).stop); + nris.sort(Comparator.comparingInt(nri -> getNriFirstUidRange(nri).getLower())); + assertEquals(TEST_PACKAGE_UID, (int) getNriFirstUidRange(nris.get(0)).getLower()); + assertEquals(TEST_PACKAGE_UID, (int) getNriFirstUidRange(nris.get(0)).getUpper()); + assertEquals(testPackageNameUid2, (int) getNriFirstUidRange(nris.get(1)).getLower()); + assertEquals(testPackageNameUid2, (int) getNriFirstUidRange(nris.get(1)).getUpper()); } @Test @@ -9971,17 +10313,17 @@ public class ConnectivityServiceTest { // UIDs for all users and all managed packages should be present. // Two users each with two packages. final int expectedUidSize = 2; - final List<UidRange> uids = + final List<Range<Integer>> uids = new ArrayList<>(nris.get(0).mRequests.get(0).networkCapabilities.getUids()); assertEquals(expectedUidSize, uids.size()); // Sort by uid to access nris by index - uids.sort(Comparator.comparingInt(uid -> uid.start)); + uids.sort(Comparator.comparingInt(uid -> uid.getLower())); final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID); - assertEquals(TEST_PACKAGE_UID, uids.get(0).start); - assertEquals(TEST_PACKAGE_UID, uids.get(0).stop); - assertEquals(secondUserTestPackageUid, uids.get(1).start); - assertEquals(secondUserTestPackageUid, uids.get(1).stop); + assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getLower()); + assertEquals(TEST_PACKAGE_UID, (int) uids.get(0).getUpper()); + assertEquals(secondUserTestPackageUid, (int) uids.get(1).getLower()); + assertEquals(secondUserTestPackageUid, (int) uids.get(1).getUpper()); } @Test @@ -10154,6 +10496,7 @@ public class ConnectivityServiceTest { mCm.registerDefaultNetworkCallback(mDefaultNetworkCallback); registerDefaultNetworkCallbackAsUid(mProfileDefaultNetworkCallback, TEST_WORK_PROFILE_APP_UID); + // TODO: test using ConnectivityManager#registerDefaultNetworkCallbackAsUid as well. mServiceContext.setPermission( Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED); } @@ -10173,7 +10516,7 @@ public class ConnectivityServiceTest { private void setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest( @OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup) throws Exception { - final int testPackageNameUid = 123; + final int testPackageNameUid = TEST_PACKAGE_UID; final String testPackageName = "per.app.defaults.package"; setupMultipleDefaultNetworksForOemNetworkPreferenceTest( networkPrefToSetup, testPackageNameUid, testPackageName); @@ -10309,6 +10652,11 @@ public class ConnectivityServiceTest { mCm.registerDefaultNetworkCallback(defaultNetworkCallback); defaultNetworkCallback.assertNoCallback(); + final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback(); + withPermission(Manifest.permission.NETWORK_SETTINGS, () -> + mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback, + new Handler(ConnectivityThread.getInstanceLooper()))); + // Setup the test process to use networkPref for their default network. setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref); @@ -10319,19 +10667,22 @@ public class ConnectivityServiceTest { null, mEthernetNetworkAgent.getNetwork()); - // At this point with a restricted network used, the available callback should trigger + // At this point with a restricted network used, the available callback should trigger. defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent); assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mEthernetNetworkAgent.getNetwork()); + otherUidDefaultCallback.assertNoCallback(); // Now bring down the default network which should trigger a LOST callback. setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false); // At this point, with no network is available, the lost callback should trigger defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent); + otherUidDefaultCallback.assertNoCallback(); // Confirm we can unregister without issues. mCm.unregisterNetworkCallback(defaultNetworkCallback); + mCm.unregisterNetworkCallback(otherUidDefaultCallback); } @Test @@ -10349,6 +10700,11 @@ public class ConnectivityServiceTest { mCm.registerDefaultNetworkCallback(defaultNetworkCallback); defaultNetworkCallback.assertNoCallback(); + final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback(); + withPermission(Manifest.permission.NETWORK_SETTINGS, () -> + mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback, + new Handler(ConnectivityThread.getInstanceLooper()))); + // Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID. // The active nai for the default is null at this point as this is a restricted network. setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true); @@ -10360,15 +10716,19 @@ public class ConnectivityServiceTest { defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent); assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mEthernetNetworkAgent.getNetwork()); + otherUidDefaultCallback.assertNoCallback(); // Now bring down the default network which should trigger a LOST callback. setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false); + otherUidDefaultCallback.assertNoCallback(); // At this point, with no network is available, the lost callback should trigger defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent); + otherUidDefaultCallback.assertNoCallback(); // Confirm we can unregister without issues. mCm.unregisterNetworkCallback(defaultNetworkCallback); + mCm.unregisterNetworkCallback(otherUidDefaultCallback); } @Test @@ -10382,6 +10742,11 @@ public class ConnectivityServiceTest { mCm.registerDefaultNetworkCallback(defaultNetworkCallback); defaultNetworkCallback.assertNoCallback(); + final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback(); + withPermission(Manifest.permission.NETWORK_SETTINGS, () -> + mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback, + new Handler(ConnectivityThread.getInstanceLooper()))); + // Setup a process different than the test process to use the default network. This means // that the defaultNetworkCallback won't be tracked by the per-app policy. setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(networkPref); @@ -10397,6 +10762,9 @@ public class ConnectivityServiceTest { defaultNetworkCallback.assertNoCallback(); assertDefaultNetworkCapabilities(userId /* no networks */); + // The other UID does have access, and gets a callback. + otherUidDefaultCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent); + // Bring up unrestricted cellular. This should now satisfy the default network. setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true); verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize, @@ -10404,25 +10772,31 @@ public class ConnectivityServiceTest { mEthernetNetworkAgent.getNetwork()); // At this point with an unrestricted network used, the available callback should trigger + // The other UID is unaffected and remains on the paid network. defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCellNetworkAgent.getNetwork()); assertDefaultNetworkCapabilities(userId, mCellNetworkAgent); + otherUidDefaultCallback.assertNoCallback(); // Now bring down the per-app network. setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false); - // Since the callback didn't use the per-app network, no callback should fire. + // Since the callback didn't use the per-app network, only the other UID gets a callback. + // Because the preference specifies no fallback, it does not switch to cellular. defaultNetworkCallback.assertNoCallback(); + otherUidDefaultCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent); // Now bring down the default network. setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false); // As this callback was tracking the default, this should now trigger. defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent); + otherUidDefaultCallback.assertNoCallback(); // Confirm we can unregister without issues. mCm.unregisterNetworkCallback(defaultNetworkCallback); + mCm.unregisterNetworkCallback(otherUidDefaultCallback); } /** diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java index ff8c632833f2..3adf08c19986 100644 --- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java +++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java @@ -20,6 +20,7 @@ import static com.android.server.connectivity.NetworkNotificationManager.Notific import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; @@ -35,6 +36,7 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Resources; +import android.net.ConnectivityResources; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.os.UserHandle; @@ -43,9 +45,10 @@ import android.telephony.TelephonyManager; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.internal.R; +import com.android.connectivity.resources.R; import com.android.server.connectivity.NetworkNotificationManager.NotificationType; +import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -119,11 +122,25 @@ public class NetworkNotificationManagerTest { when(mCtx.getSystemService(eq(Context.NOTIFICATION_SERVICE))) .thenReturn(mNotificationManager); when(mNetworkInfo.getExtraInfo()).thenReturn(TEST_EXTRA_INFO); + ConnectivityResources.setResourcesContextForTest(mCtx); when(mResources.getColor(anyInt(), any())).thenReturn(0xFF607D8B); + // Come up with some credible-looking transport names. The actual values do not matter. + String[] transportNames = new String[NetworkCapabilities.MAX_TRANSPORT + 1]; + for (int transport = 0; transport <= NetworkCapabilities.MAX_TRANSPORT; transport++) { + transportNames[transport] = NetworkCapabilities.transportNameOf(transport); + } + when(mResources.getStringArray(R.array.network_switch_type_name)) + .thenReturn(transportNames); + mManager = new NetworkNotificationManager(mCtx, mTelephonyManager); } + @After + public void tearDown() { + ConnectivityResources.setResourcesContextForTest(null); + } + private void verifyTitleByNetwork(final int id, final NetworkAgentInfo nai, final int title) { final String tag = NetworkNotificationManager.tagFor(id); mManager.showNotification(id, PRIVATE_DNS_BROKEN, nai, null, null, true); @@ -142,15 +159,15 @@ public class NetworkNotificationManagerTest { public void testTitleOfPrivateDnsBroken() { // Test the title of mobile data. verifyTitleByNetwork(100, mCellNai, R.string.mobile_no_internet); - reset(mResources); + clearInvocations(mResources); // Test the title of wifi. verifyTitleByNetwork(101, mWifiNai, R.string.wifi_no_internet); - reset(mResources); + clearInvocations(mResources); // Test the title of other networks. verifyTitleByNetwork(102, mVpnNai, R.string.other_networks_no_internet); - reset(mResources); + clearInvocations(mResources); } @Test diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index 11fcea60d98d..6ad4900989f5 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -23,6 +23,7 @@ import static android.content.pm.UserInfo.FLAG_RESTRICTED; import static android.net.ConnectivityManager.NetworkCallback; import static android.net.INetd.IF_STATE_DOWN; import static android.net.INetd.IF_STATE_UP; +import static android.os.UserHandle.PER_USER_RANGE; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -74,7 +75,6 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo.DetailedState; import android.net.RouteInfo; -import android.net.UidRange; import android.net.UidRangeParcel; import android.net.VpnManager; import android.net.VpnService; @@ -181,8 +181,7 @@ public class VpnTest { mPackages.put(PKGS[i], PKG_UIDS[i]); } } - private static final UidRange PRI_USER_RANGE = - UidRange.createForUser(UserHandle.of(primaryUser.id)); + private static final Range<Integer> PRI_USER_RANGE = uidRangeForUser(primaryUser.id); @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock private UserManager mUserManager; @@ -260,6 +259,21 @@ public class VpnTest { .thenReturn(tunnelResp); } + private Set<Range<Integer>> rangeSet(Range<Integer> ... ranges) { + final Set<Range<Integer>> range = new ArraySet<>(); + for (Range<Integer> r : ranges) range.add(r); + + return range; + } + + private static Range<Integer> uidRangeForUser(int userId) { + return new Range<Integer>(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1); + } + + private Range<Integer> uidRange(int start, int stop) { + return new Range<Integer>(start, stop); + } + @Test public void testRestrictedProfilesAreAddedToVpn() { setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB); @@ -268,12 +282,10 @@ public class VpnTest { // Assume the user can have restricted profiles. doReturn(true).when(mUserManager).canHaveRestrictedProfile(); - final Set<UidRange> ranges = + final Set<Range<Integer>> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null); - assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { - PRI_USER_RANGE, UidRange.createForUser(UserHandle.of(restrictedProfileA.id)) - })), ranges); + assertEquals(rangeSet(PRI_USER_RANGE, uidRangeForUser(restrictedProfileA.id)), ranges); } @Test @@ -281,10 +293,10 @@ public class VpnTest { setMockedUsers(primaryUser, managedProfileA); final Vpn vpn = createVpn(primaryUser.id); - final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, + final Set<Range<Integer>> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null); - assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { PRI_USER_RANGE })), ranges); + assertEquals(rangeSet(PRI_USER_RANGE), ranges); } @Test @@ -292,35 +304,38 @@ public class VpnTest { setMockedUsers(primaryUser, restrictedProfileA, managedProfileA); final Vpn vpn = createVpn(primaryUser.id); - final Set<UidRange> ranges = new ArraySet<>(); + final Set<Range<Integer>> ranges = new ArraySet<>(); vpn.addUserToRanges(ranges, primaryUser.id, null, null); - assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { PRI_USER_RANGE })), ranges); + assertEquals(rangeSet(PRI_USER_RANGE), ranges); } @Test public void testUidAllowAndDenylist() throws Exception { final Vpn vpn = createVpn(primaryUser.id); - final UidRange user = PRI_USER_RANGE; + final Range<Integer> user = PRI_USER_RANGE; + final int userStart = user.getLower(); + final int userStop = user.getUpper(); final String[] packages = {PKGS[0], PKGS[1], PKGS[2]}; // Allowed list - final Set<UidRange> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, - Arrays.asList(packages), null); - assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { - new UidRange(user.start + PKG_UIDS[0], user.start + PKG_UIDS[0]), - new UidRange(user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]) - })), allow); + final Set<Range<Integer>> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, + Arrays.asList(packages), null /* disallowedApplications */); + assertEquals(rangeSet( + uidRange(userStart + PKG_UIDS[0], userStart + PKG_UIDS[0]), + uidRange(userStart + PKG_UIDS[1], userStart + PKG_UIDS[2])), + allow); // Denied list - final Set<UidRange> disallow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, - null, Arrays.asList(packages)); - assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { - new UidRange(user.start, user.start + PKG_UIDS[0] - 1), - new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1), - /* Empty range between UIDS[1] and UIDS[2], should be excluded, */ - new UidRange(user.start + PKG_UIDS[2] + 1, user.stop) - })), disallow); + final Set<Range<Integer>> disallow = + vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, + null /* allowedApplications */, Arrays.asList(packages)); + assertEquals(rangeSet( + uidRange(userStart, userStart + PKG_UIDS[0] - 1), + uidRange(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1), + /* Empty range between UIDS[1] and UIDS[2], should be excluded, */ + uidRange(userStart + PKG_UIDS[2] + 1, userStop)), + disallow); } @Test @@ -350,84 +365,86 @@ public class VpnTest { @Test public void testLockdownChangingPackage() throws Exception { final Vpn vpn = createVpn(primaryUser.id); - final UidRange user = PRI_USER_RANGE; - + final Range<Integer> user = PRI_USER_RANGE; + final int userStart = user.getLower(); + final int userStop = user.getUpper(); // Set always-on without lockdown. assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null)); // Set always-on with lockdown. 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) + new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1), + new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop) })); // Switch to another app. 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) + new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1), + new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop) })); verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { - new UidRangeParcel(user.start, user.start + PKG_UIDS[3] - 1), - new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop) + new UidRangeParcel(userStart, userStart + PKG_UIDS[3] - 1), + new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop) })); } @Test public void testLockdownAllowlist() throws Exception { final Vpn vpn = createVpn(primaryUser.id); - final UidRange user = PRI_USER_RANGE; - + final Range<Integer> user = PRI_USER_RANGE; + final int userStart = user.getLower(); + final int userStop = user.getUpper(); // Set always-on with lockdown and allow app PKGS[2] from lockdown. assertTrue(vpn.setAlwaysOnPackage( 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) + verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { + new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1), + new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop) })); // Change allowed app list to PKGS[3]. assertTrue(vpn.setAlwaysOnPackage( PKGS[1], true, Collections.singletonList(PKGS[3]))); verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] { - new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop) + new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop) })); verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { - new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1), - new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop) + new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1), + new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop) })); // Change the VPN app. assertTrue(vpn.setAlwaysOnPackage( 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) + new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1), + new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1) })); verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { - new UidRangeParcel(user.start, user.start + PKG_UIDS[0] - 1), - new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1) + new UidRangeParcel(userStart, userStart + PKG_UIDS[0] - 1), + new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1) })); // Remove the list of allowed packages. 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) + new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1), + new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop) })); verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { - new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop), + new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStop), })); // Add the list of allowed packages. assertTrue(vpn.setAlwaysOnPackage( PKGS[0], true, Collections.singletonList(PKGS[1]))); verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] { - new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop) + new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStop) })); verify(mConnectivityManager).setRequireVpnForUids(true, 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) + new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1), + new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop) })); // Try allowing a package with a comma, should be rejected. @@ -439,12 +456,12 @@ public class VpnTest { assertTrue(vpn.setAlwaysOnPackage( 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) + new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1), + new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop) })); verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] { - new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1), - new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop) + new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[2] - 1), + new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop) })); } @@ -452,7 +469,7 @@ public class VpnTest { public void testLockdownRuleRepeatability() throws Exception { final Vpn vpn = createVpn(primaryUser.id); final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] { - new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)}; + new UidRangeParcel(PRI_USER_RANGE.getLower(), PRI_USER_RANGE.getUpper())}; // Given legacy lockdown is already enabled, vpn.setLockdown(true); verify(mConnectivityManager, times(1)).setRequireVpnForUids(true, @@ -484,7 +501,7 @@ public class VpnTest { public void testLockdownRuleReversibility() throws Exception { final Vpn vpn = createVpn(primaryUser.id); final UidRangeParcel[] entireUser = { - new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop) + new UidRangeParcel(PRI_USER_RANGE.getLower(), PRI_USER_RANGE.getUpper()) }; final UidRangeParcel[] exceptPkg0 = { new UidRangeParcel(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1), diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index 9334e2c4ad77..eeeb4fb1d929 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -89,6 +89,7 @@ import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.UnderlyingNetworkInfo; +import android.net.TelephonyNetworkSpecifier; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.os.ConditionVariable; import android.os.Handler; @@ -1280,6 +1281,77 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { } @Test + public void testDualVilteProviderStats() throws Exception { + // Pretend that network comes online. + expectDefaultSettings(); + final int subId1 = 1; + final int subId2 = 2; + final NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{ + buildImsState(IMSI_1, subId1, TEST_IFACE), + buildImsState(IMSI_2, subId2, TEST_IFACE2)}; + expectNetworkStatsSummary(buildEmptyStats()); + expectNetworkStatsUidDetail(buildEmptyStats()); + + // Register custom provider and retrieve callback. + final TestableNetworkStatsProviderBinder provider = + new TestableNetworkStatsProviderBinder(); + final INetworkStatsProviderCallback cb = + mService.registerNetworkStatsProvider("TEST", provider); + assertNotNull(cb); + + mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), + new UnderlyingNetworkInfo[0]); + + // Verifies that one requestStatsUpdate will be called during iface update. + provider.expectOnRequestStatsUpdate(0 /* unused */); + + // Create some initial traffic and report to the service. + incrementCurrentTime(HOUR_IN_MILLIS); + final String vtIface1 = NetworkStats.IFACE_VT + subId1; + final String vtIface2 = NetworkStats.IFACE_VT + subId2; + final NetworkStats expectedStats = new NetworkStats(0L, 1) + .addEntry(new NetworkStats.Entry(vtIface1, UID_RED, SET_DEFAULT, + TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, + 128L, 2L, 128L, 2L, 1L)) + .addEntry(new NetworkStats.Entry(vtIface2, UID_RED, SET_DEFAULT, + TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, + 64L, 1L, 64L, 1L, 1L)); + cb.notifyStatsUpdated(0 /* unused */, expectedStats, expectedStats); + + // Make another empty mutable stats object. This is necessary since the new NetworkStats + // object will be used to compare with the old one in NetworkStatsRecoder, two of them + // cannot be the same object. + expectNetworkStatsUidDetail(buildEmptyStats()); + + forcePollAndWaitForIdle(); + + // Verifies that one requestStatsUpdate and setAlert will be called during polling. + provider.expectOnRequestStatsUpdate(0 /* unused */); + provider.expectOnSetAlert(MB_IN_BYTES); + + // Verifies that service recorded history, does not verify uid tag part. + assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 1); + + // Verifies that onStatsUpdated updates the stats accordingly. + NetworkStats stats = mSession.getSummaryForAllUid( + sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true); + assertEquals(1, stats.size()); + assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 1L); + + stats = mSession.getSummaryForAllUid( + sTemplateImsi2, Long.MIN_VALUE, Long.MAX_VALUE, true); + assertEquals(1, stats.size()); + assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 1L); + + // Verifies that unregister the callback will remove the provider from service. + cb.unregister(); + forcePollAndWaitForIdle(); + provider.assertNoCallback(); + } + + @Test public void testStatsProviderSetAlert() throws Exception { // Pretend that network comes online. expectDefaultSettings(); @@ -1616,6 +1688,20 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { TYPE_MOBILE); } + private static NetworkStateSnapshot buildImsState( + String subscriberId, int subId, String ifaceName) { + final LinkProperties prop = new LinkProperties(); + prop.setInterfaceName(ifaceName); + final NetworkCapabilities capabilities = new NetworkCapabilities(); + capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, true); + capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true); + capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_IMS, true); + capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); + capabilities.setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)); + return new NetworkStateSnapshot( + MOBILE_NETWORK, capabilities, prop, subscriberId, TYPE_MOBILE); + } + private long getElapsedRealtime() { return mElapsedRealtime; } diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java index 7515971b8307..516c206672d2 100644 --- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java +++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java @@ -204,7 +204,7 @@ public class VcnManagerTest { new VcnStatusCallbackBinder(INLINE_EXECUTOR, mMockStatusCallback); cbBinder.onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE); - verify(mMockStatusCallback).onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE); + verify(mMockStatusCallback).onStatusChanged(VCN_STATUS_CODE_ACTIVE); cbBinder.onGatewayConnectionError( UNDERLYING_NETWORK_CAPABILITIES, diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index 814cad4ab448..f15d4204d125 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -19,6 +19,8 @@ package com.android.server; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; +import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback; @@ -32,9 +34,8 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; @@ -48,7 +49,9 @@ import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.app.AppOpsManager; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.NetworkCapabilities; @@ -239,9 +242,14 @@ public class VcnManagementServiceTest { doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO)) .when(mSubMgr) .getSubscriptionsInGroup(any()); - doReturn(isPrivileged) + doReturn(mTelMgr) .when(mTelMgr) - .hasCarrierPrivileges(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId())); + .createForSubscriptionId(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId())); + doReturn(isPrivileged + ? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS + : CARRIER_PRIVILEGE_STATUS_NO_ACCESS) + .when(mTelMgr) + .checkCarrierPrivilegesForPackage(eq(TEST_PACKAGE_NAME)); } @Test @@ -330,6 +338,13 @@ public class VcnManagementServiceTest { return captor.getValue(); } + private BroadcastReceiver getPackageChangeReceiver() { + final ArgumentCaptor<BroadcastReceiver> captor = + ArgumentCaptor.forClass(BroadcastReceiver.class); + verify(mMockContext).registerReceiver(captor.capture(), any(), any(), any()); + return captor.getValue(); + } + private Vcn startAndGetVcnInstance(ParcelUuid uuid) { mVcnMgmtSvc.setVcnConfig(uuid, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); return mVcnMgmtSvc.getAllVcns().get(uuid); @@ -392,7 +407,7 @@ public class VcnManagementServiceTest { mTestLooper.moveTimeForward( VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2); mTestLooper.dispatchAll(); - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME); final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2); // Verify that new instance was different, and the old one was torn down @@ -406,6 +421,42 @@ public class VcnManagementServiceTest { } @Test + public void testPackageChangeListenerRegistered() throws Exception { + verify(mMockContext).registerReceiver(any(BroadcastReceiver.class), argThat(filter -> { + return filter.hasAction(Intent.ACTION_PACKAGE_ADDED) + && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED) + && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED); + }), any(), any()); + } + + @Test + public void testPackageChangeListener_packageAdded() throws Exception { + final BroadcastReceiver receiver = getPackageChangeReceiver(); + + verify(mMockContext).registerReceiver(any(), argThat(filter -> { + return filter.hasAction(Intent.ACTION_PACKAGE_ADDED) + && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED) + && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED); + }), any(), any()); + + receiver.onReceive(mMockContext, new Intent(Intent.ACTION_PACKAGE_ADDED)); + verify(mSubscriptionTracker).handleSubscriptionsChanged(); + } + + @Test + public void testPackageChangeListener_packageRemoved() throws Exception { + final BroadcastReceiver receiver = getPackageChangeReceiver(); + + verify(mMockContext).registerReceiver(any(), argThat(filter -> { + return filter.hasAction(Intent.ACTION_PACKAGE_REMOVED) + && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED); + }), any(), any()); + + receiver.onReceive(mMockContext, new Intent(Intent.ACTION_PACKAGE_REMOVED)); + verify(mSubscriptionTracker).handleSubscriptionsChanged(); + } + + @Test public void testSetVcnConfigRequiresNonSystemServer() throws Exception { doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); @@ -493,7 +544,7 @@ public class VcnManagementServiceTest { doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid(); try { - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME); fail("Expected IllegalStateException exception for system server"); } catch (IllegalStateException expected) { } @@ -506,7 +557,7 @@ public class VcnManagementServiceTest { .getBinderCallingUid(); try { - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME); fail("Expected security exception for non system user"); } catch (SecurityException expected) { } @@ -517,15 +568,24 @@ public class VcnManagementServiceTest { setupMockedCarrierPrivilege(false); try { - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME); fail("Expected security exception for missing carrier privileges"); } catch (SecurityException expected) { } } @Test + public void testClearVcnConfigMismatchedPackages() throws Exception { + try { + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, "IncorrectPackage"); + fail("Expected security exception due to mismatched packages"); + } catch (SecurityException expected) { + } + } + + @Test public void testClearVcnConfig() throws Exception { - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME); assertTrue(mVcnMgmtSvc.getConfigs().isEmpty()); verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class)); } @@ -536,7 +596,7 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME); verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE); - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME); verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED); } @@ -565,7 +625,7 @@ public class VcnManagementServiceTest { verify(vcnInstance).updateConfig(TEST_VCN_CONFIG); // Verify Vcn is stopped if it was already started - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME); verify(vcnInstance).teardownAsynchronously(); } @@ -656,7 +716,7 @@ public class VcnManagementServiceTest { .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID)); } else if (transport == TRANSPORT_WIFI) { WifiInfo wifiInfo = mock(WifiInfo.class); - when(wifiInfo.makeCopy(anyBoolean())).thenReturn(wifiInfo); + when(wifiInfo.makeCopy(anyLong())).thenReturn(wifiInfo); when(mMockDeps.getSubIdForWifiInfo(eq(wifiInfo))).thenReturn(TEST_SUBSCRIPTION_ID); ncBuilder @@ -782,7 +842,7 @@ public class VcnManagementServiceTest { mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME); mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); - mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2); + mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME); verify(mMockPolicyListener).onPolicyChanged(); } diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java index 4fa63d4ff640..c853fc50fdf7 100644 --- a/tests/vcn/java/com/android/server/vcn/VcnTest.java +++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java @@ -29,6 +29,7 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -139,8 +140,7 @@ public class VcnTest { mTestLooper.dispatchAll(); } - @Test - public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() { + private void verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(boolean isActive) { final NetworkRequestListener requestListener = verifyAndGetRequestListener(); startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]); @@ -150,14 +150,27 @@ public class VcnTest { final TelephonySubscriptionSnapshot updatedSnapshot = mock(TelephonySubscriptionSnapshot.class); + mVcn.setIsActive(isActive); + mVcn.updateSubscriptionSnapshot(updatedSnapshot); mTestLooper.dispatchAll(); for (final VcnGatewayConnection gateway : gatewayConnections) { - verify(gateway).updateSubscriptionSnapshot(eq(updatedSnapshot)); + verify(gateway, isActive ? times(1) : never()) + .updateSubscriptionSnapshot(eq(updatedSnapshot)); } } + @Test + public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() { + verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(true /* isActive */); + } + + @Test + public void testSubscriptionSnapshotUpdatesVcnGatewayConnectionsWhileInactive() { + verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(false /* isActive */); + } + private void triggerVcnRequestListeners(NetworkRequestListener requestListener) { for (final int[] caps : TEST_CAPS) { startVcnGatewayWithCapabilities(requestListener, caps); @@ -187,7 +200,6 @@ public class VcnTest { NetworkRequestListener requestListener, Set<VcnGatewayConnection> expectedGatewaysTornDown) { assertFalse(mVcn.isActive()); - assertTrue(mVcn.getVcnGatewayConnections().isEmpty()); for (final VcnGatewayConnection gatewayConnection : expectedGatewaysTornDown) { verify(gatewayConnection).teardownAsynchronously(); } @@ -238,6 +250,51 @@ public class VcnTest { } @Test + public void testGatewayQuitWhileInactive() { + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); + final Set<VcnGatewayConnection> gatewayConnections = + new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener)); + + mVcn.teardownAsynchronously(); + mTestLooper.dispatchAll(); + + final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue(); + statusCallback.onQuit(); + mTestLooper.dispatchAll(); + + // Verify that the VCN requests the networkRequests be resent + assertEquals(1, mVcn.getVcnGatewayConnections().size()); + verify(mVcnNetworkProvider, never()).resendAllRequests(requestListener); + } + + @Test + public void testUpdateConfigReevaluatesGatewayConnections() { + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); + startGatewaysAndGetGatewayConnections(requestListener); + assertEquals(2, mVcn.getVcnGatewayConnectionConfigMap().size()); + + // Create VcnConfig with only one VcnGatewayConnectionConfig so a gateway connection is torn + // down + final VcnGatewayConnectionConfig activeConfig = + VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(TEST_CAPS[0]); + final VcnGatewayConnectionConfig removedConfig = + VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(TEST_CAPS[1]); + final VcnConfig updatedConfig = + new VcnConfig.Builder(mContext).addGatewayConnectionConfig(activeConfig).build(); + + mVcn.updateConfig(updatedConfig); + mTestLooper.dispatchAll(); + + final VcnGatewayConnection activeGatewayConnection = + mVcn.getVcnGatewayConnectionConfigMap().get(activeConfig); + final VcnGatewayConnection removedGatewayConnection = + mVcn.getVcnGatewayConnectionConfigMap().get(removedConfig); + verify(activeGatewayConnection, never()).teardownAsynchronously(); + verify(removedGatewayConnection).teardownAsynchronously(); + verify(mVcnNetworkProvider).resendAllRequests(requestListener); + } + + @Test public void testUpdateConfigExitsSafeMode() { final NetworkRequestListener requestListener = verifyAndGetRequestListener(); final Set<VcnGatewayConnection> gatewayConnections = @@ -261,8 +318,8 @@ public class VcnTest { verify(mVcnNetworkProvider, times(2)).registerListener(eq(requestListener)); assertTrue(mVcn.isActive()); for (final int[] caps : TEST_CAPS) { - // Expect each gateway connection created on initial startup, and again with new configs - verify(mDeps, times(2)) + // Expect each gateway connection created only on initial startup + verify(mDeps) .newVcnGatewayConnection( eq(mVcnContext), eq(TEST_SUB_GROUP), @@ -271,4 +328,14 @@ public class VcnTest { any()); } } + + @Test + public void testIgnoreNetworkRequestWhileInactive() { + mVcn.setIsActive(false /* isActive */); + + final NetworkRequestListener requestListener = verifyAndGetRequestListener(); + triggerVcnRequestListeners(requestListener); + + verify(mDeps, never()).newVcnGatewayConnection(any(), any(), any(), any(), any()); + } } |