diff options
22 files changed, 1113 insertions, 199 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index e0eccf4fc1f3..d02c7abfe802 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -29495,6 +29495,7 @@ package android.os { field public static final int PREVIEW_SDK_INT; field public static final String RELEASE; field @NonNull public static final String RELEASE_OR_CODENAME; + field @NonNull public static final String RELEASE_OR_PREVIEW_DISPLAY; field @Deprecated public static final String SDK; field public static final int SDK_INT; field public static final String SECURITY_PATCH; diff --git a/core/api/system-current.txt b/core/api/system-current.txt index af7fc7728a5b..456a4f46ebbf 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -7039,14 +7039,21 @@ package android.net { } public final class EthernetNetworkUpdateRequest implements android.os.Parcelable { - ctor public EthernetNetworkUpdateRequest(@NonNull android.net.StaticIpConfiguration, @NonNull android.net.NetworkCapabilities); method public int describeContents(); - method @NonNull public android.net.StaticIpConfiguration getIpConfig(); + method @NonNull public android.net.IpConfiguration getIpConfiguration(); method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkUpdateRequest> CREATOR; } + public static final class EthernetNetworkUpdateRequest.Builder { + ctor public EthernetNetworkUpdateRequest.Builder(); + ctor public EthernetNetworkUpdateRequest.Builder(@NonNull android.net.EthernetNetworkUpdateRequest); + method @NonNull public android.net.EthernetNetworkUpdateRequest build(); + method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setIpConfiguration(@NonNull android.net.IpConfiguration); + method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setNetworkCapabilities(@NonNull android.net.NetworkCapabilities); + } + public final class MatchAllNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { ctor public MatchAllNetworkSpecifier(); method public int describeContents(); diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 545ae38c38c0..03492aa56631 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -285,13 +285,20 @@ public class Build { public static final String RELEASE = getString("ro.build.version.release"); /** - * The version string we show to the user; may be {@link #RELEASE} or - * {@link #CODENAME} if not a final release build. + * The version string. May be {@link #RELEASE} or {@link #CODENAME} if + * not a final release build. */ @NonNull public static final String RELEASE_OR_CODENAME = getString( "ro.build.version.release_or_codename"); /** + * The version string we show to the user; may be {@link #RELEASE} or + * a descriptive string if not a final release build. + */ + @NonNull public static final String RELEASE_OR_PREVIEW_DISPLAY = getString( + "ro.build.version.release_or_preview_display"); + + /** * The base OS build the product is based on. */ public static final String BASE_OS = SystemProperties.get("ro.build.version.base_os", ""); diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS index 5d9f2189df1b..8e5ed8f6e578 100644 --- a/core/java/android/os/OWNERS +++ b/core/java/android/os/OWNERS @@ -52,6 +52,9 @@ per-file *Power* = file:/services/core/java/com/android/server/power/OWNERS per-file *Telephony* = file:/telephony/OWNERS per-file *Zygote* = file:/ZYGOTE_OWNERS +# Time +per-file *Clock* = file:/services/core/java/com/android/server/timezonedetector/OWNERS + # RecoverySystem per-file *Recovery* = file:/services/core/java/com/android/server/recoverysystem/OWNERS diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index ae9d71610aaa..fb0b7fdd6ce3 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -112,17 +112,74 @@ public class SystemConfig { public final String name; public final String filename; public final String[] dependencies; + + /** + * SDK version this library was added to the BOOTCLASSPATH. + * + * <p>At the SDK level specified in this field and higher, the apps' uses-library tags for + * this library will be ignored, since the library is always available on BOOTCLASSPATH. + * + * <p>0 means not specified. + */ + public final int onBootclasspathSince; + + /** + * SDK version this library was removed from the BOOTCLASSPATH. + * + * <p>At the SDK level specified in this field and higher, this library needs to be + * explicitly added by apps. For compatibility reasons, when an app + * targets an SDK less than the value of this attribute, this library is automatically + * added. + * + * <p>0 means not specified. + */ + public final int onBootclasspathBefore; + + /** + * Declares whether this library can be safely ignored from <uses-library> tags. + * + * <p> This can happen if the library initially had to be explicitly depended-on using that + * tag but has since been moved to the BOOTCLASSPATH which means now is always available + * and the tag is no longer required. + */ + public final boolean canBeSafelyIgnored; + public final boolean isNative; - SharedLibraryEntry(String name, String filename, String[] dependencies) { - this(name, filename, dependencies, false /* isNative */); + + @VisibleForTesting + public SharedLibraryEntry(String name, String filename, String[] dependencies, + boolean isNative) { + this(name, filename, dependencies, 0 /* onBootclasspathSince */, + 0 /* onBootclasspathBefore */, isNative); } - SharedLibraryEntry(String name, String filename, String[] dependencies, boolean isNative) { + @VisibleForTesting + public SharedLibraryEntry(String name, String filename, String[] dependencies, + int onBootclasspathSince, int onBootclassPathBefore) { + this(name, filename, dependencies, onBootclasspathSince, onBootclassPathBefore, + false /* isNative */); + } + + SharedLibraryEntry(String name, String filename, String[] dependencies, + int onBootclasspathSince, int onBootclasspathBefore, boolean isNative) { this.name = name; this.filename = filename; this.dependencies = dependencies; + this.onBootclasspathSince = onBootclasspathSince; + this.onBootclasspathBefore = onBootclasspathBefore; this.isNative = isNative; + + canBeSafelyIgnored = this.onBootclasspathSince != 0 + && isSdkAtLeast(this.onBootclasspathSince); + } + + private static boolean isSdkAtLeast(int level) { + if ("REL".equals(Build.VERSION.CODENAME)) { + return Build.VERSION.SDK_INT >= level; + } + return level == Build.VERSION_CODES.CUR_DEVELOPMENT + || Build.VERSION.SDK_INT >= level; } } @@ -509,12 +566,14 @@ public class SystemConfig { } private void readAllPermissions() { + final XmlPullParser parser = Xml.newPullParser(); + // Read configuration from system - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL); // Read configuration from the old permissions dir - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL); // Vendors are only allowed to customize these @@ -524,18 +583,18 @@ public class SystemConfig { // For backward compatibility vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS); } - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag); - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag); String vendorSkuProperty = SystemProperties.get(VENDOR_SKU_PROPERTY, ""); if (!vendorSkuProperty.isEmpty()) { String vendorSkuDir = "sku_" + vendorSkuProperty; - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getVendorDirectory(), "etc", "sysconfig", vendorSkuDir), vendorPermissionFlag); - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getVendorDirectory(), "etc", "permissions", vendorSkuDir), vendorPermissionFlag); } @@ -543,18 +602,18 @@ public class SystemConfig { // Allow ODM to customize system configs as much as Vendor, because /odm is another // vendor partition other than /vendor. int odmPermissionFlag = vendorPermissionFlag; - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag); - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag); String skuProperty = SystemProperties.get(SKU_PROPERTY, ""); if (!skuProperty.isEmpty()) { String skuDir = "sku_" + skuProperty; - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getOdmDirectory(), "etc", "sysconfig", skuDir), odmPermissionFlag); - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getOdmDirectory(), "etc", "permissions", skuDir), odmPermissionFlag); } @@ -562,9 +621,9 @@ public class SystemConfig { // Allow OEM to customize these int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS | ALLOW_VENDOR_APEX; - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag); - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag); // Allow Product to customize these configs @@ -579,15 +638,15 @@ public class SystemConfig { // DEVICE_INITIAL_SDK_INT for the devices without product interface enforcement. productPermissionFlag = ALLOW_ALL; } - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getProductDirectory(), "etc", "sysconfig"), productPermissionFlag); - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getProductDirectory(), "etc", "permissions"), productPermissionFlag); // Allow /system_ext to customize all system configs - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getSystemExtDirectory(), "etc", "sysconfig"), ALLOW_ALL); - readPermissions(Environment.buildPath( + readPermissions(parser, Environment.buildPath( Environment.getSystemExtDirectory(), "etc", "permissions"), ALLOW_ALL); // Skip loading configuration from apex if it is not a system process. @@ -601,12 +660,14 @@ public class SystemConfig { if (f.isFile() || f.getPath().contains("@")) { continue; } - readPermissions(Environment.buildPath(f, "etc", "permissions"), apexPermissionFlag); + readPermissions(parser, Environment.buildPath(f, "etc", "permissions"), + apexPermissionFlag); } + pruneVendorApexPrivappAllowlists(); } @VisibleForTesting - public void readPermissions(File libraryDir, int permissionFlag) { + public void readPermissions(final XmlPullParser parser, File libraryDir, int permissionFlag) { // Read permissions from given directory. if (!libraryDir.exists() || !libraryDir.isDirectory()) { if (permissionFlag == ALLOW_ALL) { @@ -641,12 +702,12 @@ public class SystemConfig { continue; } - readPermissionsFromXml(f, permissionFlag); + readPermissionsFromXml(parser, f, permissionFlag); } // Read platform permissions last so it will take precedence if (platformFile != null) { - readPermissionsFromXml(platformFile, permissionFlag); + readPermissionsFromXml(parser, platformFile, permissionFlag); } } @@ -655,8 +716,9 @@ public class SystemConfig { + permFile + " at " + parser.getPositionDescription()); } - private void readPermissionsFromXml(File permFile, int permissionFlag) { - FileReader permReader = null; + private void readPermissionsFromXml(final XmlPullParser parser, File permFile, + int permissionFlag) { + final FileReader permReader; try { permReader = new FileReader(permFile); } catch (FileNotFoundException e) { @@ -668,7 +730,6 @@ public class SystemConfig { final boolean lowRam = ActivityManager.isLowRamDeviceStatic(); try { - XmlPullParser parser = Xml.newPullParser(); parser.setInput(permReader); int type; @@ -789,11 +850,17 @@ public class SystemConfig { XmlUtils.skipCurrentTag(parser); } } break; + case "apex-library": + // "apex-library" is meant to behave exactly like "library" case "library": { if (allowLibs) { String lname = parser.getAttributeValue(null, "name"); String lfile = parser.getAttributeValue(null, "file"); String ldependency = parser.getAttributeValue(null, "dependency"); + int minDeviceSdk = XmlUtils.readIntAttribute(parser, "min-device-sdk", + 0); + int maxDeviceSdk = XmlUtils.readIntAttribute(parser, "max-device-sdk", + 0); if (lname == null) { Slog.w(TAG, "<" + name + "> without name in " + permFile + " at " + parser.getPositionDescription()); @@ -801,10 +868,34 @@ public class SystemConfig { Slog.w(TAG, "<" + name + "> without file in " + permFile + " at " + parser.getPositionDescription()); } else { - //Log.i(TAG, "Got library " + lname + " in " + lfile); - SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile, - ldependency == null ? new String[0] : ldependency.split(":")); - mSharedLibraries.put(lname, entry); + boolean allowedMinSdk = minDeviceSdk <= Build.VERSION.SDK_INT; + boolean allowedMaxSdk = + maxDeviceSdk == 0 || maxDeviceSdk >= Build.VERSION.SDK_INT; + final boolean exists = new File(lfile).exists(); + if (allowedMinSdk && allowedMaxSdk && exists) { + int bcpSince = XmlUtils.readIntAttribute(parser, + "on-bootclasspath-since", 0); + int bcpBefore = XmlUtils.readIntAttribute(parser, + "on-bootclasspath-before", 0); + SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile, + ldependency == null + ? new String[0] : ldependency.split(":"), + bcpSince, bcpBefore); + mSharedLibraries.put(lname, entry); + } else { + final StringBuilder msg = new StringBuilder( + "Ignore shared library ").append(lname).append(":"); + if (!allowedMinSdk) { + msg.append(" min-device-sdk=").append(minDeviceSdk); + } + if (!allowedMaxSdk) { + msg.append(" max-device-sdk=").append(maxDeviceSdk); + } + if (!exists) { + msg.append(" ").append(lfile).append(" does not exist"); + } + Slog.i(TAG, msg.toString()); + } } } else { logNotAllowedInPartition(name, permFile, parser); @@ -1085,7 +1176,8 @@ public class SystemConfig { readPrivAppPermissions(parser, mSystemExtPrivAppPermissions, mSystemExtPrivAppDenyPermissions); } else if (apex) { - readApexPrivAppPermissions(parser, permFile); + readApexPrivAppPermissions(parser, permFile, + Environment.getApexDirectory().toPath()); } else { readPrivAppPermissions(parser, mPrivAppPermissions, mPrivAppDenyPermissions); @@ -1435,6 +1527,21 @@ public class SystemConfig { } } + /** + * Prunes out any privileged permission allowlists bundled in vendor apexes. + */ + @VisibleForTesting + public void pruneVendorApexPrivappAllowlists() { + for (String moduleName: mAllowedVendorApexes.keySet()) { + if (mApexPrivAppPermissions.containsKey(moduleName) + || mApexPrivAppDenyPermissions.containsKey(moduleName)) { + Slog.w(TAG, moduleName + " is a vendor apex, ignore its priv-app allowlist"); + mApexPrivAppPermissions.remove(moduleName); + mApexPrivAppDenyPermissions.remove(moduleName); + } + } + } + private void readInstallInUserType(XmlPullParser parser, Map<String, Set<String>> doInstallMap, Map<String, Set<String>> nonInstallMap) @@ -1645,8 +1752,7 @@ public class SystemConfig { /** * Returns the module name for a file in the apex module's partition. */ - private String getApexModuleNameFromFilePath(Path path) { - final Path apexDirectoryPath = Environment.getApexDirectory().toPath(); + private String getApexModuleNameFromFilePath(Path path, Path apexDirectoryPath) { if (!path.startsWith(apexDirectoryPath)) { throw new IllegalArgumentException("File " + path + " is not part of an APEX."); } @@ -1658,9 +1764,14 @@ public class SystemConfig { return path.getName(apexDirectoryPath.getNameCount()).toString(); } - private void readApexPrivAppPermissions(XmlPullParser parser, File permFile) - throws IOException, XmlPullParserException { - final String moduleName = getApexModuleNameFromFilePath(permFile.toPath()); + /** + * Reads the contents of the privileged permission allowlist stored inside an APEX. + */ + @VisibleForTesting + public void readApexPrivAppPermissions(XmlPullParser parser, File permFile, + Path apexDirectoryPath) throws IOException, XmlPullParserException { + final String moduleName = + getApexModuleNameFromFilePath(permFile.toPath(), apexDirectoryPath); final ArrayMap<String, ArraySet<String>> privAppPermissions; if (mApexPrivAppPermissions.containsKey(moduleName)) { privAppPermissions = mApexPrivAppPermissions.get(moduleName); diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java index 2e85b304ec47..31dd10a8ed53 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java @@ -66,6 +66,7 @@ import java.security.SecureRandom; import java.security.UnrecoverableKeyException; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.ECGenParameterSpec; +import java.security.spec.NamedParameterSpec; import java.security.spec.RSAKeyGenParameterSpec; import java.util.ArrayList; import java.util.Arrays; @@ -119,36 +120,42 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato private static final int RSA_MIN_KEY_SIZE = 512; private static final int RSA_MAX_KEY_SIZE = 8192; - private static final Map<String, Integer> SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE = + private static final Map<String, Integer> SUPPORTED_EC_CURVE_NAME_TO_SIZE = new HashMap<String, Integer>(); - private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>(); - private static final List<Integer> SUPPORTED_EC_NIST_CURVE_SIZES = new ArrayList<Integer>(); + private static final List<String> SUPPORTED_EC_CURVE_NAMES = new ArrayList<String>(); + private static final List<Integer> SUPPORTED_EC_CURVE_SIZES = new ArrayList<Integer>(); + private static final String CURVE_X_25519 = NamedParameterSpec.X25519.getName(); + private static final String CURVE_ED_25519 = NamedParameterSpec.ED25519.getName(); + static { // Aliases for NIST P-224 - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224); - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp224r1", 224); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-224", 224); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp224r1", 224); // Aliases for NIST P-256 - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-256", 256); - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp256r1", 256); - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("prime256v1", 256); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-256", 256); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp256r1", 256); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("prime256v1", 256); + // Aliases for Curve 25519 + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put(CURVE_X_25519.toLowerCase(Locale.US), 256); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put(CURVE_ED_25519.toLowerCase(Locale.US), 256); // Aliases for NIST P-384 - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-384", 384); - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp384r1", 384); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-384", 384); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp384r1", 384); // Aliases for NIST P-521 - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-521", 521); - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp521r1", 521); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("p-521", 521); + SUPPORTED_EC_CURVE_NAME_TO_SIZE.put("secp521r1", 521); - SUPPORTED_EC_NIST_CURVE_NAMES.addAll(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet()); - Collections.sort(SUPPORTED_EC_NIST_CURVE_NAMES); + SUPPORTED_EC_CURVE_NAMES.addAll(SUPPORTED_EC_CURVE_NAME_TO_SIZE.keySet()); + Collections.sort(SUPPORTED_EC_CURVE_NAMES); - SUPPORTED_EC_NIST_CURVE_SIZES.addAll( - new HashSet<Integer>(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.values())); - Collections.sort(SUPPORTED_EC_NIST_CURVE_SIZES); + SUPPORTED_EC_CURVE_SIZES.addAll( + new HashSet<Integer>(SUPPORTED_EC_CURVE_NAME_TO_SIZE.values())); + Collections.sort(SUPPORTED_EC_CURVE_SIZES); } private final int mOriginalKeymasterAlgorithm; @@ -164,6 +171,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato private int mKeySizeBits; private SecureRandom mRng; private KeyDescriptor mAttestKeyDescriptor; + private String mEcCurveName; private int[] mKeymasterPurposes; private int[] mKeymasterBlockModes; @@ -177,12 +185,15 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato mOriginalKeymasterAlgorithm = keymasterAlgorithm; } - private @EcCurve int keySize2EcCurve(int keySizeBits) + private static @EcCurve int keySizeAndNameToEcCurve(int keySizeBits, String ecCurveName) throws InvalidAlgorithmParameterException { switch (keySizeBits) { case 224: return EcCurve.P_224; case 256: + if (isCurve25519(ecCurveName)) { + return EcCurve.CURVE_25519; + } return EcCurve.P_256; case 384: return EcCurve.P_384; @@ -247,7 +258,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato if (mKeySizeBits == -1) { mKeySizeBits = getDefaultKeySize(keymasterAlgorithm); } - checkValidKeySize(keymasterAlgorithm, mKeySizeBits, mSpec.isStrongBoxBacked()); + checkValidKeySize(keymasterAlgorithm, mKeySizeBits, mSpec.isStrongBoxBacked(), + mEcCurveName); if (spec.getKeystoreAlias() == null) { throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided"); @@ -299,6 +311,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato mAttestKeyDescriptor = buildAndCheckAttestKeyDescriptor(spec); checkAttestKeyPurpose(spec); + checkCorrectKeyPurposeForCurve(spec); success = true; } finally { @@ -317,6 +330,42 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato } } + private void checkCorrectKeyPurposeForCurve(KeyGenParameterSpec spec) + throws InvalidAlgorithmParameterException { + // Validate the key usage purposes against the curve. x25519 should be + // key exchange only, ed25519 signing and attesting. + + if (!isCurve25519(mEcCurveName)) { + return; + } + + if (mEcCurveName.equalsIgnoreCase(CURVE_X_25519) + && spec.getPurposes() != KeyProperties.PURPOSE_AGREE_KEY) { + throw new InvalidAlgorithmParameterException( + "x25519 may only be used for key agreement."); + } else if (mEcCurveName.equalsIgnoreCase(CURVE_ED_25519) + && !hasOnlyAllowedPurposeForEd25519(spec.getPurposes())) { + throw new InvalidAlgorithmParameterException( + "ed25519 may not be used for key agreement."); + } + } + + private static boolean isCurve25519(String ecCurveName) { + if (ecCurveName == null) { + return false; + } + return ecCurveName.equalsIgnoreCase(CURVE_X_25519) + || ecCurveName.equalsIgnoreCase(CURVE_ED_25519); + } + + private static boolean hasOnlyAllowedPurposeForEd25519(@KeyProperties.PurposeEnum int purpose) { + final int allowedPurposes = KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY + | KeyProperties.PURPOSE_ATTEST_KEY; + boolean hasAllowedPurpose = (purpose & allowedPurposes) != 0; + boolean hasDisallowedPurpose = (purpose & ~allowedPurposes) != 0; + return hasAllowedPurpose && !hasDisallowedPurpose; + } + private KeyDescriptor buildAndCheckAttestKeyDescriptor(KeyGenParameterSpec spec) throws InvalidAlgorithmParameterException { if (spec.getAttestKeyAlias() != null) { @@ -473,6 +522,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato mRSAPublicExponent = null; mRng = null; mKeyStore = null; + mEcCurveName = null; } private void initAlgorithmSpecificParameters() throws InvalidAlgorithmParameterException { @@ -514,13 +564,13 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato case KeymasterDefs.KM_ALGORITHM_EC: if (algSpecificSpec instanceof ECGenParameterSpec) { ECGenParameterSpec ecSpec = (ECGenParameterSpec) algSpecificSpec; - String curveName = ecSpec.getName(); - Integer ecSpecKeySizeBits = SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.get( - curveName.toLowerCase(Locale.US)); + mEcCurveName = ecSpec.getName(); + final Integer ecSpecKeySizeBits = SUPPORTED_EC_CURVE_NAME_TO_SIZE.get( + mEcCurveName.toLowerCase(Locale.US)); if (ecSpecKeySizeBits == null) { throw new InvalidAlgorithmParameterException( - "Unsupported EC curve name: " + curveName - + ". Supported: " + SUPPORTED_EC_NIST_CURVE_NAMES); + "Unsupported EC curve name: " + mEcCurveName + + ". Supported: " + SUPPORTED_EC_CURVE_NAMES); } if (mKeySizeBits == -1) { mKeySizeBits = ecSpecKeySizeBits; @@ -744,7 +794,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC) { params.add(KeyStore2ParameterUtils.makeEnum( - Tag.EC_CURVE, keySize2EcCurve(mKeySizeBits) + Tag.EC_CURVE, keySizeAndNameToEcCurve(mKeySizeBits, mEcCurveName) )); } @@ -864,7 +914,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato private static void checkValidKeySize( int keymasterAlgorithm, int keySize, - boolean isStrongBoxBacked) + boolean isStrongBoxBacked, + String mEcCurveName) throws InvalidAlgorithmParameterException { switch (keymasterAlgorithm) { case KeymasterDefs.KM_ALGORITHM_EC: @@ -873,9 +924,13 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato "Unsupported StrongBox EC key size: " + keySize + " bits. Supported: 256"); } - if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) { + if (isStrongBoxBacked && isCurve25519(mEcCurveName)) { + throw new InvalidAlgorithmParameterException( + "Unsupported StrongBox EC: " + mEcCurveName); + } + if (!SUPPORTED_EC_CURVE_SIZES.contains(keySize)) { throw new InvalidAlgorithmParameterException("Unsupported EC key size: " - + keySize + " bits. Supported: " + SUPPORTED_EC_NIST_CURVE_SIZES); + + keySize + " bits. Supported: " + SUPPORTED_EC_CURVE_SIZES); } break; case KeymasterDefs.KM_ALGORITHM_RSA: diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java index 72a145fa6a05..358104fffbf6 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java @@ -66,6 +66,11 @@ public class AndroidKeyStoreProvider extends Provider { private static final String DESEDE_SYSTEM_PROPERTY = "ro.hardware.keystore_desede"; + // Conscrypt returns the Ed25519 OID as the JCA key algorithm. + private static final String ED25519_OID = "1.3.101.112"; + // Conscrypt returns "XDH" as the X25519 JCA key algorithm. + private static final String X25519_ALIAS = "XDH"; + /** @hide **/ public AndroidKeyStoreProvider() { super(PROVIDER_NAME, 1.0, "Android KeyStore security provider"); @@ -78,10 +83,16 @@ public class AndroidKeyStoreProvider extends Provider { // java.security.KeyPairGenerator put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$EC"); put("KeyPairGenerator.RSA", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA"); + put("KeyPairGenerator." + X25519_ALIAS, + PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA"); + put("KeyPairGenerator." + ED25519_OID, + PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA"); // java.security.KeyFactory putKeyFactoryImpl("EC"); putKeyFactoryImpl("RSA"); + putKeyFactoryImpl(X25519_ALIAS); + putKeyFactoryImpl(ED25519_OID); // javax.crypto.KeyGenerator put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES"); @@ -219,12 +230,17 @@ public class AndroidKeyStoreProvider extends Provider { KeyStoreSecurityLevel securityLevel = iSecurityLevel; if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(jcaKeyAlgorithm)) { - return new AndroidKeyStoreECPublicKey(descriptor, metadata, iSecurityLevel, (ECPublicKey) publicKey); } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(jcaKeyAlgorithm)) { return new AndroidKeyStoreRSAPublicKey(descriptor, metadata, iSecurityLevel, (RSAPublicKey) publicKey); + } else if (ED25519_OID.equalsIgnoreCase(jcaKeyAlgorithm)) { + //TODO(b/214203951) missing classes in conscrypt + throw new ProviderException("Curve " + ED25519_OID + " not supported yet"); + } else if (X25519_ALIAS.equalsIgnoreCase(jcaKeyAlgorithm)) { + //TODO(b/214203951) missing classes in conscrypt + throw new ProviderException("Curve " + X25519_ALIAS + " not supported yet"); } else { throw new ProviderException("Unsupported Android Keystore public key algorithm: " + jcaKeyAlgorithm); diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BluetoothProfileConnectionInfoTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BluetoothProfileConnectionInfoTest.java deleted file mode 100644 index f23794b50543..000000000000 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BluetoothProfileConnectionInfoTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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.mediaframeworktest.unit; - -import static org.junit.Assert.assertEquals; - -import android.bluetooth.BluetoothProfile; -import android.media.BluetoothProfileConnectionInfo; - -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class BluetoothProfileConnectionInfoTest { - - @Test - public void testCoverageA2dp() { - final boolean supprNoisy = false; - final int volume = 42; - final BluetoothProfileConnectionInfo info = BluetoothProfileConnectionInfo - .createA2dpInfo(supprNoisy, volume); - assertEquals(info.getProfile(), BluetoothProfile.A2DP); - assertEquals(info.isSuppressNoisyIntent(), supprNoisy); - assertEquals(info.getVolume(), volume); - } - - @Test - public void testCoverageA2dpSink() { - final int volume = 42; - final BluetoothProfileConnectionInfo info = BluetoothProfileConnectionInfo - .createA2dpSinkInfo(volume); - assertEquals(info.getProfile(), BluetoothProfile.A2DP_SINK); - assertEquals(info.getVolume(), volume); - } - - @Test - public void testCoveragehearingAid() { - final boolean supprNoisy = true; - final BluetoothProfileConnectionInfo info = BluetoothProfileConnectionInfo - .createHearingAidInfo(supprNoisy); - assertEquals(info.getProfile(), BluetoothProfile.HEARING_AID); - assertEquals(info.isSuppressNoisyIntent(), supprNoisy); - } - - @Test - public void testCoverageLeAudio() { - final boolean supprNoisy = false; - final boolean isLeOutput = true; - final BluetoothProfileConnectionInfo info = BluetoothProfileConnectionInfo - .createLeAudioInfo(supprNoisy, isLeOutput); - assertEquals(info.getProfile(), BluetoothProfile.LE_AUDIO); - assertEquals(info.isSuppressNoisyIntent(), supprNoisy); - assertEquals(info.isLeOutput(), isLeOutput); - } -} - diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java index e879e40247cf..a6269711055a 100644 --- a/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java +++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetNetworkUpdateRequest.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -27,13 +28,13 @@ import java.util.Objects; @SystemApi public final class EthernetNetworkUpdateRequest implements Parcelable { @NonNull - private final StaticIpConfiguration mIpConfig; + private final IpConfiguration mIpConfig; @NonNull private final NetworkCapabilities mNetworkCapabilities; @NonNull - public StaticIpConfiguration getIpConfig() { - return new StaticIpConfiguration(mIpConfig); + public IpConfiguration getIpConfiguration() { + return new IpConfiguration(mIpConfig); } @NonNull @@ -41,20 +42,75 @@ public final class EthernetNetworkUpdateRequest implements Parcelable { return new NetworkCapabilities(mNetworkCapabilities); } - public EthernetNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig, + private EthernetNetworkUpdateRequest(@NonNull final IpConfiguration ipConfig, @NonNull final NetworkCapabilities networkCapabilities) { Objects.requireNonNull(ipConfig); Objects.requireNonNull(networkCapabilities); - mIpConfig = new StaticIpConfiguration(ipConfig); + mIpConfig = new IpConfiguration(ipConfig); mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); } private EthernetNetworkUpdateRequest(@NonNull final Parcel source) { Objects.requireNonNull(source); - mIpConfig = StaticIpConfiguration.CREATOR.createFromParcel(source); + mIpConfig = IpConfiguration.CREATOR.createFromParcel(source); mNetworkCapabilities = NetworkCapabilities.CREATOR.createFromParcel(source); } + /** + * Builder used to create {@link EthernetNetworkUpdateRequest} objects. + */ + public static final class Builder { + @Nullable + private IpConfiguration mBuilderIpConfig; + @Nullable + private NetworkCapabilities mBuilderNetworkCapabilities; + + public Builder(){} + + /** + * Constructor to populate the builder's values with an already built + * {@link EthernetNetworkUpdateRequest}. + * @param request the {@link EthernetNetworkUpdateRequest} to populate with. + */ + public Builder(@NonNull final EthernetNetworkUpdateRequest request) { + Objects.requireNonNull(request); + mBuilderIpConfig = new IpConfiguration(request.mIpConfig); + mBuilderNetworkCapabilities = new NetworkCapabilities(request.mNetworkCapabilities); + } + + /** + * Set the {@link IpConfiguration} to be used with the {@code Builder}. + * @param ipConfig the {@link IpConfiguration} to set. + * @return The builder to facilitate chaining. + */ + @NonNull + public Builder setIpConfiguration(@NonNull final IpConfiguration ipConfig) { + Objects.requireNonNull(ipConfig); + mBuilderIpConfig = new IpConfiguration(ipConfig); + return this; + } + + /** + * Set the {@link NetworkCapabilities} to be used with the {@code Builder}. + * @param nc the {@link NetworkCapabilities} to set. + * @return The builder to facilitate chaining. + */ + @NonNull + public Builder setNetworkCapabilities(@NonNull final NetworkCapabilities nc) { + Objects.requireNonNull(nc); + mBuilderNetworkCapabilities = new NetworkCapabilities(nc); + return this; + } + + /** + * Build {@link EthernetNetworkUpdateRequest} return the current update request. + */ + @NonNull + public EthernetNetworkUpdateRequest build() { + return new EthernetNetworkUpdateRequest(mBuilderIpConfig, mBuilderNetworkCapabilities); + } + } + @Override public String toString() { return "EthernetNetworkUpdateRequest{" @@ -68,7 +124,7 @@ public final class EthernetNetworkUpdateRequest implements Parcelable { if (o == null || getClass() != o.getClass()) return false; EthernetNetworkUpdateRequest that = (EthernetNetworkUpdateRequest) o; - return Objects.equals(that.getIpConfig(), mIpConfig) + return Objects.equals(that.getIpConfiguration(), mIpConfig) && Objects.equals(that.getNetworkCapabilities(), mNetworkCapabilities); } diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java index a0f239d43927..fcde533fe05c 100644 --- a/services/core/java/com/android/server/NetworkTimeUpdateService.java +++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java @@ -171,7 +171,9 @@ public class NetworkTimeUpdateService extends Binder { >= mPollingIntervalMs) { if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh"); boolean isSuccessful = mTime.forceRefresh(); - if (!isSuccessful) { + if (isSuccessful) { + mTryAgainCounter = 0; + } else { String logMsg = "forceRefresh() returned false: cachedNtpResult=" + cachedNtpResult + ", currentElapsedRealtimeMillis=" + currentElapsedRealtimeMillis; @@ -188,7 +190,8 @@ public class NetworkTimeUpdateService extends Binder { && cachedNtpResult.getAgeMillis(currentElapsedRealtimeMillis) < mPollingIntervalMs) { // Obtained fresh fix; schedule next normal update - resetAlarm(mPollingIntervalMs); + resetAlarm(mPollingIntervalMs + - cachedNtpResult.getAgeMillis(currentElapsedRealtimeMillis)); // Suggest the time to the time detector. It may choose use it to set the system clock. TimestampedValue<Long> timeSignal = new TimestampedValue<>( diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS index 71b463a4db8c..f4b8f5ddda66 100644 --- a/services/core/java/com/android/server/OWNERS +++ b/services/core/java/com/android/server/OWNERS @@ -23,14 +23,13 @@ per-file *Alarm* = file:/apex/jobscheduler/OWNERS per-file *AppOp* = file:/core/java/android/permission/OWNERS per-file *Battery* = file:/BATTERY_STATS_OWNERS per-file *Binder* = file:/core/java/com/android/internal/os/BINDER_OWNERS -per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS per-file **IpSec* = file:/services/core/java/com/android/server/net/OWNERS per-file **IpSec* = file:/services/core/java/com/android/server/vcn/OWNERS per-file *Location* = file:/services/core/java/com/android/server/location/OWNERS per-file *Network* = file:/services/core/java/com/android/server/net/OWNERS per-file *Storage* = file:/core/java/android/os/storage/OWNERS -per-file *TimeUpdate* = file:/core/java/android/app/timezone/OWNERS +per-file *TimeUpdate* = file:/services/core/java/com/android/server/timezonedetector/OWNERS per-file DynamicSystemService.java = file:/packages/DynamicSystemInstallationService/OWNERS per-file GestureLauncherService.java = file:platform/packages/apps/EmergencyInfo:/OWNERS per-file MmsServiceBroker.java = file:/telephony/OWNERS diff --git a/services/core/java/com/android/server/infra/OWNERS b/services/core/java/com/android/server/infra/OWNERS new file mode 100644 index 000000000000..0466d8a88053 --- /dev/null +++ b/services/core/java/com/android/server/infra/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 655446 + +include /core/java/android/service/cloudsearch/OWNERS diff --git a/services/core/java/com/android/server/pm/parsing/library/ApexSharedLibraryUpdater.java b/services/core/java/com/android/server/pm/parsing/library/ApexSharedLibraryUpdater.java new file mode 100644 index 000000000000..0418afbf29ee --- /dev/null +++ b/services/core/java/com/android/server/pm/parsing/library/ApexSharedLibraryUpdater.java @@ -0,0 +1,67 @@ +/* + * 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.pm.parsing.library; + +import android.util.ArrayMap; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.SystemConfig; +import com.android.server.pm.parsing.pkg.ParsedPackage; + +/** + * Updates packages to add or remove dependencies on shared libraries as per attributes + * in the library declaration + * + * @hide + */ +@VisibleForTesting +public class ApexSharedLibraryUpdater extends PackageSharedLibraryUpdater { + + /** + * ArrayMap like the one you find in {@link SystemConfig}. The keys are the library names. + */ + private final ArrayMap<String, SystemConfig.SharedLibraryEntry> mSharedLibraries; + + public ApexSharedLibraryUpdater( + ArrayMap<String, SystemConfig.SharedLibraryEntry> sharedLibraries) { + mSharedLibraries = sharedLibraries; + } + + @Override + public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) { + final int builtInLibCount = mSharedLibraries.size(); + for (int i = 0; i < builtInLibCount; i++) { + updateSharedLibraryForPackage(mSharedLibraries.valueAt(i), parsedPackage); + } + } + + private void updateSharedLibraryForPackage(SystemConfig.SharedLibraryEntry entry, + ParsedPackage parsedPackage) { + if (entry.onBootclasspathBefore != 0 + && parsedPackage.getTargetSdkVersion() < entry.onBootclasspathBefore) { + // this package targets an API where this library was in the BCP, so add + // the library transparently in case the package is using it + prefixRequiredLibrary(parsedPackage, entry.name); + } + + if (entry.canBeSafelyIgnored) { + // the library is now present in the BCP and always available; we don't need to add + // it a second time + removeLibrary(parsedPackage, entry.name); + } + } +} diff --git a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java index 8a8a302734b1..d81e7d05fd73 100644 --- a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java +++ b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java @@ -25,6 +25,7 @@ import android.content.pm.PackageParser; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.SystemConfig; import com.android.server.pm.parsing.pkg.ParsedPackage; import java.util.ArrayList; @@ -63,6 +64,11 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { boolean bootClassPathContainsATB = !addUpdaterForAndroidTestBase(packageUpdaters); + // ApexSharedLibraryUpdater should be the last one, to allow modifications introduced by + // mainline after dessert release. + packageUpdaters.add(new ApexSharedLibraryUpdater( + SystemConfig.getInstance().getSharedLibraries())); + PackageSharedLibraryUpdater[] updaterArray = packageUpdaters .toArray(new PackageSharedLibraryUpdater[0]); INSTANCE = new PackageBackwardCompatibility( @@ -106,6 +112,11 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { private final PackageSharedLibraryUpdater[] mPackageUpdaters; + @VisibleForTesting + PackageSharedLibraryUpdater[] getPackageUpdaters() { + return mPackageUpdaters; + } + private PackageBackwardCompatibility( boolean bootClassPathContainsATB, PackageSharedLibraryUpdater[] packageUpdaters) { this.mBootClassPathContainsATB = bootClassPathContainsATB; diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java new file mode 100644 index 000000000000..1d9ea4b6028c --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/ApexSharedLibraryUpdaterTest.java @@ -0,0 +1,281 @@ +/* + * 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.pm.parsing.library; + +import android.os.Build; +import android.platform.test.annotations.Presubmit; +import android.util.ArrayMap; + +import androidx.test.filters.SmallTest; + +import com.android.server.SystemConfig; +import com.android.server.pm.parsing.pkg.AndroidPackage; +import com.android.server.pm.parsing.pkg.PackageImpl; +import com.android.server.pm.parsing.pkg.ParsedPackage; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + + +/** + * Test for {@link ApexSharedLibraryUpdater} + */ +@Presubmit +@SmallTest +@RunWith(JUnit4.class) +public class ApexSharedLibraryUpdaterTest extends PackageSharedLibraryUpdaterTest { + + private final ArrayMap<String, SystemConfig.SharedLibraryEntry> mSharedLibraries = + new ArrayMap<>(8); + + @Before + public void setUp() throws Exception { + installSharedLibraries(); + } + + private void installSharedLibraries() throws Exception { + mSharedLibraries.clear(); + insertLibrary("foo", 0, 0); + insertLibrary("fooBcpSince30", 30, 0); + insertLibrary("fooBcpBefore30", 0, 30); + insertLibrary("fooFromFuture", Build.VERSION.SDK_INT + 2, 0); + } + + private void insertLibrary(String libraryName, int onBootclasspathSince, + int onBootclasspathBefore) { + mSharedLibraries.put(libraryName, new SystemConfig.SharedLibraryEntry( + libraryName, + "foo.jar", + new String[0] /* dependencies */, + onBootclasspathSince, + onBootclasspathBefore + ) + ); + } + + @Test + public void testRegularAppOnRPlus() { + // platform Q should have changes (tested below) + + // these should have no changes + checkNoChanges(Build.VERSION_CODES.R); + checkNoChanges(Build.VERSION_CODES.S); + checkNoChanges(Build.VERSION_CODES.TIRAMISU); + checkNoChanges(Build.VERSION_CODES.CUR_DEVELOPMENT); + } + + private void checkNoChanges(int targetSdkVersion) { + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(targetSdkVersion) + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(targetSdkVersion) + .hideAsParsed()) + .hideAsFinal(); + + checkBackwardsCompatibility(before, after); + } + + @Test + public void testBcpSince30Applied() { + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .addUsesLibrary("fooBcpSince30") + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .hideAsParsed()) + .hideAsFinal(); + + // note: target sdk is not what matters in this logic. It's the system SDK + // should be removed because on 30+ (R+) it is implicit + + checkBackwardsCompatibility(before, after); + } + + @Test + public void testBcpSince11kNotAppliedWithoutLibrary() { + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .hideAsParsed()) + .hideAsFinal(); + + // note: target sdk is not what matters in this logic. It's the system SDK + // nothing should change because the implicit from is only from a future platform release + checkBackwardsCompatibility(before, after); + } + + @Test + public void testBcpSince11kNotAppliedWithLibrary() { + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .addUsesLibrary("fooFromFuture") + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .addUsesLibrary("fooFromFuture") + .hideAsParsed()) + .hideAsFinal(); + + // note: target sdk is not what matters in this logic. It's the system SDK + // nothing should change because the implicit from is only from a future platform release + checkBackwardsCompatibility(before, after); + } + + @Test + public void testBcpBefore30NotApplied() { + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .hideAsParsed()) + .hideAsFinal(); + + // should not be affected because it is still in the BCP in 30 / R + checkBackwardsCompatibility(before, after); + } + + @Test + public void testBcpBefore30Applied() { + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesLibrary("fooBcpBefore30") + .hideAsParsed()) + .hideAsFinal(); + + // should be present because this was in BCP in 29 / Q + checkBackwardsCompatibility(before, after); + } + + /** + * Test a library that was first removed from the BCP [to a mainline module] and later was + * moved back to the BCP via a mainline module update. All of this happening before the current + * SDK. + */ + @Test + public void testBcpRemovedThenAddedPast() { + insertLibrary("fooBcpRemovedThenAdded", 30, 28); + + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.N) + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.N) + .addUsesLibrary("fooBcpBefore30") + .hideAsParsed()) + .hideAsFinal(); + + // the library is now in the BOOTCLASSPATH (for the second time) so it doesn't need to be + // listed + checkBackwardsCompatibility(before, after); + } + + /** + * Test a library that was first removed from the BCP [to a mainline module] and later was + * moved back to the BCP via a mainline module update. The first part happening before the + * current SDK and the second part after. + */ + @Test + public void testBcpRemovedThenAddedMiddle_targetQ() { + insertLibrary("fooBcpRemovedThenAdded", Build.VERSION.SDK_INT + 1, 30); + + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.Q) + .addUsesLibrary("fooBcpRemovedThenAdded") + .addUsesLibrary("fooBcpBefore30") + .hideAsParsed()) + .hideAsFinal(); + + // in this example, we are at the point where the library is not in the BOOTCLASSPATH. + // Because the app targets Q / 29 (when this library was in the BCP) then we need to add it + checkBackwardsCompatibility(before, after); + } + + /** + * Test a library that was first removed from the BCP [to a mainline module] and later was + * moved back to the BCP via a mainline module update. The first part happening before the + * current SDK and the second part after. + */ + @Test + public void testBcpRemovedThenAddedMiddle_targetR() { + insertLibrary("fooBcpRemovedThenAdded", Build.VERSION.SDK_INT + 1, 30); + + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .hideAsParsed()) + .hideAsFinal(); + + // in this example, we are at the point where the library is not in the BOOTCLASSPATH. + // Because the app targets R/30 (when this library was removed from the BCP) then we don't + //need to add it + checkBackwardsCompatibility(before, after); + } + + /** + * Test a library that was first removed from the BCP [to a mainline module] and later was + * moved back to the BCP via a mainline module update. The first part happening before the + * current SDK and the second part after. + */ + @Test + public void testBcpRemovedThenAddedMiddle_targetR_usingLib() { + insertLibrary("fooBcpRemovedThenAdded", Build.VERSION.SDK_INT + 1, 30); + + ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .addUsesLibrary("fooBcpRemovedThenAdded") + .hideAsParsed()); + + AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME) + .setTargetSdkVersion(Build.VERSION_CODES.R) + .addUsesLibrary("fooBcpRemovedThenAdded") + .hideAsParsed()) + .hideAsFinal(); + + // in this example, we are at the point where the library is not in the BOOTCLASSPATH. + // Because the app wants to use the library, it needs to be present + checkBackwardsCompatibility(before, after); + } + + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { + checkBackwardsCompatibility(before, after, + () -> new ApexSharedLibraryUpdater(mSharedLibraries)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java index 9768f176ea85..5bcd0f6bb029 100644 --- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java @@ -21,6 +21,8 @@ import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_T import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER; import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; +import static com.google.common.truth.Truth.assertThat; + import android.content.pm.parsing.ParsingPackage; import android.os.Build; import android.platform.test.annotations.Presubmit; @@ -182,6 +184,22 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate checkBackwardsCompatibility(before, ((ParsedPackage) after.hideAsParsed()).hideAsFinal()); } + /** + * Ensures that ApexSharedLibraryUpdater is the last updater in the list of package updaters + * used by PackageBackwardCompatibility. + * + * This is required so mainline can add and remove libraries installed by the platform updaters. + */ + @Test + public void testApexPackageUpdaterOrdering() { + PackageBackwardCompatibility instance = + (PackageBackwardCompatibility) PackageBackwardCompatibility.getInstance(); + PackageSharedLibraryUpdater[] updaterArray = instance.getPackageUpdaters(); + + PackageSharedLibraryUpdater lastUpdater = updaterArray[updaterArray.length - 1]; + assertThat(lastUpdater).isInstanceOf(ApexSharedLibraryUpdater.class); + } + private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) { checkBackwardsCompatibility(before, after, PackageBackwardCompatibility::getInstance); } diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigNamedActorTest.kt b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigNamedActorTest.kt index b7199d4a2443..150822bdff6b 100644 --- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigNamedActorTest.kt +++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigNamedActorTest.kt @@ -17,6 +17,7 @@ package com.android.server.systemconfig import android.content.Context +import android.util.Xml import androidx.test.InstrumentationRegistry import com.android.server.SystemConfig import com.google.common.truth.Truth.assertThat @@ -227,6 +228,7 @@ class SystemConfigNamedActorTest { .writeText(this.trimIndent()) private fun assertPermissions() = SystemConfig(false).apply { - readPermissions(tempFolder.root, 0) + val parser = Xml.newPullParser() + readPermissions(parser, tempFolder.root, 0) }. let { assertThat(it.namedActors) } } diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java index 5eb21a58c38e..bfdffc0e6567 100644 --- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java @@ -21,10 +21,12 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.testng.Assert.expectThrows; +import android.os.Build; import android.platform.test.annotations.Presubmit; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; +import android.util.Xml; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; @@ -36,9 +38,12 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; import java.io.BufferedWriter; import java.io.File; +import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Arrays; @@ -59,12 +64,15 @@ public class SystemConfigTest { private static final String LOG_TAG = "SystemConfigTest"; private SystemConfig mSysConfig; + private File mFooJar; @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder(); @Before public void setUp() throws Exception { mSysConfig = new SystemConfigTestClass(); + mFooJar = createTempFile( + mTemporaryFolder.getRoot().getCanonicalFile(), "foo.jar", "JAR"); } /** @@ -76,6 +84,11 @@ public class SystemConfigTest { } } + private void readPermissions(File libraryDir, int permissionFlag) { + final XmlPullParser parser = Xml.newPullParser(); + mSysConfig.readPermissions(parser, libraryDir, permissionFlag); + } + /** * Tests that readPermissions works correctly for the tag: install-in-user-type */ @@ -126,16 +139,17 @@ public class SystemConfigTest { new ArraySet<>(Arrays.asList("GUEST", "PROFILE"))); final File folder1 = createTempSubfolder("folder1"); - createTempFile(folder1, "permFile1.xml", contents1); + createTempFile(folder1, "permissionFile1.xml", contents1); final File folder2 = createTempSubfolder("folder2"); - createTempFile(folder2, "permFile2.xml", contents2); + createTempFile(folder2, "permissionFile2.xml", contents2); - // Also, make a third file, but with the name folder1/permFile2.xml, to prove no conflicts. - createTempFile(folder1, "permFile2.xml", contents3); + // Also, make a third file, but with the name folder1/permissionFile2.xml, to prove no + // conflicts. + createTempFile(folder1, "permissionFile2.xml", contents3); - mSysConfig.readPermissions(folder1, /* No permission needed anyway */ 0); - mSysConfig.readPermissions(folder2, /* No permission needed anyway */ 0); + readPermissions(folder1, /* No permission needed anyway */ 0); + readPermissions(folder2, /* No permission needed anyway */ 0); Map<String, Set<String>> actualWhite = mSysConfig.getAndClearPackageToUserTypeWhitelist(); Map<String, Set<String>> actualBlack = mSysConfig.getAndClearPackageToUserTypeBlacklist(); @@ -165,7 +179,7 @@ public class SystemConfigTest { final File folder = createTempSubfolder("folder"); createTempFile(folder, "component-override.xml", contents); - mSysConfig.readPermissions(folder, /* No permission needed anyway */ 0); + readPermissions(folder, /* No permission needed anyway */ 0); final ArrayMap<String, Boolean> packageOneExpected = new ArrayMap<>(); packageOneExpected.put("com.android.package1.Full", true); @@ -197,7 +211,7 @@ public class SystemConfigTest { final File folder = createTempSubfolder("folder"); createTempFile(folder, "staged-installer-whitelist.xml", contents); - mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0); + readPermissions(folder, /* Grant all permission flags */ ~0); assertThat(mSysConfig.getWhitelistedStagedInstallers()) .containsExactly("com.android.package1"); @@ -215,7 +229,7 @@ public class SystemConfigTest { final File folder = createTempSubfolder("folder"); createTempFile(folder, "staged-installer-whitelist.xml", contents); - mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0); + readPermissions(folder, /* Grant all permission flags */ ~0); assertThat(mSysConfig.getWhitelistedStagedInstallers()) .containsExactly("com.android.package1"); @@ -238,7 +252,7 @@ public class SystemConfigTest { IllegalStateException e = expectThrows( IllegalStateException.class, - () -> mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0)); + () -> readPermissions(folder, /* Grant all permission flags */ ~0)); assertThat(e).hasMessageThat().contains("Multiple modules installers"); } @@ -257,7 +271,7 @@ public class SystemConfigTest { final File folder = createTempSubfolder("folder"); createTempFile(folder, "staged-installer-whitelist.xml", contents); - mSysConfig.readPermissions(folder, /* Grant all but ALLOW_APP_CONFIGS flag */ ~0x08); + readPermissions(folder, /* Grant all but ALLOW_APP_CONFIGS flag */ ~0x08); assertThat(mSysConfig.getWhitelistedStagedInstallers()).isEmpty(); } @@ -277,7 +291,7 @@ public class SystemConfigTest { final File folder = createTempSubfolder("folder"); createTempFile(folder, "vendor-apex-allowlist.xml", contents); - mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0); + readPermissions(folder, /* Grant all permission flags */ ~0); assertThat(mSysConfig.getAllowedVendorApexes()) .containsExactly("com.android.apex1", "com.installer"); @@ -297,7 +311,7 @@ public class SystemConfigTest { final File folder = createTempSubfolder("folder"); createTempFile(folder, "vendor-apex-allowlist.xml", contents); - mSysConfig.readPermissions(folder, /* Grant all permission flags */ ~0); + readPermissions(folder, /* Grant all permission flags */ ~0); assertThat(mSysConfig.getAllowedVendorApexes()).isEmpty(); } @@ -317,11 +331,273 @@ public class SystemConfigTest { final File folder = createTempSubfolder("folder"); createTempFile(folder, "vendor-apex-allowlist.xml", contents); - mSysConfig.readPermissions(folder, /* Grant all but ALLOW_VENDOR_APEX flag */ ~0x400); + readPermissions(folder, /* Grant all but ALLOW_VENDOR_APEX flag */ ~0x400); assertThat(mSysConfig.getAllowedVendorApexes()).isEmpty(); } + @Test + public void readApexPrivAppPermissions_addAllPermissions() + throws Exception { + final String contents = + "<privapp-permissions package=\"com.android.apk_in_apex\">" + + "<permission name=\"android.permission.FOO\"/>" + + "<deny-permission name=\"android.permission.BAR\"/>" + + "</privapp-permissions>"; + File apexDir = createTempSubfolder("apex"); + File permissionFile = createTempFile( + createTempSubfolder("apex/com.android.my_module/etc/permissions"), + "permissions.xml", contents); + XmlPullParser parser = readXmlUntilStartTag(permissionFile); + + mSysConfig.readApexPrivAppPermissions(parser, permissionFile, apexDir.toPath()); + + assertThat(mSysConfig.getApexPrivAppPermissions("com.android.my_module", + "com.android.apk_in_apex")) + .containsExactly("android.permission.FOO"); + assertThat(mSysConfig.getApexPrivAppDenyPermissions("com.android.my_module", + "com.android.apk_in_apex")) + .containsExactly("android.permission.BAR"); + } + + @Test + public void pruneVendorApexPrivappAllowlists_removeVendor() + throws Exception { + File apexDir = createTempSubfolder("apex"); + + // Read non-vendor apex permission allowlists + final String allowlistNonVendorContents = + "<privapp-permissions package=\"com.android.apk_in_non_vendor_apex\">" + + "<permission name=\"android.permission.FOO\"/>" + + "<deny-permission name=\"android.permission.BAR\"/>" + + "</privapp-permissions>"; + File nonVendorPermDir = + createTempSubfolder("apex/com.android.non_vendor/etc/permissions"); + File nonVendorPermissionFile = + createTempFile(nonVendorPermDir, "permissions.xml", allowlistNonVendorContents); + XmlPullParser nonVendorParser = readXmlUntilStartTag(nonVendorPermissionFile); + mSysConfig.readApexPrivAppPermissions(nonVendorParser, nonVendorPermissionFile, + apexDir.toPath()); + + // Read vendor apex permission allowlists + final String allowlistVendorContents = + "<privapp-permissions package=\"com.android.apk_in_vendor_apex\">" + + "<permission name=\"android.permission.BAZ\"/>" + + "<deny-permission name=\"android.permission.BAT\"/>" + + "</privapp-permissions>"; + File vendorPermissionFile = + createTempFile(createTempSubfolder("apex/com.android.vendor/etc/permissions"), + "permissions.xml", allowlistNonVendorContents); + XmlPullParser vendorParser = readXmlUntilStartTag(vendorPermissionFile); + mSysConfig.readApexPrivAppPermissions(vendorParser, vendorPermissionFile, + apexDir.toPath()); + + // Read allowed vendor apex list + final String allowedVendorContents = + "<config>\n" + + " <allowed-vendor-apex package=\"com.android.vendor\" " + + "installerPackage=\"com.installer\" />\n" + + "</config>"; + final File allowedVendorFolder = createTempSubfolder("folder"); + createTempFile(allowedVendorFolder, "vendor-apex-allowlist.xml", allowedVendorContents); + readPermissions(allowedVendorFolder, /* Grant all permission flags */ ~0); + + // Finally, prune non-vendor allowlists. + // There is no guarantee in which order the above reads will be done, however pruning + // will always happen last. + mSysConfig.pruneVendorApexPrivappAllowlists(); + + assertThat(mSysConfig.getApexPrivAppPermissions("com.android.non_vendor", + "com.android.apk_in_non_vendor_apex")) + .containsExactly("android.permission.FOO"); + assertThat(mSysConfig.getApexPrivAppDenyPermissions("com.android.non_vendor", + "com.android.apk_in_non_vendor_apex")) + .containsExactly("android.permission.BAR"); + assertThat(mSysConfig.getApexPrivAppPermissions("com.android.vendor", + "com.android.apk_in_vendor_apex")) + .isNull(); + assertThat(mSysConfig.getApexPrivAppDenyPermissions("com.android.vendor", + "com.android.apk_in_vendor_apex")) + .isNull(); + } + + /** + * Tests that readPermissions works correctly for a library with on-bootclasspath-before + * and on-bootclasspath-since. + */ + @Test + public void readPermissions_allowLibs_parsesSimpleLibrary() throws IOException { + String contents = + "<permissions>\n" + + " <library \n" + + " name=\"foo\"\n" + + " file=\"" + mFooJar + "\"\n" + + " on-bootclasspath-before=\"10\"\n" + + " on-bootclasspath-since=\"20\"\n" + + " />\n\n" + + " </permissions>"; + parseSharedLibraries(contents); + assertFooIsOnlySharedLibrary(); + SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo"); + assertThat(entry.onBootclasspathBefore).isEqualTo(10); + assertThat(entry.onBootclasspathSince).isEqualTo(20); + } + + /** + * Tests that readPermissions works correctly for a library using the new + * {@code apex-library} tag. + */ + @Test + public void readPermissions_allowLibs_parsesUpdatableLibrary() throws IOException { + String contents = + "<permissions>\n" + + " <apex-library \n" + + " name=\"foo\"\n" + + " file=\"" + mFooJar + "\"\n" + + " on-bootclasspath-before=\"10\"\n" + + " on-bootclasspath-since=\"20\"\n" + + " />\n\n" + + " </permissions>"; + parseSharedLibraries(contents); + assertFooIsOnlySharedLibrary(); + SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo"); + assertThat(entry.onBootclasspathBefore).isEqualTo(10); + assertThat(entry.onBootclasspathSince).isEqualTo(20); + } + + /** + * Tests that readPermissions for a library with {@code min-device-sdk} lower than the current + * SDK results in the library being added to the shared libraries. + */ + @Test + public void readPermissions_allowLibs_allowsOldMinSdk() throws IOException { + String contents = + "<permissions>\n" + + " <library \n" + + " name=\"foo\"\n" + + " file=\"" + mFooJar + "\"\n" + + " min-device-sdk=\"30\"\n" + + " />\n\n" + + " </permissions>"; + parseSharedLibraries(contents); + assertFooIsOnlySharedLibrary(); + } + + /** + * Tests that readPermissions for a library with {@code min-device-sdk} equal to the current + * SDK results in the library being added to the shared libraries. + */ + @Test + public void readPermissions_allowLibs_allowsCurrentMinSdk() throws IOException { + String contents = + "<permissions>\n" + + " <library \n" + + " name=\"foo\"\n" + + " file=\"" + mFooJar + "\"\n" + + " min-device-sdk=\"" + Build.VERSION.SDK_INT + "\"\n" + + " />\n\n" + + " </permissions>"; + parseSharedLibraries(contents); + assertFooIsOnlySharedLibrary(); + } + + /** + * Tests that readPermissions for a library with {@code min-device-sdk} greater than the current + * SDK results in the library being ignored. + */ + @Test + public void readPermissions_allowLibs_ignoresMinSdkInFuture() throws IOException { + String contents = + "<permissions>\n" + + " <library \n" + + " name=\"foo\"\n" + + " file=\"" + mFooJar + "\"\n" + + " min-device-sdk=\"" + (Build.VERSION.SDK_INT + 1) + "\"\n" + + " />\n\n" + + " </permissions>"; + parseSharedLibraries(contents); + assertThat(mSysConfig.getSharedLibraries()).isEmpty(); + } + + /** + * Tests that readPermissions for a library with {@code max-device-sdk} less than the current + * SDK results in the library being ignored. + */ + @Test + public void readPermissions_allowLibs_ignoredOldMaxSdk() throws IOException { + String contents = + "<permissions>\n" + + " <library \n" + + " name=\"foo\"\n" + + " file=\"" + mFooJar + "\"\n" + + " max-device-sdk=\"30\"\n" + + " />\n\n" + + " </permissions>"; + parseSharedLibraries(contents); + assertThat(mSysConfig.getSharedLibraries()).isEmpty(); + } + + /** + * Tests that readPermissions for a library with {@code max-device-sdk} equal to the current + * SDK results in the library being added to the shared libraries. + */ + @Test + public void readPermissions_allowLibs_allowsCurrentMaxSdk() throws IOException { + String contents = + "<permissions>\n" + + " <library \n" + + " name=\"foo\"\n" + + " file=\"" + mFooJar + "\"\n" + + " max-device-sdk=\"" + Build.VERSION.SDK_INT + "\"\n" + + " />\n\n" + + " </permissions>"; + parseSharedLibraries(contents); + assertFooIsOnlySharedLibrary(); + } + + /** + * Tests that readPermissions for a library with {@code max-device-sdk} greater than the current + * SDK results in the library being added to the shared libraries. + */ + @Test + public void readPermissions_allowLibs_allowsMaxSdkInFuture() throws IOException { + String contents = + "<permissions>\n" + + " <library \n" + + " name=\"foo\"\n" + + " file=\"" + mFooJar + "\"\n" + + " max-device-sdk=\"" + (Build.VERSION.SDK_INT + 1) + "\"\n" + + " />\n\n" + + " </permissions>"; + parseSharedLibraries(contents); + assertFooIsOnlySharedLibrary(); + } + + private void parseSharedLibraries(String contents) throws IOException { + File folder = createTempSubfolder("permissions_folder"); + createTempFile(folder, "permissions.xml", contents); + readPermissions(folder, /* permissionFlag = ALLOW_LIBS */ 0x02); + } + + /** + * Create an {@link XmlPullParser} for {@param permissionFile} and begin parsing it until + * reaching the root tag. + */ + private XmlPullParser readXmlUntilStartTag(File permissionFile) + throws IOException, XmlPullParserException { + FileReader permReader = new FileReader(permissionFile); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(permReader); + int type; + do { + type = parser.next(); + } while (type != parser.START_TAG && type != parser.END_DOCUMENT); + if (type != parser.START_TAG) { + throw new XmlPullParserException("No start tag found"); + } + return parser; + } + /** * Creates folderName/fileName in the mTemporaryFolder and fills it with the contents. * @@ -331,7 +607,7 @@ public class SystemConfigTest { private File createTempSubfolder(String folderName) throws IOException { File folder = new File(mTemporaryFolder.getRoot(), folderName); - folder.mkdir(); + folder.mkdirs(); return folder; } @@ -341,7 +617,7 @@ public class SystemConfigTest { * @param folder pre-existing subdirectory of mTemporaryFolder to put the file * @param fileName name of the file (e.g. filename.xml) to create * @param contents contents to write to the file - * @return the folder containing the newly created file (not the file itself!) + * @return the newly created file */ private File createTempFile(File folder, String fileName, String contents) throws IOException { @@ -357,6 +633,13 @@ public class SystemConfigTest { Log.d(LOG_TAG, input.nextLine()); } - return folder; + return file; + } + + private void assertFooIsOnlySharedLibrary() { + assertThat(mSysConfig.getSharedLibraries().size()).isEqualTo(1); + SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo"); + assertThat(entry.name).isEqualTo("foo"); + assertThat(entry.filename).isEqualTo(mFooJar.toString()); } } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index f8014c88a037..4f94a6213234 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -28,6 +28,7 @@ import android.annotation.SystemService; import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; +import android.net.NetworkCapabilities; import android.net.ipsec.ike.SaProposal; import android.os.Build; import android.os.PersistableBundle; @@ -3777,30 +3778,42 @@ public class CarrierConfigManager { public static final String KEY_OPPORTUNISTIC_ESIM_DOWNLOAD_VIA_WIFI_ONLY_BOOL = "opportunistic_esim_download_via_wifi_only_bool"; - /** - * Controls RSRP threshold at which OpportunisticNetworkService will decide whether +/** + * Controls RSRP threshold, in dBm, at which OpportunisticNetworkService will decide whether * the opportunistic network is good enough for internet data. + * + * <p>The value of {@link CellSignalStrengthLte#getRsrp()} will be compared with this + * threshold. */ public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT = "opportunistic_network_entry_threshold_rsrp_int"; /** - * Controls RSSNR threshold at which OpportunisticNetworkService will decide whether - * the opportunistic network is good enough for internet data. + * Controls RSSNR threshold, in dB, at which OpportunisticNetworkService will + * decide whether the opportunistic network is good enough for internet data. + * + * <p>The value of {@link CellSignalStrengthLte#getRssnr()} will be compared with this + * threshold. */ public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT = "opportunistic_network_entry_threshold_rssnr_int"; /** - * Controls RSRP threshold below which OpportunisticNetworkService will decide whether + * Controls RSRP threshold, in dBm, below which OpportunisticNetworkService will decide whether * the opportunistic network available is not good enough for internet data. + * + * <p>The value of {@link CellSignalStrengthLte#getRsrp()} will be compared with this + * threshold. */ public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT = "opportunistic_network_exit_threshold_rsrp_int"; /** - * Controls RSSNR threshold below which OpportunisticNetworkService will decide whether - * the opportunistic network available is not good enough for internet data. + * Controls RSSNR threshold, in dB, below which OpportunisticNetworkService will + * decide whether the opportunistic network available is not good enough for internet data. + * + * <p>The value of {@link CellSignalStrengthLte#getRssnr()} will be compared with this + * threshold. */ public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT = "opportunistic_network_exit_threshold_rssnr_int"; @@ -3898,7 +3911,7 @@ public class CarrierConfigManager { * good enough for internet data. Note other factors may be considered for the final * decision. * - * <p>The value of {@link CellSignalStrengthNr#getSsRsrp} will be compared with this + * <p>The value of {@link CellSignalStrengthNr#getSsRsrp()} will be compared with this * threshold. * * @hide @@ -3925,7 +3938,7 @@ public class CarrierConfigManager { * good enough for internet data. Note other factors may be considered for the final * decision. * - * <p>The value of {@link CellSignalStrengthNr#getSsRsrq} will be compared with this + * <p>The value of {@link CellSignalStrengthNr#getSsRsrq()} will be compared with this * threshold. * * @hide @@ -3952,6 +3965,9 @@ public class CarrierConfigManager { * be considered good enough for internet data. Note other factors may be considered * for the final decision. * + * <p>The value of {@link CellSignalStrengthNr#getSsRsrp()} will be compared with this + * threshold. + * * @hide */ public static final String KEY_EXIT_THRESHOLD_SS_RSRP_INT = @@ -3975,6 +3991,9 @@ public class CarrierConfigManager { * be considered good enough for internet data. Note other factors may be considered * for the final decision. * + * <p>The value of {@link CellSignalStrengthNr#getSsRsrq()} will be compared with this + * threshold. + * * @hide */ public static final String KEY_EXIT_THRESHOLD_SS_RSRQ_DOUBLE = @@ -5457,6 +5476,38 @@ public class CarrierConfigManager { */ public static final String KEY_TELEPHONY_NETWORK_CAPABILITY_PRIORITIES_STRING_ARRAY = "telephony_network_capability_priorities_string_array"; + + /** + * Defines the rules for data retry. + * + * The syntax of the retry rule: + * 1. Retry based on {@link NetworkCapabilities} + * "capabilities=[netCaps1|netCaps2|...], [retry_interval=x], [backoff=[true|false]], + * [maximum_retries=y]" + * + * 2. Retry based on {@link DataFailCause} + * "fail_causes=[cause1|cause2|cause3|...], [retry_interval=x], [backoff=[true|false]], + * [maximum_retries=y]" + * + * 3. Retry based on {@link NetworkCapabilities} and {@link DataFailCause} + * "capabilities=[netCaps1|netCaps2|...], fail_causes=[cause1|cause2|cause3|...], + * [retry_interval=x], [backoff=[true|false]], [maximum_retries=y]" + * + * For example, + * "capabilities=eims, retry_interval=1000, maximum_retries=20" means if the attached + * network request is emergency, then retry data network setup every 1 second for up to 20 + * times. + * + * "fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|2253|2254 + * , maximum_retries=0" means for those fail causes, never retry with timers. Note that + * when environment changes, retry can still happens. + * + * // TODO: remove KEY_CARRIER_DATA_CALL_RETRY_CONFIG_STRINGS + * @hide + */ + public static final String KEY_TELEPHONY_DATA_RETRY_RULES_STRING_ARRAY = + "telephony_data_retry_rules_string_array"; + /** * The patterns of missed incoming call sms. This is the regular expression used for * matching the missed incoming call's date, time, and caller id. The pattern should match @@ -6147,9 +6198,9 @@ public class CarrierConfigManager { /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_MODERATE */ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT, -118); /* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_GOOD */ - sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT, 45); + sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT, 5); /* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_MODERATE */ - sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT, 10); + sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT, 1); /* Default value is 1024 kbps */ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_BANDWIDTH_INT, 1024); /* Default value is 10 seconds */ @@ -6230,6 +6281,15 @@ public class CarrierConfigManager { "eims:90", "supl:80", "mms:70", "xcap:70", "cbs:50", "mcx:50", "fota:50", "ims:40", "dun:30", "enterprise:20", "internet:20" }); + sDefaults.putStringArray( + KEY_TELEPHONY_DATA_RETRY_RULES_STRING_ARRAY, new String[] { + "capabilities=eims, retry_interval=1000, maximum_retries=20", + "fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|2253|" + + "2254, maximum_retries=0", // No retry for those causes + "capabilities=internet|enterprise|dun|ims|fota, retry_interval=2000, " + + "backoff=true, maximum_retries=13", + "capabilities=mms|supl|cbs, retry_interval=2000" + }); sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]); sDefaults.putBoolean(KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, false); sDefaults.putString(KEY_DEFAULT_PREFERRED_APN_NAME_STRING, ""); diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java index 947dc0107dba..5e902613a654 100644 --- a/telephony/java/android/telephony/CellSignalStrengthLte.java +++ b/telephony/java/android/telephony/CellSignalStrengthLte.java @@ -125,13 +125,13 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P /** * Construct a cell signal strength * - * @param rssi in dBm [-113,-51], UNKNOWN - * @param rsrp in dBm [-140,-43], UNKNOWN - * @param rsrq in dB [-34, 3], UNKNOWN - * @param rssnr in dB [-20, +30], UNKNOWN - * @param cqiTableIndex [1, 6], UNKNOWN - * @param cqi [0, 15], UNKNOWN - * @param timingAdvance [0, 1282], UNKNOWN + * @param rssi in dBm [-113,-51], {@link CellInfo#UNAVAILABLE} + * @param rsrp in dBm [-140,-43], {@link CellInfo#UNAVAILABLE} + * @param rsrq in dB [-34, 3], {@link CellInfo#UNAVAILABLE} + * @param rssnr in dB [-20, +30], {@link CellInfo#UNAVAILABLE} + * @param cqiTableIndex [1, 6], {@link CellInfo#UNAVAILABLE} + * @param cqi [0, 15], {@link CellInfo#UNAVAILABLE} + * @param timingAdvance [0, 1282], {@link CellInfo#UNAVAILABLE} * */ /** @hide */ @@ -151,12 +151,12 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P /** * Construct a cell signal strength * - * @param rssi in dBm [-113,-51], UNKNOWN - * @param rsrp in dBm [-140,-43], UNKNOWN - * @param rsrq in dB [-34, 3], UNKNOWN - * @param rssnr in dB [-20, +30], UNKNOWN - * @param cqi [0, 15], UNKNOWN - * @param timingAdvance [0, 1282], UNKNOWN + * @param rssi in dBm [-113,-51], {@link CellInfo#UNAVAILABLE} + * @param rsrp in dBm [-140,-43], {@link CellInfo#UNAVAILABLE} + * @param rsrq in dB [-34, 3], {@link CellInfo#UNAVAILABLE} + * @param rssnr in dB [-20, +30], {@link CellInfo#UNAVAILABLE} + * @param cqi [0, 15], {@link CellInfo#UNAVAILABLE} + * @param timingAdvance [0, 1282], {@link CellInfo#UNAVAILABLE} * */ /** @hide */ @@ -403,10 +403,11 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P } /** - * Get reference signal signal-to-noise ratio + * Get reference signal signal-to-noise ratio in dB + * Range: -20 dB to +30 dB. * * @return the RSSNR if available or - * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable. + * {@link android.telephony.CellInfo#UNAVAILABLE} if unavailable. */ public int getRssnr() { return mRssnr; @@ -414,8 +415,10 @@ public final class CellSignalStrengthLte extends CellSignalStrength implements P /** * Get reference signal received power in dBm + * Range: -140 dBm to -43 dBm. * - * @return the RSRP of the measured cell. + * @return the RSRP of the measured cell or {@link CellInfo#UNAVAILABLE} if + * unavailable. */ public int getRsrp() { return mRsrp; diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index d6dce25d931f..8c02ffe12363 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -2158,8 +2158,7 @@ public class ApnSetting implements Parcelable { | TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX | TYPE_XCAP | TYPE_VSIM | TYPE_BIP | TYPE_ENTERPRISE)) == 0 || TextUtils.isEmpty(mApnName) || TextUtils.isEmpty(mEntryName)) { - throw new IllegalArgumentException("mApName=" + mApnName + ", mEntryName=" - + mEntryName + ", mApnTypeBitmask=" + mApnTypeBitmask); + return null; } return new ApnSetting(this); } diff --git a/tests/TrustTests/OWNERS b/tests/TrustTests/OWNERS new file mode 100644 index 000000000000..e2c6ce15b51e --- /dev/null +++ b/tests/TrustTests/OWNERS @@ -0,0 +1 @@ +include /core/java/android/service/trust/OWNERS |