diff options
54 files changed, 2943 insertions, 487 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 0b1fa771cba4..be9dccce637a 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -39224,6 +39224,7 @@ package android.telephony { field public static final String KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array"; field public static final String KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL = "has_in_call_noise_suppression_bool"; field public static final String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool"; + field public static final String KEY_HIDE_ENABLE_2G = "hide_enable_2g_bool"; field public static final String KEY_HIDE_ENHANCED_4G_LTE_BOOL = "hide_enhanced_4g_lte_bool"; field public static final String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool"; field public static final String KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL = "hide_lte_plus_data_icon_bool"; diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index bd4c3011c67e..03aadbb05806 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -46,6 +46,25 @@ package android.net { method public int getResourceId(); } + public class NetworkPolicyManager { + method @NonNull public static String blockedReasonsToString(int); + method public static boolean isUidBlocked(int, boolean); + 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 { + method public default void onUidBlockedReasonChanged(int, int); + } + public final class NetworkStateSnapshot implements android.os.Parcelable { ctor public NetworkStateSnapshot(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @Nullable String, int); method public int describeContents(); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index ad867880aec5..9c6f3caee8ca 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -1480,6 +1480,7 @@ package android.bluetooth { public final class BluetoothDevice implements android.os.Parcelable { method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean cancelBondProcess(); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean createBondOutOfBand(int, @Nullable android.bluetooth.OobData, @Nullable android.bluetooth.OobData); method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public byte[] getMetadata(int); method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public int getSimAccessPermission(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected(); @@ -1656,6 +1657,55 @@ package android.bluetooth { field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BufferConstraints> CREATOR; } + public final class OobData implements android.os.Parcelable { + method @NonNull public static android.bluetooth.OobData.ClassicBuilder createClassicBuilder(@NonNull byte[], @NonNull byte[], @NonNull byte[]); + method @NonNull public static android.bluetooth.OobData.LeBuilder createLeBuilder(@NonNull byte[], @NonNull byte[], int); + method @NonNull public byte[] getClassOfDevice(); + method @NonNull public byte[] getClassicLength(); + method @NonNull public byte[] getConfirmationHash(); + method @NonNull public byte[] getDeviceAddressWithType(); + method @Nullable public byte[] getDeviceName(); + method @Nullable public byte[] getLeAppearance(); + method @NonNull public int getLeDeviceRole(); + method @NonNull public int getLeFlags(); + method @Nullable public byte[] getLeTemporaryKey(); + method @NonNull public byte[] getRandomizerHash(); + field public static final int CLASS_OF_DEVICE_OCTETS = 3; // 0x3 + field public static final int CONFIRMATION_OCTETS = 16; // 0x10 + field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.OobData> CREATOR; + field public static final int DEVICE_ADDRESS_OCTETS = 7; // 0x7 + field public static final int LE_APPEARANCE_OCTETS = 2; // 0x2 + field public static final int LE_DEVICE_FLAG_OCTETS = 1; // 0x1 + field public static final int LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL = 3; // 0x3 + field public static final int LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL = 2; // 0x2 + field public static final int LE_DEVICE_ROLE_CENTRAL_ONLY = 1; // 0x1 + field public static final int LE_DEVICE_ROLE_OCTETS = 1; // 0x1 + field public static final int LE_DEVICE_ROLE_PERIPHERAL_ONLY = 0; // 0x0 + field public static final int LE_FLAG_BREDR_NOT_SUPPORTED = 2; // 0x2 + field public static final int LE_FLAG_GENERAL_DISCOVERY_MODE = 1; // 0x1 + field public static final int LE_FLAG_LIMITED_DISCOVERY_MODE = 0; // 0x0 + field public static final int LE_FLAG_SIMULTANEOUS_CONTROLLER = 3; // 0x3 + field public static final int LE_FLAG_SIMULTANEOUS_HOST = 4; // 0x4 + field public static final int LE_TK_OCTETS = 16; // 0x10 + field public static final int OOB_LENGTH_OCTETS = 2; // 0x2 + field public static final int RANDOMIZER_OCTETS = 16; // 0x10 + } + + public static final class OobData.ClassicBuilder { + method @NonNull public android.bluetooth.OobData build(); + method @NonNull public android.bluetooth.OobData.ClassicBuilder setClassOfDevice(@NonNull byte[]); + method @NonNull public android.bluetooth.OobData.ClassicBuilder setDeviceName(@NonNull byte[]); + method @NonNull public android.bluetooth.OobData.ClassicBuilder setRandomizerHash(@NonNull byte[]); + } + + public static final class OobData.LeBuilder { + method @NonNull public android.bluetooth.OobData build(); + method @NonNull public android.bluetooth.OobData.LeBuilder setDeviceName(@NonNull byte[]); + method @NonNull public android.bluetooth.OobData.LeBuilder setLeFlags(int); + method @NonNull public android.bluetooth.OobData.LeBuilder setLeTemporaryKey(@NonNull byte[]); + method @NonNull public android.bluetooth.OobData.LeBuilder setRandomizerHash(@NonNull byte[]); + } + } package android.bluetooth.le { @@ -1677,6 +1727,7 @@ package android.bluetooth.le { } 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 field public static final int SCAN_RESULT_TYPE_FULL = 0; // 0x0 } @@ -10234,6 +10285,7 @@ package android.telephony { field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED"; field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED"; field public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2; // 0x2 + field public static final int ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G = 3; // 0x3 field public static final int ALLOWED_NETWORK_TYPES_REASON_POWER = 1; // 0x1 field public static final int ALLOWED_NETWORK_TYPES_REASON_USER = 0; // 0x0 field public static final int CALL_WAITING_STATUS_DISABLED = 2; // 0x2 diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 89030bcf12e0..41bc77651db6 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -1279,7 +1279,6 @@ public final class BluetoothDevice implements Parcelable { * the bonding process completes, and its result. * <p>Android system services will handle the necessary user interactions * to confirm and complete the bonding process. - * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. * * @param transport The transport to use for the pairing procedure. * @return false on immediate error, true if bonding will begin @@ -1287,8 +1286,9 @@ public final class BluetoothDevice implements Parcelable { * @hide */ @UnsupportedAppUsage + @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN) public boolean createBond(int transport) { - return createBondOutOfBand(transport, null); + return createBondInternal(transport, null, null); } /** @@ -1302,21 +1302,38 @@ public final class BluetoothDevice implements Parcelable { * <p>Android system services will handle the necessary user interactions * to confirm and complete the bonding process. * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. + * <p>There are two possible versions of OOB Data. This data can come in as + * P192 or P256. This is a reference to the cryptography used to generate the key. + * The caller may pass one or both. If both types of data are passed, then the + * P256 data will be preferred, and thus used. * * @param transport - Transport to use - * @param oobData - Out Of Band data + * @param remoteP192Data - Out Of Band data (P192) or null + * @param remoteP256Data - Out Of Band data (P256) or null * @return false on immediate error, true if bonding will begin * @hide */ - public boolean createBondOutOfBand(int transport, OobData oobData) { + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public boolean createBondOutOfBand(int transport, @Nullable OobData remoteP192Data, + @Nullable OobData remoteP256Data) { + if (remoteP192Data == null && remoteP256Data == null) { + throw new IllegalArgumentException( + "One or both arguments for the OOB data types are required to not be null." + + " Please use createBond() instead if you do not have OOB data to pass."); + } + return createBondInternal(transport, remoteP192Data, remoteP256Data); + } + + private boolean createBondInternal(int transport, @Nullable OobData remoteP192Data, + @Nullable OobData remoteP256Data) { final IBluetooth service = sService; if (service == null) { Log.w(TAG, "BT not enabled, createBondOutOfBand failed"); return false; } try { - return service.createBond(this, transport, oobData); + return service.createBond(this, transport, remoteP192Data, remoteP256Data); } catch (RemoteException e) { Log.e(TAG, "", e); } @@ -1347,27 +1364,6 @@ public final class BluetoothDevice implements Parcelable { } /** - * Set the Out Of Band data for a remote device to be used later - * in the pairing mechanism. Users can obtain this data through other - * trusted channels - * - * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}. - * - * @param hash Simple Secure pairing hash - * @param randomizer The random key obtained using OOB - * @return false on error; true otherwise - * @hide - */ - public boolean setDeviceOutOfBandData(byte[] hash, byte[] randomizer) { - //TODO(BT) - /* - try { - return sService.setDeviceOutOfBandData(this, hash, randomizer); - } catch (RemoteException e) {Log.e(TAG, "", e);} */ - return false; - } - - /** * Cancel an in-progress bonding request started with {@link #createBond}. * * @return true on success, false on error diff --git a/core/java/android/bluetooth/OobData.java b/core/java/android/bluetooth/OobData.java index 0d0c6ab2efa9..08d694eb93e2 100644 --- a/core/java/android/bluetooth/OobData.java +++ b/core/java/android/bluetooth/OobData.java @@ -1,4 +1,4 @@ -/* +/** * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,88 +16,949 @@ package android.bluetooth; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.util.Preconditions; + +import java.lang.IllegalArgumentException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Out Of Band Data for Bluetooth device pairing. * * <p>This object represents optional data obtained from a remote device through - * an out-of-band channel (eg. NFC). + * an out-of-band channel (eg. NFC, QR). + * + * <p>References: + * NFC AD Forum SSP 1.1 (AD) + * {@link https://members.nfc-forum.org//apps/group_public/download.php/24620/NFCForum-AD-BTSSP_1_1.pdf} + * Core Specification Supplement (CSS) V9 + * + * <p>There are several BR/EDR Examples + * + * <p>Negotiated Handover: + * Bluetooth Carrier Configuration Record: + * - OOB Data Length + * - Device Address + * - Class of Device + * - Simple Pairing Hash C + * - Simple Pairing Randomizer R + * - Service Class UUID + * - Bluetooth Local Name + * + * <p>Static Handover: + * Bluetooth Carrier Configuration Record: + * - OOB Data Length + * - Device Address + * - Class of Device + * - Service Class UUID + * - Bluetooth Local Name + * + * <p>Simplified Tag Format for Single BT Carrier: + * Bluetooth OOB Data Record: + * - OOB Data Length + * - Device Address + * - Class of Device + * - Service Class UUID + * - Bluetooth Local Name * * @hide */ -public class OobData implements Parcelable { - private byte[] mLeBluetoothDeviceAddress; - private byte[] mSecurityManagerTk; - private byte[] mLeSecureConnectionsConfirmation; - private byte[] mLeSecureConnectionsRandom; +@SystemApi +public final class OobData implements Parcelable { + + private static final String TAG = "OobData"; + /** The {@link OobData#mClassicLength} may be. (AD 3.1.1) (CSS 1.6.2) @hide */ + @SystemApi + public static final int OOB_LENGTH_OCTETS = 2; + /** + * The length for the {@link OobData#mDeviceAddressWithType}(6) and Address Type(1). + * (AD 3.1.2) (CSS 1.6.2) + * @hide + */ + @SystemApi + public static final int DEVICE_ADDRESS_OCTETS = 7; + /** The Class of Device is 3 octets. (AD 3.1.3) (CSS 1.6.2) @hide */ + @SystemApi + public static final int CLASS_OF_DEVICE_OCTETS = 3; + /** The Confirmation data must be 16 octets. (AD 3.2.2) (CSS 1.6.2) @hide */ + @SystemApi + public static final int CONFIRMATION_OCTETS = 16; + /** The Randomizer data must be 16 octets. (AD 3.2.3) (CSS 1.6.2) @hide */ + @SystemApi + public static final int RANDOMIZER_OCTETS = 16; + /** The LE Device Role length is 1 octet. (AD 3.3.2) (CSS 1.17) @hide */ + @SystemApi + public static final int LE_DEVICE_ROLE_OCTETS = 1; + /** The {@link OobData#mLeTemporaryKey} length. (3.4.1) @hide */ + @SystemApi + public static final int LE_TK_OCTETS = 16; + /** The {@link OobData#mLeAppearance} length. (3.4.1) @hide */ + @SystemApi + public static final int LE_APPEARANCE_OCTETS = 2; + /** The {@link OobData#mLeFlags} length. (3.4.1) @hide */ + @SystemApi + public static final int LE_DEVICE_FLAG_OCTETS = 1; // 1 octet to hold the 0-4 value. + + // Le Roles + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = { "LE_DEVICE_ROLE_" }, + value = { + LE_DEVICE_ROLE_PERIPHERAL_ONLY, + LE_DEVICE_ROLE_CENTRAL_ONLY, + LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL, + LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL + } + ) + public @interface LeRole {} + + /** @hide */ + @SystemApi + public static final int LE_DEVICE_ROLE_PERIPHERAL_ONLY = 0x00; + /** @hide */ + @SystemApi + public static final int LE_DEVICE_ROLE_CENTRAL_ONLY = 0x01; + /** @hide */ + @SystemApi + public static final int LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL = 0x02; + /** @hide */ + @SystemApi + public static final int LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL = 0x03; + + // Le Flags + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef( + prefix = { "LE_FLAG_" }, + value = { + LE_FLAG_LIMITED_DISCOVERY_MODE, + LE_FLAG_GENERAL_DISCOVERY_MODE, + LE_FLAG_BREDR_NOT_SUPPORTED, + LE_FLAG_SIMULTANEOUS_CONTROLLER, + LE_FLAG_SIMULTANEOUS_HOST + } + ) + public @interface LeFlag {} + + /** @hide */ + @SystemApi + public static final int LE_FLAG_LIMITED_DISCOVERY_MODE = 0x00; + /** @hide */ + @SystemApi + public static final int LE_FLAG_GENERAL_DISCOVERY_MODE = 0x01; + /** @hide */ + @SystemApi + public static final int LE_FLAG_BREDR_NOT_SUPPORTED = 0x02; + /** @hide */ + @SystemApi + public static final int LE_FLAG_SIMULTANEOUS_CONTROLLER = 0x03; + /** @hide */ + @SystemApi + public static final int LE_FLAG_SIMULTANEOUS_HOST = 0x04; + + /** + * Main creation method for creating a Classic version of {@link OobData}. + * + * <p>This object will allow the caller to call {@link ClassicBuilder#build()} + * to build the data object or add any option information to the builder. + * + * @param confirmationHash byte array consisting of {@link OobData#CONFIRMATION_OCTETS} octets + * of data. Data is derived from controller/host stack and is required for pairing OOB. + * @param classicLength byte array representing the length of data from 8-65535 across 2 + * octets (0xXXXX). + * @param deviceAddressWithType byte array representing the Bluetooth Address of the device + * that owns the OOB data. (i.e. the originator) [6 octets] + * + * @return a Classic Builder instance with all the given data set or null. + * + * @throws IllegalArgumentException if any of the values fail to be set. + * @throws NullPointerException if any argument is null. + * + * @hide + */ + @NonNull + @SystemApi + public static ClassicBuilder createClassicBuilder(@NonNull byte[] confirmationHash, + @NonNull byte[] classicLength, @NonNull byte[] deviceAddressWithType) { + return new ClassicBuilder(confirmationHash, classicLength, deviceAddressWithType); + } + + /** + * Main creation method for creating a LE version of {@link OobData}. + * + * <p>This object will allow the caller to call {@link LeBuilder#build()} + * to build the data object or add any option information to the builder. + * + * @param deviceAddressWithType the LE device address plus the address type (7 octets); + * not null. + * @param leDeviceRole whether the device supports Peripheral, Central, + * Both including preference; not null. (1 octet) + * @param confirmationHash Array consisting of {@link OobData#CONFIRMATION_OCTETS} octets + * of data. Data is derived from controller/host stack and is + * required for pairing OOB. + * + * <p>Possible LE Device Role Values: + * 0x00 Only Peripheral supported + * 0x01 Only Central supported + * 0x02 Central & Peripheral supported; Peripheral Preferred + * 0x03 Only peripheral supported; Central Preferred + * 0x04 - 0xFF Reserved + * + * @return a LeBuilder instance with all the given data set or null. + * + * @throws IllegalArgumentException if any of the values fail to be set. + * @throws NullPointerException if any argument is null. + * + * @hide + */ + @NonNull + @SystemApi + public static LeBuilder createLeBuilder(@NonNull byte[] confirmationHash, + @NonNull byte[] deviceAddressWithType, @LeRole int leDeviceRole) { + return new LeBuilder(confirmationHash, deviceAddressWithType, leDeviceRole); + } + + /** + * Builds an {@link OobData} object and validates that the required combination + * of values are present to create the LE specific OobData type. + * + * @hide + */ + @SystemApi + public static final class LeBuilder { + + /** + * It is recommended that this Hash C is generated anew for each + * pairing. + * + * <p>It should be noted that on passive NFC this isn't possible as the data is static + * and immutable. + */ + private byte[] mConfirmationHash = null; + + /** + * Optional, but adds more validity to the pairing. + * + * <p>If not present a value of 0 is assumed. + */ + private byte[] mRandomizerHash = new byte[] { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + }; + + /** + * The Bluetooth Device user-friendly name presented over Bluetooth Technology. + * + * <p>This is the name that may be displayed to the device user as part of the UI. + */ + private byte[] mDeviceName = null; + + /** + * Sets the Bluetooth Device name to be used for UI purposes. + * + * <p>Optional attribute. + * + * @param deviceName byte array representing the name, may be 0 in length, not null. + * + * @return {@link OobData#ClassicBuilder} + * + * @throws NullPointerException if deviceName is null. + * + * @hide + */ + @NonNull + @SystemApi + public LeBuilder setDeviceName(@NonNull byte[] deviceName) { + Preconditions.checkNotNull(deviceName); + this.mDeviceName = deviceName; + return this; + } + + /** + * The Bluetooth Device Address is the address to which the OOB data belongs. + * + * <p>The length MUST be {@link OobData#DEVICE_ADDRESS_OCTETS} octets. + * + * <p> Address is encoded in Little Endian order. + * + * <p>e.g. 00:01:02:03:04:05 would be x05x04x03x02x01x00 + */ + private final byte[] mDeviceAddressWithType; + + /** + * During an LE connection establishment, one must be in the Peripheral mode and the other + * in the Central role. + * + * <p>Possible Values: + * {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported + * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported + * {@link LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported; + * Peripheral Preferred + * {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central Preferred + * 0x04 - 0xFF Reserved + */ + private final @LeRole int mLeDeviceRole; + + /** + * Temporary key value from the Security Manager. + * + * <p> Must be {@link LE_TK_OCTETS} in size + */ + private byte[] mLeTemporaryKey = null; + + /** + * Defines the representation of the external appearance of the device. + * + * <p>For example, a mouse, remote control, or keyboard. + * + * <p>Used for visual on discovering device to represent icon/string/etc... + */ + private byte[] mLeAppearance = null; + + /** + * Contains which discoverable mode to use, BR/EDR support and capability. + * + * <p>Possible LE Flags: + * {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable Mode. + * {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode. + * {@link LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of + * LMP Feature Mask Definitions. + * {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to + * Same Device Capable (Controller). + * Bit 49 of LMP Feature Mask Definitions. + * {@link LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to + * Same Device Capable (Host). + * Bit 55 of LMP Feature Mask Definitions. + * <b>0x05- 0x07 Reserved</b> + */ + private @LeFlag int mLeFlags = LE_FLAG_GENERAL_DISCOVERY_MODE; // Invalid default + + /** + * Constructing an OobData object for use with LE requires + * a LE Device Address and LE Device Role as well as the Confirmation + * and optionally, the Randomizer, however it is recommended to use. + * + * @param confirmationHash byte array consisting of {@link OobData#CONFIRMATION_OCTETS} + * octets of data. Data is derived from controller/host stack and is required for + * pairing OOB. + * @param deviceAddressWithType 7 bytes containing the 6 byte address with the 1 byte + * address type. + * @param leDeviceRole indicating device's role and preferences (Central or Peripheral) + * + * <p>Possible Values: + * {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported + * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported + * {@link LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported; + * Peripheral Preferred + * {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central Preferred + * 0x04 - 0xFF Reserved + * + * @throws IllegalArgumentException if deviceAddressWithType is not + * {@link LE_DEVICE_ADDRESS_OCTETS} octets + * @throws NullPointerException if any argument is null. + */ + private LeBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] deviceAddressWithType, + @LeRole int leDeviceRole) { + Preconditions.checkNotNull(confirmationHash); + Preconditions.checkNotNull(deviceAddressWithType); + if (confirmationHash.length != OobData.CONFIRMATION_OCTETS) { + throw new IllegalArgumentException("confirmationHash must be " + + OobData.CONFIRMATION_OCTETS + " octets in length."); + } + this.mConfirmationHash = confirmationHash; + if (deviceAddressWithType.length != OobData.DEVICE_ADDRESS_OCTETS) { + throw new IllegalArgumentException("confirmationHash must be " + + OobData.DEVICE_ADDRESS_OCTETS+ " octets in length."); + } + this.mDeviceAddressWithType = deviceAddressWithType; + if (leDeviceRole < LE_DEVICE_ROLE_PERIPHERAL_ONLY + || leDeviceRole > LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL) { + throw new IllegalArgumentException("leDeviceRole must be a valid value."); + } + this.mLeDeviceRole = leDeviceRole; + } + + /** + * Sets the Temporary Key value to be used by the LE Security Manager during + * LE pairing. + * + * @param leTemporaryKey byte array that shall be 16 bytes. Please see Bluetooth CSSv6, + * Part A 1.8 for a detailed description. + * + * @return {@link OobData#Builder} + * + * @throws IllegalArgumentException if the leTemporaryKey is an invalid format. + * @throws NullinterException if leTemporaryKey is null. + * + * @hide + */ + @NonNull + @SystemApi + public LeBuilder setLeTemporaryKey(@NonNull byte[] leTemporaryKey) { + Preconditions.checkNotNull(leTemporaryKey); + if (leTemporaryKey.length != LE_TK_OCTETS) { + throw new IllegalArgumentException("leTemporaryKey must be " + + LE_TK_OCTETS + " octets in length."); + } + this.mLeTemporaryKey = leTemporaryKey; + return this; + } + + /** + * @param randomizerHash byte array consisting of {@link OobData#RANDOMIZER_OCTETS} octets + * of data. Data is derived from controller/host stack and is required for pairing OOB. + * Also, randomizerHash may be all 0s or null in which case it becomes all 0s. + * + * @throws IllegalArgumentException if null or incorrect length randomizerHash was passed. + * @throws NullPointerException if randomizerHash is null. + * + * @hide + */ + @NonNull + @SystemApi + public LeBuilder setRandomizerHash(@NonNull byte[] randomizerHash) { + Preconditions.checkNotNull(randomizerHash); + if (randomizerHash.length != OobData.RANDOMIZER_OCTETS) { + throw new IllegalArgumentException("randomizerHash must be " + + OobData.RANDOMIZER_OCTETS + " octets in length."); + } + this.mRandomizerHash = randomizerHash; + return this; + } + + /** + * Sets the LE Flags necessary for the pairing scenario or discovery mode. + * + * @param leFlags enum value representing the 1 octet of data about discovery modes. + * + * <p>Possible LE Flags: + * {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable Mode. + * {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode. + * {@link LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of + * LMP Feature Mask Definitions. + * {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to + * Same Device Capable (Controller) Bit 49 of LMP Feature Mask Definitions. + * {@link LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to + * Same Device Capable (Host). + * Bit 55 of LMP Feature Mask Definitions. + * 0x05- 0x07 Reserved + * + * @throws IllegalArgumentException for invalid flag + * @hide + */ + @NonNull + @SystemApi + public LeBuilder setLeFlags(@LeFlag int leFlags) { + if (leFlags < LE_FLAG_LIMITED_DISCOVERY_MODE || leFlags > LE_FLAG_SIMULTANEOUS_HOST) { + throw new IllegalArgumentException("leFlags must be a valid value."); + } + this.mLeFlags = leFlags; + return this; + } + + /** + * Validates and builds the {@link OobData} object for LE Security. + * + * @return {@link OobData} with given builder values + * + * @throws IllegalStateException if either of the 2 required fields were not set. + * + * @hide + */ + @NonNull + @SystemApi + public OobData build() { + final OobData oob = + new OobData(this.mDeviceAddressWithType, this.mLeDeviceRole, + this.mConfirmationHash); + + // If we have values, set them, otherwise use default + oob.mLeTemporaryKey = + (this.mLeTemporaryKey != null) ? this.mLeTemporaryKey : oob.mLeTemporaryKey; + oob.mLeAppearance = (this.mLeAppearance != null) + ? this.mLeAppearance : oob.mLeAppearance; + oob.mLeFlags = (this.mLeFlags != 0xF) ? this.mLeFlags : oob.mLeFlags; + oob.mDeviceName = (this.mDeviceName != null) ? this.mDeviceName : oob.mDeviceName; + oob.mRandomizerHash = this.mRandomizerHash; + return oob; + } + } + + /** + * Builds an {@link OobData} object and validates that the required combination + * of values are present to create the Classic specific OobData type. + * + * @hide + */ + @SystemApi + public static final class ClassicBuilder { + // Used by both Classic and LE + /** + * It is recommended that this Hash C is generated anew for each + * pairing. + * + * <p>It should be noted that on passive NFC this isn't possible as the data is static + * and immutable. + * + * @hide + */ + private byte[] mConfirmationHash = null; + + /** + * Optional, but adds more validity to the pairing. + * + * <p>If not present a value of 0 is assumed. + * + * @hide + */ + private byte[] mRandomizerHash = new byte[] { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + }; + + /** + * The Bluetooth Device user-friendly name presented over Bluetooth Technology. + * + * <p>This is the name that may be displayed to the device user as part of the UI. + * + * @hide + */ + private byte[] mDeviceName = null; + + /** + * This length value provides the absolute length of total OOB data block used for + * Bluetooth BR/EDR + * + * <p>OOB communication, which includes the length field itself and the Bluetooth + * Device Address. + * + * <p>The minimum length that may be represented in this field is 8. + * + * @hide + */ + private final byte[] mClassicLength; + + /** + * The Bluetooth Device Address is the address to which the OOB data belongs. + * + * <p>The length MUST be {@link OobData#DEVICE_ADDRESS_OCTETS} octets. + * + * <p> Address is encoded in Little Endian order. + * + * <p>e.g. 00:01:02:03:04:05 would be x05x04x03x02x01x00 + * + * @hide + */ + private final byte[] mDeviceAddressWithType; + + /** + * Class of Device information is to be used to provide a graphical representation + * to the user as part of UI involving operations. + * + * <p>This is not to be used to determine a particular service can be used. + * + * <p>The length MUST be {@link OobData#CLASS_OF_DEVICE_OCTETS} octets. + * + * @hide + */ + private byte[] mClassOfDevice = null; + + /** + * @param confirmationHash byte array consisting of {@link OobData#CONFIRMATION_OCTETS} + * octets of data. Data is derived from controller/host stack and is required for pairing + * OOB. + * @param randomizerHash byte array consisting of {@link OobData#RANDOMIZER_OCTETS} octets + * of data. Data is derived from controller/host stack and is required + * for pairing OOB. Also, randomizerHash may be all 0s or null in which case + * it becomes all 0s. + * @param classicLength byte array representing the length of data from 8-65535 across 2 + * octets (0xXXXX). Inclusive of this value in the length. + * @param deviceAddressWithType byte array representing the Bluetooth Address of the device + * that owns the OOB data. (i.e. the originator) [7 octets] this includes the Address Type + * as the last octet. + * + * @throws IllegalArgumentException if any value is not the correct length + * @throws NullPointerException if anything passed is null + * + * @hide + */ + private ClassicBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] classicLength, + @NonNull byte[] deviceAddressWithType) { + Preconditions.checkNotNull(confirmationHash); + Preconditions.checkNotNull(classicLength); + Preconditions.checkNotNull(deviceAddressWithType); + if (confirmationHash.length != OobData.CONFIRMATION_OCTETS) { + throw new IllegalArgumentException("confirmationHash must be " + + OobData.CONFIRMATION_OCTETS + " octets in length."); + } + this.mConfirmationHash = confirmationHash; + if (classicLength.length != OOB_LENGTH_OCTETS) { + throw new IllegalArgumentException("classicLength must be " + + OOB_LENGTH_OCTETS + " octets in length."); + } + this.mClassicLength = classicLength; + if (deviceAddressWithType.length != DEVICE_ADDRESS_OCTETS) { + throw new IllegalArgumentException("deviceAddressWithType must be " + + DEVICE_ADDRESS_OCTETS + " octets in length."); + } + this.mDeviceAddressWithType = deviceAddressWithType; + } - public byte[] getLeBluetoothDeviceAddress() { - return mLeBluetoothDeviceAddress; + /** + * @param randomizerHash byte array consisting of {@link OobData#RANDOMIZER_OCTETS} octets + * of data. Data is derived from controller/host stack and is required for pairing OOB. + * Also, randomizerHash may be all 0s or null in which case it becomes all 0s. + * + * @throws IllegalArgumentException if null or incorrect length randomizerHash was passed. + * @throws NullPointerException if randomizerHash is null. + * + * @hide + */ + @NonNull + @SystemApi + public ClassicBuilder setRandomizerHash(@NonNull byte[] randomizerHash) { + Preconditions.checkNotNull(randomizerHash); + if (randomizerHash.length != OobData.RANDOMIZER_OCTETS) { + throw new IllegalArgumentException("randomizerHash must be " + + OobData.RANDOMIZER_OCTETS + " octets in length."); + } + this.mRandomizerHash = randomizerHash; + return this; + } + + /** + * Sets the Bluetooth Device name to be used for UI purposes. + * + * <p>Optional attribute. + * + * @param deviceName byte array representing the name, may be 0 in length, not null. + * + * @return {@link OobData#ClassicBuilder} + * + * @throws NullPointerException if deviceName is null + * + * @hide + */ + @NonNull + @SystemApi + public ClassicBuilder setDeviceName(@NonNull byte[] deviceName) { + Preconditions.checkNotNull(deviceName); + this.mDeviceName = deviceName; + return this; + } + + /** + * Sets the Bluetooth Class of Device; used for UI purposes only. + * + * <p>Not an indicator of available services! + * + * <p>Optional attribute. + * + * @param classOfDevice byte array of {@link OobData#CLASS_OF_DEVICE_OCTETS} octets. + * + * @return {@link OobData#ClassicBuilder} + * + * @throws IllegalArgumentException if length is not equal to + * {@link OobData#CLASS_OF_DEVICE_OCTETS} octets. + * @throws NullPointerException if classOfDevice is null. + * + * @hide + */ + @NonNull + @SystemApi + public ClassicBuilder setClassOfDevice(@NonNull byte[] classOfDevice) { + Preconditions.checkNotNull(classOfDevice); + if (classOfDevice.length != OobData.CLASS_OF_DEVICE_OCTETS) { + throw new IllegalArgumentException("classOfDevice must be " + + OobData.CLASS_OF_DEVICE_OCTETS + " octets in length."); + } + this.mClassOfDevice = classOfDevice; + return this; + } + + /** + * Validates and builds the {@link OobDat object for Classic Security. + * + * @return {@link OobData} with previously given builder values. + * + * @hide + */ + @NonNull + @SystemApi + public OobData build() { + final OobData oob = + new OobData(this.mClassicLength, this.mDeviceAddressWithType, + this.mConfirmationHash); + // If we have values, set them, otherwise use default + oob.mDeviceName = (this.mDeviceName != null) ? this.mDeviceName : oob.mDeviceName; + oob.mClassOfDevice = (this.mClassOfDevice != null) + ? this.mClassOfDevice : oob.mClassOfDevice; + oob.mRandomizerHash = this.mRandomizerHash; + return oob; + } + } + + // Members (Defaults for Optionals must be set or Parceling fails on NPE) + // Both + private final byte[] mDeviceAddressWithType; + private final byte[] mConfirmationHash; + private byte[] mRandomizerHash = new byte[] { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + }; + // Default the name to "Bluetooth Device" + private byte[] mDeviceName = new byte[] { + // Bluetooth + 0x42, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, + // <space>Device + 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65 + }; + + // Classic + private final byte[] mClassicLength; + private byte[] mClassOfDevice = new byte[CLASS_OF_DEVICE_OCTETS]; + + // LE + private final @LeRole int mLeDeviceRole; + private byte[] mLeTemporaryKey = new byte[LE_TK_OCTETS]; + private byte[] mLeAppearance = new byte[LE_APPEARANCE_OCTETS]; + private @LeFlag int mLeFlags = LE_FLAG_LIMITED_DISCOVERY_MODE; + + /** + * @return byte array representing the MAC address of a bluetooth device. + * The Address is 6 octets long with a 1 octet address type associated with the address. + * + * <p>For classic this will be 6 byte address plus the default of PUBLIC_ADDRESS Address Type. + * For LE there are more choices for Address Type. + * + * @hide + */ + @NonNull + @SystemApi + public byte[] getDeviceAddressWithType() { + return mDeviceAddressWithType; + } + + /** + * @return byte array representing the confirmationHash value + * which is used to confirm the identity to the controller. + * + * @hide + */ + @NonNull + @SystemApi + public byte[] getConfirmationHash() { + return mConfirmationHash; } /** - * Sets the LE Bluetooth Device Address value to be used during LE pairing. - * The value shall be 7 bytes. Please see Bluetooth CSSv6, Part A 1.16 for - * a detailed description. + * @return byte array representing the randomizerHash value + * which is used to verify the identity of the controller. + * + * @hide */ - public void setLeBluetoothDeviceAddress(byte[] leBluetoothDeviceAddress) { - mLeBluetoothDeviceAddress = leBluetoothDeviceAddress; + @NonNull + @SystemApi + public byte[] getRandomizerHash() { + return mRandomizerHash; } - public byte[] getSecurityManagerTk() { - return mSecurityManagerTk; + /** + * @return Device Name used for displaying name in UI. + * + * <p>Also, this will be populated with the LE Local Name if the data is for LE. + * + * @hide + */ + @Nullable + @SystemApi + public byte[] getDeviceName() { + return mDeviceName; + } + + /** + * @return byte array representing the oob data length which is the length + * of all of the data including these octets. + * + * @hide + */ + @NonNull + @SystemApi + public byte[] getClassicLength() { + return mClassicLength; + } + + /** + * @return byte array representing the class of device for UI display. + * + * <p>Does not indicate services available; for display only. + * + * @hide + */ + @NonNull + @SystemApi + public byte[] getClassOfDevice() { + return mClassOfDevice; } /** - * Sets the Temporary Key value to be used by the LE Security Manager during - * LE pairing. The value shall be 16 bytes. Please see Bluetooth CSSv6, - * Part A 1.8 for a detailed description. + * @return Temporary Key used for LE pairing. + * + * @hide */ - public void setSecurityManagerTk(byte[] securityManagerTk) { - mSecurityManagerTk = securityManagerTk; + @Nullable + @SystemApi + public byte[] getLeTemporaryKey() { + return mLeTemporaryKey; } - public byte[] getLeSecureConnectionsConfirmation() { - return mLeSecureConnectionsConfirmation; + /** + * @return Appearance used for LE pairing. For use in UI situations + * when determining what sort of icons or text to display regarding + * the device. + * + * @hide + */ + @Nullable + @SystemApi + public byte[] getLeAppearance() { + return mLeTemporaryKey; } - public void setLeSecureConnectionsConfirmation(byte[] leSecureConnectionsConfirmation) { - mLeSecureConnectionsConfirmation = leSecureConnectionsConfirmation; + /** + * @return Flags used to determing discoverable mode to use, BR/EDR Support, and Capability. + * + * <p>Possible LE Flags: + * {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable Mode. + * {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode. + * {@link LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of + * LMP Feature Mask Definitions. + * {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to + * Same Device Capable (Controller). + * Bit 49 of LMP Feature Mask Definitions. + * {@link LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to + * Same Device Capable (Host). + * Bit 55 of LMP Feature Mask Definitions. + * <b>0x05- 0x07 Reserved</b> + * + * @hide + */ + @NonNull + @SystemApi + @LeFlag + public int getLeFlags() { + return mLeFlags; } - public byte[] getLeSecureConnectionsRandom() { - return mLeSecureConnectionsRandom; + /** + * @return the supported and preferred roles of the LE device. + * + * <p>Possible Values: + * {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported + * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported + * {@link LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported; + * Peripheral Preferred + * {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central Preferred + * 0x04 - 0xFF Reserved + * + * @hide + */ + @NonNull + @SystemApi + @LeRole + public int getLeDeviceRole() { + return mLeDeviceRole; } - public void setLeSecureConnectionsRandom(byte[] leSecureConnectionsRandom) { - mLeSecureConnectionsRandom = leSecureConnectionsRandom; + /** + * Classic Security Constructor + */ + private OobData(@NonNull byte[] classicLength, @NonNull byte[] deviceAddressWithType, + @NonNull byte[] confirmationHash) { + mClassicLength = classicLength; + mDeviceAddressWithType = deviceAddressWithType; + mConfirmationHash = confirmationHash; + mLeDeviceRole = -1; // Satisfy final } - public OobData() { + /** + * LE Security Constructor + */ + private OobData(@NonNull byte[] deviceAddressWithType, @LeRole int leDeviceRole, + @NonNull byte[] confirmationHash) { + mDeviceAddressWithType = deviceAddressWithType; + mLeDeviceRole = leDeviceRole; + mConfirmationHash = confirmationHash; + mClassicLength = new byte[OOB_LENGTH_OCTETS]; // Satisfy final } private OobData(Parcel in) { - mLeBluetoothDeviceAddress = in.createByteArray(); - mSecurityManagerTk = in.createByteArray(); - mLeSecureConnectionsConfirmation = in.createByteArray(); - mLeSecureConnectionsRandom = in.createByteArray(); + // Both + mDeviceAddressWithType = in.createByteArray(); + mConfirmationHash = in.createByteArray(); + mRandomizerHash = in.createByteArray(); + mDeviceName = in.createByteArray(); + + // Classic + mClassicLength = in.createByteArray(); + mClassOfDevice = in.createByteArray(); + + // LE + mLeDeviceRole = in.readInt(); + mLeTemporaryKey = in.createByteArray(); + mLeAppearance = in.createByteArray(); + mLeFlags = in.readInt(); } + /** + * @hide + */ @Override public int describeContents() { return 0; } + /** + * @hide + */ @Override - public void writeToParcel(Parcel out, int flags) { - out.writeByteArray(mLeBluetoothDeviceAddress); - out.writeByteArray(mSecurityManagerTk); - out.writeByteArray(mLeSecureConnectionsConfirmation); - out.writeByteArray(mLeSecureConnectionsRandom); + public void writeToParcel(@NonNull Parcel out, int flags) { + // Both + // Required + out.writeByteArray(mDeviceAddressWithType); + // Required + out.writeByteArray(mConfirmationHash); + // Optional + out.writeByteArray(mRandomizerHash); + // Optional + out.writeByteArray(mDeviceName); + + // Classic + // Required + out.writeByteArray(mClassicLength); + // Optional + out.writeByteArray(mClassOfDevice); + + // LE + // Required + out.writeInt(mLeDeviceRole); + // Required + out.writeByteArray(mLeTemporaryKey); + // Optional + out.writeByteArray(mLeAppearance); + // Optional + out.writeInt(mLeFlags); } + // For Parcelable public static final @android.annotation.NonNull Parcelable.Creator<OobData> CREATOR = new Parcelable.Creator<OobData>() { public OobData createFromParcel(Parcel in) { @@ -108,4 +969,47 @@ public class OobData implements Parcelable { return new OobData[size]; } }; + + /** + * @return a {@link String} representation of the OobData object. + * + * @hide + */ + @Override + @NonNull + public String toString() { + return "OobData: \n\t" + // Both + + "Device Address With Type: " + toHexString(mDeviceAddressWithType) + "\n\t" + + "Confirmation: " + toHexString(mConfirmationHash) + "\n\t" + + "Randomizer: " + toHexString(mRandomizerHash) + "\n\t" + + "Device Name: " + toHexString(mDeviceName) + "\n\t" + // Classic + + "OobData Length: " + toHexString(mClassicLength) + "\n\t" + + "Class of Device: " + toHexString(mClassOfDevice) + "\n\t" + // LE + + "LE Device Role: " + toHexString(mLeDeviceRole) + "\n\t" + + "LE Temporary Key: " + toHexString(mLeTemporaryKey) + "\n\t" + + "LE Appearance: " + toHexString(mLeAppearance) + "\n\t" + + "LE Flags: " + toHexString(mLeFlags) + "\n\t"; + } + + @NonNull + private String toHexString(@NonNull int b) { + return toHexString(new byte[] {(byte) b}); + } + + @NonNull + private String toHexString(@NonNull byte b) { + return toHexString(new byte[] {b}); + } + + @NonNull + private String toHexString(@NonNull byte[] array) { + StringBuilder builder = new StringBuilder(array.length * 2); + for (byte b: array) { + builder.append(String.format("%02x", b)); + } + return builder.toString(); + } } diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java index 504118ec5da8..368d1eecade4 100644 --- a/core/java/android/bluetooth/le/ScanSettings.java +++ b/core/java/android/bluetooth/le/ScanSettings.java @@ -52,6 +52,16 @@ public final class ScanSettings implements Parcelable { public static final int SCAN_MODE_LOW_LATENCY = 2; /** + * Perform Bluetooth LE scan in ambient discovery mode. This mode has lower duty cycle and more + * aggressive scan interval than balanced mode that provides a good trade-off between scan + * latency and power consumption. + * + * @hide + */ + @SystemApi + public static final int SCAN_MODE_AMBIENT_DISCOVERY = 3; + + /** * Trigger a callback for every Bluetooth advertisement found that matches the filter criteria. * If no filter is active, all advertisement packets are reported. */ @@ -276,10 +286,17 @@ public final class ScanSettings implements Parcelable { * @throws IllegalArgumentException If the {@code scanMode} is invalid. */ public Builder setScanMode(int scanMode) { - if (scanMode < SCAN_MODE_OPPORTUNISTIC || scanMode > SCAN_MODE_LOW_LATENCY) { - throw new IllegalArgumentException("invalid scan mode " + scanMode); + switch (scanMode) { + case SCAN_MODE_OPPORTUNISTIC: + case SCAN_MODE_LOW_POWER: + case SCAN_MODE_BALANCED: + case SCAN_MODE_LOW_LATENCY: + case SCAN_MODE_AMBIENT_DISCOVERY: + mScanMode = scanMode; + break; + default: + throw new IllegalArgumentException("invalid scan mode " + scanMode); } - mScanMode = scanMode; return this; } diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 7f834afd7b30..933dee3a6470 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -2024,7 +2024,9 @@ public final class CameraManager { // Tell listeners that the cameras and torch modes are unavailable and schedule a // reconnection to camera service. When camera service is reconnected, the camera // and torch statuses will be updated. - for (int i = 0; i < mDeviceStatus.size(); i++) { + // Iterate from the end to the beginning befcause onStatusChangedLocked removes + // entries from the ArrayMap. + for (int i = mDeviceStatus.size() - 1; i >= 0; i--) { String cameraId = mDeviceStatus.keyAt(i); onStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT, cameraId); } diff --git a/core/java/android/net/INetworkPolicyListener.aidl b/core/java/android/net/INetworkPolicyListener.aidl index dfb1e996c55a..00c691379187 100644 --- a/core/java/android/net/INetworkPolicyListener.aidl +++ b/core/java/android/net/INetworkPolicyListener.aidl @@ -25,4 +25,5 @@ oneway interface INetworkPolicyListener { void onUidPoliciesChanged(int uid, int uidPolicies); void onSubscriptionOverride(int subId, int overrideMask, int overrideValue, in int[] networkTypes); void onSubscriptionPlansChanged(int subId, in SubscriptionPlan[] plans); + void onBlockedReasonChanged(int uid, int oldBlockedReason, int newBlockedReason); } diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index 1c56954a1c36..c544c3275cf3 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -23,6 +23,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.app.ActivityManager; @@ -44,6 +45,8 @@ import android.util.DebugUtils; import android.util.Pair; import android.util.Range; +import com.android.internal.util.function.pooled.PooledLambda; + import com.google.android.collect.Sets; import java.lang.annotation.Retention; @@ -53,6 +56,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; /** * Manager for creating and modifying network policy rules. @@ -60,6 +64,7 @@ import java.util.concurrent.ConcurrentHashMap; * @hide */ @TestApi +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @SystemService(Context.NETWORK_POLICY_SERVICE) public class NetworkPolicyManager { @@ -198,12 +203,157 @@ 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 + */ + public static final int ALLOWED_REASON_NONE = 0; + /** + * Flag to indicate that app is exempt from certain network restrictions because of it being a + * system component. + * + * @hide + */ + public static final int ALLOWED_REASON_SYSTEM = 1 << 0; + /** + * Flag to indicate that app is exempt from certain network restrictions because of it being + * in the foreground. + * + * @hide + */ + public static final int ALLOWED_REASON_FOREGROUND = 1 << 1; + /** + * Flag to indicate that app is exempt from certain network restrictions because of it being + * in the {@code allow-in-power-save} list. + * + * @hide + */ + public static final int ALLOWED_REASON_POWER_SAVE_ALLOWLIST = 1 << 2; + /** + * Flag to indicate that app is exempt from certain network restrictions because of it being + * in the {@code allow-in-power-save-except-idle} list. + * + * @hide + */ + public static final int ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST = 1 << 3; + /** + * Flag to indicate that app is exempt from certain network restrictions because of it holding + * certain privileged permissions. + * + * @hide + */ + public static final int ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS = 1 << 4; + /** + * Flag to indicate that app is exempt from certain metered network restrictions because user + * explicitly exempted it. + * + * @hide + */ + public static final int ALLOWED_METERED_REASON_USER_EXEMPTED = 1 << 16; + + /** @hide */ + public static final int ALLOWED_METERED_REASON_MASK = 0xffff0000; + + /** + * @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 {} + private final Context mContext; @UnsupportedAppUsage private INetworkPolicyManager mService; private final Map<SubscriptionCallback, SubscriptionCallbackProxy> - mCallbackMap = new ConcurrentHashMap<>(); + mSubscriptionCallbackMap = new ConcurrentHashMap<>(); + private final Map<NetworkPolicyCallback, NetworkPolicyCallbackProxy> + mNetworkPolicyCallbackMap = new ConcurrentHashMap<>(); /** @hide */ public NetworkPolicyManager(Context context, INetworkPolicyManager service) { @@ -318,7 +468,7 @@ public class NetworkPolicyManager { } final SubscriptionCallbackProxy callbackProxy = new SubscriptionCallbackProxy(callback); - if (null != mCallbackMap.putIfAbsent(callback, callbackProxy)) { + if (null != mSubscriptionCallbackMap.putIfAbsent(callback, callbackProxy)) { throw new IllegalArgumentException("Callback is already registered."); } registerListener(callbackProxy); @@ -331,7 +481,7 @@ public class NetworkPolicyManager { throw new NullPointerException("Callback cannot be null."); } - final SubscriptionCallbackProxy callbackProxy = mCallbackMap.remove(callback); + final SubscriptionCallbackProxy callbackProxy = mSubscriptionCallbackMap.remove(callback); if (callbackProxy == null) return; unregisterListener(callbackProxy); @@ -689,6 +839,142 @@ public class NetworkPolicyManager { return WifiInfo.sanitizeSsid(ssid); } + /** + * 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 + * blocked. + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @NonNull + public static String blockedReasonsToString(@BlockedReason int blockedReasons) { + return DebugUtils.flagsToString(NetworkPolicyManager.class, "BLOCKED_", blockedReasons); + } + + /** + * Register a {@link NetworkPolicyCallback} to listen for changes to network blocked status + * of apps. + * + * Note that when a caller tries to register a new callback, it might replace a previously + * registered callback if it is considered equal to the new one, based on the + * {@link Object#equals(Object)} check. + * + * @param executor The {@link Executor} to run the callback on. + * @param callback The {@link NetworkPolicyCallback} to be registered. + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) + public void registerNetworkPolicyCallback(@Nullable Executor executor, + @NonNull NetworkPolicyCallback callback) { + if (callback == null) { + throw new NullPointerException("Callback cannot be null."); + } + + final NetworkPolicyCallbackProxy callbackProxy = new NetworkPolicyCallbackProxy( + executor, callback); + registerListener(callbackProxy); + mNetworkPolicyCallbackMap.put(callback, callbackProxy); + } + + /** + * Unregister a previously registered {@link NetworkPolicyCallback}. + * + * @param callback The {@link NetworkPolicyCallback} to be unregistered. + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) + public void unregisterNetworkPolicyCallback(@NonNull NetworkPolicyCallback callback) { + if (callback == null) { + throw new NullPointerException("Callback cannot be null."); + } + + final NetworkPolicyCallbackProxy callbackProxy = mNetworkPolicyCallbackMap.remove(callback); + if (callbackProxy == null) return; + unregisterListener(callbackProxy); + } + + /** + * Interface for the callback to listen for changes to network blocked status of apps. + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public interface NetworkPolicyCallback { + /** + * Called when the reason for why the network access of an UID is blocked changes. + * + * @param uid The UID for which the blocked status changed. + * @param blockedReasons Value indicating the reasons for why the network access of an + * UID is blocked. + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + default void onUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {} + } + + /** @hide */ + public static class NetworkPolicyCallbackProxy extends Listener { + private final Executor mExecutor; + private final NetworkPolicyCallback mCallback; + + NetworkPolicyCallbackProxy(@Nullable Executor executor, + @NonNull NetworkPolicyCallback callback) { + mExecutor = executor; + mCallback = callback; + } + + @Override + public void onBlockedReasonChanged(int uid, @BlockedReason int oldBlockedReasons, + @BlockedReason int newBlockedReasons) { + if (oldBlockedReasons != newBlockedReasons) { + dispatchOnUidBlockedReasonChanged(mExecutor, mCallback, uid, newBlockedReasons); + } + } + } + + private static void dispatchOnUidBlockedReasonChanged(@Nullable Executor executor, + @NonNull NetworkPolicyCallback callback, int uid, @BlockedReason int blockedReasons) { + if (executor == null) { + callback.onUidBlockedReasonChanged(uid, blockedReasons); + } else { + executor.execute(PooledLambda.obtainRunnable( + NetworkPolicyCallback::onUidBlockedReasonChanged, + callback, uid, blockedReasons).recycleOnUse()); + } + } + /** @hide */ public static class SubscriptionCallback { /** @@ -743,5 +1029,7 @@ public class NetworkPolicyManager { @Override public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue, int[] networkTypes) { } @Override public void onSubscriptionPlansChanged(int subId, SubscriptionPlan[] plans) { } + @Override public void onBlockedReasonChanged(int uid, + int oldBlockedReasons, int newBlockedReasons) { } } } diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 9cb76c1ffb5d..753abea2cfe2 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -5284,7 +5284,8 @@ public final class Telephony { * which network types are allowed for * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_USER}, * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_POWER}, - * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER}. + * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_CARRIER}, + * {@link TelephonyManager#ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G}. * <P>Type: TEXT </P> * * @hide diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS index 7ade05cc6de1..e6c911e5b41d 100644 --- a/core/java/com/android/internal/app/OWNERS +++ b/core/java/com/android/internal/app/OWNERS @@ -3,6 +3,9 @@ per-file *Resolver* = file:/packages/SystemUI/OWNERS per-file *Chooser* = file:/packages/SystemUI/OWNERS per-file SimpleIconFactory.java = file:/packages/SystemUI/OWNERS per-file NetInitiatedActivity.java = file:/location/java/android/location/OWNERS -per-file IVoice* = file:/core/java/android/service/voice/OWNERS -per-file *Hotword* = file:/core/java/android/service/voice/OWNERS per-file *BatteryStats* = file:/BATTERY_STATS_OWNERS + +# Voice Interaction +per-file *Assist* = file:/core/java/android/service/voice/OWNERS +per-file *Hotword* = file:/core/java/android/service/voice/OWNERS +per-file *Voice* = file:/core/java/android/service/voice/OWNERS diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index c220428df58b..5fea76a7228e 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -41,7 +41,6 @@ import android.os.UserHandle; import android.os.ZygoteProcess; import android.os.storage.StorageManager; import android.provider.DeviceConfig; -import android.security.keystore.AndroidKeyStoreProvider; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; @@ -74,7 +73,6 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.security.Provider; import java.security.Security; -import java.util.Optional; /** * Startup class for the zygote process. @@ -227,17 +225,7 @@ public class ZygoteInit { // AndroidKeyStoreProvider.install() manipulates the list of JCA providers to insert // preferred providers. Note this is not done via security.properties as the JCA providers // are not on the classpath in the case of, for example, raw dalvikvm runtimes. - // TODO b/171305684 This code is used to conditionally enable the installation of the - // Keystore 2.0 provider to enable teams adjusting to Keystore 2.0 at their own - // pace. This code will be removed when all calling code was adjusted to - // Keystore 2.0. - Optional<Boolean> keystore2_enabled = - android.sysprop.Keystore2Properties.keystore2_enabled(); - if (keystore2_enabled.isPresent() && keystore2_enabled.get()) { - android.security.keystore2.AndroidKeyStoreProvider.install(); - } else { - AndroidKeyStoreProvider.install(); - } + android.security.keystore2.AndroidKeyStoreProvider.install(); Log.i(TAG, "Installed AndroidKeyStoreProvider in " + (SystemClock.uptimeMillis() - startTime) + "ms."); Trace.traceEnd(Trace.TRACE_TAG_DALVIK); diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 04faebc7beff..63743051bc40 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -52,6 +52,7 @@ #include <string.h> #include <sys/epoll.h> #include <sys/errno.h> +#include <sys/pidfd.h> #include <sys/resource.h> #include <sys/stat.h> #include <sys/syscall.h> @@ -1290,14 +1291,8 @@ void android_os_Process_removeAllProcessGroups(JNIEnv* env, jobject clazz) return removeAllProcessGroups(); } -// Wrapper function to the syscall pidfd_open, which creates a file -// descriptor that refers to the process whose PID is specified in pid. -static inline int sys_pidfd_open(pid_t pid, unsigned int flags) { - return syscall(__NR_pidfd_open, pid, flags); -} - static jint android_os_Process_nativePidFdOpen(JNIEnv* env, jobject, jint pid, jint flags) { - int fd = sys_pidfd_open(pid, flags); + int fd = pidfd_open(pid, flags); if (fd < 0) { jniThrowErrnoException(env, "nativePidFdOpen", errno); return -1; diff --git a/core/proto/android/net/networkcapabilities.proto b/core/proto/android/net/networkcapabilities.proto new file mode 100644 index 000000000000..edb6c0400062 --- /dev/null +++ b/core/proto/android/net/networkcapabilities.proto @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2017 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"; + +package android.net; + +option java_multiple_files = true; + +import "frameworks/base/core/proto/android/privacy.proto"; +import "frameworks/proto_logging/stats/enums/net/enums.proto"; + +/** + * An android.net.NetworkCapabilities object. + */ +message NetworkCapabilitiesProto { + option (.android.msg_privacy).dest = DEST_AUTOMATIC; + + repeated Transport transports = 1; + + enum NetCapability { + // Indicates this is a network that has the ability to reach the + // carrier's MMSC for sending and receiving MMS messages. + NET_CAPABILITY_MMS = 0; + // Indicates this is a network that has the ability to reach the + // carrier's SUPL server, used to retrieve GPS information. + NET_CAPABILITY_SUPL = 1; + // Indicates this is a network that has the ability to reach the + // carrier's DUN or tethering gateway. + NET_CAPABILITY_DUN = 2; + // Indicates this is a network that has the ability to reach the + // carrier's FOTA portal, used for over the air updates. + NET_CAPABILITY_FOTA = 3; + // Indicates this is a network that has the ability to reach the + // carrier's IMS servers, used for network registration and signaling. + NET_CAPABILITY_IMS = 4; + // Indicates this is a network that has the ability to reach the + // carrier's CBS servers, used for carrier specific services. + NET_CAPABILITY_CBS = 5; + // Indicates this is a network that has the ability to reach a Wi-Fi + // direct peer. + NET_CAPABILITY_WIFI_P2P = 6; + // Indicates this is a network that has the ability to reach a carrier's + // Initial Attach servers. + NET_CAPABILITY_IA = 7; + // Indicates this is a network that has the ability to reach a carrier's + // RCS servers, used for Rich Communication Services. + NET_CAPABILITY_RCS = 8; + // Indicates this is a network that has the ability to reach a carrier's + // XCAP servers, used for configuration and control. + NET_CAPABILITY_XCAP = 9; + // Indicates this is a network that has the ability to reach a carrier's + // Emergency IMS servers or other services, used for network signaling + // during emergency calls. + NET_CAPABILITY_EIMS = 10; + // Indicates that this network is unmetered. + NET_CAPABILITY_NOT_METERED = 11; + // Indicates that this network should be able to reach the internet. + NET_CAPABILITY_INTERNET = 12; + // Indicates that this network is available for general use. If this is + // not set applications should not attempt to communicate on this + // network. Note that this is simply informative and not enforcement - + // enforcement is handled via other means. Set by default. + NET_CAPABILITY_NOT_RESTRICTED = 13; + // Indicates that the user has indicated implicit trust of this network. + // This generally means it's a sim-selected carrier, a plugged in + // ethernet, a paired BT device or a wifi the user asked to connect to. + // Untrusted networks are probably limited to unknown wifi AP. Set by + // default. + NET_CAPABILITY_TRUSTED = 14; + // Indicates that this network is not a VPN. This capability is set by + // default and should be explicitly cleared for VPN networks. + NET_CAPABILITY_NOT_VPN = 15; + // Indicates that connectivity on this network was successfully + // validated. For example, for a network with NET_CAPABILITY_INTERNET, + // it means that Internet connectivity was successfully detected. + NET_CAPABILITY_VALIDATED = 16; + // Indicates that this network was found to have a captive portal in + // place last time it was probed. + NET_CAPABILITY_CAPTIVE_PORTAL = 17; + // Indicates that this network is not roaming. + NET_CAPABILITY_NOT_ROAMING = 18; + // Indicates that this network is available for use by apps, and not a + // network that is being kept up in the background to facilitate fast + // network switching. + NET_CAPABILITY_FOREGROUND = 19; + } + repeated NetCapability capabilities = 2; + + // Passive link bandwidth. This is a rough guide of the expected peak + // bandwidth for the first hop on the given transport. It is not measured, + // but may take into account link parameters (Radio technology, allocated + // channels, etc). + optional int32 link_up_bandwidth_kbps = 3; + optional int32 link_down_bandwidth_kbps = 4; + + optional string network_specifier = 5 [ (.android.privacy).dest = DEST_EXPLICIT ]; + + // True if this object specifies a signal strength. + optional bool can_report_signal_strength = 6; + // This is a signed integer, and higher values indicate better signal. The + // exact units are bearer-dependent. For example, Wi-Fi uses RSSI. + // Only valid if can_report_signal_strength is true. + optional sint32 signal_strength = 7; +} diff --git a/core/proto/android/net/networkrequest.proto b/core/proto/android/net/networkrequest.proto index 0041f199b448..57b9f7162e67 100644 --- a/core/proto/android/net/networkrequest.proto +++ b/core/proto/android/net/networkrequest.proto @@ -20,8 +20,8 @@ package android.net; option java_multiple_files = true; +import "frameworks/base/core/proto/android/net/networkcapabilities.proto"; import "frameworks/base/core/proto/android/privacy.proto"; -import "frameworks/proto_logging/stats/enums/net/networkcapabilities.proto"; /** * An android.net.NetworkRequest object. diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto index e97b1a8770ed..64cf75d51c3d 100644 --- a/core/proto/android/os/incident.proto +++ b/core/proto/android/os/incident.proto @@ -55,13 +55,13 @@ import "frameworks/base/core/proto/android/service/print.proto"; import "frameworks/base/core/proto/android/service/procstats.proto"; import "frameworks/base/core/proto/android/service/restricted_image.proto"; import "frameworks/base/core/proto/android/service/sensor_service.proto"; +import "frameworks/base/core/proto/android/service/usb.proto"; import "frameworks/base/core/proto/android/util/event_log_tags.proto"; import "frameworks/base/core/proto/android/util/log.proto"; import "frameworks/base/core/proto/android/util/textdump.proto"; import "frameworks/base/core/proto/android/privacy.proto"; import "frameworks/base/core/proto/android/section.proto"; import "frameworks/base/proto/src/ipconnectivity.proto"; -import "frameworks/proto_logging/stats/enums/service/usb.proto"; package android.os; diff --git a/core/proto/android/service/enums.proto b/core/proto/android/service/enums.proto deleted file mode 100644 index b64e685104b7..000000000000 --- a/core/proto/android/service/enums.proto +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2018 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"; -package android.service; - -option java_outer_classname = "ServiceProtoEnums"; -option java_multiple_files = true; - -enum UsbEndPointType { - USB_ENDPOINT_TYPE_XFER_CONTROL = 0; - USB_ENDPOINT_TYPE_XFER_ISOC = 1; - USB_ENDPOINT_TYPE_XFER_BULK = 2; - USB_ENDPOINT_TYPE_XFER_INT = 3; -} - -enum UsbEndPointDirection { - USB_ENDPOINT_DIR_OUT = 0; - USB_ENDPOINT_DIR_IN = 0x80; -} - -enum UsbConnectionRecordMode { - USB_CONNECTION_RECORD_MODE_CONNECT = 0; - USB_CONNECTION_RECORD_MODE_CONNECT_BADPARSE = 1; - USB_CONNECTION_RECORD_MODE_CONNECT_BADDEVICE = 2; - USB_CONNECTION_RECORD_MODE_DISCONNECT = -1; -}
\ No newline at end of file diff --git a/core/proto/android/service/usb.proto b/core/proto/android/service/usb.proto new file mode 100644 index 000000000000..dd313aa81726 --- /dev/null +++ b/core/proto/android/service/usb.proto @@ -0,0 +1,431 @@ +/* + * Copyright (C) 2018 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"; +package android.service.usb; + +option java_multiple_files = true; +option java_outer_classname = "UsbServiceProto"; + +import "frameworks/base/core/proto/android/content/component_name.proto"; +import "frameworks/base/core/proto/android/privacy.proto"; +import "frameworks/proto_logging/stats/enums/service/enums.proto"; + +message UsbServiceDumpProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional UsbDeviceManagerProto device_manager = 1; + optional UsbHostManagerProto host_manager = 2; + optional UsbPortManagerProto port_manager = 3; + optional UsbAlsaManagerProto alsa_manager = 4; + optional UsbSettingsManagerProto settings_manager = 5; + optional UsbPermissionsManagerProto permissions_manager = 6; +} + +message UsbDeviceManagerProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional UsbHandlerProto handler = 1; + optional UsbDebuggingManagerProto debugging_manager = 2; +} + +message UsbHandlerProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + /* Same as android.hardware.usb.gadget.V1_0.GadgetFunction.* */ + enum Function { + FUNCTION_ADB = 1; + FUNCTION_ACCESSORY = 2; + FUNCTION_MTP = 4; + FUNCTION_MIDI = 8; + FUNCTION_PTP = 16; + FUNCTION_RNDIS = 32; + FUNCTION_AUDIO_SOURCE = 64; + } + + repeated Function current_functions = 1; + optional bool current_functions_applied = 2; + repeated Function screen_unlocked_functions = 3; + optional bool screen_locked = 4; + optional bool connected = 5; + optional bool configured = 6; + optional UsbAccessoryProto current_accessory = 7; + optional bool host_connected = 8; + optional bool source_power = 9; + optional bool sink_power = 10; + optional bool usb_charging = 11; + optional bool hide_usb_notification = 12; + optional bool audio_accessory_connected = 13; + optional bool adb_enabled = 14; + optional string kernel_state = 15; + optional string kernel_function_list = 16; +} + +message UsbAccessoryProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional string manufacturer = 1; + optional string model = 2; + // For "classical" USB-accessories the manufacturer bakes this into the + // firmware of the device. If an Android phone is configured as accessory, the + // app that sets up the accessory side of the connection set this. Either way, + // these are part of the detection protocol, and so they cannot be user set or + // unique. + optional string description = 3; + optional string version = 4; + optional string uri = 5 [ (android.privacy).dest = DEST_EXPLICIT ]; + // Non-resettable hardware ID. + optional string serial = 6 [ (android.privacy).dest = DEST_LOCAL ]; +} + +message UsbDebuggingManagerProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional bool connected_to_adb = 1; + // A workstation that connects to the phone for debugging is identified by + // this key. + optional string last_key_received = 2 [ (android.privacy).dest = DEST_EXPLICIT ]; + optional string user_keys = 3 [ (android.privacy).dest = DEST_LOCAL ]; + optional string system_keys = 4 [ (android.privacy).dest = DEST_LOCAL ]; +} + +message UsbHostManagerProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional android.content.ComponentNameProto default_usb_host_connection_handler = 1; + repeated UsbDeviceProto devices = 2; + optional int32 num_connects = 3; + repeated UsbConnectionRecordProto connections = 4; +} + +message UsbDeviceProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + // Generic USB name, not user-provided. + optional string name = 1; + // ID specific to the vendor, not the device. + optional int32 vendor_id = 2; + // ID of this product type: Each vendor gives each product a unique ID. E.g. + // all mice of the same model would have the same ID. + optional int32 product_id = 3; + optional int32 class = 4; + optional int32 subclass = 5; + optional int32 protocol = 6; + optional string manufacturer_name = 7; + optional string product_name = 8; + optional string version = 9; + // Non-resettable hardware ID. + optional string serial_number = 10 [ (android.privacy).dest = DEST_LOCAL ]; + repeated UsbConfigurationProto configurations = 11; +} + +message UsbConfigurationProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + // A single USB device can have several configurations and the app accessing + // the USB device can switch between them. At any time only one can be active. + // Each configuration can present completely different interfaces end + // endpoints, i.e. a completely different behavior. + optional int32 id = 1; + // Hardware-defined name, not set by the user. + optional string name = 2; + optional uint32 attributes = 3; + optional int32 max_power = 4; + repeated UsbInterfaceProto interfaces = 5; +} + +message UsbInterfaceProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + // Hardware defined. This is the id used by the app to identify the interface. + optional int32 id = 1; + optional int32 alternate_settings = 2; + optional string name = 3; + optional int32 class = 4; + optional int32 subclass = 5; + optional int32 protocol = 6; + repeated UsbEndPointProto endpoints = 7; +} + +message UsbEndPointProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional int32 endpoint_number = 1; + optional android.service.UsbEndPointDirection direction = 2; + // The address of the endpoint. Needed to read and write to the endpoint. + optional int32 address = 3; + optional android.service.UsbEndPointType type = 4; + optional uint32 attributes = 5; + optional int32 max_packet_size = 6; + optional int32 interval = 7; +} + +message UsbConnectionRecordProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + // usb device's address, e.g. 001/002, nothing about the phone + optional string device_address = 1; + optional android.service.UsbConnectionRecordMode mode = 2; + optional int64 timestamp = 3; + optional int32 manufacturer = 4; + optional int32 product = 5; + optional UsbIsHeadsetProto is_headset = 6; +} + +message UsbIsHeadsetProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional bool in = 1; + optional bool out = 2; +} + +message UsbPortManagerProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional bool is_simulation_active = 1; + repeated UsbPortInfoProto usb_ports = 2; +} + +message UsbPortInfoProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional UsbPortProto port = 1; + optional UsbPortStatusProto status = 2; + optional bool can_change_mode = 3; + optional bool can_change_power_role = 4; + optional bool can_change_data_role = 5; + optional int64 connected_at_millis = 6; + optional int64 last_connect_duration_millis = 7; +} + +message UsbPortProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + /* Same as android.hardware.usb.V1_1.Constants.PortMode_1_1 */ + enum Mode { + MODE_NONE = 0; + MODE_UFP = 1; + MODE_DFP = 2; + MODE_DRP = 3; + MODE_AUDIO_ACCESSORY = 4; + MODE_DEBUG_ACCESSORY = 8; + } + + // ID of the port. A device (eg: Chromebooks) might have multiple ports. + optional string id = 1; + repeated Mode supported_modes = 2; +} + +message UsbPortStatusProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + /* Same as android.hardware.usb.V1_0.Constants.PortPowerRole */ + enum PowerRole { + POWER_ROLE_NONE = 0; + POWER_ROLE_SOURCE = 1; + POWER_ROLE_SINK = 2; + } + + /* Same as android.hardware.usb.V1_0.Constants.PortDataRole */ + enum DataRole { + DATA_ROLE_NONE = 0; + DATA_ROLE_HOST = 1; + DATA_ROLE_DEVICE = 2; + } + + optional bool connected = 1; + optional UsbPortProto.Mode current_mode = 2; + optional PowerRole power_role = 3; + optional DataRole data_role = 4; + repeated UsbPortStatusRoleCombinationProto role_combinations = 5; + optional android.service.ContaminantPresenceStatus contaminant_presence_status = 6; +} + +message UsbPortStatusRoleCombinationProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional UsbPortStatusProto.PowerRole power_role = 1; + optional UsbPortStatusProto.DataRole data_role = 2; +} + +message UsbAlsaManagerProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional int32 cards_parser = 1; + repeated UsbAlsaDeviceProto alsa_devices = 2; + repeated UsbMidiDeviceProto midi_devices = 3; +} + +message UsbAlsaDeviceProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional int32 card = 1; + optional int32 device = 2; + optional string name = 3; + optional bool has_playback = 4; + optional bool has_capture = 5; + // usb device's address, e.g. 001/002, nothing about the phone + optional string address = 6; +} + +message UsbMidiDeviceProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional int32 card = 1; + optional int32 device = 2; + // usb device's address, e.g. 001/002, nothing about the phone + optional string device_address = 3; +} + +message UsbSettingsManagerProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + repeated UsbUserSettingsManagerProto user_settings = 1; + repeated UsbProfileGroupSettingsManagerProto profile_group_settings = 2; +} + +message UsbUserSettingsManagerProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional int32 user_id = 1; + reserved 2; // previously device_permissions, now unused + reserved 3; // previously accessory_permissions, now unused + repeated UsbDeviceAttachedActivities device_attached_activities = 4; + repeated UsbAccessoryAttachedActivities accessory_attached_activities = 5; +} + +message UsbProfileGroupSettingsManagerProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + // The user id of the personal profile if the device has a work profile. + optional int32 parent_user_id = 1; + repeated UsbSettingsDevicePreferenceProto device_preferences = 2; + repeated UsbSettingsAccessoryPreferenceProto accessory_preferences = 3; +} + +message UsbSettingsDevicePreferenceProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional UsbDeviceFilterProto filter = 1; + optional UserPackageProto user_package = 2; +} + +message UsbPermissionsManagerProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + repeated UsbUserPermissionsManagerProto user_permissions = 1; +} + +message UsbUserPermissionsManagerProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional int32 user_id = 1; + + repeated UsbDevicePermissionProto device_permissions = 2; + repeated UsbAccessoryPermissionProto accessory_permissions = 3; + + repeated UsbDevicePersistentPermissionProto device_persistent_permissions = 4; + repeated UsbAccessoryPersistentPermissionProto accessory_persistent_permissions = 5; +} + +message UsbDevicePermissionProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + // Name of device set by manufacturer + // All devices of the same model have the same name + optional string device_name = 1; + repeated int32 uids = 2; +} + +message UsbAccessoryPermissionProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + // Description of accessory set by manufacturer + // All accessories of the same model have the same description + optional string accessory_description = 1; + repeated int32 uids = 2; +} + +message UsbDevicePersistentPermissionProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional UsbDeviceFilterProto device_filter = 1; + repeated UsbUidPermissionProto permission_values = 2; +} + +message UsbAccessoryPersistentPermissionProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional UsbAccessoryFilterProto accessory_filter = 1; + repeated UsbUidPermissionProto permission_values = 2; +} + +message UsbUidPermissionProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional int32 uid = 1; + optional bool is_granted = 2; +} + +message UsbDeviceFilterProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + // Mirrors the vendor_id of UsbDeviceProto. + optional int32 vendor_id = 1; + optional int32 product_id = 2; + optional int32 class = 3; + optional int32 subclass = 4; + optional int32 protocol = 5; + optional string manufacturer_name = 6; + optional string product_name = 7; + optional string serial_number = 8 [ (android.privacy).dest = DEST_EXPLICIT ]; +} + +message UserPackageProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional int32 user_id = 1; + optional string package_name =2; +} + +message UsbSettingsAccessoryPreferenceProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional UsbAccessoryFilterProto filter = 1; + optional UserPackageProto user_package = 2; +} + +message UsbAccessoryFilterProto { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional string manufacturer = 1; + optional string model = 2; + optional string version = 3; +} + +message UsbDeviceAttachedActivities { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional android.content.ComponentNameProto activity = 1; + repeated UsbDeviceFilterProto filters = 2; +} + +message UsbAccessoryAttachedActivities { + option (android.msg_privacy).dest = DEST_AUTOMATIC; + + optional android.content.ComponentNameProto activity = 1; + repeated UsbAccessoryFilterProto filters = 2; +} diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java index d9d5300e43f9..9d8a5effc2d7 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java @@ -124,7 +124,7 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor resetAll(); // Public key operations get diverted to the default provider. - if (opmode == Cipher.ENCRYPT_MODE + if (!(key instanceof AndroidKeyStorePrivateKey) && (key instanceof PrivateKey || key instanceof PublicKey)) { try { mCipher = Cipher.getInstance(getTransform()); @@ -186,7 +186,7 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor resetAll(); // Public key operations get diverted to the default provider. - if (opmode == Cipher.ENCRYPT_MODE + if (!(key instanceof AndroidKeyStorePrivateKey) && (key instanceof PrivateKey || key instanceof PublicKey)) { try { mCipher = Cipher.getInstance(getTransform()); @@ -216,7 +216,7 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor resetAll(); // Public key operations get diverted to the default provider. - if (opmode == Cipher.ENCRYPT_MODE + if (!(key instanceof AndroidKeyStorePrivateKey) && (key instanceof PrivateKey || key instanceof PublicKey)) { try { mCipher = Cipher.getInstance(getTransform()); diff --git a/media/jni/Android.bp b/media/jni/Android.bp index f65dfddef008..517e192e00af 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -19,6 +19,7 @@ cc_library_shared { name: "libmedia_jni", defaults: ["libcodec2-internal-defaults"], + min_sdk_version: "", srcs: [ "android_media_ImageWriter.cpp", diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt index f22d4b7b779a..e415e01fea3a 100644 --- a/packages/Connectivity/framework/api/current.txt +++ b/packages/Connectivity/framework/api/current.txt @@ -291,6 +291,7 @@ package android.net { ctor public NetworkCapabilities(); ctor public NetworkCapabilities(android.net.NetworkCapabilities); method public int describeContents(); + method @NonNull public int[] getCapabilities(); method public int getLinkDownstreamBandwidthKbps(); method public int getLinkUpstreamBandwidthKbps(); method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier(); diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt index 7a91f6454b90..8629c1971b7b 100644 --- a/packages/Connectivity/framework/api/module-lib-current.txt +++ b/packages/Connectivity/framework/api/module-lib-current.txt @@ -19,6 +19,7 @@ package android.net { method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo); 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.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 String PRIVATE_DNS_MODE_OFF = "off"; field public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic"; diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java index f748159e893c..e32622391cda 100644 --- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java +++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java @@ -4461,12 +4461,20 @@ public class ConnectivityManager { /** * Requests that the system open the captive portal app on the specified network. * + * <p>This is to be used on networks where a captive portal was detected, as per + * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}. + * * @param network The network to log into. * * @hide */ - @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) - public void startCaptivePortalApp(Network network) { + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_SETTINGS, + android.Manifest.permission.NETWORK_STACK, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK + }) + public void startCaptivePortalApp(@NonNull Network network) { try { mService.startCaptivePortalApp(network); } catch (RemoteException e) { diff --git a/packages/Connectivity/framework/src/android/net/InetAddressCompat.java b/packages/Connectivity/framework/src/android/net/InetAddressCompat.java index 8404441de669..6b7e75c75359 100644 --- a/packages/Connectivity/framework/src/android/net/InetAddressCompat.java +++ b/packages/Connectivity/framework/src/android/net/InetAddressCompat.java @@ -41,7 +41,12 @@ public class InetAddressCompat { public static void clearDnsCache() { try { InetAddress.class.getMethod("clearDnsCache").invoke(null); - } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + } catch (InvocationTargetException e) { + if (e.getCause() instanceof RuntimeException) { + throw (RuntimeException) e.getCause(); + } + throw new IllegalStateException("Unknown InvocationTargetException", e.getCause()); + } catch (IllegalAccessException | NoSuchMethodException e) { Log.wtf(InetAddressCompat.class.getSimpleName(), "Error clearing DNS cache", e); } } @@ -51,13 +56,7 @@ public class InetAddressCompat { */ public static InetAddress[] getAllByNameOnNet(String host, int netId) throws UnknownHostException { - try { - return (InetAddress[]) InetAddress.class.getMethod("getAllByNameOnNet", - String.class, int.class).invoke(null, host, netId); - } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { - Log.wtf(InetAddressCompat.class.getSimpleName(), "Error calling getAllByNameOnNet", e); - throw new IllegalStateException("Error querying via getAllNameOnNet", e); - } + return (InetAddress[]) callGetByNameMethod("getAllByNameOnNet", host, netId); } /** @@ -65,12 +64,25 @@ public class InetAddressCompat { */ public static InetAddress getByNameOnNet(String host, int netId) throws UnknownHostException { + return (InetAddress) callGetByNameMethod("getByNameOnNet", host, netId); + } + + private static Object callGetByNameMethod(String method, String host, int netId) + throws UnknownHostException { try { - return (InetAddress) InetAddress.class.getMethod("getByNameOnNet", - String.class, int.class).invoke(null, host, netId); - } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { - Log.wtf(InetAddressCompat.class.getSimpleName(), "Error calling getAllByNameOnNet", e); - throw new IllegalStateException("Error querying via getByNameOnNet", e); + return InetAddress.class.getMethod(method, String.class, int.class) + .invoke(null, host, netId); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof UnknownHostException) { + throw (UnknownHostException) e.getCause(); + } + if (e.getCause() instanceof RuntimeException) { + throw (RuntimeException) e.getCause(); + } + throw new IllegalStateException("Unknown InvocationTargetException", e.getCause()); + } catch (IllegalAccessException | NoSuchMethodException e) { + Log.wtf(InetAddressCompat.class.getSimpleName(), "Error calling " + method, e); + throw new IllegalStateException("Error querying via " + method, e); } } } diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java index 664c2650ff0c..5e50a6404acb 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java +++ b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java @@ -50,7 +50,8 @@ public final class NetworkAgentConfig implements Parcelable { * ap in the wifi settings to trigger a connection is explicit. A 3rd party app asking to * connect to a particular access point is also explicit, though this may change in the future * as we want apps to use the multinetwork apis. - * + * TODO : this is a bad name, because it sounds like the user just tapped on the network. + * It's not necessarily the case ; auto-reconnection to WiFi has this true for example. * @hide */ public boolean explicitlySelected; diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java index 058f3c999dd7..5ec7aa1b23ac 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java +++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java @@ -609,10 +609,8 @@ public final class NetworkCapabilities implements Parcelable { * Gets all the capabilities set on this {@code NetworkCapability} instance. * * @return an array of capability values for this instance. - * @hide */ - @UnsupportedAppUsage - public @NetCapability int[] getCapabilities() { + public @NonNull @NetCapability int[] getCapabilities() { return NetworkCapabilitiesUtils.unpackBits(mNetworkCapabilities); } diff --git a/packages/Connectivity/framework/src/android/net/NetworkScore.java b/packages/Connectivity/framework/src/android/net/NetworkScore.java index f47801002296..eadcb2d0a7f4 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkScore.java +++ b/packages/Connectivity/framework/src/android/net/NetworkScore.java @@ -20,6 +20,8 @@ import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.annotations.VisibleForTesting; + /** * Object representing the quality of a network as perceived by the user. * @@ -33,19 +35,39 @@ public final class NetworkScore implements Parcelable { // a migration. private final int mLegacyInt; + // Agent-managed policies + // TODO : add them here, starting from 1 + /** @hide */ + public static final int MIN_AGENT_MANAGED_POLICY = 0; + /** @hide */ + public static final int MAX_AGENT_MANAGED_POLICY = -1; + + // Bitmask of all the policies applied to this score. + private final long mPolicies; + /** @hide */ - NetworkScore(final int legacyInt) { - this.mLegacyInt = legacyInt; + NetworkScore(final int legacyInt, final long policies) { + mLegacyInt = legacyInt; + mPolicies = policies; } private NetworkScore(@NonNull final Parcel in) { mLegacyInt = in.readInt(); + mPolicies = in.readLong(); } public int getLegacyInt() { return mLegacyInt; } + /** + * @return whether this score has a particular policy. + */ + @VisibleForTesting + public boolean hasPolicy(final int policy) { + return 0 != (mPolicies & (1L << policy)); + } + @Override public String toString() { return "Score(" + mLegacyInt + ")"; @@ -54,6 +76,7 @@ public final class NetworkScore implements Parcelable { @Override public void writeToParcel(@NonNull final Parcel dest, final int flags) { dest.writeInt(mLegacyInt); + dest.writeLong(mPolicies); } @Override @@ -79,6 +102,7 @@ public final class NetworkScore implements Parcelable { * A builder for NetworkScore. */ public static final class Builder { + private static final long POLICY_NONE = 0L; private static final int INVALID_LEGACY_INT = Integer.MIN_VALUE; private int mLegacyInt = INVALID_LEGACY_INT; @@ -102,7 +126,7 @@ public final class NetworkScore implements Parcelable { */ @NonNull public NetworkScore build() { - return new NetworkScore(mLegacyInt); + return new NetworkScore(mLegacyInt, POLICY_NONE); } } } diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java index 3bb3a0c412a5..7f12cc8e6911 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java @@ -18,6 +18,7 @@ package com.android.settingslib.deviceinfo; import android.content.Context; import android.net.ConnectivityManager; +import android.net.LinkAddress; import android.net.LinkProperties; import android.net.wifi.WifiManager; @@ -28,7 +29,6 @@ import androidx.preference.PreferenceScreen; import com.android.settingslib.R; import com.android.settingslib.core.lifecycle.Lifecycle; -import java.net.InetAddress; import java.util.Iterator; /** @@ -93,19 +93,19 @@ public abstract class AbstractIpAddressPreferenceController * @return the formatted and newline-separated IP addresses, or null if none. */ private static String getDefaultIpAddresses(ConnectivityManager cm) { - LinkProperties prop = cm.getActiveLinkProperties(); + LinkProperties prop = cm.getLinkProperties(cm.getActiveNetwork()); return formatIpAddresses(prop); } private static String formatIpAddresses(LinkProperties prop) { if (prop == null) return null; - Iterator<InetAddress> iter = prop.getAllAddresses().iterator(); + Iterator<LinkAddress> iter = prop.getAllLinkAddresses().iterator(); // If there are no entries, return null if (!iter.hasNext()) return null; // Concatenate all available addresses, newline separated StringBuilder addresses = new StringBuilder(); while (iter.hasNext()) { - addresses.append(iter.next().getHostAddress()); + addresses.append(iter.next().getAddress().getHostAddress()); if (iter.hasNext()) addresses.append("\n"); } return addresses.toString(); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 58a921f0e3be..f527da582959 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -72,8 +72,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; 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.RULE_NONE; -import static android.net.NetworkPolicyManager.uidRulesToString; +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; import static android.os.Process.INVALID_UID; @@ -117,7 +117,6 @@ import android.net.INetd; import android.net.INetworkActivityListener; import android.net.INetworkMonitor; import android.net.INetworkMonitorCallbacks; -import android.net.INetworkPolicyListener; import android.net.IOnCompleteListener; import android.net.IQosCallback; import android.net.ISocketKeepaliveCallback; @@ -135,6 +134,7 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkMonitorManager; import android.net.NetworkPolicyManager; +import android.net.NetworkPolicyManager.NetworkPolicyCallback; import android.net.NetworkProvider; import android.net.NetworkRequest; import android.net.NetworkScore; @@ -331,12 +331,10 @@ public class ConnectivityService extends IConnectivityManager.Stub private volatile boolean mLockdownEnabled; /** - * Stale copy of uid rules provided by NPMS. As long as they are accessed only in internal - * handler thread, they don't need a lock. + * Stale copy of uid blocked reasons provided by NPMS. As long as they are accessed only in + * internal handler thread, they don't need a lock. */ - private SparseIntArray mUidRules = new SparseIntArray(); - /** Flag indicating if background data is restricted. */ - private boolean mRestrictBackground; + private SparseIntArray mUidBlockedReasons = new SparseIntArray(); private final Context mContext; private final ConnectivityResources mResources; @@ -510,16 +508,6 @@ public class ConnectivityService extends IConnectivityManager.Stub // Handle private DNS validation status updates. private static final int EVENT_PRIVATE_DNS_VALIDATION_UPDATE = 38; - /** - * Used to handle onUidRulesChanged event from NetworkPolicyManagerService. - */ - private static final int EVENT_UID_RULES_CHANGED = 39; - - /** - * Used to handle onRestrictBackgroundChanged event from NetworkPolicyManagerService. - */ - private static final int EVENT_DATA_SAVER_CHANGED = 40; - /** * Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the network has * been tested. @@ -596,6 +584,13 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final int EVENT_SET_PROFILE_NETWORK_PREFERENCE = 50; /** + * Event to specify that reasons for why an uid is blocked changed. + * arg1 = uid + * arg2 = blockedReasons + */ + private static final int EVENT_UID_BLOCKED_REASON_CHANGED = 51; + + /** * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification * should be shown. */ @@ -1253,10 +1248,10 @@ public class ConnectivityService extends IConnectivityManager.Stub mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); mLocationPermissionChecker = new LocationPermissionChecker(mContext); - // To ensure uid rules are synchronized with Network Policy, register for + // To ensure uid state is synchronized with Network Policy, register for // NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService // reading existing policy from disk. - mPolicyManager.registerListener(mPolicyListener); + mPolicyManager.registerNetworkPolicyCallback(null, mPolicyCallback); final PowerManager powerManager = (PowerManager) context.getSystemService( Context.POWER_SERVICE); @@ -1785,7 +1780,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } // No need to check mLockdownEnabled. If it's true, getVpnUnderlyingNetworks returns null. - final Network[] networks = getVpnUnderlyingNetworks(Binder.getCallingUid()); + final Network[] networks = getVpnUnderlyingNetworks(mDeps.getCallingUid()); if (null != networks) { for (final Network network : networks) { final NetworkCapabilities nc = getNetworkCapabilitiesInternal(network); @@ -2237,53 +2232,17 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private final INetworkPolicyListener mPolicyListener = new NetworkPolicyManager.Listener() { - @Override - public void onUidRulesChanged(int uid, int uidRules) { - mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_RULES_CHANGED, uid, uidRules)); - } + private final NetworkPolicyCallback mPolicyCallback = new NetworkPolicyCallback() { @Override - public void onRestrictBackgroundChanged(boolean restrictBackground) { - // caller is NPMS, since we only register with them - if (LOGD_BLOCKED_NETWORKINFO) { - log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")"); - } - mHandler.sendMessage(mHandler.obtainMessage( - EVENT_DATA_SAVER_CHANGED, restrictBackground ? 1 : 0, 0)); + public void onUidBlockedReasonChanged(int uid, int blockedReasons) { + mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_BLOCKED_REASON_CHANGED, + uid, blockedReasons)); } }; - void handleUidRulesChanged(int uid, int newRules) { - // skip update when we've already applied rules - final int oldRules = mUidRules.get(uid, RULE_NONE); - if (oldRules == newRules) return; - - maybeNotifyNetworkBlockedForNewUidRules(uid, newRules); - - if (newRules == RULE_NONE) { - mUidRules.delete(uid); - } else { - mUidRules.put(uid, newRules); - } - } - - void handleRestrictBackgroundChanged(boolean restrictBackground) { - if (mRestrictBackground == restrictBackground) return; - - final List<UidRange> blockedRanges = mVpnBlockedUidRanges; - for (final NetworkAgentInfo nai : mNetworkAgentInfos) { - final boolean curMetered = nai.networkCapabilities.isMetered(); - maybeNotifyNetworkBlocked(nai, curMetered, curMetered, mRestrictBackground, - restrictBackground, blockedRanges, blockedRanges); - } - - mRestrictBackground = restrictBackground; - } - - private boolean isUidBlockedByRules(int uid, int uidRules, boolean isNetworkMetered, - boolean isBackgroundRestricted) { - return mPolicyManager.checkUidNetworkingBlocked(uid, uidRules, isNetworkMetered, - isBackgroundRestricted); + void handleUidBlockedReasonChanged(int uid, int blockedReasons) { + maybeNotifyNetworkBlockedForNewState(uid, blockedReasons); + mUidBlockedReasons.put(uid, blockedReasons); } private boolean checkAnyPermissionOf(String... permissions) { @@ -2757,19 +2716,16 @@ public class ConnectivityService extends IConnectivityManager.Stub pw.decreaseIndent(); pw.println(); - pw.print("Restrict background: "); - pw.println(mRestrictBackground); - pw.println(); - pw.println("Status for known UIDs:"); pw.increaseIndent(); - final int size = mUidRules.size(); + final int size = mUidBlockedReasons.size(); for (int i = 0; i < size; i++) { // Don't crash if the array is modified while dumping in bugreports. try { - final int uid = mUidRules.keyAt(i); - final int uidRules = mUidRules.get(uid, RULE_NONE); - pw.println("UID=" + uid + " rules=" + uidRulesToString(uidRules)); + final int uid = mUidBlockedReasons.keyAt(i); + final int blockedReasons = mUidBlockedReasons.valueAt(i); + pw.println("UID=" + uid + " blockedReasons=" + + blockedReasonsToString(blockedReasons)); } catch (ArrayIndexOutOfBoundsException e) { pw.println(" ArrayIndexOutOfBoundsException"); } catch (ConcurrentModificationException e) { @@ -3005,6 +2961,9 @@ public class ConnectivityService extends IConnectivityManager.Stub case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: { if (nai.everConnected) { loge("ERROR: cannot call explicitlySelected on already-connected network"); + // Note that if the NAI had been connected, this would affect the + // score, and therefore would require re-mixing the score and performing + // a rematch. } nai.networkAgentConfig.explicitlySelected = toBool(msg.arg1); nai.networkAgentConfig.acceptUnvalidated = toBool(msg.arg1) && toBool(msg.arg2); @@ -3691,7 +3650,7 @@ public class ConnectivityService extends IConnectivityManager.Stub log("Replacing " + existingRequest.mRequests.get(0) + " with " + nri.mRequests.get(0) + " because their intents matched."); } - handleReleaseNetworkRequest(existingRequest.mRequests.get(0), getCallingUid(), + handleReleaseNetworkRequest(existingRequest.mRequests.get(0), mDeps.getCallingUid(), /* callOnUnavailable */ false); } handleRegisterNetworkRequest(nri); @@ -4089,6 +4048,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // network, we should respect the user's option and don't need to popup the // PARTIAL_CONNECTIVITY notification to user again. nai.networkAgentConfig.acceptPartialConnectivity = accept; + nai.updateScoreForNetworkAgentConfigUpdate(); rematchAllNetworksAndRequests(); sendUpdatedScoreToFactories(nai); } @@ -4351,7 +4311,7 @@ public class ConnectivityService extends IConnectivityManager.Stub Intent intent = new Intent(action); if (type != NotificationType.PRIVATE_DNS_BROKEN) { - intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.getNetId()), null)); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK, nai.network); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // Some OEMs have their own Settings package. Thus, need to get the current using // Settings package name instead of just use default name "com.android.settings". @@ -4566,11 +4526,8 @@ public class ConnectivityService extends IConnectivityManager.Stub handlePrivateDnsValidationUpdate( (PrivateDnsValidationUpdate) msg.obj); break; - case EVENT_UID_RULES_CHANGED: - handleUidRulesChanged(msg.arg1, msg.arg2); - break; - case EVENT_DATA_SAVER_CHANGED: - handleRestrictBackgroundChanged(toBool(msg.arg1)); + case EVENT_UID_BLOCKED_REASON_CHANGED: + handleUidBlockedReasonChanged(msg.arg1, msg.arg2); break; case EVENT_SET_REQUIRE_VPN_FOR_UIDS: handleSetRequireVpnForUids(toBool(msg.arg1), (UidRange[]) msg.obj); @@ -5043,8 +5000,8 @@ public class ConnectivityService extends IConnectivityManager.Stub for (final NetworkAgentInfo nai : mNetworkAgentInfos) { final boolean curMetered = nai.networkCapabilities.isMetered(); - maybeNotifyNetworkBlocked(nai, curMetered, curMetered, mRestrictBackground, - mRestrictBackground, mVpnBlockedUidRanges, newVpnBlockedUidRanges); + maybeNotifyNetworkBlocked(nai, curMetered, curMetered, + mVpnBlockedUidRanges, newVpnBlockedUidRanges); } mVpnBlockedUidRanges = newVpnBlockedUidRanges; @@ -5777,14 +5734,14 @@ public class ConnectivityService extends IConnectivityManager.Stub private void releasePendingNetworkRequestWithDelay(PendingIntent operation) { mHandler.sendMessageDelayed( mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT, - getCallingUid(), 0, operation), mReleasePendingIntentDelayMs); + mDeps.getCallingUid(), 0, operation), mReleasePendingIntentDelayMs); } @Override public void releasePendingNetworkRequest(PendingIntent operation) { Objects.requireNonNull(operation, "PendingIntent cannot be null."); mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT, - getCallingUid(), 0, operation)); + mDeps.getCallingUid(), 0, operation)); } // In order to implement the compatibility measure for pre-M apps that call @@ -5881,7 +5838,7 @@ public class ConnectivityService extends IConnectivityManager.Stub public void releaseNetworkRequest(NetworkRequest networkRequest) { ensureNetworkRequestHasType(networkRequest); mHandler.sendMessage(mHandler.obtainMessage( - EVENT_RELEASE_NETWORK_REQUEST, getCallingUid(), 0, networkRequest)); + EVENT_RELEASE_NETWORK_REQUEST, mDeps.getCallingUid(), 0, networkRequest)); } private void handleRegisterNetworkProvider(NetworkProviderInfo npi) { @@ -6827,8 +6784,8 @@ public class ConnectivityService extends IConnectivityManager.Stub final boolean meteredChanged = oldMetered != newMetered; if (meteredChanged) { - maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground, - mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges); + maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, + mVpnBlockedUidRanges, mVpnBlockedUidRanges); } final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) @@ -7951,8 +7908,8 @@ public class ConnectivityService extends IConnectivityManager.Stub final boolean metered = nai.networkCapabilities.isMetered(); boolean blocked; blocked = isUidBlockedByVpn(nri.mUid, mVpnBlockedUidRanges); - blocked |= isUidBlockedByRules(nri.mUid, mUidRules.get(nri.mUid), - metered, mRestrictBackground); + blocked |= NetworkPolicyManager.isUidBlocked( + mUidBlockedReasons.get(nri.mUid, BLOCKED_REASON_NONE), metered); callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, blocked ? 1 : 0); } @@ -7970,16 +7927,14 @@ public class ConnectivityService extends IConnectivityManager.Stub * * @param nai The target NetworkAgentInfo. * @param oldMetered True if the previous network capabilities is metered. - * @param newRestrictBackground True if data saver is enabled. */ private void maybeNotifyNetworkBlocked(NetworkAgentInfo nai, boolean oldMetered, - boolean newMetered, boolean oldRestrictBackground, boolean newRestrictBackground, - List<UidRange> oldBlockedUidRanges, List<UidRange> newBlockedUidRanges) { + boolean newMetered, List<UidRange> oldBlockedUidRanges, + List<UidRange> newBlockedUidRanges) { for (int i = 0; i < nai.numNetworkRequests(); i++) { NetworkRequest nr = nai.requestAt(i); NetworkRequestInfo nri = mNetworkRequests.get(nr); - final int uidRules = mUidRules.get(nri.mUid); final boolean oldBlocked, newBlocked, oldVpnBlocked, newVpnBlocked; oldVpnBlocked = isUidBlockedByVpn(nri.mUid, oldBlockedUidRanges); @@ -7987,10 +7942,11 @@ public class ConnectivityService extends IConnectivityManager.Stub ? isUidBlockedByVpn(nri.mUid, newBlockedUidRanges) : oldVpnBlocked; - oldBlocked = oldVpnBlocked || isUidBlockedByRules(nri.mUid, uidRules, oldMetered, - oldRestrictBackground); - newBlocked = newVpnBlocked || isUidBlockedByRules(nri.mUid, uidRules, newMetered, - newRestrictBackground); + 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) { callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED, @@ -8000,19 +7956,20 @@ public class ConnectivityService extends IConnectivityManager.Stub } /** - * Notify apps with a given UID of the new blocked state according to new uid rules. + * Notify apps with a given UID of the new blocked state according to new uid state. * @param uid The uid for which the rules changed. - * @param newRules The new rules to apply. + * @param blockedReasons The reasons for why an uid is blocked. */ - private void maybeNotifyNetworkBlockedForNewUidRules(int uid, int newRules) { + private void maybeNotifyNetworkBlockedForNewState(int uid, 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 || isUidBlockedByRules( - uid, mUidRules.get(uid), metered, mRestrictBackground); - newBlocked = vpnBlocked || isUidBlockedByRules( - uid, newRules, metered, mRestrictBackground); + + oldBlocked = vpnBlocked || NetworkPolicyManager.isUidBlocked( + mUidBlockedReasons.get(uid, BLOCKED_REASON_NONE), metered); + newBlocked = vpnBlocked || NetworkPolicyManager.isUidBlocked( + blockedReasons, metered); if (oldBlocked == newBlocked) { continue; } @@ -8359,7 +8316,7 @@ public class ConnectivityService extends IConnectivityManager.Stub final NetworkAgentInfo vpn = getVpnForUid(uid); if (vpn == null || getVpnType(vpn) != VpnManager.TYPE_VPN_SERVICE - || vpn.networkCapabilities.getOwnerUid() != Binder.getCallingUid()) { + || vpn.networkCapabilities.getOwnerUid() != mDeps.getCallingUid()) { return INVALID_UID; } diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 10d6570929ed..3ea0ce173745 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -643,7 +643,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { String route, String gateway, String ifName) throws RemoteException { final RouteInfo processRoute = new RouteInfo(new IpPrefix(route), ("".equals(gateway)) ? null : InetAddresses.parseNumericAddress(gateway), - ifName); + ifName, RouteInfo.RTN_UNICAST); mDaemonHandler.post(() -> notifyRouteChange(updated, processRoute)); } diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS index 1c38c86d08c8..90d940939be8 100644 --- a/services/core/java/com/android/server/am/OWNERS +++ b/services/core/java/com/android/server/am/OWNERS @@ -30,6 +30,10 @@ per-file BatteryExternalStats* = file:/BATTERY_STATS_OWNERS michaelwr@google.com narayan@google.com +# Voice Interaction +per-file *Assist* = file:/core/java/android/service/voice/OWNERS +per-file *Voice* = file:/core/java/android/service/voice/OWNERS + per-file SettingsToPropertiesMapper.java = omakoto@google.com, svetoslavganov@google.com, yamasani@google.com per-file CarUserSwitchingDialog.java = keunyoung@google.com, felipeal@google.com, gurunagarajan@google.com diff --git a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java index 0fb6fecd4fe2..325a2cd7bd69 100644 --- a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java +++ b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java @@ -18,18 +18,10 @@ package com.android.server.connectivity; /** * A class encapsulating various constants used by Connectivity. + * TODO : remove this class. * @hide */ public class ConnectivityConstants { - - // Penalty applied to scores of Networks that have not been validated. - public static final int UNVALIDATED_SCORE_PENALTY = 40; - - // Score for explicitly connected network. - // - // This ensures that a) the explicitly selected network is never trumped by anything else, and - // b) the explicitly selected network is never torn down. - public static final int EXPLICITLY_SELECTED_NETWORK_SCORE = 100; // VPNs typically have priority over other networks. Give them a score that will // let them win every single time. public static final int VPN_DEFAULT_SCORE = 101; diff --git a/services/core/java/com/android/server/connectivity/FullScore.java b/services/core/java/com/android/server/connectivity/FullScore.java new file mode 100644 index 000000000000..028cfee36593 --- /dev/null +++ b/services/core/java/com/android/server/connectivity/FullScore.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity; + +import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.net.NetworkAgentConfig; +import android.net.NetworkCapabilities; +import android.net.NetworkScore; + +import com.android.internal.annotations.VisibleForTesting; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.StringJoiner; + +/** + * This class represents how desirable a network is. + * + * FullScore is very similar to NetworkScore, but it contains the bits that are managed + * by ConnectivityService. This provides static guarantee that all users must know whether + * they are handling a score that had the CS-managed bits set. + */ +public class FullScore { + // This will be removed soon. Do *NOT* depend on it for any new code that is not part of + // a migration. + private final int mLegacyInt; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"POLICY_"}, value = { + POLICY_IS_VALIDATED, + POLICY_IS_VPN, + POLICY_EVER_USER_SELECTED, + POLICY_ACCEPT_UNVALIDATED + }) + public @interface Policy { + } + + // Agent-managed policies are in NetworkScore. They start from 1. + // CS-managed policies, counting from 63 downward + // This network is validated. CS-managed because the source of truth is in NetworkCapabilities. + /** @hide */ + public static final int POLICY_IS_VALIDATED = 63; + + // This is a VPN and behaves as one for scoring purposes. + /** @hide */ + public static final int POLICY_IS_VPN = 62; + + // This network has been selected by the user manually from settings or a 3rd party app + // at least once. {@see NetworkAgentConfig#explicitlySelected}. + /** @hide */ + public static final int POLICY_EVER_USER_SELECTED = 61; + + // The user has indicated in UI that this network should be used even if it doesn't + // validate. {@see NetworkAgentConfig#acceptUnvalidated}. + /** @hide */ + public static final int POLICY_ACCEPT_UNVALIDATED = 60; + + // To help iterate when printing + @VisibleForTesting + static final int MIN_CS_MANAGED_POLICY = POLICY_ACCEPT_UNVALIDATED; + @VisibleForTesting + static final int MAX_CS_MANAGED_POLICY = POLICY_IS_VALIDATED; + + @VisibleForTesting + static @NonNull String policyNameOf(final int policy) { + switch (policy) { + case POLICY_IS_VALIDATED: return "IS_VALIDATED"; + case POLICY_IS_VPN: return "IS_VPN"; + case POLICY_EVER_USER_SELECTED: return "EVER_USER_SELECTED"; + case POLICY_ACCEPT_UNVALIDATED: return "ACCEPT_UNVALIDATED"; + } + throw new IllegalArgumentException("Unknown policy : " + policy); + } + + // Bitmask of all the policies applied to this score. + private final long mPolicies; + + FullScore(final int legacyInt, final long policies) { + mLegacyInt = legacyInt; + mPolicies = policies; + } + + /** + * Given a score supplied by the NetworkAgent and CS-managed objects, produce a full score. + * + * @param score the score supplied by the agent + * @param caps the NetworkCapabilities of the network + * @param config the NetworkAgentConfig of the network + * @return an FullScore that is appropriate to use for ranking. + */ + public static FullScore fromNetworkScore(@NonNull final NetworkScore score, + @NonNull final NetworkCapabilities caps, @NonNull final NetworkAgentConfig config) { + return withPolicies(score.getLegacyInt(), caps.hasCapability(NET_CAPABILITY_VALIDATED), + caps.hasTransport(TRANSPORT_VPN), + config.explicitlySelected, + config.acceptUnvalidated); + } + + /** + * Return a new score given updated caps and config. + * + * @param caps the NetworkCapabilities of the network + * @param config the NetworkAgentConfig of the network + * @return a score with the policies from the arguments reset + */ + public FullScore mixInScore(@NonNull final NetworkCapabilities caps, + @NonNull final NetworkAgentConfig config) { + return withPolicies(mLegacyInt, caps.hasCapability(NET_CAPABILITY_VALIDATED), + caps.hasTransport(TRANSPORT_VPN), + config.explicitlySelected, + config.acceptUnvalidated); + } + + private static FullScore withPolicies(@NonNull final int legacyInt, + final boolean isValidated, + final boolean isVpn, + final boolean everUserSelected, + final boolean acceptUnvalidated) { + return new FullScore(legacyInt, + (isValidated ? 1L << POLICY_IS_VALIDATED : 0) + | (isVpn ? 1L << POLICY_IS_VPN : 0) + | (everUserSelected ? 1L << POLICY_EVER_USER_SELECTED : 0) + | (acceptUnvalidated ? 1L << POLICY_ACCEPT_UNVALIDATED : 0)); + } + + /** + * For backward compatibility, get the legacy int. + * This will be removed before S is published. + */ + public int getLegacyInt() { + return getLegacyInt(false /* pretendValidated */); + } + + public int getLegacyIntAsValidated() { + return getLegacyInt(true /* pretendValidated */); + } + + // TODO : remove these two constants + // Penalty applied to scores of Networks that have not been validated. + private static final int UNVALIDATED_SCORE_PENALTY = 40; + + // Score for a network that can be used unvalidated + private static final int ACCEPT_UNVALIDATED_NETWORK_SCORE = 100; + + private int getLegacyInt(boolean pretendValidated) { + // If the user has chosen this network at least once, give it the maximum score when + // checking to pretend it's validated, or if it doesn't need to validate because the + // user said to use it even if it doesn't validate. + // This ensures that networks that have been selected in UI are not torn down before the + // user gets a chance to prefer it when a higher-scoring network (e.g., Ethernet) is + // available. + if (hasPolicy(POLICY_EVER_USER_SELECTED) + && (hasPolicy(POLICY_ACCEPT_UNVALIDATED) || pretendValidated)) { + return ACCEPT_UNVALIDATED_NETWORK_SCORE; + } + + int score = mLegacyInt; + // Except for VPNs, networks are subject to a penalty for not being validated. + // Apply the penalty unless the network is a VPN, or it's validated or pretending to be. + if (!hasPolicy(POLICY_IS_VALIDATED) && !pretendValidated && !hasPolicy(POLICY_IS_VPN)) { + score -= UNVALIDATED_SCORE_PENALTY; + } + if (score < 0) score = 0; + return score; + } + + /** + * @return whether this score has a particular policy. + */ + @VisibleForTesting + public boolean hasPolicy(final int policy) { + return 0 != (mPolicies & (1L << policy)); + } + + // Example output : + // Score(50 ; Policies : EVER_USER_SELECTED&IS_VALIDATED) + @Override + public String toString() { + final StringJoiner sj = new StringJoiner( + "&", // delimiter + "Score(" + mLegacyInt + " ; Policies : ", // prefix + ")"); // suffix + for (int i = NetworkScore.MIN_AGENT_MANAGED_POLICY; + i <= NetworkScore.MAX_AGENT_MANAGED_POLICY; ++i) { + if (hasPolicy(i)) sj.add(policyNameOf(i)); + } + for (int i = MIN_CS_MANAGED_POLICY; i <= MAX_CS_MANAGED_POLICY; ++i) { + if (hasPolicy(i)) sj.add(policyNameOf(i)); + } + return sj.toString(); + } +} diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index e44dcf5975f1..fde4f5d87e8c 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -303,8 +303,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // validated). private boolean mInactive; - // This represents the quality of the network. - private NetworkScore mScore; + // This represents the quality of the network. As opposed to NetworkScore, FullScore includes + // the ConnectivityService-managed bits. + private FullScore mScore; // The list of NetworkRequests being satisfied by this Network. private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>(); @@ -356,12 +357,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { networkInfo = info; linkProperties = lp; networkCapabilities = nc; - mScore = score; + networkAgentConfig = config; + setScore(score); // uses members networkCapabilities and networkAgentConfig clatd = new Nat464Xlat(this, netd, dnsResolver, deps); mConnService = connService; mContext = context; mHandler = handler; - networkAgentConfig = config; this.factorySerialNumber = factorySerialNumber; this.creatorUid = creatorUid; mQosCallbackTracker = qosCallbackTracker; @@ -667,6 +668,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { @NonNull final NetworkCapabilities nc) { final NetworkCapabilities oldNc = networkCapabilities; networkCapabilities = nc; + mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig); final NetworkMonitorManager nm = mNetworkMonitor; if (nm != null) { nm.notifyNetworkCapabilitiesChanged(nc); @@ -844,30 +846,6 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { return isVPN(); } - private int getCurrentScore(boolean pretendValidated) { - // TODO: We may want to refactor this into a NetworkScore class that takes a base score from - // the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the - // score. The NetworkScore class would provide a nice place to centralize score constants - // so they are not scattered about the transports. - - // If this network is explicitly selected and the user has decided to use it even if it's - // unvalidated, give it the maximum score. Also give it the maximum score if it's explicitly - // selected and we're trying to see what its score could be. This ensures that we don't tear - // down an explicitly selected network before the user gets a chance to prefer it when - // a higher-scoring network (e.g., Ethernet) is available. - if (networkAgentConfig.explicitlySelected - && (networkAgentConfig.acceptUnvalidated || pretendValidated)) { - return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE; - } - - int score = mScore.getLegacyInt(); - if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) { - score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY; - } - if (score < 0) score = 0; - return score; - } - // Return true on devices configured to ignore score penalty for wifi networks // that become unvalidated (b/31075769). private boolean ignoreWifiUnvalidationPenalty() { @@ -880,17 +858,29 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // Get the current score for this Network. This may be modified from what the // NetworkAgent sent, as it has modifiers applied to it. public int getCurrentScore() { - return getCurrentScore(false); + return mScore.getLegacyInt(); } // Get the current score for this Network as if it was validated. This may be modified from // what the NetworkAgent sent, as it has modifiers applied to it. public int getCurrentScoreAsValidated() { - return getCurrentScore(true); + return mScore.getLegacyIntAsValidated(); } + /** + * Mix-in the ConnectivityService-managed bits in the score. + */ public void setScore(final NetworkScore score) { - mScore = score; + mScore = FullScore.fromNetworkScore(score, networkCapabilities, networkAgentConfig); + } + + /** + * Update the ConnectivityService-managed bits in the score. + * + * Call this after updating the network agent config. + */ + public void updateScoreForNetworkAgentConfigUpdate() { + mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig); } /** diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java index f8833071d1bf..f572b46a9b58 100644 --- a/services/core/java/com/android/server/connectivity/ProxyTracker.java +++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java @@ -34,7 +34,6 @@ import android.net.ProxyInfo; import android.net.Uri; import android.os.Binder; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; @@ -105,7 +104,7 @@ public class ProxyTracker { PacProxyInstalledListener listener = new PacProxyInstalledListener(pacChangedEvent); mPacProxyManager.addPacProxyInstalledListener( - new HandlerExecutor(mConnectivityServiceHandler), listener); + mConnectivityServiceHandler::post, listener); } // Convert empty ProxyInfo's to null as null-checks are used to determine if proxies are present diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 124c3741ad57..e35a1ab71492 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -68,6 +68,7 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkProvider; import android.net.NetworkRequest; +import android.net.NetworkScore; import android.net.RouteInfo; import android.net.UidRange; import android.net.UidRangeParcel; @@ -1174,11 +1175,13 @@ public class Vpn { if (!allowIPv4) { lp.addRoute(new RouteInfo(new IpPrefix( - NetworkStackConstants.IPV4_ADDR_ANY, 0), RTN_UNREACHABLE)); + NetworkStackConstants.IPV4_ADDR_ANY, 0), null /*gateway*/, + null /*iface*/, RTN_UNREACHABLE)); } if (!allowIPv6) { lp.addRoute(new RouteInfo(new IpPrefix( - NetworkStackConstants.IPV6_ADDR_ANY, 0), RTN_UNREACHABLE)); + NetworkStackConstants.IPV6_ADDR_ANY, 0), null /*gateway*/, + null /*iface*/, RTN_UNREACHABLE)); } // Concatenate search domains into a string. @@ -1239,7 +1242,7 @@ public class Vpn { mLegacyState = LegacyVpnInfo.STATE_CONNECTING; updateState(DetailedState.CONNECTING, "agentConnect"); - NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig(); + NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig.Builder().build(); networkAgentConfig.allowBypass = mConfig.allowBypass && !mLockdown; mNetworkCapabilities.setOwnerUid(mOwnerUID); @@ -1258,9 +1261,11 @@ public class Vpn { } mNetworkAgent = new NetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */, - mNetworkCapabilities, lp, VPN_DEFAULT_SCORE, networkAgentConfig, mNetworkProvider) { + mNetworkCapabilities, lp, + new NetworkScore.Builder().setLegacyInt(VPN_DEFAULT_SCORE).build(), + networkAgentConfig, mNetworkProvider) { @Override - public void unwanted() { + public void onNetworkUnwanted() { // We are user controlled, not driven by NetworkRequest. } }; @@ -2696,7 +2701,8 @@ public class Vpn { mConfig.routes.clear(); for (final RouteInfo route : oldRoutes) { - mConfig.routes.add(new RouteInfo(route.getDestination(), RTN_UNREACHABLE)); + mConfig.routes.add(new RouteInfo(route.getDestination(), null /*gateway*/, + null /*iface*/, RTN_UNREACHABLE)); } if (mNetworkAgent != null) { mNetworkAgent.sendLinkProperties(makeLinkProperties()); @@ -3035,10 +3041,12 @@ public class Vpn { // Add a throw route for the VPN server endpoint, if one was specified. if (endpointAddress instanceof Inet4Address) { mConfig.routes.add(new RouteInfo( - new IpPrefix(endpointAddress, 32), RTN_THROW)); + new IpPrefix(endpointAddress, 32), null /*gateway*/, + null /*iface*/, RTN_THROW)); } else if (endpointAddress instanceof Inet6Address) { mConfig.routes.add(new RouteInfo( - new IpPrefix(endpointAddress, 128), RTN_THROW)); + new IpPrefix(endpointAddress, 128), null /*gateway*/, + null /*iface*/, RTN_THROW)); } else { Log.e(TAG, "Unknown IP address family for VPN endpoint: " + endpointAddress); diff --git a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java index fa03e59f2f2e..47eb3eb70434 100644 --- a/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java +++ b/services/core/java/com/android/server/connectivity/VpnIkev2Utils.java @@ -405,7 +405,8 @@ public class VpnIkev2Utils { for (final IkeTrafficSelector selector : trafficSelectors) { for (final IpPrefix prefix : new IpRange(selector.startingAddress, selector.endingAddress).asIpPrefixes()) { - routes.add(new RouteInfo(prefix, null)); + routes.add(new RouteInfo(prefix, null /*gateway*/, null /*iface*/, + RouteInfo.RTN_UNICAST)); } } diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 294d7e257b6e..0215188bc1a4 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -92,7 +92,6 @@ import android.provider.Settings.SettingNotFoundException; import android.security.AndroidKeyStoreMaintenance; import android.security.Authorization; import android.security.KeyStore; -import android.security.keystore.AndroidKeyStoreProvider; import android.security.keystore.KeyProperties; import android.security.keystore.KeyProtection; import android.security.keystore.UserNotAuthenticatedException; @@ -157,7 +156,6 @@ import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; -import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -264,13 +262,7 @@ public class LockSettingsService extends ILockSettings.Stub { @Override public void onStart() { - Optional<Boolean> keystore2_enabled = - android.sysprop.Keystore2Properties.keystore2_enabled(); - if (keystore2_enabled.isPresent() && keystore2_enabled.get()) { - android.security.keystore2.AndroidKeyStoreProvider.install(); - } else { - AndroidKeyStoreProvider.install(); - } + android.security.keystore2.AndroidKeyStoreProvider.install(); mLockSettingsService = new LockSettingsService(getContext()); publishBinderService("lock_settings", mLockSettingsService); } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index aee0947f39f9..b7367e5170c6 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -56,6 +56,23 @@ 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_MASK; +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; +import static android.net.NetworkPolicyManager.ALLOWED_REASON_POWER_SAVE_ALLOWLIST; +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; @@ -414,6 +431,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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; + // TODO: Add similar docs for other messages. + /** + * Message to indicate that reasons for why an uid is blocked changed. + * arg1 = uid + * arg2 = oldBlockedReasons + * obj = newBlockedReasons + */ + private static final int MSG_BLOCKED_REASON_CHANGED = 21; private static final int UID_MSG_STATE_CHANGED = 100; private static final int UID_MSG_GONE = 101; @@ -560,7 +585,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** Foreground at UID granularity. */ @GuardedBy("mUidRulesFirstLock") - final SparseArray<UidState> mUidState = new SparseArray<UidState>(); + private final SparseArray<UidState> mUidState = new SparseArray<>(); + + @GuardedBy("mUidRulesFirstLock") + private final SparseArray<UidBlockedState> mUidBlockedState = new SparseArray<>(); /** Map from network ID to last observed meteredness state */ @GuardedBy("mNetworkPoliciesSecondLock") @@ -2879,15 +2907,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @Override - public void registerListener(INetworkPolicyListener listener) { + public void registerListener(@NonNull INetworkPolicyListener listener) { + Objects.requireNonNull(listener); // TODO: Remove CONNECTIVITY_INTERNAL and the *AnyPermissionOf methods above after all apps // have declared OBSERVE_NETWORK_POLICY. enforceAnyPermissionOf(CONNECTIVITY_INTERNAL, OBSERVE_NETWORK_POLICY); mListeners.register(listener); + // TODO: Send callbacks to the newly registered listener } @Override - public void unregisterListener(INetworkPolicyListener listener) { + public void unregisterListener(@NonNull INetworkPolicyListener listener) { + Objects.requireNonNull(listener); // TODO: Remove CONNECTIVITY_INTERNAL and the *AnyPermissionOf methods above after all apps // have declared OBSERVE_NETWORK_POLICY. enforceAnyPermissionOf(CONNECTIVITY_INTERNAL, OBSERVE_NETWORK_POLICY); @@ -3923,6 +3954,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mUidRules.put(uid, newUidRule); mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRule).sendToTarget(); } + updateBlockedReasonsForRestrictedModeUL(uid); }); if (mRestrictedNetworkingMode) { // firewall rules only need to be set when this mode is being enabled. @@ -3943,6 +3975,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mUidRules.put(uid, newUidRule); mHandler.obtainMessage(MSG_RULES_CHANGED, uid, newUidRule).sendToTarget(); } + updateBlockedReasonsForRestrictedModeUL(uid); // if restricted networking mode is on, and the app has an access exemption, the uid rule // will not change, but the firewall rule will have to be updated. @@ -3954,6 +3987,31 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + private void updateBlockedReasonsForRestrictedModeUL(int uid) { + UidBlockedState uidBlockedState = mUidBlockedState.get(uid); + if (uidBlockedState == null) { + uidBlockedState = new UidBlockedState(); + mUidBlockedState.put(uid, uidBlockedState); + } + final int oldEffectiveBlockedReasons = uidBlockedState.effectiveBlockedReasons; + if (mRestrictedNetworkingMode) { + uidBlockedState.blockedReasons |= BLOCKED_REASON_RESTRICTED_MODE; + } else { + uidBlockedState.blockedReasons &= ~BLOCKED_REASON_RESTRICTED_MODE; + } + if (hasRestrictedModeAccess(uid)) { + uidBlockedState.allowedReasons |= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS; + } else { + uidBlockedState.allowedReasons &= ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS; + } + uidBlockedState.updateEffectiveBlockedReasons(); + if (oldEffectiveBlockedReasons != uidBlockedState.effectiveBlockedReasons) { + mHandler.obtainMessage(MSG_BLOCKED_REASON_CHANGED, uid, + uidBlockedState.effectiveBlockedReasons, oldEffectiveBlockedReasons) + .sendToTarget(); + } + } + private int getNewRestrictedModeUidRule(int uid, int oldUidRule) { int newRule = oldUidRule; newRule &= ~MASK_RESTRICTED_MODE_NETWORKS; @@ -4074,11 +4132,21 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { boolean isWhitelisted = mPowerSaveTempWhitelistAppIds.get(appId) || mPowerSaveWhitelistAppIds.get(appId); if (!deviceIdleMode) { - isWhitelisted = isWhitelisted || mPowerSaveWhitelistExceptIdleAppIds.get(appId); + isWhitelisted = isWhitelisted || isWhitelistedFromPowerSaveExceptIdleUL(uid); } return isWhitelisted; } + /** + * Returns whether a uid is allowlisted from power saving restrictions, except Device idle + * (eg: Battery Saver and app idle). + */ + @GuardedBy("mUidRulesFirstLock") + private boolean isWhitelistedFromPowerSaveExceptIdleUL(int uid) { + final int appId = UserHandle.getAppId(uid); + return mPowerSaveWhitelistExceptIdleAppIds.get(appId); + } + // NOTE: since both fw_dozable and fw_powersave uses the same map // (mPowerSaveTempWhitelistAppIds) for allowlisting, we can reuse their logic in this method. @GuardedBy("mUidRulesFirstLock") @@ -4523,6 +4591,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final int oldUidRules = mUidRules.get(uid, RULE_NONE); final boolean isForeground = isUidForegroundOnRestrictBackgroundUL(uid); final boolean isRestrictedByAdmin = isRestrictedByAdminUL(uid); + UidBlockedState uidBlockedState = mUidBlockedState.get(uid); + if (uidBlockedState == null) { + uidBlockedState = new UidBlockedState(); + mUidBlockedState.put(uid, uidBlockedState); + } final boolean isDenied = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0; final boolean isAllowed = (uidPolicy & POLICY_ALLOW_METERED_BACKGROUND) != 0; @@ -4547,6 +4620,16 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + int newBlockedReasons = BLOCKED_REASON_NONE; + int newAllowedReasons = ALLOWED_REASON_NONE; + newBlockedReasons |= (isRestrictedByAdmin ? BLOCKED_METERED_REASON_ADMIN_DISABLED : 0); + 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 |= (isAllowed ? ALLOWED_METERED_REASON_USER_EXEMPTED : 0); + if (LOGV) { Log.v(TAG, "updateRuleForRestrictBackgroundUL(" + uid + ")" + ": isForeground=" +isForeground @@ -4618,6 +4701,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(); + } } } @@ -4692,6 +4787,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // Copy existing uid rules and clear ALL_NETWORK rules. int newUidRules = oldUidRules & (~MASK_ALL_NETWORKS); + UidBlockedState uidBlockedState = mUidBlockedState.get(uid); + if (uidBlockedState == null) { + uidBlockedState = new UidBlockedState(); + mUidBlockedState.put(uid, uidBlockedState); + } + // First step: define the new rule based on user restrictions and foreground state. // NOTE: if statements below could be inlined, but it's easier to understand the logic @@ -4704,6 +4805,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { newUidRules |= isWhitelisted ? RULE_ALLOW_ALL : RULE_REJECT_ALL; } + int newBlockedReasons = BLOCKED_REASON_NONE; + int newAllowedReasons = ALLOWED_REASON_NONE; + newBlockedReasons |= (mRestrictPower ? BLOCKED_REASON_BATTERY_SAVER : 0); + newBlockedReasons |= (mDeviceIdleMode ? BLOCKED_REASON_DOZE : 0); + newBlockedReasons |= (isUidIdle ? BLOCKED_REASON_APP_STANDBY : 0); + newBlockedReasons |= (uidBlockedState.blockedReasons & BLOCKED_REASON_RESTRICTED_MODE); + + newAllowedReasons |= (isSystem(uid) ? ALLOWED_REASON_SYSTEM : 0); + newAllowedReasons |= (isForeground ? ALLOWED_REASON_FOREGROUND : 0); + newAllowedReasons |= (isWhitelistedFromPowerSaveUL(uid, true) + ? ALLOWED_REASON_POWER_SAVE_ALLOWLIST : 0); + newAllowedReasons |= (isWhitelistedFromPowerSaveExceptIdleUL(uid) + ? ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST : 0); + if (LOGV) { Log.v(TAG, "updateRulesForPowerRestrictionsUL(" + uid + ")" + ", isIdle: " + isUidIdle @@ -4735,6 +4850,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { 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(); + } + return newUidRules; } @@ -4764,61 +4891,57 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) { - if (listener != null) { - try { - listener.onUidRulesChanged(uid, uidRules); - } catch (RemoteException ignored) { - } + try { + listener.onUidRulesChanged(uid, uidRules); + } catch (RemoteException ignored) { } } private void dispatchMeteredIfacesChanged(INetworkPolicyListener listener, String[] meteredIfaces) { - if (listener != null) { - try { - listener.onMeteredIfacesChanged(meteredIfaces); - } catch (RemoteException ignored) { - } + try { + listener.onMeteredIfacesChanged(meteredIfaces); + } catch (RemoteException ignored) { } } private void dispatchRestrictBackgroundChanged(INetworkPolicyListener listener, boolean restrictBackground) { - if (listener != null) { - try { - listener.onRestrictBackgroundChanged(restrictBackground); - } catch (RemoteException ignored) { - } + try { + listener.onRestrictBackgroundChanged(restrictBackground); + } catch (RemoteException ignored) { } } private void dispatchUidPoliciesChanged(INetworkPolicyListener listener, int uid, int uidPolicies) { - if (listener != null) { - try { - listener.onUidPoliciesChanged(uid, uidPolicies); - } catch (RemoteException ignored) { - } + try { + listener.onUidPoliciesChanged(uid, uidPolicies); + } catch (RemoteException ignored) { } } private void dispatchSubscriptionOverride(INetworkPolicyListener listener, int subId, int overrideMask, int overrideValue, int[] networkTypes) { - if (listener != null) { - try { - listener.onSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes); - } catch (RemoteException ignored) { - } + try { + listener.onSubscriptionOverride(subId, overrideMask, overrideValue, networkTypes); + } catch (RemoteException ignored) { } } private void dispatchSubscriptionPlansChanged(INetworkPolicyListener listener, int subId, SubscriptionPlan[] plans) { - if (listener != null) { - try { - listener.onSubscriptionPlansChanged(subId, plans); - } catch (RemoteException ignored) { - } + try { + listener.onSubscriptionPlansChanged(subId, plans); + } catch (RemoteException ignored) { + } + } + + private void dispatchBlockedReasonChanged(INetworkPolicyListener listener, int uid, + int oldBlockedReasons, int newBlockedReasons) { + try { + listener.onBlockedReasonChanged(uid, oldBlockedReasons, newBlockedReasons); + } catch (RemoteException ignored) { } } @@ -4975,6 +5098,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mListeners.finishBroadcast(); return true; } + case MSG_BLOCKED_REASON_CHANGED: { + final int uid = msg.arg1; + final int newBlockedReasons = msg.arg2; + final int oldBlockedReasons = (int) msg.obj; + final int length = mListeners.beginBroadcast(); + for (int i = 0; i < length; i++) { + final INetworkPolicyListener listener = mListeners.getBroadcastItem(i); + dispatchBlockedReasonChanged(listener, uid, + oldBlockedReasons, newBlockedReasons); + } + mListeners.finishBroadcast(); + return true; + } default: { return false; } @@ -5706,6 +5842,51 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue; } + private class UidBlockedState { + public int blockedReasons; + public int allowedReasons; + public int effectiveBlockedReasons; + + UidBlockedState() { + blockedReasons = BLOCKED_REASON_NONE; + allowedReasons = ALLOWED_REASON_NONE; + effectiveBlockedReasons = BLOCKED_REASON_NONE; + } + + void updateEffectiveBlockedReasons() { + effectiveBlockedReasons = blockedReasons; + // If the uid is not subject to any blocked reasons, then return early + if (blockedReasons == BLOCKED_REASON_NONE) { + return; + } + if ((allowedReasons & ALLOWED_REASON_SYSTEM) != 0) { + effectiveBlockedReasons = BLOCKED_REASON_NONE; + } + if ((allowedReasons & ALLOWED_REASON_FOREGROUND) != 0) { + effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER; + effectiveBlockedReasons &= ~BLOCKED_REASON_DOZE; + effectiveBlockedReasons &= ~BLOCKED_REASON_APP_STANDBY; + effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_DATA_SAVER; + effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_USER_RESTRICTED; + } + if ((allowedReasons & ALLOWED_REASON_POWER_SAVE_ALLOWLIST) != 0) { + effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER; + effectiveBlockedReasons &= ~BLOCKED_REASON_DOZE; + effectiveBlockedReasons &= ~BLOCKED_REASON_APP_STANDBY; + } + if ((allowedReasons & ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST) != 0) { + effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER; + effectiveBlockedReasons &= ~BLOCKED_REASON_APP_STANDBY; + } + if ((allowedReasons & ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS) != 0) { + effectiveBlockedReasons &= ~BLOCKED_REASON_RESTRICTED_MODE; + } + if ((allowedReasons & ALLOWED_METERED_REASON_USER_EXEMPTED) != 0) { + effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_DATA_SAVER; + } + } + } + private class NotificationId { private final String mTag; private final int mId; diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java index 9c4c5101cb6c..cc6a8243799d 100644 --- a/services/core/java/com/android/server/os/NativeTombstoneManager.java +++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java @@ -411,8 +411,13 @@ public final class NativeTombstoneManager { processName = stream.readString(Tombstone.PROCESS_NAME); break; - case (int) Tombstone.CAUSE: - long token = stream.start(Tombstone.CAUSE); + case (int) Tombstone.CAUSES: + if (!crashReason.equals("")) { + // Causes appear in decreasing order of likelihood. For now we only + // want the most likely crash reason here, so ignore all others. + break; + } + long token = stream.start(Tombstone.CAUSES); cause: while (stream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { switch (stream.getFieldNumber()) { diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java index 0c8e36b75425..c8dc1b1ff562 100644 --- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java +++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java @@ -146,47 +146,11 @@ public class ArtStatsLogUtils { uid, compilationReason, compilerFilter, - ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES, - getDexBytes(path), - dexMetadataType); - logger.write( - sessionId, - uid, - compilationReason, - compilerFilter, ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME, compileTime, dexMetadataType); } - private static long getDexBytes(String apkPath) { - StrictJarFile jarFile = null; - long dexBytes = 0; - try { - jarFile = new StrictJarFile(apkPath, - /*verify=*/ false, - /*signatureSchemeRollbackProtectionsEnforced=*/ false); - Iterator<ZipEntry> it = jarFile.iterator(); - while (it.hasNext()) { - ZipEntry entry = it.next(); - if (entry.getName().matches("classes(\\d)*[.]dex")) { - dexBytes += entry.getSize(); - } - } - return dexBytes; - } catch (IOException ignore) { - Slog.e(TAG, "Error when parsing APK " + apkPath); - return -1L; - } finally { - try { - if (jarFile != null) { - jarFile.close(); - } - } catch (IOException ignore) { - } - } - } - private static int getDexMetadataType(String dexMetadataPath) { if (dexMetadataPath == null) { return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_NONE; diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java index fd2d8e1b834b..beebb3145018 100644 --- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java +++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java @@ -16,6 +16,8 @@ package com.android.server.recoverysystem; +import static android.os.UserHandle.USER_SYSTEM; + import android.annotation.IntDef; import android.content.Context; import android.content.IntentSender; @@ -33,12 +35,14 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; import android.os.SystemProperties; +import android.provider.DeviceConfig; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.FrameworkStatsLog; import com.android.internal.widget.LockSettingsInternal; import com.android.internal.widget.RebootEscrowListener; import com.android.server.LocalServices; @@ -52,6 +56,8 @@ import java.io.FileDescriptor; import java.io.FileWriter; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; /** * The recovery system service is responsible for coordinating recovery related @@ -127,10 +133,28 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo /** * The action to perform upon resume on reboot clear request for a given client. */ - @IntDef({ROR_NOT_REQUESTED, + @IntDef({ ROR_NOT_REQUESTED, ROR_REQUESTED_NEED_CLEAR, ROR_REQUESTED_SKIP_CLEAR}) - private @interface ResumeOnRebootActionsOnClear{} + private @interface ResumeOnRebootActionsOnClear {} + + /** + * The error code for reboots initiated by resume on reboot clients. + */ + private static final int REBOOT_ERROR_NONE = 0; + private static final int REBOOT_ERROR_UNKNOWN = 1; + private static final int REBOOT_ERROR_INVALID_PACKAGE_NAME = 2; + private static final int REBOOT_ERROR_LSKF_NOT_CAPTURED = 3; + private static final int REBOOT_ERROR_SLOT_MISMATCH = 4; + private static final int REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE = 5; + + @IntDef({ REBOOT_ERROR_NONE, + REBOOT_ERROR_UNKNOWN, + REBOOT_ERROR_INVALID_PACKAGE_NAME, + REBOOT_ERROR_LSKF_NOT_CAPTURED, + REBOOT_ERROR_SLOT_MISMATCH, + REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE}) + private @interface ResumeOnRebootRebootErrorCode {} static class Injector { protected final Context mContext; @@ -202,6 +226,35 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo public void threadSleep(long millis) throws InterruptedException { Thread.sleep(millis); } + + public int getUidFromPackageName(String packageName) { + try { + return mContext.getPackageManager().getPackageUidAsUser(packageName, USER_SYSTEM); + } catch (PackageManager.NameNotFoundException e) { + Slog.w(TAG, "Failed to find uid for " + packageName); + } + return -1; + } + + public void reportRebootEscrowPreparationMetrics(int uid, + @ResumeOnRebootActionsOnRequest int requestResult, int requestedClientCount) { + FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_PREPARATION_REPORTED, uid, + requestResult, requestedClientCount); + } + + public void reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount, + int requestedToLskfCapturedDurationInSeconds) { + FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_LSKF_CAPTURE_REPORTED, uid, + requestedClientCount, requestedToLskfCapturedDurationInSeconds); + } + + public void reportRebootEscrowRebootMetrics(int errorCode, int uid, + int preparedClientCount, int requestCount, boolean slotSwitch, boolean serverBased, + int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts) { + FrameworkStatsLog.write(FrameworkStatsLog.REBOOT_ESCROW_REBOOT_REPORTED, errorCode, + uid, preparedClientCount, requestCount, slotSwitch, serverBased, + lskfCapturedToRebootDurationInSeconds, lskfCapturedCounts); + } } /** @@ -367,6 +420,16 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo } } + private void reportMetricsOnRequestLskf(String packageName, int requestResult) { + int uid = mInjector.getUidFromPackageName(packageName); + int pendingRequestCount; + synchronized (this) { + pendingRequestCount = mCallerPendingRequest.size(); + } + + mInjector.reportRebootEscrowPreparationMetrics(uid, requestResult, pendingRequestCount); + } + @Override // Binder call public boolean requestLskf(String packageName, IntentSender intentSender) { enforcePermissionForResumeOnReboot(); @@ -378,6 +441,8 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo @ResumeOnRebootActionsOnRequest int action = updateRoRPreparationStateOnNewRequest( packageName, intentSender); + reportMetricsOnRequestLskf(packageName, action); + switch (action) { case ROR_SKIP_PREPARATION_AND_NOTIFY: // We consider the preparation done if someone else has prepared. @@ -420,12 +485,26 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo return needPreparation ? ROR_NEED_PREPARATION : ROR_SKIP_PREPARATION_NOT_NOTIFY; } + private void reportMetricsOnPreparedForReboot() { + List<String> preparedClients; + synchronized (this) { + preparedClients = new ArrayList<>(mCallerPreparedForReboot); + } + + for (String packageName : preparedClients) { + int uid = mInjector.getUidFromPackageName(packageName); + mInjector.reportRebootEscrowLskfCapturedMetrics(uid, preparedClients.size(), + -1 /* duration */); + } + } + @Override public void onPreparedForReboot(boolean ready) { if (!ready) { return; } updateRoRPreparationStateOnPreparedForReboot(); + reportMetricsOnPreparedForReboot(); } private synchronized void updateRoRPreparationStateOnPreparedForReboot() { @@ -548,22 +627,49 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo return true; } - private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) { + private @ResumeOnRebootRebootErrorCode int armRebootEscrow(String packageName, + boolean slotSwitch) { if (packageName == null) { Slog.w(TAG, "Missing packageName when rebooting with lskf."); - return false; + return REBOOT_ERROR_INVALID_PACKAGE_NAME; } if (!isLskfCaptured(packageName)) { - return false; + return REBOOT_ERROR_LSKF_NOT_CAPTURED; } if (!verifySlotForNextBoot(slotSwitch)) { - return false; + return REBOOT_ERROR_SLOT_MISMATCH; } - // TODO(xunchang) write the vbmeta digest along with the escrowKey before reboot. if (!mInjector.getLockSettingsService().armRebootEscrow()) { Slog.w(TAG, "Failure to escrow key for reboot"); + return REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE; + } + + return REBOOT_ERROR_NONE; + } + + 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); + int preparedClientCount; + synchronized (this) { + preparedClientCount = mCallerPreparedForReboot.size(); + } + + // TODO(b/179105110) report the true value of duration and counts + mInjector.reportRebootEscrowRebootMetrics(errorCode, uid, preparedClientCount, + 1 /* request count */, slotSwitch, serverBased, + -1 /* duration */, 1 /* lskf capture count */); + } + + private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) { + @ResumeOnRebootRebootErrorCode int errorCode = armRebootEscrow(packageName, slotSwitch); + reportMetricsOnRebootWithLskf(packageName, slotSwitch, errorCode); + + if (errorCode != REBOOT_ERROR_NONE) { return false; } diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 69a153f79a1b..9589505ef251 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -42,7 +42,6 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkAgent; -import android.net.NetworkAgent.ValidationStatus; import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.RouteInfo; @@ -1442,17 +1441,16 @@ public class VcnGatewayConnection extends StateMachine { caps, lp, Vcn.getNetworkScore(), - new NetworkAgentConfig(), + new NetworkAgentConfig.Builder().build(), mVcnContext.getVcnNetworkProvider()) { @Override - public void unwanted() { + public void onNetworkUnwanted() { Slog.d(TAG, "NetworkAgent was unwanted"); teardownAsynchronously(); } @Override - public void onValidationStatus( - @ValidationStatus int status, @Nullable Uri redirectUri) { + public void onValidationStatus(int status, @Nullable Uri redirectUri) { if (status == NetworkAgent.VALIDATION_STATUS_VALID) { clearFailedAttemptCounterAndSafeModeAlarm(); } @@ -1798,8 +1796,10 @@ public class VcnGatewayConnection extends StateMachine { lp.addDnsServer(addr); } - lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); - lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); + lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null /*gateway*/, + null /*iface*/, RouteInfo.RTN_UNICAST)); + lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/, + null /*iface*/, RouteInfo.RTN_UNICAST)); lp.setMtu(gatewayConnectionConfig.getMaxMtu()); diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS b/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS index 5a4431ee8c89..5492dc8e37a3 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS +++ b/services/tests/mockingservicestests/src/com/android/server/pm/dex/OWNERS @@ -1,2 +1 @@ -calin@google.com -ngeoffray@google.com +include platform/art:/OWNERS
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java index e605d755183f..13d75a77507f 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java @@ -245,14 +245,6 @@ public final class ArtStatsLogUtilsTest { UID, COMPILATION_REASON, COMPILER_FILTER, - ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES, - DEX_CONTENT.length, - dexMetadataType); - inorder.verify(mockLogger).write( - SESSION_ID, - UID, - COMPILATION_REASON, - COMPILER_FILTER, ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME, COMPILE_TIME, dexMetadataType); 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 9b8a2a82c6df..324e5929f77f 100644 --- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java @@ -18,6 +18,7 @@ package com.android.server.recoverysystem; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; +import static org.mockito.AdditionalMatchers.not; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -70,6 +71,7 @@ public class RecoverySystemServiceTest { private FileWriter mUncryptUpdateFileWriter; private LockSettingsInternal mLockSettingsInternal; private IBootControl mIBootControl; + private RecoverySystemServiceTestable.IMetricsReporter mMetricsReporter; private static final String FAKE_OTA_PACKAGE_NAME = "fake.ota.package"; private static final String FAKE_OTHER_PACKAGE_NAME = "fake.other.package"; @@ -94,9 +96,11 @@ public class RecoverySystemServiceTest { when(mIBootControl.getCurrentSlot()).thenReturn(0); when(mIBootControl.getActiveBootSlot()).thenReturn(1); + mMetricsReporter = mock(RecoverySystemServiceTestable.IMetricsReporter.class); + mRecoverySystemService = new RecoverySystemServiceTestable(mContext, mSystemProperties, powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal, - mIBootControl); + mIBootControl, mMetricsReporter); } @Test @@ -227,12 +231,24 @@ public class RecoverySystemServiceTest { } @Test + public void requestLskf_reportMetrics() throws Exception { + IntentSender intentSender = mock(IntentSender.class); + assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender), + is(true)); + verify(mMetricsReporter).reportRebootEscrowPreparationMetrics( + eq(1000), eq(0) /* need preparation */, eq(1) /* client count */); + } + + + @Test public void requestLskf_success() throws Exception { IntentSender intentSender = mock(IntentSender.class); assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender), is(true)); mRecoverySystemService.onPreparedForReboot(true); verify(intentSender).sendIntent(any(), anyInt(), any(), any(), any()); + verify(mMetricsReporter).reportRebootEscrowLskfCapturedMetrics( + eq(1000), eq(1) /* client count */, anyInt() /* duration */); } @Test @@ -255,6 +271,8 @@ public class RecoverySystemServiceTest { assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, intentSender), is(true)); verify(intentSender, never()).sendIntent(any(), anyInt(), any(), any(), any()); + verify(mMetricsReporter, never()).reportRebootEscrowLskfCapturedMetrics( + anyInt(), anyInt(), anyInt()); } @Test @@ -337,6 +355,9 @@ public class RecoverySystemServiceTest { 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 */); } @@ -373,6 +394,20 @@ public class RecoverySystemServiceTest { verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean()); } + @Test + public void rebootWithLskf_multiClient_success_reportMetrics() throws Exception { + assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true)); + assertThat(mRecoverySystemService.requestLskf(FAKE_OTHER_PACKAGE_NAME, null), is(true)); + mRecoverySystemService.onPreparedForReboot(true); + + // Client B's clear won't affect client A's preparation. + 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 */); + } @Test public void rebootWithLskf_multiClient_ClientBSuccess() throws Exception { @@ -384,12 +419,18 @@ public class RecoverySystemServiceTest { 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 */); 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 */); } @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 0727e5adb9ca..a894178fca06 100644 --- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java @@ -32,11 +32,12 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { private final UncryptSocket mUncryptSocket; private final LockSettingsInternal mLockSettingsInternal; private final IBootControl mIBootControl; + private final IMetricsReporter mIMetricsReporter; MockInjector(Context context, FakeSystemProperties systemProperties, PowerManager powerManager, FileWriter uncryptPackageFileWriter, UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal, - IBootControl bootControl) { + IBootControl bootControl, IMetricsReporter metricsReporter) { super(context); mSystemProperties = systemProperties; mPowerManager = powerManager; @@ -44,6 +45,7 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { mUncryptSocket = uncryptSocket; mLockSettingsInternal = lockSettingsInternal; mIBootControl = bootControl; + mIMetricsReporter = metricsReporter; } @Override @@ -94,14 +96,45 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { public IBootControl getBootControl() { return mIBootControl; } + @Override + public int getUidFromPackageName(String packageName) { + if ("fake.ota.package".equals(packageName)) { + return 1000; + } + if ("fake.other.package".equals(packageName)) { + return 2000; + } + return 3000; + } + + @Override + public void reportRebootEscrowPreparationMetrics(int uid, int requestResult, + int requestedClientCount) { + mIMetricsReporter.reportRebootEscrowPreparationMetrics(uid, requestResult, + requestedClientCount); + } + + public void reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount, + int requestedToLskfCapturedDurationInSeconds) { + mIMetricsReporter.reportRebootEscrowLskfCapturedMetrics(uid, requestedClientCount, + requestedToLskfCapturedDurationInSeconds); + } + + public void reportRebootEscrowRebootMetrics(int errorCode, int uid, int preparedClientCount, + int requestCount, boolean slotSwitch, boolean serverBased, + int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts) { + mIMetricsReporter.reportRebootEscrowRebootMetrics(errorCode, uid, preparedClientCount, + requestCount, slotSwitch, serverBased, lskfCapturedToRebootDurationInSeconds, + lskfCapturedCounts); + } } RecoverySystemServiceTestable(Context context, FakeSystemProperties systemProperties, PowerManager powerManager, FileWriter uncryptPackageFileWriter, UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal, - IBootControl bootControl) { + IBootControl bootControl, IMetricsReporter metricsReporter) { super(new MockInjector(context, systemProperties, powerManager, uncryptPackageFileWriter, - uncryptSocket, lockSettingsInternal, bootControl)); + uncryptSocket, lockSettingsInternal, bootControl, metricsReporter)); } public static class FakeSystemProperties { @@ -131,4 +164,17 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { return mCtlStart; } } + + public interface IMetricsReporter { + void reportRebootEscrowPreparationMetrics(int uid, int requestResult, + int requestedClientCount); + + void reportRebootEscrowLskfCapturedMetrics(int uid, int requestedClientCount, + int requestedToLskfCapturedDurationInSeconds); + + void reportRebootEscrowRebootMetrics(int errorCode, int uid, int preparedClientCount, + int requestCount, boolean slotSwitch, boolean serverBased, + int lskfCapturedToRebootDurationInSeconds, int lskfCapturedCounts); + } + } diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java index ec7d4bd0d8c0..647a2a2ec53d 100644 --- a/services/usb/java/com/android/server/usb/UsbPortManager.java +++ b/services/usb/java/com/android/server/usb/UsbPortManager.java @@ -60,9 +60,9 @@ import android.os.Parcelable; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; +import android.service.ServiceProtoEnums; import android.service.usb.UsbPortInfoProto; import android.service.usb.UsbPortManagerProto; -import android.service.usb.UsbServiceProto; import android.util.ArrayMap; import android.util.Log; import android.util.Slog; @@ -992,15 +992,15 @@ public class UsbPortManager { private static int convertContaminantDetectionStatusToProto(int contaminantDetectionStatus) { switch (contaminantDetectionStatus) { case UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED: - return UsbServiceProto.CONTAMINANT_STATUS_NOT_SUPPORTED; + return ServiceProtoEnums.CONTAMINANT_STATUS_NOT_SUPPORTED; case UsbPortStatus.CONTAMINANT_DETECTION_DISABLED: - return UsbServiceProto.CONTAMINANT_STATUS_DISABLED; + return ServiceProtoEnums.CONTAMINANT_STATUS_DISABLED; case UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED: - return UsbServiceProto.CONTAMINANT_STATUS_NOT_DETECTED; + return ServiceProtoEnums.CONTAMINANT_STATUS_NOT_DETECTED; case UsbPortStatus.CONTAMINANT_DETECTION_DETECTED: - return UsbServiceProto.CONTAMINANT_STATUS_DETECTED; + return ServiceProtoEnums.CONTAMINANT_STATUS_DETECTED; default: - return UsbServiceProto.CONTAMINANT_STATUS_UNKNOWN; + return ServiceProtoEnums.CONTAMINANT_STATUS_UNKNOWN; } } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 217570e1401c..464d37510034 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -4268,6 +4268,14 @@ public class CarrierConfigManager { public static final String KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL = "store_sim_pin_for_unattended_reboot_bool"; + /** + * Determine whether "Enable 2G" toggle can be shown. + * + * Used to trade privacy/security against potentially reduced carrier coverage for some + * carriers. + */ + public static final String KEY_HIDE_ENABLE_2G = "hide_enable_2g_bool"; + /** The default value for every variable. */ private final static PersistableBundle sDefaults; @@ -4825,6 +4833,7 @@ public class CarrierConfigManager { sDefaults.putStringArray(KEY_ALLOWED_INITIAL_ATTACH_APN_TYPES_STRING_ARRAY, new String[]{"ia", "default", "ims", "mms", "dun", "emergency"}); sDefaults.putBoolean(KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL, true); + sDefaults.putBoolean(KEY_HIDE_ENABLE_2G, false); } /** diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index b958bff6d00b..ce5a8ccf0fd0 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -2127,7 +2127,7 @@ public final class SmsManager { ret = iccISms.getSmsCapacityOnIccForSubscriber(getSubscriptionId()); } } catch (RemoteException ex) { - throw new RuntimeException(ex); + Log.e(TAG, "getSmsCapacityOnIcc() RemoteException", ex); } return ret; } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 99b5687ba20d..26fcf5e08508 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -8224,7 +8224,8 @@ public class TelephonyManager { @IntDef({ ALLOWED_NETWORK_TYPES_REASON_USER, ALLOWED_NETWORK_TYPES_REASON_POWER, - ALLOWED_NETWORK_TYPES_REASON_CARRIER + ALLOWED_NETWORK_TYPES_REASON_CARRIER, + ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G }) @Retention(RetentionPolicy.SOURCE) public @interface AllowedNetworkTypesReason { @@ -8261,6 +8262,14 @@ public class TelephonyManager { public static final int ALLOWED_NETWORK_TYPES_REASON_CARRIER = 2; /** + * To indicate allowed network type change is requested by the user via the 2G toggle. + * + * @hide + */ + @SystemApi + 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. * This can be called for following reasons @@ -8269,6 +8278,8 @@ public class TelephonyManager { * <li>Allowed network types control by power manager * {@link #ALLOWED_NETWORK_TYPES_REASON_POWER} * <li>Allowed network types control by carrier {@link #ALLOWED_NETWORK_TYPES_REASON_CARRIER} + * <li>Allowed network types control by the user-controlled "Allow 2G" toggle + * {@link #ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G} * </ol> * This API will result in allowing an intersection of allowed network types for all reasons, * including the configuration done through other reasons. @@ -8358,6 +8369,7 @@ public class TelephonyManager { case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER: case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_POWER: case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_CARRIER: + case TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G: return true; } return false; @@ -14574,6 +14586,11 @@ public class TelephonyManager { */ public void registerTelephonyCallback(@NonNull @CallbackExecutor Executor executor, @NonNull TelephonyCallback callback) { + + if (mContext == null) { + throw new IllegalStateException("telephony service is null."); + } + if (executor == null || callback == null) { throw new IllegalArgumentException("TelephonyCallback and executor must be non-null"); } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 7ac488d7de21..c4f3fea770ed 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -87,10 +87,10 @@ 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.RULE_ALLOW_METERED; -import static android.net.NetworkPolicyManager.RULE_NONE; -import static android.net.NetworkPolicyManager.RULE_REJECT_ALL; -import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; +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; @@ -188,7 +188,6 @@ import android.net.IDnsResolver; import android.net.INetd; import android.net.INetworkMonitor; import android.net.INetworkMonitorCallbacks; -import android.net.INetworkPolicyListener; import android.net.IOnCompleteListener; import android.net.IQosCallback; import android.net.InetAddresses; @@ -207,6 +206,7 @@ import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkPolicyManager; +import android.net.NetworkPolicyManager.NetworkPolicyCallback; import android.net.NetworkRequest; import android.net.NetworkScore; import android.net.NetworkSpecifier; @@ -423,7 +423,7 @@ public class ConnectivityServiceTest { private TestNetworkAgentWrapper mEthernetNetworkAgent; private MockVpn mMockVpn; private Context mContext; - private INetworkPolicyListener mPolicyListener; + private NetworkPolicyCallback mPolicyCallback; private WrappedMultinetworkPolicyTracker mPolicyTracker; private HandlerThread mAlarmManagerThread; private TestNetIdManager mNetIdManager; @@ -435,8 +435,7 @@ public class ConnectivityServiceTest { private TestNetworkCallback mProfileDefaultNetworkCallback; // State variables required to emulate NetworkPolicyManagerService behaviour. - private int mUidRules = RULE_NONE; - private boolean mRestrictBackground = false; + private int mBlockedReasons = BLOCKED_REASON_NONE; @Mock DeviceIdleInternal mDeviceIdleInternal; @Mock INetworkManagementService mNetworkManagementService; @@ -1375,28 +1374,13 @@ public class ConnectivityServiceTest { } private void mockUidNetworkingBlocked() { - doAnswer(i -> mContext.getSystemService(NetworkPolicyManager.class) - .checkUidNetworkingBlocked(i.getArgument(0) /* uid */, mUidRules, - i.getArgument(1) /* metered */, mRestrictBackground) + doAnswer(i -> NetworkPolicyManager.isUidBlocked(mBlockedReasons, i.getArgument(1)) ).when(mNetworkPolicyManager).isUidNetworkingBlocked(anyInt(), anyBoolean()); - - doAnswer(inv -> mContext.getSystemService(NetworkPolicyManager.class) - .checkUidNetworkingBlocked(inv.getArgument(0) /* uid */, - inv.getArgument(1) /* uidRules */, - inv.getArgument(2) /* isNetworkMetered */, - inv.getArgument(3) /* isBackgroundRestricted */) - ).when(mNetworkPolicyManager).checkUidNetworkingBlocked( - anyInt(), anyInt(), anyBoolean(), anyBoolean()); - } - - private void setUidRulesChanged(int uidRules) throws RemoteException { - mUidRules = uidRules; - mPolicyListener.onUidRulesChanged(Process.myUid(), mUidRules); } - private void setRestrictBackgroundChanged(boolean restrictBackground) throws RemoteException { - mRestrictBackground = restrictBackground; - mPolicyListener.onRestrictBackgroundChanged(mRestrictBackground); + private void setBlockedReasonChanged(int blockedReasons) { + mBlockedReasons = blockedReasons; + mPolicyCallback.onUidBlockedReasonChanged(Process.myUid(), blockedReasons); } private Nat464Xlat getNat464Xlat(NetworkAgentWrapper mna) { @@ -1538,10 +1522,11 @@ public class ConnectivityServiceTest { mService.mNascentDelayMs = TEST_NASCENT_DELAY_MS; verify(mDeps).makeMultinetworkPolicyTracker(any(), any(), any()); - final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor = - ArgumentCaptor.forClass(INetworkPolicyListener.class); - verify(mNetworkPolicyManager).registerListener(policyListenerCaptor.capture()); - mPolicyListener = policyListenerCaptor.getValue(); + final ArgumentCaptor<NetworkPolicyCallback> policyCallbackCaptor = + ArgumentCaptor.forClass(NetworkPolicyCallback.class); + verify(mNetworkPolicyManager).registerNetworkPolicyCallback(any(), + policyCallbackCaptor.capture()); + mPolicyCallback = policyCallbackCaptor.getValue(); // Create local CM before sending system ready so that we can answer // getSystemService() correctly. @@ -4343,6 +4328,7 @@ public class ConnectivityServiceTest { assertTrue(mPolicyTracker.shouldNotifyWifiUnvalidated()); } + @Ignore("Refactoring in progress b/178071397") @Test public void testAvoidBadWifi() throws Exception { final ContentResolver cr = mServiceContext.getContentResolver(); @@ -7265,7 +7251,7 @@ public class ConnectivityServiceTest { assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertExtraInfoFromCmPresent(mCellNetworkAgent); - setUidRulesChanged(RULE_REJECT_ALL); + setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER); cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); @@ -7273,17 +7259,17 @@ public class ConnectivityServiceTest { assertExtraInfoFromCmBlocked(mCellNetworkAgent); // ConnectivityService should cache it not to invoke the callback again. - setUidRulesChanged(RULE_REJECT_METERED); + setBlockedReasonChanged(BLOCKED_METERED_REASON_USER_RESTRICTED); cellNetworkCallback.assertNoCallback(); - setUidRulesChanged(RULE_NONE); + setBlockedReasonChanged(BLOCKED_REASON_NONE); cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertExtraInfoFromCmPresent(mCellNetworkAgent); - setUidRulesChanged(RULE_REJECT_METERED); + setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER); cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); @@ -7308,33 +7294,33 @@ public class ConnectivityServiceTest { assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertExtraInfoFromCmBlocked(mCellNetworkAgent); - setUidRulesChanged(RULE_ALLOW_METERED); + setBlockedReasonChanged(BLOCKED_REASON_NONE); cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertExtraInfoFromCmPresent(mCellNetworkAgent); - setUidRulesChanged(RULE_NONE); + setBlockedReasonChanged(BLOCKED_REASON_NONE); cellNetworkCallback.assertNoCallback(); // Restrict background data. Networking is not blocked because the network is unmetered. - setRestrictBackgroundChanged(true); + setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER); cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent); assertNull(mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); assertExtraInfoFromCmBlocked(mCellNetworkAgent); - setRestrictBackgroundChanged(true); + setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER); cellNetworkCallback.assertNoCallback(); - setUidRulesChanged(RULE_ALLOW_METERED); + setBlockedReasonChanged(BLOCKED_REASON_NONE); cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); assertExtraInfoFromCmPresent(mCellNetworkAgent); - setRestrictBackgroundChanged(false); + setBlockedReasonChanged(BLOCKED_REASON_NONE); cellNetworkCallback.assertNoCallback(); assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); @@ -7351,9 +7337,9 @@ public class ConnectivityServiceTest { mockUidNetworkingBlocked(); // No Networkcallbacks invoked before any network is active. - setUidRulesChanged(RULE_REJECT_ALL); - setUidRulesChanged(RULE_NONE); - setUidRulesChanged(RULE_REJECT_METERED); + setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER); + setBlockedReasonChanged(BLOCKED_REASON_NONE); + setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER); defaultCallback.assertNoCallback(); mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); @@ -7378,8 +7364,8 @@ public class ConnectivityServiceTest { defaultCallback.expectBlockedStatusCallback(false, mCellNetworkAgent); // Verify there's no Networkcallbacks invoked after data saver on/off. - setRestrictBackgroundChanged(true); - setRestrictBackgroundChanged(false); + setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER); + setBlockedReasonChanged(BLOCKED_REASON_NONE); defaultCallback.assertNoCallback(); mCellNetworkAgent.disconnect(); diff --git a/tests/net/java/com/android/server/connectivity/FullScoreTest.kt b/tests/net/java/com/android/server/connectivity/FullScoreTest.kt new file mode 100644 index 000000000000..eb3b4df1a282 --- /dev/null +++ b/tests/net/java/com/android/server/connectivity/FullScoreTest.kt @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.connectivity + +import android.net.NetworkAgentConfig +import android.net.NetworkCapabilities +import android.text.TextUtils +import android.util.ArraySet +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.server.connectivity.FullScore.MAX_CS_MANAGED_POLICY +import com.android.server.connectivity.FullScore.POLICY_ACCEPT_UNVALIDATED +import com.android.server.connectivity.FullScore.POLICY_EVER_USER_SELECTED +import com.android.server.connectivity.FullScore.POLICY_IS_VALIDATED +import com.android.server.connectivity.FullScore.POLICY_IS_VPN +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.collections.minOfOrNull +import kotlin.collections.maxOfOrNull +import kotlin.reflect.full.staticProperties +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +@RunWith(AndroidJUnit4::class) +@SmallTest +class FullScoreTest { + // Convenience methods + fun FullScore.withPolicies( + validated: Boolean = false, + vpn: Boolean = false, + onceChosen: Boolean = false, + acceptUnvalidated: Boolean = false + ): FullScore { + val nac = NetworkAgentConfig.Builder().apply { + setUnvalidatedConnectivityAcceptable(acceptUnvalidated) + setExplicitlySelected(onceChosen) + }.build() + val nc = NetworkCapabilities.Builder().apply { + if (vpn) addTransportType(NetworkCapabilities.TRANSPORT_VPN) + if (validated) addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) + }.build() + return mixInScore(nc, nac) + } + + @Test + fun testGetLegacyInt() { + val ns = FullScore(50, 0L /* policy */) + assertEquals(10, ns.legacyInt) // -40 penalty for not being validated + assertEquals(50, ns.legacyIntAsValidated) + + val vpnNs = FullScore(101, 0L /* policy */).withPolicies(vpn = true) + assertEquals(101, vpnNs.legacyInt) // VPNs are not subject to unvalidation penalty + assertEquals(101, vpnNs.legacyIntAsValidated) + assertEquals(101, vpnNs.withPolicies(validated = true).legacyInt) + assertEquals(101, vpnNs.withPolicies(validated = true).legacyIntAsValidated) + + val validatedNs = ns.withPolicies(validated = true) + assertEquals(50, validatedNs.legacyInt) // No penalty, this is validated + assertEquals(50, validatedNs.legacyIntAsValidated) + + val chosenNs = ns.withPolicies(onceChosen = true) + assertEquals(10, chosenNs.legacyInt) + assertEquals(100, chosenNs.legacyIntAsValidated) + assertEquals(10, chosenNs.withPolicies(acceptUnvalidated = true).legacyInt) + assertEquals(50, chosenNs.withPolicies(acceptUnvalidated = true).legacyIntAsValidated) + } + + @Test + fun testToString() { + val string = FullScore(10, 0L /* policy */) + .withPolicies(vpn = true, acceptUnvalidated = true).toString() + assertTrue(string.contains("Score(10"), string) + assertTrue(string.contains("ACCEPT_UNVALIDATED"), string) + assertTrue(string.contains("IS_VPN"), string) + assertFalse(string.contains("IS_VALIDATED"), string) + val foundNames = ArraySet<String>() + getAllPolicies().forEach { + val name = FullScore.policyNameOf(it.get() as Int) + assertFalse(TextUtils.isEmpty(name)) + assertFalse(foundNames.contains(name)) + foundNames.add(name) + } + assertFailsWith<IllegalArgumentException> { + FullScore.policyNameOf(MAX_CS_MANAGED_POLICY + 1) + } + } + + fun getAllPolicies() = Regex("POLICY_.*").let { nameRegex -> + FullScore::class.staticProperties.filter { it.name.matches(nameRegex) } + } + + @Test + fun testHasPolicy() { + val ns = FullScore(50, 0L /* policy */) + assertFalse(ns.hasPolicy(POLICY_IS_VALIDATED)) + assertFalse(ns.hasPolicy(POLICY_IS_VPN)) + assertFalse(ns.hasPolicy(POLICY_EVER_USER_SELECTED)) + assertFalse(ns.hasPolicy(POLICY_ACCEPT_UNVALIDATED)) + assertTrue(ns.withPolicies(validated = true).hasPolicy(POLICY_IS_VALIDATED)) + assertTrue(ns.withPolicies(vpn = true).hasPolicy(POLICY_IS_VPN)) + assertTrue(ns.withPolicies(onceChosen = true).hasPolicy(POLICY_EVER_USER_SELECTED)) + assertTrue(ns.withPolicies(acceptUnvalidated = true).hasPolicy(POLICY_ACCEPT_UNVALIDATED)) + } + + @Test + fun testMinMaxPolicyConstants() { + val policies = getAllPolicies() + + policies.forEach { policy -> + assertTrue(policy.get() as Int >= FullScore.MIN_CS_MANAGED_POLICY) + assertTrue(policy.get() as Int <= FullScore.MAX_CS_MANAGED_POLICY) + } + assertEquals(FullScore.MIN_CS_MANAGED_POLICY, + policies.minOfOrNull { it.get() as Int }) + assertEquals(FullScore.MAX_CS_MANAGED_POLICY, + policies.maxOfOrNull { it.get() as Int }) + } +} diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java index ea2b362c537a..9ab60a41a397 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java @@ -357,7 +357,7 @@ public class LingerMonitorTest { caps.addTransportType(transport); NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info, new LinkProperties(), caps, new NetworkScore.Builder().setLegacyInt(50).build(), - mCtx, null, new NetworkAgentConfig() /* config */, mConnService, mNetd, + mCtx, null, new NetworkAgentConfig.Builder().build(), mConnService, mNetd, mDnsResolver, NetworkProvider.ID_NONE, Binder.getCallingUid(), mQosCallbackTracker, new ConnectivityService.Dependencies()); nai.everValidated = true; |