Merge "Add DPM.hasKeyPair()"
diff --git a/apex/OWNERS b/apex/OWNERS
index bde2bec..b3e81b9 100644
--- a/apex/OWNERS
+++ b/apex/OWNERS
@@ -1,8 +1 @@
-# Mainline modularization team
-
-andreionea@google.com
-dariofreni@google.com
-hansson@google.com
-mathewi@google.com
-pedroql@google.com
-satayev@google.com
+file:platform/packages/modules/common:/OWNERS
diff --git a/core/api/current.txt b/core/api/current.txt
index 285506f..8e70bc5 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1142,6 +1142,7 @@
field public static final int reqNavigation = 16843306; // 0x101022a
field public static final int reqTouchScreen = 16843303; // 0x1010227
field public static final int requestLegacyExternalStorage = 16844291; // 0x1010603
+ field public static final int requireDeviceScreenOn = 16844312; // 0x1010618
field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
field public static final int required = 16843406; // 0x101028e
field public static final int requiredAccountType = 16843734; // 0x10103d6
@@ -9139,7 +9140,7 @@
method public boolean getIncludeTxPowerLevel();
method public android.util.SparseArray<byte[]> getManufacturerSpecificData();
method public java.util.Map<android.os.ParcelUuid,byte[]> getServiceData();
- method @Nullable public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids();
+ method @NonNull public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids();
method public java.util.List<android.os.ParcelUuid> getServiceUuids();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.AdvertiseData> CREATOR;
@@ -12133,6 +12134,8 @@
field public static final String FEATURE_INPUT_METHODS = "android.software.input_methods";
field public static final String FEATURE_IPSEC_TUNNELS = "android.software.ipsec_tunnels";
field public static final String FEATURE_IRIS = "android.hardware.biometrics.iris";
+ field public static final String FEATURE_KEYSTORE_LIMITED_USE_KEY = "android.hardware.keystore.limited_use_key";
+ field public static final String FEATURE_KEYSTORE_SINGLE_USE_KEY = "android.hardware.keystore.single_use_key";
field public static final String FEATURE_LEANBACK = "android.software.leanback";
field public static final String FEATURE_LEANBACK_ONLY = "android.software.leanback_only";
field public static final String FEATURE_LIVE_TV = "android.software.live_tv";
@@ -36204,6 +36207,7 @@
method @Nullable public java.util.Date getKeyValidityForOriginationEnd();
method @Nullable public java.util.Date getKeyValidityStart();
method @NonNull public String getKeystoreAlias();
+ method public int getMaxUsageCount();
method public int getPurposes();
method @NonNull public String[] getSignaturePaddings();
method public int getUserAuthenticationType();
@@ -36240,6 +36244,7 @@
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityStart(java.util.Date);
+ method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setMaxUsageCount(int);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
@@ -36262,6 +36267,7 @@
method public String getKeystoreAlias();
method public int getOrigin();
method public int getPurposes();
+ method public int getRemainingUsageCount();
method public int getSecurityLevel();
method @NonNull public String[] getSignaturePaddings();
method public int getUserAuthenticationType();
@@ -36331,6 +36337,7 @@
field public static final int SECURITY_LEVEL_UNKNOWN_SECURE = -1; // 0xffffffff
field public static final String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1";
field public static final String SIGNATURE_PADDING_RSA_PSS = "PSS";
+ field public static final int UNRESTRICTED_USAGE_COUNT = -1; // 0xffffffff
}
public final class KeyProtection implements java.security.KeyStore.ProtectionParameter {
@@ -36340,6 +36347,7 @@
method @Nullable public java.util.Date getKeyValidityForConsumptionEnd();
method @Nullable public java.util.Date getKeyValidityForOriginationEnd();
method @Nullable public java.util.Date getKeyValidityStart();
+ method public int getMaxUsageCount();
method public int getPurposes();
method @NonNull public String[] getSignaturePaddings();
method public int getUserAuthenticationType();
@@ -36365,6 +36373,7 @@
method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
method @NonNull public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
+ method @NonNull public android.security.keystore.KeyProtection.Builder setMaxUsageCount(int);
method @NonNull public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
method @NonNull public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
method @NonNull public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 854e8fd..ab9799f 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -61,6 +61,16 @@
method public void teardownTestNetwork(@NonNull android.net.Network);
}
+ public final class UnderlyingNetworkInfo implements android.os.Parcelable {
+ ctor public UnderlyingNetworkInfo(int, @NonNull String, @NonNull java.util.List<java.lang.String>);
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.UnderlyingNetworkInfo> CREATOR;
+ field @NonNull public final String iface;
+ field public final int ownerUid;
+ field @NonNull public final java.util.List<java.lang.String> underlyingIfaces;
+ }
+
}
package android.os {
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 1ddfe0d..1d5dc1d 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -28,7 +28,6 @@
import android.net.ConnectivityManager;
import android.net.DataUsageRequest;
import android.net.INetworkStatsService;
-import android.net.NetworkIdentity;
import android.net.NetworkStack;
import android.net.NetworkTemplate;
import android.net.netstats.provider.INetworkStatsProviderCallback;
@@ -47,6 +46,7 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.NetworkIdentityUtils;
import java.util.Objects;
@@ -628,7 +628,7 @@
default:
throw new IllegalArgumentException("Cannot create template for network type "
+ networkType + ", subscriberId '"
- + NetworkIdentity.scrubSubscriberId(subscriberId) + "'.");
+ + NetworkIdentityUtils.scrubSubscriberId(subscriberId) + "'.");
}
return template;
}
diff --git a/core/java/android/bluetooth/le/AdvertiseData.java b/core/java/android/bluetooth/le/AdvertiseData.java
index 573b932..fa7ac2b 100644
--- a/core/java/android/bluetooth/le/AdvertiseData.java
+++ b/core/java/android/bluetooth/le/AdvertiseData.java
@@ -44,7 +44,7 @@
@Nullable
private final List<ParcelUuid> mServiceUuids;
- @Nullable
+ @NonNull
private final List<ParcelUuid> mServiceSolicitationUuids;
private final SparseArray<byte[]> mManufacturerSpecificData;
@@ -77,7 +77,7 @@
/**
* Returns a list of service solicitation UUIDs within the advertisement that we invite to connect.
*/
- @Nullable
+ @NonNull
public List<ParcelUuid> getServiceSolicitationUuids() {
return mServiceSolicitationUuids;
}
@@ -221,7 +221,7 @@
public static final class Builder {
@Nullable
private List<ParcelUuid> mServiceUuids = new ArrayList<ParcelUuid>();
- @Nullable
+ @NonNull
private List<ParcelUuid> mServiceSolicitationUuids = new ArrayList<ParcelUuid>();
private SparseArray<byte[]> mManufacturerSpecificData = new SparseArray<byte[]>();
private Map<ParcelUuid, byte[]> mServiceData = new ArrayMap<ParcelUuid, byte[]>();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 31beb6e..742f48c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3224,6 +3224,24 @@
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_APP_ENUMERATION = "android.software.app_enumeration";
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
+ * a Keystore implementation that can only enforce limited use key in hardware with max usage
+ * count equals to 1.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_KEYSTORE_SINGLE_USE_KEY =
+ "android.hardware.keystore.single_use_key";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device has
+ * a Keystore implementation that can enforce limited use key in hardware with any max usage
+ * count (including count equals to 1).
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_KEYSTORE_LIMITED_USE_KEY =
+ "android.hardware.keystore.limited_use_key";
+
/** @hide */
public static final boolean APP_ENUMERATION_ENABLED_BY_DEFAULT = true;
diff --git a/core/java/android/inputmethodservice/OWNERS b/core/java/android/inputmethodservice/OWNERS
index e6a04da..d7db7c7 100644
--- a/core/java/android/inputmethodservice/OWNERS
+++ b/core/java/android/inputmethodservice/OWNERS
@@ -2,3 +2,5 @@
set noparent
include /services/core/java/com/android/server/inputmethod/OWNERS
+
+per-file *InlineSuggestion* = file:/core/java/android/service/autofill/OWNERS
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index b644ed5..521ed9b 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -21,11 +21,12 @@
import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
-import android.os.Build;
import android.service.NetworkIdentityProto;
import android.telephony.Annotation.NetworkType;
import android.util.proto.ProtoOutputStream;
+import com.android.net.module.util.NetworkIdentityUtils;
+
import java.util.Objects;
/**
@@ -89,7 +90,8 @@
builder.append(mSubType);
}
if (mSubscriberId != null) {
- builder.append(", subscriberId=").append(scrubSubscriberId(mSubscriberId));
+ builder.append(", subscriberId=")
+ .append(NetworkIdentityUtils.scrubSubscriberId(mSubscriberId));
}
if (mNetworkId != null) {
builder.append(", networkId=").append(mNetworkId);
@@ -110,7 +112,8 @@
// Not dumping mSubType, subtypes are no longer supported.
if (mSubscriberId != null) {
- proto.write(NetworkIdentityProto.SUBSCRIBER_ID, scrubSubscriberId(mSubscriberId));
+ proto.write(NetworkIdentityProto.SUBSCRIBER_ID,
+ NetworkIdentityUtils.scrubSubscriberId(mSubscriberId));
}
proto.write(NetworkIdentityProto.NETWORK_ID, mNetworkId);
proto.write(NetworkIdentityProto.ROAMING, mRoaming);
@@ -149,32 +152,6 @@
}
/**
- * Scrub given IMSI on production builds.
- */
- public static String scrubSubscriberId(String subscriberId) {
- if (Build.IS_ENG) {
- return subscriberId;
- } else if (subscriberId != null) {
- // TODO: parse this as MCC+MNC instead of hard-coding
- return subscriberId.substring(0, Math.min(6, subscriberId.length())) + "...";
- } else {
- return "null";
- }
- }
-
- /**
- * Scrub given IMSI on production builds.
- */
- public static String[] scrubSubscriberId(String[] subscriberId) {
- if (subscriberId == null) return null;
- final String[] res = new String[subscriberId.length];
- for (int i = 0; i < res.length; i++) {
- res[i] = NetworkIdentity.scrubSubscriberId(subscriberId[i]);
- }
- return res;
- }
-
- /**
* Build a {@link NetworkIdentity} from the given {@link NetworkState} and {@code subType},
* assuming that any mobile networks are using the current IMSI. The subType if applicable,
* should be set as one of the TelephonyManager.NETWORK_TYPE_* constants, or
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 72be835..2322048 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -48,6 +48,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.net.module.util.NetworkIdentityUtils;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
@@ -296,11 +297,11 @@
builder.append("matchRule=").append(getMatchRuleName(mMatchRule));
if (mSubscriberId != null) {
builder.append(", subscriberId=").append(
- NetworkIdentity.scrubSubscriberId(mSubscriberId));
+ NetworkIdentityUtils.scrubSubscriberId(mSubscriberId));
}
if (mMatchSubscriberIds != null) {
builder.append(", matchSubscriberIds=").append(
- Arrays.toString(NetworkIdentity.scrubSubscriberId(mMatchSubscriberIds)));
+ Arrays.toString(NetworkIdentityUtils.scrubSubscriberIds(mMatchSubscriberIds)));
}
if (mNetworkId != null) {
builder.append(", networkId=").append(mNetworkId);
diff --git a/core/java/android/net/UnderlyingNetworkInfo.java b/core/java/android/net/UnderlyingNetworkInfo.java
index 8fb4832..7bf9231 100644
--- a/core/java/android/net/UnderlyingNetworkInfo.java
+++ b/core/java/android/net/UnderlyingNetworkInfo.java
@@ -16,11 +16,15 @@
package android.net;
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -30,6 +34,7 @@
*
* @hide
*/
+@SystemApi(client = MODULE_LIBRARIES)
public final class UnderlyingNetworkInfo implements Parcelable {
/** The owner of this network. */
public final int ownerUid;
@@ -46,7 +51,7 @@
Objects.requireNonNull(underlyingIfaces);
this.ownerUid = ownerUid;
this.iface = iface;
- this.underlyingIfaces = underlyingIfaces;
+ this.underlyingIfaces = Collections.unmodifiableList(new ArrayList<>(underlyingIfaces));
}
private UnderlyingNetworkInfo(@NonNull Parcel in) {
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index d7c2e05..64ab074 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -97,6 +97,11 @@
final boolean mRequiresDeviceUnlock;
/**
+ * Whether this service should only be started when the device is screen on.
+ */
+ final boolean mRequiresDeviceScreenOn;
+
+ /**
* The id of the service banner specified in XML.
*/
final int mBannerResourceId;
@@ -119,6 +124,18 @@
ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
boolean requiresUnlock, int bannerResource, int uid,
String settingsActivityName, String offHost, String staticOffHost) {
+ this(info, onHost, description, staticAidGroups, dynamicAidGroups,
+ requiresUnlock, onHost ? true : false, bannerResource, uid,
+ settingsActivityName, offHost, staticOffHost);
+ }
+
+ /**
+ * @hide
+ */
+ public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
+ ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
+ boolean requiresUnlock, boolean requiresScreenOn, int bannerResource, int uid,
+ String settingsActivityName, String offHost, String staticOffHost) {
this.mService = info;
this.mDescription = description;
this.mStaticAidGroups = new HashMap<String, AidGroup>();
@@ -127,6 +144,7 @@
this.mStaticOffHostName = staticOffHost;
this.mOnHost = onHost;
this.mRequiresDeviceUnlock = requiresUnlock;
+ this.mRequiresDeviceScreenOn = requiresScreenOn;
for (AidGroup aidGroup : staticAidGroups) {
this.mStaticAidGroups.put(aidGroup.category, aidGroup);
}
@@ -183,6 +201,9 @@
mRequiresDeviceUnlock = sa.getBoolean(
com.android.internal.R.styleable.HostApduService_requireDeviceUnlock,
false);
+ mRequiresDeviceScreenOn = sa.getBoolean(
+ com.android.internal.R.styleable.HostApduService_requireDeviceScreenOn,
+ true);
mBannerResourceId = sa.getResourceId(
com.android.internal.R.styleable.HostApduService_apduServiceBanner, -1);
mSettingsActivityName = sa.getString(
@@ -196,7 +217,12 @@
mService = info;
mDescription = sa.getString(
com.android.internal.R.styleable.OffHostApduService_description);
- mRequiresDeviceUnlock = false;
+ mRequiresDeviceUnlock = sa.getBoolean(
+ com.android.internal.R.styleable.OffHostApduService_requireDeviceUnlock,
+ false);
+ mRequiresDeviceScreenOn = sa.getBoolean(
+ com.android.internal.R.styleable.OffHostApduService_requireDeviceScreenOn,
+ false);
mBannerResourceId = sa.getResourceId(
com.android.internal.R.styleable.OffHostApduService_apduServiceBanner, -1);
mSettingsActivityName = sa.getString(
@@ -419,6 +445,13 @@
return mRequiresDeviceUnlock;
}
+ /**
+ * Returns whether this service should only be started when the device is screen on.
+ */
+ public boolean requiresScreenOn() {
+ return mRequiresDeviceScreenOn;
+ }
+
@UnsupportedAppUsage
public String getDescription() {
return mDescription;
@@ -542,6 +575,7 @@
dest.writeTypedList(new ArrayList<AidGroup>(mDynamicAidGroups.values()));
}
dest.writeInt(mRequiresDeviceUnlock ? 1 : 0);
+ dest.writeInt(mRequiresDeviceScreenOn ? 1 : 0);
dest.writeInt(mBannerResourceId);
dest.writeInt(mUid);
dest.writeString(mSettingsActivityName);
@@ -568,11 +602,12 @@
source.readTypedList(dynamicAidGroups, AidGroup.CREATOR);
}
boolean requiresUnlock = source.readInt() != 0;
+ boolean requiresScreenOn = source.readInt() != 0;
int bannerResource = source.readInt();
int uid = source.readInt();
String settingsActivityName = source.readString();
return new ApduServiceInfo(info, onHost, description, staticAidGroups,
- dynamicAidGroups, requiresUnlock, bannerResource, uid,
+ dynamicAidGroups, requiresUnlock, requiresScreenOn, bannerResource, uid,
settingsActivityName, offHostName, staticOffHostName);
}
@@ -607,6 +642,8 @@
}
}
pw.println(" Settings Activity: " + mSettingsActivityName);
+ pw.println(" Requires Device Unlock: " + mRequiresDeviceUnlock);
+ pw.println(" Requires Device ScreenOn: " + mRequiresDeviceScreenOn);
}
/**
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 0185ba4..16d041a 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -547,7 +547,8 @@
}
try {
- return transactNative(code, data, reply, flags);
+ boolean replyOwnsNative = (reply == null) ? false : reply.ownsNativeParcelObject();
+ return transactNative(code, data, reply, replyOwnsNative, flags);
} finally {
AppOpsManager.resumeNotedAppOpsCollection(prevCollection);
@@ -572,7 +573,7 @@
* Native implementation of transact() for proxies
*/
public native boolean transactNative(int code, Parcel data, Parcel reply,
- int flags) throws RemoteException;
+ boolean replyOwnsNativeParcelObject, int flags) throws RemoteException;
/**
* See {@link IBinder#linkToDeath(DeathRecipient, int)}
*/
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 6acdcc4..f0a99ed 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -3691,4 +3691,9 @@
public long getBlobAshmemSize() {
return nativeGetBlobAshmemSize(mNativePtr);
}
+
+ /** @hide */
+ /*package*/ boolean ownsNativeParcelObject() {
+ return mOwnsNativeParcelObject;
+ }
}
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index f994d29..c39b8c5 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -80,6 +80,7 @@
public static final int KM_TAG_MIN_SECONDS_BETWEEN_OPS =
Tag.MIN_SECONDS_BETWEEN_OPS; // KM_UINT | 403;
public static final int KM_TAG_MAX_USES_PER_BOOT = Tag.MAX_USES_PER_BOOT; // KM_UINT | 404;
+ public static final int KM_TAG_USAGE_COUNT_LIMIT = Tag.USAGE_COUNT_LIMIT; // KM_UINT | 405;
public static final int KM_TAG_USER_ID = Tag.USER_ID; // KM_UINT | 501;
public static final int KM_TAG_USER_SECURE_ID = Tag.USER_SECURE_ID; // KM_ULONG_REP | 502;
diff --git a/core/java/android/view/inputmethod/OWNERS b/core/java/android/view/inputmethod/OWNERS
index e6a04da..d7db7c7 100644
--- a/core/java/android/view/inputmethod/OWNERS
+++ b/core/java/android/view/inputmethod/OWNERS
@@ -2,3 +2,5 @@
set noparent
include /services/core/java/com/android/server/inputmethod/OWNERS
+
+per-file *InlineSuggestion* = file:/core/java/android/service/autofill/OWNERS
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 023d9ff2..20230e7 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -98,9 +98,17 @@
public abstract boolean acceptThirdPartyCookies(WebView webview);
/**
- * Sets a cookie for the given URL. Any existing cookie with the same host,
- * path and name will be replaced with the new cookie. The cookie being set
- * will be ignored if it is expired.
+ * Sets a single cookie (key-value pair) for the given URL. Any existing cookie with the same
+ * host, path and name will be replaced with the new cookie. The cookie being set
+ * will be ignored if it is expired. To set multiple cookies, your application should invoke
+ * this method multiple times.
+ *
+ * <p>The {@code value} parameter must follow the format of the {@code Set-Cookie} HTTP
+ * response header defined by
+ * <a href="https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03">RFC6265bis</a>.
+ * This is a key-value pair of the form {@code "key=value"}, optionally followed by a list of
+ * cookie attributes delimited with semicolons (ex. {@code "key=value; Max-Age=123"}). Please
+ * consult the RFC specification for a list of valid attributes.
*
* <p class="note"><b>Note:</b> if specifying a {@code value} containing the {@code "Secure"}
* attribute, {@code url} must use the {@code "https://"} scheme.
@@ -112,13 +120,20 @@
public abstract void setCookie(String url, String value);
/**
- * Sets a cookie for the given URL. Any existing cookie with the same host,
- * path and name will be replaced with the new cookie. The cookie being set
- * will be ignored if it is expired.
- * <p>
- * This method is asynchronous.
- * If a {@link ValueCallback} is provided,
- * {@link ValueCallback#onReceiveValue(T) onReceiveValue()} will be called on the current
+ * Sets a single cookie (key-value pair) for the given URL. Any existing cookie with the same
+ * host, path and name will be replaced with the new cookie. The cookie being set
+ * will be ignored if it is expired. To set multiple cookies, your application should invoke
+ * this method multiple times.
+ *
+ * <p>The {@code value} parameter must follow the format of the {@code Set-Cookie} HTTP
+ * response header defined by
+ * <a href="https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03">RFC6265bis</a>.
+ * This is a key-value pair of the form {@code "key=value"}, optionally followed by a list of
+ * cookie attributes delimited with semicolons (ex. {@code "key=value; Max-Age=123"}). Please
+ * consult the RFC specification for a list of valid attributes.
+ *
+ * <p>This method is asynchronous. If a {@link ValueCallback} is provided,
+ * {@link ValueCallback#onReceiveValue} will be called on the current
* thread's {@link android.os.Looper} once the operation is complete.
* The value provided to the callback indicates whether the cookie was set successfully.
* You can pass {@code null} as the callback if you don't need to know when the operation
@@ -137,7 +152,10 @@
callback);
/**
- * Gets the cookies for the given URL.
+ * Gets all the cookies for the given URL. This may return multiple key-value pairs if multiple
+ * cookies are associated with this URL, in which case each cookie will be delimited by {@code
+ * "; "} characters (semicolon followed by a space). Each key-value pair will be of the form
+ * {@code "key=value"}.
*
* @param url the URL for which the cookies are requested
* @return value the cookies as a string, using the format of the 'Cookie'
diff --git a/core/java/com/android/internal/widget/OWNERS b/core/java/com/android/internal/widget/OWNERS
index ae566c3..3fc3933 100644
--- a/core/java/com/android/internal/widget/OWNERS
+++ b/core/java/com/android/internal/widget/OWNERS
@@ -5,3 +5,16 @@
per-file *LockScreen* = file:/services/core/java/com/android/server/locksettings/OWNERS
per-file *Lockscreen* = file:/services/core/java/com/android/server/locksettings/OWNERS
per-file *LockSettings* = file:/services/core/java/com/android/server/locksettings/OWNERS
+
+# Notification related
+per-file *Notification* = file:/services/core/java/com/android/server/notification/OWNERS
+per-file *Messaging* = file:/services/core/java/com/android/server/notification/OWNERS
+per-file *Message* = file:/services/core/java/com/android/server/notification/OWNERS
+per-file *Conversation* = file:/services/core/java/com/android/server/notification/OWNERS
+per-file *ImageResolver* = file:/services/core/java/com/android/server/notification/OWNERS
+per-file CallLayout.java = file:/services/core/java/com/android/server/notification/OWNERS
+per-file CachingIconView.java = file:/services/core/java/com/android/server/notification/OWNERS
+per-file ImageFloatingTextView.java = file:/services/core/java/com/android/server/notification/OWNERS
+per-file ObservableTextView.java = file:/services/core/java/com/android/server/notification/OWNERS
+per-file RemeasuringLinearLayout.java = file:/services/core/java/com/android/server/notification/OWNERS
+per-file ViewClippingUtil.java = file:/services/core/java/com/android/server/notification/OWNERS
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 241570a..0fdab72 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -36,6 +36,7 @@
#include <utils/List.h>
#include <utils/KeyedVector.h>
#include <binder/Parcel.h>
+#include <binder/ParcelRef.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/threads.h>
@@ -529,8 +530,9 @@
static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
{
- Parcel* parcel = new Parcel();
- return reinterpret_cast<jlong>(parcel);
+ sp<ParcelRef> parcelRef = ParcelRef::create();
+ parcelRef->incStrong(reinterpret_cast<const void*>(android_os_Parcel_create));
+ return reinterpret_cast<jlong>(static_cast<Parcel *>(parcelRef.get()));
}
static jlong android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
@@ -545,8 +547,8 @@
static void android_os_Parcel_destroy(JNIEnv* env, jclass clazz, jlong nativePtr)
{
- Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
- delete parcel;
+ ParcelRef* derivative = static_cast<ParcelRef*>(reinterpret_cast<Parcel*>(nativePtr));
+ derivative->decStrong(reinterpret_cast<const void*>(android_os_Parcel_create));
}
static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jclass clazz, jlong nativePtr)
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 581dc08..f71b42c 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -35,6 +35,7 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
+#include <binder/ParcelRef.h>
#include <binder/ProcessState.h>
#include <binder/Stability.h>
#include <binderthreadstate/CallerUtils.h>
@@ -1374,7 +1375,8 @@
}
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
- jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
+ jint code, jobject dataObj, jobject replyObj, jboolean replyObjOwnsNativeParcel,
+ jint flags) // throws RemoteException
{
if (dataObj == NULL) {
jniThrowNullPointerException(env, NULL);
@@ -1416,6 +1418,21 @@
status_t err = target->transact(code, *data, reply, flags);
//if (reply) printf("Transact from Java code to %p received: ", target); reply->print();
+ if (reply) {
+ if (replyObjOwnsNativeParcel) {
+ // as per Parcel java class constructor, here, "reply" MUST be a "ParcelRef"
+ // only for Parcel that contained Binder objects
+ if (reply->objectsCount() > 0) {
+ IPCThreadState::self()->createTransactionReference(static_cast<ParcelRef*>(reply));
+ }
+ } else {
+ // as per Parcel.java, if Parcel java object NOT owning native Parcel object, it will
+ // NOT destroy the native Parcel object upon GC(finalize()), so, there will be no race
+ // condtion in this case. Please refer to the java class methods: Parcel.finalize(),
+ // Parcel.destroy().
+ }
+ }
+
if (kEnableBinderSample) {
if (time_binder_calls) {
conditionally_log_binder_call(start_millis, target, code);
@@ -1542,7 +1559,7 @@
{"pingBinder", "()Z", (void*)android_os_BinderProxy_pingBinder},
{"isBinderAlive", "()Z", (void*)android_os_BinderProxy_isBinderAlive},
{"getInterfaceDescriptor", "()Ljava/lang/String;", (void*)android_os_BinderProxy_getInterfaceDescriptor},
- {"transactNative", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
+ {"transactNative", "(ILandroid/os/Parcel;Landroid/os/Parcel;ZI)Z", (void*)android_os_BinderProxy_transact},
{"linkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
{"unlinkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
{"getNativeFinalizer", "()J", (void*)android_os_BinderProxy_getNativeFinalizer},
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a668e8e..0e80c7b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1673,7 +1673,7 @@
@SystemApi
<p>Not for use by third-party applications. @hide -->
<permission android:name="android.permission.RESTART_WIFI_SUBSYSTEM"
- android:protectionLevel="signature|setup" />
+ android:protectionLevel="signature|privileged" />
<!-- @SystemApi @hide Allows applications to toggle airplane mode.
<p>Not for use by third-party or privileged applications.
diff --git a/core/res/OWNERS b/core/res/OWNERS
index a30111b..9d739b9 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -6,9 +6,12 @@
dupin@google.com
hackbod@android.com
hackbod@google.com
+ilyamaty@google.com
+jaggies@google.com
jsharkey@android.com
jsharkey@google.com
juliacr@google.com
+kchyn@google.com
michaelwr@google.com
nandana@google.com
narayan@google.com
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4b3d82a..9cc0690 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3856,6 +3856,9 @@
<!-- Component name of an activity that allows the user to modify
the settings for this service. -->
<attr name="settingsActivity"/>
+ <!-- Whether the device must be screen on before routing data to this service.
+ The default is true.-->
+ <attr name="requireDeviceScreenOn" format="boolean"/>
</declare-styleable>
<!-- Use <code>offhost-apdu-service</code> as the root tag of the XML resource that
@@ -3874,6 +3877,12 @@
<attr name="settingsActivity"/>
<!-- Secure Element which the AIDs should be routed to -->
<attr name="secureElementName" format="string"/>
+ <!-- Whether the device must be unlocked before routing data to this service.
+ The default is false.-->
+ <attr name="requireDeviceUnlock"/>
+ <!-- Whether the device must be screen on before routing data to this service.
+ The default is false.-->
+ <attr name="requireDeviceScreenOn"/>
</declare-styleable>
<!-- Specify one or more <code>aid-group</code> elements inside a
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index a0be068..0874a77 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3045,6 +3045,7 @@
<public-group type="attr" first-id="0x01010617">
<public name="canPauseRecording" />
<!-- attribute definitions go here -->
+ <public name="requireDeviceScreenOn" />
</public-group>
<public-group type="drawable" first-id="0x010800b5">
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index b1b6306..16bf546 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -23,7 +23,6 @@
import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterDefs;
-import android.sysprop.Keystore2Properties;
import java.io.IOException;
import java.security.KeyFactory;
@@ -117,8 +116,6 @@
putSecretKeyFactoryImpl("HmacSHA512");
}
- private static boolean sKeystore2Enabled;
-
/**
* This function indicates whether or not Keystore 2.0 is enabled. Some parts of the
* Keystore SPI must behave subtly differently when Keystore 2.0 is enabled. However,
@@ -133,10 +130,9 @@
* @hide
*/
public static boolean isKeystore2Enabled() {
- return sKeystore2Enabled;
+ return android.security.keystore2.AndroidKeyStoreProvider.isInstalled();
}
-
/**
* Installs a new instance of this provider (and the
* {@link AndroidKeyStoreBCWorkaroundProvider}).
@@ -164,11 +160,6 @@
// priority.
Security.addProvider(workaroundProvider);
}
-
- // {@code install()} is run by zygote when this property is still accessible. We store its
- // value so that the Keystore SPI can act accordingly without having to access an internal
- // property.
- sKeystore2Enabled = Keystore2Properties.keystore2_enabled().orElse(false);
}
private void putSecretKeyFactoryImpl(String algorithm) {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
index 3694d63..d2678c7 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -215,7 +215,8 @@
// Keystore 1.0 does not tell us the exact security level of the key
// so we report an unknown but secure security level.
insideSecureHardware ? KeyProperties.SECURITY_LEVEL_UNKNOWN_SECURE
- : KeyProperties.SECURITY_LEVEL_SOFTWARE);
+ : KeyProperties.SECURITY_LEVEL_SOFTWARE,
+ KeyProperties.UNRESTRICTED_USAGE_COUNT);
}
private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index e9aac7d..c2a7b2e 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -274,6 +274,7 @@
private final boolean mUserConfirmationRequired;
private final boolean mUnlockedDeviceRequired;
private final boolean mCriticalToDeviceEncryption;
+ private final int mMaxUsageCount;
/*
* ***NOTE***: All new fields MUST also be added to the following:
* ParcelableKeyGenParameterSpec class.
@@ -313,7 +314,8 @@
boolean isStrongBoxBacked,
boolean userConfirmationRequired,
boolean unlockedDeviceRequired,
- boolean criticalToDeviceEncryption) {
+ boolean criticalToDeviceEncryption,
+ int maxUsageCount) {
if (TextUtils.isEmpty(keyStoreAlias)) {
throw new IllegalArgumentException("keyStoreAlias must not be empty");
}
@@ -366,6 +368,7 @@
mUserConfirmationRequired = userConfirmationRequired;
mUnlockedDeviceRequired = unlockedDeviceRequired;
mCriticalToDeviceEncryption = criticalToDeviceEncryption;
+ mMaxUsageCount = maxUsageCount;
}
/**
@@ -782,7 +785,7 @@
}
/**
- * Return whether this key is critical to the device encryption flow.
+ * Returns whether this key is critical to the device encryption flow.
*
* @see android.security.KeyStore#FLAG_CRITICAL_TO_DEVICE_ENCRYPTION
* @hide
@@ -792,6 +795,17 @@
}
/**
+ * Returns the maximum number of times the limited use key is allowed to be used or
+ * {@link KeyProperties#UNRESTRICTED_USAGE_COUNT} if there’s no restriction on the number of
+ * times the key can be used.
+ *
+ * @see Builder#setMaxUsageCount(int)
+ */
+ public int getMaxUsageCount() {
+ return mMaxUsageCount;
+ }
+
+ /**
* Builder of {@link KeyGenParameterSpec} instances.
*/
public final static class Builder {
@@ -827,6 +841,7 @@
private boolean mUserConfirmationRequired;
private boolean mUnlockedDeviceRequired = false;
private boolean mCriticalToDeviceEncryption = false;
+ private int mMaxUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT;
/**
* Creates a new instance of the {@code Builder}.
@@ -894,6 +909,7 @@
mUserConfirmationRequired = sourceSpec.isUserConfirmationRequired();
mUnlockedDeviceRequired = sourceSpec.isUnlockedDeviceRequired();
mCriticalToDeviceEncryption = sourceSpec.isCriticalToDeviceEncryption();
+ mMaxUsageCount = sourceSpec.getMaxUsageCount();
}
/**
@@ -1553,6 +1569,47 @@
}
/**
+ * Sets the maximum number of times the key is allowed to be used. After every use of the
+ * key, the use counter will decrease. This authorization applies only to secret key and
+ * private key operations. Public key operations are not restricted. For example, after
+ * successfully encrypting and decrypting data using methods such as
+ * {@link Cipher#doFinal()}, the use counter of the secret key will decrease. After
+ * successfully signing data using methods such as {@link Signature#sign()}, the use
+ * counter of the private key will decrease.
+ *
+ * When the use counter is depleted, the key will be marked for deletion by Android
+ * Keystore and any subsequent attempt to use the key will throw
+ * {@link KeyPermanentlyInvalidatedException}. There is no key to be loaded from the
+ * Android Keystore once the exhausted key is permanently deleted, as if the key never
+ * existed before.
+ *
+ * <p>By default, there is no restriction on the usage of key.
+ *
+ * <p>Some secure hardware may not support this feature at all, in which case it will
+ * be enforced in software, some secure hardware may support it but only with
+ * maxUsageCount = 1, and some secure hardware may support it with larger value
+ * of maxUsageCount.
+ *
+ * <p>The PackageManger feature flags:
+ * {@link android.content.pm.PackageManager#FEATURE_KEYSTORE_SINGLE_USE_KEY} and
+ * {@link android.content.pm.PackageManager#FEATURE_KEYSTORE_LIMITED_USE_KEY} can be used
+ * to check whether the secure hardware cannot enforce this feature, can only enforce it
+ * with maxUsageCount = 1, or can enforce it with larger value of maxUsageCount.
+ *
+ * @param maxUsageCount maximum number of times the key is allowed to be used or
+ * {@link KeyProperties#UNRESTRICTED_USAGE_COUNT} if there is no restriction on the
+ * usage.
+ */
+ @NonNull
+ public Builder setMaxUsageCount(int maxUsageCount) {
+ if (maxUsageCount == KeyProperties.UNRESTRICTED_USAGE_COUNT || maxUsageCount > 0) {
+ mMaxUsageCount = maxUsageCount;
+ return this;
+ }
+ throw new IllegalArgumentException("maxUsageCount is not valid");
+ }
+
+ /**
* Builds an instance of {@code KeyGenParameterSpec}.
*/
@NonNull
@@ -1587,7 +1644,8 @@
mIsStrongBoxBacked,
mUserConfirmationRequired,
mUnlockedDeviceRequired,
- mCriticalToDeviceEncryption);
+ mCriticalToDeviceEncryption,
+ mMaxUsageCount);
}
}
}
diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java
index 7158d0c..f50efd2 100644
--- a/keystore/java/android/security/keystore/KeyInfo.java
+++ b/keystore/java/android/security/keystore/KeyInfo.java
@@ -85,6 +85,7 @@
private final boolean mInvalidatedByBiometricEnrollment;
private final boolean mUserConfirmationRequired;
private final @KeyProperties.SecurityLevelEnum int mSecurityLevel;
+ private final int mRemainingUsageCount;
/**
* @hide
@@ -109,7 +110,8 @@
boolean trustedUserPresenceRequired,
boolean invalidatedByBiometricEnrollment,
boolean userConfirmationRequired,
- @KeyProperties.SecurityLevelEnum int securityLevel) {
+ @KeyProperties.SecurityLevelEnum int securityLevel,
+ int remainingUsageCount) {
mKeystoreAlias = keystoreKeyAlias;
mInsideSecureHardware = insideSecureHardware;
mOrigin = origin;
@@ -134,6 +136,7 @@
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
mUserConfirmationRequired = userConfirmationRequired;
mSecurityLevel = securityLevel;
+ mRemainingUsageCount = remainingUsageCount;
}
/**
@@ -374,4 +377,15 @@
public @KeyProperties.SecurityLevelEnum int getSecurityLevel() {
return mSecurityLevel;
}
+
+ /**
+ * Returns the remaining number of times the key is allowed to be used or
+ * {@link KeyProperties#UNRESTRICTED_USAGE_COUNT} if there's no restriction on the number of
+ * times the key can be used. Note that this gives a best effort count and need not be
+ * accurate (as there might be usages happening in parallel and the count maintained here need
+ * not be in sync with the usage).
+ */
+ public int getRemainingUsageCount() {
+ return mRemainingUsageCount;
+ }
}
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index 014d688..fa4f8b1 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -907,4 +907,9 @@
+ uid);
}
}
+
+ /**
+ * This value indicates that there is no restriction on the number of times the key can be used.
+ */
+ public static final int UNRESTRICTED_USAGE_COUNT = -1;
}
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 2e793de..76ce23e 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -235,6 +235,7 @@
private final boolean mUserConfirmationRequired;
private final boolean mUnlockedDeviceRequired;
private final boolean mIsStrongBoxBacked;
+ private final int mMaxUsageCount;
private KeyProtection(
Date keyValidityStart,
@@ -256,7 +257,8 @@
boolean criticalToDeviceEncryption,
boolean userConfirmationRequired,
boolean unlockedDeviceRequired,
- boolean isStrongBoxBacked) {
+ boolean isStrongBoxBacked,
+ int maxUsageCount) {
mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -279,6 +281,7 @@
mUserConfirmationRequired = userConfirmationRequired;
mUnlockedDeviceRequired = unlockedDeviceRequired;
mIsStrongBoxBacked = isStrongBoxBacked;
+ mMaxUsageCount = maxUsageCount;
}
/**
@@ -548,6 +551,17 @@
}
/**
+ * Returns the maximum number of times the limited use key is allowed to be used or
+ * {@link KeyProperties#UNRESTRICTED_USAGE_COUNT} if there’s no restriction on the number of
+ * times the key can be used.
+ *
+ * @see Builder#setMaxUsageCount(int)
+ */
+ public int getMaxUsageCount() {
+ return mMaxUsageCount;
+ }
+
+ /**
* Builder of {@link KeyProtection} instances.
*/
public final static class Builder {
@@ -574,6 +588,7 @@
private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
private boolean mCriticalToDeviceEncryption = false;
private boolean mIsStrongBoxBacked = false;
+ private int mMaxUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT;
/**
* Creates a new instance of the {@code Builder}.
@@ -1040,6 +1055,47 @@
}
/**
+ * Sets the maximum number of times the key is allowed to be used. After every use of the
+ * key, the use counter will decrease. This authorization applies only to secret key and
+ * private key operations. Public key operations are not restricted. For example, after
+ * successfully encrypting and decrypting data using methods such as
+ * {@link Cipher#doFinal()}, the use counter of the secret key will decrease. After
+ * successfully signing data using methods such as {@link Signature#sign()}, the use
+ * counter of the private key will decrease.
+ *
+ * When the use counter is depleted, the key will be marked for deletion by Android
+ * Keystore and any subsequent attempt to use the key will throw
+ * {@link KeyPermanentlyInvalidatedException}. There is no key to be loaded from the
+ * Android Keystore once the exhausted key is permanently deleted, as if the key never
+ * existed before.
+ *
+ * <p>By default, there is no restriction on the usage of key.
+ *
+ * <p>Some secure hardware may not support this feature at all, in which case it will
+ * be enforced in software, some secure hardware may support it but only with
+ * maxUsageCount = 1, and some secure hardware may support it with larger value
+ * of maxUsageCount.
+ *
+ * <p>The PackageManger feature flags:
+ * {@link android.content.pm.PackageManager#FEATURE_KEYSTORE_SINGLE_USE_KEY} and
+ * {@link android.content.pm.PackageManager#FEATURE_KEYSTORE_LIMITED_USE_KEY} can be used
+ * to check whether the secure hardware cannot enforce this feature, can only enforce it
+ * with maxUsageCount = 1, or can enforce it with larger value of maxUsageCount.
+ *
+ * @param maxUsageCount maximum number of times the key is allowed to be used or
+ * {@link KeyProperties#UNRESTRICTED_USAGE_COUNT} if there is no restriction on the
+ * usage.
+ */
+ @NonNull
+ public Builder setMaxUsageCount(int maxUsageCount) {
+ if (maxUsageCount == KeyProperties.UNRESTRICTED_USAGE_COUNT || maxUsageCount > 0) {
+ mMaxUsageCount = maxUsageCount;
+ return this;
+ }
+ throw new IllegalArgumentException("maxUsageCount is not valid");
+ }
+
+ /**
* Builds an instance of {@link KeyProtection}.
*
* @throws IllegalArgumentException if a required field is missing
@@ -1066,7 +1122,8 @@
mCriticalToDeviceEncryption,
mUserConfirmationRequired,
mUnlockedDeviceRequired,
- mIsStrongBoxBacked);
+ mIsStrongBoxBacked,
+ mMaxUsageCount);
}
}
}
diff --git a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
index 69c15cc..8163472 100644
--- a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
@@ -108,6 +108,7 @@
out.writeBoolean(mSpec.isUserConfirmationRequired());
out.writeBoolean(mSpec.isUnlockedDeviceRequired());
out.writeBoolean(mSpec.isCriticalToDeviceEncryption());
+ out.writeInt(mSpec.getMaxUsageCount());
}
private static Date readDateOrNull(Parcel in) {
@@ -166,6 +167,7 @@
final boolean userConfirmationRequired = in.readBoolean();
final boolean unlockedDeviceRequired = in.readBoolean();
final boolean criticalToDeviceEncryption = in.readBoolean();
+ final int maxUsageCount = in.readInt();
// The KeyGenParameterSpec is intentionally not constructed using a Builder here:
// The intention is for this class to break if new parameters are added to the
// KeyGenParameterSpec constructor (whereas using a builder would silently drop them).
@@ -199,7 +201,8 @@
isStrongBoxBacked,
userConfirmationRequired,
unlockedDeviceRequired,
- criticalToDeviceEncryption);
+ criticalToDeviceEncryption,
+ maxUsageCount);
}
public static final @android.annotation.NonNull Creator<ParcelableKeyGenParameterSpec> CREATOR = new Creator<ParcelableKeyGenParameterSpec>() {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
index 233f352..1575bb4 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
@@ -366,6 +366,13 @@
));
}
+ if (spec.getMaxUsageCount() != KeyProperties.UNRESTRICTED_USAGE_COUNT) {
+ params.add(KeyStore2ParameterUtils.makeInt(
+ KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT,
+ spec.getMaxUsageCount()
+ ));
+ }
+
byte[] additionalEntropy =
KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
mRng, (mKeySizeBits + 7) / 8);
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index df0e146..6a92980 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -586,6 +586,13 @@
));
}
+ if (mSpec.getMaxUsageCount() != KeyProperties.UNRESTRICTED_USAGE_COUNT) {
+ params.add(KeyStore2ParameterUtils.makeInt(
+ KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT,
+ mSpec.getMaxUsageCount()
+ ));
+ }
+
addAlgorithmSpecificParameters(params);
if (mSpec.isUniqueIdIncluded()) {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
index 74503e1..fe05989 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -95,6 +95,7 @@
boolean userAuthenticationValidWhileOnBody = false;
boolean trustedUserPresenceRequired = false;
boolean trustedUserConfirmationRequired = false;
+ int remainingUsageCount = KeyProperties.UNRESTRICTED_USAGE_COUNT;
try {
for (Authorization a : key.getAuthorizations()) {
switch (a.keyParameter.tag) {
@@ -195,6 +196,16 @@
trustedUserConfirmationRequired =
KeyStore2ParameterUtils.isSecureHardware(a.securityLevel);
break;
+ case KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT:
+ long remainingUsageCountUnsigned =
+ KeyStore2ParameterUtils.getUnsignedInt(a);
+ if (remainingUsageCountUnsigned > Integer.MAX_VALUE) {
+ throw new ProviderException(
+ "Usage count of limited use key too long: "
+ + remainingUsageCountUnsigned);
+ }
+ remainingUsageCount = (int) remainingUsageCountUnsigned;
+ break;
}
}
} catch (IllegalArgumentException e) {
@@ -247,7 +258,8 @@
trustedUserPresenceRequired,
invalidatedByBiometricEnrollment,
trustedUserConfirmationRequired,
- securityLevel);
+ securityLevel,
+ remainingUsageCount);
}
private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 07169ce..8c8acc4 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -535,6 +535,12 @@
spec.getKeyValidityForConsumptionEnd()
));
}
+ if (spec.getMaxUsageCount() != KeyProperties.UNRESTRICTED_USAGE_COUNT) {
+ importArgs.add(KeyStore2ParameterUtils.makeInt(
+ KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT,
+ spec.getMaxUsageCount()
+ ));
+ }
} catch (IllegalArgumentException | IllegalStateException e) {
throw new KeyStoreException(e);
}
@@ -772,6 +778,12 @@
params.getKeyValidityForConsumptionEnd()
));
}
+ if (params.getMaxUsageCount() != KeyProperties.UNRESTRICTED_USAGE_COUNT) {
+ importArgs.add(KeyStore2ParameterUtils.makeInt(
+ KeymasterDefs.KM_TAG_USAGE_COUNT_LIMIT,
+ params.getMaxUsageCount()
+ ));
+ }
} catch (IllegalArgumentException | IllegalStateException e) {
throw new KeyStoreException(e);
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index c091dfa..f2e1920 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -739,11 +739,11 @@
}
private void maybeLogBroadcast(NetworkAgentInfo nai, DetailedState state, int type,
- boolean isDefaultNetwork) {
+ boolean isFallbackNetwork) {
if (DBG) {
log("Sending " + state
+ " broadcast for type " + type + " " + nai.toShortString()
- + " isDefaultNetwork=" + isDefaultNetwork);
+ + " isFallbackNetwork=" + isFallbackNetwork);
}
}
@@ -762,10 +762,10 @@
list.add(nai);
}
- // Send a broadcast if this is the first network of its type or if it's the default.
- final boolean isDefaultNetwork = mService.isDefaultNetwork(nai);
- if ((list.size() == 1) || isDefaultNetwork) {
- maybeLogBroadcast(nai, DetailedState.CONNECTED, type, isDefaultNetwork);
+ // Send a broadcast if this is the first network of its type or if it's the fallback.
+ final boolean isFallbackNetwork = mService.isFallbackNetwork(nai);
+ if ((list.size() == 1) || isFallbackNetwork) {
+ maybeLogBroadcast(nai, DetailedState.CONNECTED, type, isFallbackNetwork);
mService.sendLegacyNetworkBroadcast(nai, DetailedState.CONNECTED, type);
}
}
@@ -794,7 +794,7 @@
", sending connected broadcast");
final NetworkAgentInfo replacement = list.get(0);
maybeLogBroadcast(replacement, DetailedState.CONNECTED, type,
- mService.isDefaultNetwork(replacement));
+ mService.isFallbackNetwork(replacement));
mService.sendLegacyNetworkBroadcast(replacement, DetailedState.CONNECTED, type);
}
}
@@ -810,14 +810,14 @@
// send out another legacy broadcast - currently only used for suspend/unsuspend
// toggle
public void update(NetworkAgentInfo nai) {
- final boolean isDefault = mService.isDefaultNetwork(nai);
+ final boolean isFallback = mService.isFallbackNetwork(nai);
final DetailedState state = nai.networkInfo.getDetailedState();
for (int type = 0; type < mTypeLists.length; type++) {
final ArrayList<NetworkAgentInfo> list = mTypeLists[type];
final boolean contains = (list != null && list.contains(nai));
final boolean isFirst = contains && (nai == list.get(0));
- if (isFirst || contains && isDefault) {
- maybeLogBroadcast(nai, state, type, isDefault);
+ if (isFirst || contains && isFallback) {
+ maybeLogBroadcast(nai, state, type, isFallback);
mService.sendLegacyNetworkBroadcast(nai, state, type);
}
}
@@ -1021,11 +1021,13 @@
mNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_UID);
mMetricsLog = logger;
- mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
mNetworkRanker = new NetworkRanker();
- NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder());
- mNetworkRequests.put(mDefaultRequest, defaultNRI);
- mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI);
+ final NetworkRequest fallbackRequest = createDefaultInternetRequestForTransport(
+ -1, NetworkRequest.Type.REQUEST);
+ mFallbackRequest = new NetworkRequestInfo(null, fallbackRequest, new Binder());
+ mNetworkRequests.put(fallbackRequest, mFallbackRequest);
+ mDefaultNetworkRequests.add(mFallbackRequest);
+ mNetworkRequestInfoLogs.log("REGISTER " + mFallbackRequest);
mDefaultMobileDataRequest = createDefaultInternetRequestForTransport(
NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST);
@@ -1364,7 +1366,7 @@
}
private NetworkState getUnfilteredActiveNetworkState(int uid) {
- NetworkAgentInfo nai = getDefaultNetwork();
+ NetworkAgentInfo nai = getFallbackNetwork();
final Network[] networks = getVpnUnderlyingNetworks(uid);
if (networks != null) {
@@ -1497,7 +1499,7 @@
}
}
- NetworkAgentInfo nai = getDefaultNetwork();
+ NetworkAgentInfo nai = getFallbackNetwork();
if (nai == null || isNetworkWithCapabilitiesBlocked(nai.networkCapabilities, uid,
ignoreBlocked)) {
return null;
@@ -1636,7 +1638,7 @@
HashMap<Network, NetworkCapabilities> result = new HashMap<>();
- NetworkAgentInfo nai = getDefaultNetwork();
+ final NetworkAgentInfo nai = getFallbackNetwork();
NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
if (nc != null) {
result.put(
@@ -2023,7 +2025,7 @@
// TODO: Move the Dns Event to NetworkMonitor. NetdEventListenerService only allow one
// callback from each caller type. Need to re-factor NetdEventListenerService to allow
// multiple NetworkMonitor registrants.
- if (nai != null && nai.satisfies(mDefaultRequest)) {
+ if (nai != null && nai.satisfies(mFallbackRequest.mRequests.get(0))) {
nai.networkMonitor().notifyDnsResponse(returnCode);
}
}
@@ -2580,12 +2582,12 @@
pw.println();
pw.println();
- final NetworkAgentInfo defaultNai = getDefaultNetwork();
+ final NetworkAgentInfo fallbackNai = getFallbackNetwork();
pw.print("Active default network: ");
- if (defaultNai == null) {
+ if (fallbackNai == null) {
pw.println("none");
} else {
- pw.println(defaultNai.network.getNetId());
+ pw.println(fallbackNai.network.getNetId());
}
pw.println();
@@ -2968,7 +2970,7 @@
final boolean valid = ((testResult & NETWORK_VALIDATION_RESULT_VALID) != 0);
final boolean wasValidated = nai.lastValidated;
- final boolean wasDefault = isDefaultNetwork(nai);
+ final boolean wasFallback = isFallbackNetwork(nai);
if (DBG) {
final String logMsg = !TextUtils.isEmpty(redirectUrl)
@@ -2977,7 +2979,7 @@
log(nai.toShortString() + " validation " + (valid ? "passed" : "failed") + logMsg);
}
if (valid != nai.lastValidated) {
- if (wasDefault) {
+ if (wasFallback) {
mMetricsLog.logDefaultNetworkValidity(valid);
}
final int oldScore = nai.getCurrentScore();
@@ -3353,13 +3355,13 @@
loge("Error connecting NetworkAgent");
mNetworkAgentInfos.remove(nai);
if (nai != null) {
- final boolean wasDefault = isDefaultNetwork(nai);
+ final boolean wasFallback = isFallbackNetwork(nai);
synchronized (mNetworkForNetId) {
mNetworkForNetId.remove(nai.network.getNetId());
}
mNetIdManager.releaseNetId(nai.network.getNetId());
// Just in case.
- mLegacyTypeTracker.remove(nai, wasDefault);
+ mLegacyTypeTracker.remove(nai, wasFallback);
}
}
}
@@ -3398,8 +3400,8 @@
nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
null, null);
}
- final boolean wasDefault = isDefaultNetwork(nai);
- if (wasDefault) {
+ final boolean wasFallback = isFallbackNetwork(nai);
+ if (wasFallback) {
mDefaultInetConditionPublished = 0;
// Log default network disconnection before required book-keeping.
// Let rematchAllNetworksAndRequests() below record a new default network event
@@ -3441,19 +3443,24 @@
&& currentNetwork.network.getNetId() == nai.network.getNetId()) {
nri.setSatisfier(null, null);
sendUpdatedScoreToFactories(request, null);
+
+ if (mFallbackRequest == nri) {
+ // TODO : make battery stats aware that since 2013 multiple interfaces may be
+ // active at the same time. For now keep calling this with the fallback
+ // network, because while incorrect this is the closest to the old (also
+ // incorrect) behavior.
+ mNetworkActivityTracker.updateDataActivityTracking(
+ null /* newNetwork */, nai);
+ notifyLockdownVpn(nai);
+ ensureNetworkTransitionWakelock(nai.toShortString());
+ }
}
}
nai.clearLingerState();
- // TODO: this loop, and the mLegacyTypeTracker.remove just below it, seem redundant given
- // there's a full rematch right after. Currently, deleting it breaks tests that check for
- // the default network disconnecting. Find out why, fix the rematch code, and delete this.
- if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
- mDefaultNetworkNai = null;
- mNetworkActivityTracker.updateDataActivityTracking(null /* newNetwork */, nai);
- notifyLockdownVpn(nai);
- ensureNetworkTransitionWakelock(nai.toShortString());
- }
- mLegacyTypeTracker.remove(nai, wasDefault);
+ // TODO: mLegacyTypeTracker.remove seems redundant given there's a full rematch right after.
+ // Currently, deleting it breaks tests that check for the fallback network disconnecting.
+ // Find out why, fix the rematch code, and delete this.
+ mLegacyTypeTracker.remove(nai, wasFallback);
rematchAllNetworksAndRequests();
mLingerMonitor.noteDisconnect(nai);
if (nai.created) {
@@ -4253,7 +4260,7 @@
@Override
public NetworkRequest getDefaultRequest() {
- return mDefaultRequest;
+ return mFallbackRequest.mRequests.get(0);
}
private class InternalHandler extends Handler {
@@ -4499,7 +4506,7 @@
// revalidate the network and generate a ConnectivityDiagnostics ConnectivityReport event.
final NetworkAgentInfo nai;
if (network == null) {
- nai = getDefaultNetwork();
+ nai = getFallbackNetwork();
} else {
nai = getNetworkAgentInfoForNetwork(network);
}
@@ -4518,7 +4525,7 @@
Network network, int uid, boolean hasConnectivity) {
final NetworkAgentInfo nai;
if (network == null) {
- nai = getDefaultNetwork();
+ nai = getFallbackNetwork();
} else {
nai = getNetworkAgentInfoForNetwork(network);
}
@@ -4831,7 +4838,7 @@
}
synchronized (mVpns) {
throwIfLockdownEnabled();
- mVpns.get(user).startLegacyVpn(profile, mKeyStore, egress);
+ mVpns.get(user).startLegacyVpn(profile, mKeyStore, null /* underlying */, egress);
}
}
@@ -4884,7 +4891,7 @@
// see VpnService.setUnderlyingNetworks()'s javadoc about how to interpret
// the underlyingNetworks list.
if (underlyingNetworks == null) {
- NetworkAgentInfo defaultNai = getDefaultNetwork();
+ final NetworkAgentInfo defaultNai = getFallbackNetwork();
if (defaultNai != null) {
underlyingNetworks = new Network[] { defaultNai.network };
}
@@ -4936,7 +4943,7 @@
}
private Network[] underlyingNetworksOrDefault(Network[] underlyingNetworks) {
- final Network defaultNetwork = getNetwork(getDefaultNetwork());
+ final Network defaultNetwork = getNetwork(getFallbackNetwork());
if (underlyingNetworks == null && defaultNetwork != null) {
// null underlying networks means to track the default.
underlyingNetworks = new Network[] { defaultNetwork };
@@ -5493,6 +5500,8 @@
*/
@VisibleForTesting
protected class NetworkRequestInfo implements IBinder.DeathRecipient {
+ // The requests to be satisfied in priority order. Non-multilayer requests will only have a
+ // single NetworkRequest in mRequests.
final List<NetworkRequest> mRequests;
// mSatisfier and mActiveRequest rely on one another therefore set them together.
@@ -6038,11 +6047,13 @@
@GuardedBy("mBlockedAppUids")
private final HashSet<Integer> mBlockedAppUids = new HashSet<>();
+ // The always-on request for an Internet-capable network that apps without a specific default
+ // fall back to.
@NonNull
- private final NetworkRequest mDefaultRequest;
- // The NetworkAgentInfo currently satisfying the default request, if any.
- @Nullable
- private volatile NetworkAgentInfo mDefaultNetworkNai = null;
+ private final NetworkRequestInfo mFallbackRequest;
+ // Collection of NetworkRequestInfo's used for default networks.
+ @NonNull
+ private final ArraySet<NetworkRequestInfo> mDefaultNetworkRequests = new ArraySet<>();
// Request used to optionally keep mobile data active even when higher
// priority networks like Wi-Fi are active.
@@ -6055,8 +6066,10 @@
// Request used to optionally keep vehicle internal network always active
private final NetworkRequest mDefaultVehicleRequest;
- private NetworkAgentInfo getDefaultNetwork() {
- return mDefaultNetworkNai;
+ // TODO: b/178729499 update this in favor of a method taking in a UID.
+ // The NetworkAgentInfo currently satisfying the fallback request, if any.
+ private NetworkAgentInfo getFallbackNetwork() {
+ return mFallbackRequest.mSatisfier;
}
@Nullable
@@ -6073,8 +6086,8 @@
}
@VisibleForTesting
- protected boolean isDefaultNetwork(NetworkAgentInfo nai) {
- return nai == getDefaultNetwork();
+ protected boolean isFallbackNetwork(NetworkAgentInfo nai) {
+ return nai == getFallbackNetwork();
}
// TODO : remove this method. It's a stopgap measure to help sheperding a number of dependent
@@ -6143,8 +6156,8 @@
LinkProperties lp = new LinkProperties(linkProperties);
- // TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
- // satisfies mDefaultRequest.
+ // TODO: Instead of passing mFallbackRequest, provide an API to determine whether a Network
+ // satisfies mFallbackRequest.
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
final NetworkAgentInfo nai = new NetworkAgentInfo(na,
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
@@ -6221,7 +6234,7 @@
// for (LinkProperties lp : newLp.getStackedLinks()) {
// updateMtu(lp, null);
// }
- if (isDefaultNetwork(networkAgent)) {
+ if (isFallbackNetwork(networkAgent)) {
updateTcpBufferSizes(newLp.getTcpBufferSizes());
}
@@ -6233,7 +6246,7 @@
// updateDnses will fetch the private DNS configuration from DnsManager.
mDnsManager.updatePrivateDnsStatus(netId, newLp);
- if (isDefaultNetwork(networkAgent)) {
+ if (isFallbackNetwork(networkAgent)) {
handleApplyDefaultProxy(newLp.getHttpProxy());
} else {
updateProxy(newLp, oldLp);
@@ -7184,14 +7197,41 @@
}
}
- private void makeDefault(@Nullable final NetworkAgentInfo newNetwork) {
- if (DBG) log("Switching to new default network: " + newNetwork);
+ private void processDefaultNetworkChanges(@NonNull final NetworkReassignment changes) {
+ boolean isDefaultChanged = false;
+ for (final NetworkRequestInfo defaultRequestInfo : mDefaultNetworkRequests) {
+ final NetworkReassignment.RequestReassignment reassignment =
+ changes.getReassignment(defaultRequestInfo);
+ if (null == reassignment) {
+ continue;
+ }
+ // reassignment only contains those instances where the satisfying network changed.
+ isDefaultChanged = true;
+ // Notify system services of the new default.
+ makeDefault(defaultRequestInfo, reassignment.mOldNetwork, reassignment.mNewNetwork);
+ }
- mDefaultNetworkNai = newNetwork;
+ if (isDefaultChanged) {
+ // Hold a wakelock for a short time to help apps in migrating to a new default.
+ scheduleReleaseNetworkTransitionWakelock();
+ }
+ }
+
+ private void makeDefault(@NonNull final NetworkRequestInfo nri,
+ @Nullable final NetworkAgentInfo oldDefaultNetwork,
+ @Nullable final NetworkAgentInfo newDefaultNetwork) {
+ if (DBG) {
+ log("Switching to new default network for: " + nri + " using " + newDefaultNetwork);
+ }
try {
- if (null != newNetwork) {
- mNetd.networkSetDefault(newNetwork.network.getNetId());
+ // TODO http://b/176191930 update netd calls in follow-up CL for multinetwork changes.
+ if (mFallbackRequest != nri) {
+ return;
+ }
+
+ if (null != newDefaultNetwork) {
+ mNetd.networkSetDefault(newDefaultNetwork.network.getNetId());
} else {
mNetd.networkClearDefault();
}
@@ -7199,16 +7239,41 @@
loge("Exception setting default network :" + e);
}
- notifyLockdownVpn(newNetwork);
- handleApplyDefaultProxy(null != newNetwork
- ? newNetwork.linkProperties.getHttpProxy() : null);
- updateTcpBufferSizes(null != newNetwork
- ? newNetwork.linkProperties.getTcpBufferSizes() : null);
+ if (oldDefaultNetwork != null) {
+ mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork);
+ }
+ mNetworkActivityTracker.updateDataActivityTracking(newDefaultNetwork, oldDefaultNetwork);
+ notifyLockdownVpn(newDefaultNetwork);
+ handleApplyDefaultProxy(null != newDefaultNetwork
+ ? newDefaultNetwork.linkProperties.getHttpProxy() : null);
+ updateTcpBufferSizes(null != newDefaultNetwork
+ ? newDefaultNetwork.linkProperties.getTcpBufferSizes() : null);
notifyIfacesChangedForNetworkStats();
// Fix up the NetworkCapabilities of any networks that have this network as underlying.
- if (newNetwork != null) {
- propagateUnderlyingNetworkCapabilities(newNetwork.network);
+ if (newDefaultNetwork != null) {
+ propagateUnderlyingNetworkCapabilities(newDefaultNetwork.network);
}
+
+ // Log 0 -> X and Y -> X default network transitions, where X is the new default.
+ final Network network = (newDefaultNetwork != null) ? newDefaultNetwork.network : null;
+ final int score = (newDefaultNetwork != null) ? newDefaultNetwork.getCurrentScore() : 0;
+ final boolean validated = newDefaultNetwork != null && newDefaultNetwork.lastValidated;
+ final LinkProperties lp = (newDefaultNetwork != null)
+ ? newDefaultNetwork.linkProperties : null;
+ final NetworkCapabilities nc = (newDefaultNetwork != null)
+ ? newDefaultNetwork.networkCapabilities : null;
+
+ final Network prevNetwork = (oldDefaultNetwork != null)
+ ? oldDefaultNetwork.network : null;
+ final int prevScore = (oldDefaultNetwork != null)
+ ? oldDefaultNetwork.getCurrentScore() : 0;
+ final LinkProperties prevLp = (oldDefaultNetwork != null)
+ ? oldDefaultNetwork.linkProperties : null;
+ final NetworkCapabilities prevNc = (oldDefaultNetwork != null)
+ ? oldDefaultNetwork.networkCapabilities : null;
+
+ mMetricsLog.logDefaultNetworkEvent(network, score, validated, lp, nc,
+ prevNetwork, prevScore, prevLp, prevNc);
}
private void processListenRequests(@NonNull final NetworkAgentInfo nai) {
@@ -7460,46 +7525,8 @@
now);
}
- final NetworkAgentInfo oldDefaultNetwork = getDefaultNetwork();
- final NetworkRequestInfo defaultRequestInfo = mNetworkRequests.get(mDefaultRequest);
- final NetworkReassignment.RequestReassignment reassignment =
- changes.getReassignment(defaultRequestInfo);
- final NetworkAgentInfo newDefaultNetwork =
- null != reassignment ? reassignment.mNewNetwork : oldDefaultNetwork;
-
- if (oldDefaultNetwork != newDefaultNetwork) {
- if (oldDefaultNetwork != null) {
- mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork);
- }
- mNetworkActivityTracker.updateDataActivityTracking(
- newDefaultNetwork, oldDefaultNetwork);
- // Notify system services of the new default.
- makeDefault(newDefaultNetwork);
-
- // Log 0 -> X and Y -> X default network transitions, where X is the new default.
- final Network network = (newDefaultNetwork != null) ? newDefaultNetwork.network : null;
- final int score = (newDefaultNetwork != null) ? newDefaultNetwork.getCurrentScore() : 0;
- final boolean validated = newDefaultNetwork != null && newDefaultNetwork.lastValidated;
- final LinkProperties lp = (newDefaultNetwork != null)
- ? newDefaultNetwork.linkProperties : null;
- final NetworkCapabilities nc = (newDefaultNetwork != null)
- ? newDefaultNetwork.networkCapabilities : null;
-
- final Network prevNetwork = (oldDefaultNetwork != null)
- ? oldDefaultNetwork.network : null;
- final int prevScore = (oldDefaultNetwork != null)
- ? oldDefaultNetwork.getCurrentScore() : 0;
- final LinkProperties prevLp = (oldDefaultNetwork != null)
- ? oldDefaultNetwork.linkProperties : null;
- final NetworkCapabilities prevNc = (oldDefaultNetwork != null)
- ? oldDefaultNetwork.networkCapabilities : null;
-
- mMetricsLog.logDefaultNetworkEvent(network, score, validated, lp, nc,
- prevNetwork, prevScore, prevLp, prevNc);
-
- // Have a new default network, release the transition wakelock in
- scheduleReleaseNetworkTransitionWakelock();
- }
+ // Process default network changes if applicable.
+ processDefaultNetworkChanges(changes);
// Notify requested networks are available after the default net is switched, but
// before LegacyTypeTracker sends legacy broadcasts
@@ -7552,7 +7579,7 @@
notifyNetworkLosing(nai, now);
}
- updateLegacyTypeTrackerAndVpnLockdownForRematch(oldDefaultNetwork, newDefaultNetwork, nais);
+ updateLegacyTypeTrackerAndVpnLockdownForRematch(changes, nais);
// Tear down all unneeded networks.
for (NetworkAgentInfo nai : mNetworkAgentInfos) {
@@ -7595,29 +7622,36 @@
}
private void updateLegacyTypeTrackerAndVpnLockdownForRematch(
- @Nullable final NetworkAgentInfo oldDefaultNetwork,
- @Nullable final NetworkAgentInfo newDefaultNetwork,
+ @NonNull final NetworkReassignment changes,
@NonNull final Collection<NetworkAgentInfo> nais) {
- if (oldDefaultNetwork != newDefaultNetwork) {
+ final NetworkReassignment.RequestReassignment fallbackReassignment =
+ changes.getReassignment(mFallbackRequest);
+ final NetworkAgentInfo oldFallbackNetwork =
+ null != fallbackReassignment ? fallbackReassignment.mOldNetwork : null;
+ final NetworkAgentInfo newFallbackNetwork =
+ null != fallbackReassignment ? fallbackReassignment.mNewNetwork : null;
+
+ if (oldFallbackNetwork != newFallbackNetwork) {
// Maintain the illusion : since the legacy API only understands one network at a time,
// if the default network changed, apps should see a disconnected broadcast for the
// old default network before they see a connected broadcast for the new one.
- if (oldDefaultNetwork != null) {
- mLegacyTypeTracker.remove(oldDefaultNetwork.networkInfo.getType(),
- oldDefaultNetwork, true);
+ if (oldFallbackNetwork != null) {
+ mLegacyTypeTracker.remove(oldFallbackNetwork.networkInfo.getType(),
+ oldFallbackNetwork, true);
}
- if (newDefaultNetwork != null) {
+ if (newFallbackNetwork != null) {
// The new default network can be newly null if and only if the old default
// network doesn't satisfy the default request any more because it lost a
// capability.
- mDefaultInetConditionPublished = newDefaultNetwork.lastValidated ? 100 : 0;
- mLegacyTypeTracker.add(newDefaultNetwork.networkInfo.getType(), newDefaultNetwork);
+ mDefaultInetConditionPublished = newFallbackNetwork.lastValidated ? 100 : 0;
+ mLegacyTypeTracker.add(
+ newFallbackNetwork.networkInfo.getType(), newFallbackNetwork);
// If the legacy VPN is connected, notifyLockdownVpn may end up sending a broadcast
// to reflect the NetworkInfo of this new network. This broadcast has to be sent
// after the disconnect broadcasts above, but before the broadcasts sent by the
// legacy type tracker below.
// TODO : refactor this, it's too complex
- notifyLockdownVpn(newDefaultNetwork);
+ notifyLockdownVpn(newFallbackNetwork);
}
}
@@ -7652,7 +7686,7 @@
}
// A VPN generally won't get added to the legacy tracker in the "for (nri)" loop above,
- // because usually there are no NetworkRequests it satisfies (e.g., mDefaultRequest
+ // because usually there are no NetworkRequests it satisfies (e.g., mFallbackRequest
// wants the NOT_VPN capability, so it will never be satisfied by a VPN). So, add the
// newNetwork to the tracker explicitly (it's a no-op if it has already been added).
if (nai.isVPN()) {
@@ -7663,9 +7697,9 @@
private void updateInetCondition(NetworkAgentInfo nai) {
// Don't bother updating until we've graduated to validated at least once.
if (!nai.everValidated) return;
- // For now only update icons for default connection.
+ // For now only update icons for the fallback connection.
// TODO: Update WiFi and cellular icons separately. b/17237507
- if (!isDefaultNetwork(nai)) return;
+ if (!isFallbackNetwork(nai)) return;
int newInetCondition = nai.lastValidated ? 100 : 0;
// Don't repeat publish.
@@ -7933,8 +7967,8 @@
intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo());
}
NetworkAgentInfo newDefaultAgent = null;
- if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
- newDefaultAgent = getDefaultNetwork();
+ if (nai.isSatisfyingRequest(mFallbackRequest.mRequests.get(0).requestId)) {
+ newDefaultAgent = getFallbackNetwork();
if (newDefaultAgent != null) {
intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO,
newDefaultAgent.networkInfo);
@@ -7981,10 +8015,10 @@
*/
private Network[] getDefaultNetworks() {
ensureRunningOnConnectivityServiceThread();
- ArrayList<Network> defaultNetworks = new ArrayList<>();
- NetworkAgentInfo defaultNetwork = getDefaultNetwork();
+ final ArrayList<Network> defaultNetworks = new ArrayList<>();
+ final NetworkAgentInfo fallbackNetwork = getFallbackNetwork();
for (NetworkAgentInfo nai : mNetworkAgentInfos) {
- if (nai.everConnected && (nai == defaultNetwork || nai.isVPN())) {
+ if (nai.everConnected && (nai == fallbackNetwork || nai.isVPN())) {
defaultNetworks.add(nai.network);
}
}
@@ -8034,7 +8068,6 @@
int user = UserHandle.getUserId(mDeps.getCallingUid());
final boolean success;
synchronized (mVpns) {
- throwIfLockdownEnabled();
success = mVpns.get(user).setUnderlyingNetworks(networks);
}
return success;
diff --git a/services/core/java/com/android/server/connectivity/PacProxyInstaller.java b/services/core/java/com/android/server/connectivity/PacProxyInstaller.java
index 5dc8c1a..aadaf4d 100644
--- a/services/core/java/com/android/server/connectivity/PacProxyInstaller.java
+++ b/services/core/java/com/android/server/connectivity/PacProxyInstaller.java
@@ -16,7 +16,6 @@
package com.android.server.connectivity;
-import android.annotation.NonNull;
import android.annotation.WorkerThread;
import android.app.AlarmManager;
import android.app.PendingIntent;
@@ -72,6 +71,10 @@
private static final int DELAY_LONG = 4;
private static final long MAX_PAC_SIZE = 20 * 1000 * 1000;
+ // Return values for #setCurrentProxyScriptUrl
+ public static final boolean DONT_SEND_BROADCAST = false;
+ public static final boolean DO_SEND_BROADCAST = true;
+
private String mCurrentPac;
@GuardedBy("mProxyLock")
private volatile Uri mPacUrl = Uri.EMPTY;
@@ -90,7 +93,7 @@
private volatile boolean mHasSentBroadcast;
private volatile boolean mHasDownloaded;
- private final Handler mConnectivityHandler;
+ private Handler mConnectivityHandler;
private final int mProxyMessage;
/**
@@ -99,13 +102,6 @@
private final Object mProxyLock = new Object();
/**
- * Lock ensuring consistency between the values of mHasSentBroadcast, mHasDownloaded, the
- * last URL and port, and the broadcast message being sent with the correct arguments.
- * TODO : this should probably protect all instances of these variables
- */
- private final Object mBroadcastStateLock = new Object();
-
- /**
* Runnable to download PAC script.
* The behavior relies on the assumption it always runs on mNetThread to guarantee that the
* latest data fetched from mPacUrl is stored in mProxyService.
@@ -150,7 +146,7 @@
}
}
- public PacProxyInstaller(@NonNull Context context, @NonNull Handler handler, int proxyMessage) {
+ public PacProxyInstaller(Context context, Handler handler, int proxyMessage) {
mContext = context;
mLastPort = -1;
final HandlerThread netThread = new HandlerThread("android.pacproxyinstaller",
@@ -180,27 +176,31 @@
* PacProxyInstaller will trigger a new broadcast when it is ready.
*
* @param proxy Proxy information that is about to be broadcast.
+ * @return Returns whether the broadcast should be sent : either DO_ or DONT_SEND_BROADCAST
*/
- public void setCurrentProxyScriptUrl(@NonNull ProxyInfo proxy) {
- synchronized (mBroadcastStateLock) {
- if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) {
- if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) return;
- mPacUrl = proxy.getPacFileUrl();
- mCurrentDelay = DELAY_1;
- mHasSentBroadcast = false;
- mHasDownloaded = false;
- getAlarmManager().cancel(mPacRefreshIntent);
- bind();
- } else {
- getAlarmManager().cancel(mPacRefreshIntent);
- synchronized (mProxyLock) {
- mPacUrl = Uri.EMPTY;
- mCurrentPac = null;
- if (mProxyService != null) {
- unbind();
- }
+ public synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
+ if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) {
+ if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) {
+ // Allow to send broadcast, nothing to do.
+ return DO_SEND_BROADCAST;
+ }
+ mPacUrl = proxy.getPacFileUrl();
+ mCurrentDelay = DELAY_1;
+ mHasSentBroadcast = false;
+ mHasDownloaded = false;
+ getAlarmManager().cancel(mPacRefreshIntent);
+ bind();
+ return DONT_SEND_BROADCAST;
+ } else {
+ getAlarmManager().cancel(mPacRefreshIntent);
+ synchronized (mProxyLock) {
+ mPacUrl = Uri.EMPTY;
+ mCurrentPac = null;
+ if (mProxyService != null) {
+ unbind();
}
}
+ return DO_SEND_BROADCAST;
}
}
@@ -275,7 +275,6 @@
getAlarmManager().set(AlarmManager.ELAPSED_REALTIME, timeTillTrigger, mPacRefreshIntent);
}
- @GuardedBy("mProxyLock")
private void setCurrentProxyScript(String script) {
if (mProxyService == null) {
Log.e(TAG, "setCurrentProxyScript: no proxy service");
@@ -348,9 +347,6 @@
public void setProxyPort(int port) {
if (mLastPort != -1) {
// Always need to send if port changed
- // TODO: Here lacks synchronization because this write cannot
- // guarantee that it's visible from sendProxyIfNeeded() when
- // it's called by a Runnable which is post by mNetThread.
mHasSentBroadcast = false;
}
mLastPort = port;
@@ -390,15 +386,13 @@
mConnectivityHandler.sendMessage(mConnectivityHandler.obtainMessage(mProxyMessage, proxy));
}
- private void sendProxyIfNeeded() {
- synchronized (mBroadcastStateLock) {
- if (!mHasDownloaded || (mLastPort == -1)) {
- return;
- }
- if (!mHasSentBroadcast) {
- sendPacBroadcast(ProxyInfo.buildPacProxy(mPacUrl, mLastPort));
- mHasSentBroadcast = true;
- }
+ private synchronized void sendProxyIfNeeded() {
+ if (!mHasDownloaded || (mLastPort == -1)) {
+ return;
+ }
+ if (!mHasSentBroadcast) {
+ sendPacBroadcast(ProxyInfo.buildPacProxy(mPacUrl, mLastPort));
+ mHasSentBroadcast = true;
}
}
}
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index b618d2b..d83ff83 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -226,9 +226,9 @@
final ProxyInfo defaultProxy = getDefaultProxy();
final ProxyInfo proxyInfo = null != defaultProxy ?
defaultProxy : ProxyInfo.buildDirectProxy("", 0, Collections.emptyList());
- mPacProxyInstaller.setCurrentProxyScriptUrl(proxyInfo);
- if (!shouldSendBroadcast(proxyInfo)) {
+ if (mPacProxyInstaller.setCurrentProxyScriptUrl(proxyInfo)
+ == PacProxyInstaller.DONT_SEND_BROADCAST) {
return;
}
if (DBG) Log.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
@@ -244,13 +244,6 @@
}
}
- private boolean shouldSendBroadcast(ProxyInfo proxy) {
- if (Uri.EMPTY.equals(proxy.getPacFileUrl())) return false;
- if (proxy.getPacFileUrl().equals(proxy.getPacFileUrl())
- && (proxy.getPort() > 0)) return true;
- return true;
- }
-
/**
* Sets the global proxy in memory. Also writes the values to the global settings of the device.
*
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index b455a3f..d956ba3 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1982,27 +1982,28 @@
* secondary thread to perform connection work, returning quickly.
*
* Should only be called to respond to Binder requests as this enforces caller permission. Use
- * {@link #startLegacyVpnPrivileged(VpnProfile, KeyStore, LinkProperties)} to skip the
+ * {@link #startLegacyVpnPrivileged(VpnProfile, KeyStore, Network, LinkProperties)} to skip the
* permission check only when the caller is trusted (or the call is initiated by the system).
*/
- public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) {
+ public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, @Nullable Network underlying,
+ LinkProperties egress) {
enforceControlPermission();
final long token = Binder.clearCallingIdentity();
try {
- startLegacyVpnPrivileged(profile, keyStore, egress);
+ startLegacyVpnPrivileged(profile, keyStore, underlying, egress);
} finally {
Binder.restoreCallingIdentity(token);
}
}
/**
- * Like {@link #startLegacyVpn(VpnProfile, KeyStore, LinkProperties)}, but does not check
- * permissions under the assumption that the caller is the system.
+ * Like {@link #startLegacyVpn(VpnProfile, KeyStore, Network, LinkProperties)}, but does not
+ * check permissions under the assumption that the caller is the system.
*
* Callers are responsible for checking permissions if needed.
*/
public void startLegacyVpnPrivileged(VpnProfile profile, KeyStore keyStore,
- LinkProperties egress) {
+ @Nullable Network underlying, @NonNull LinkProperties egress) {
UserManager mgr = UserManager.get(mContext);
UserInfo user = mgr.getUserInfo(mUserId);
if (user.isRestricted() || mgr.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN,
@@ -2128,6 +2129,9 @@
config.session = profile.name;
config.isMetered = false;
config.proxyInfo = profile.proxy;
+ if (underlying != null) {
+ config.underlyingNetworks = new Network[] { underlying };
+ }
config.addLegacyRoutes(profile.routes);
if (!profile.dnsServers.isEmpty()) {
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index ea2788c..6d1c680 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -155,7 +155,7 @@
try {
// Use the privileged method because Lockdown VPN is initiated by the system, so
// no additional permission checks are necessary.
- mVpn.startLegacyVpnPrivileged(mProfile, mKeyStore, egressProp);
+ mVpn.startLegacyVpnPrivileged(mProfile, mKeyStore, null, egressProp);
} catch (IllegalStateException e) {
mAcceptedEgressIface = null;
Log.e(TAG, "Failed to start VPN", e);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 01d4faf..0fd39a4 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -239,6 +239,7 @@
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.StatLogger;
import com.android.internal.util.XmlUtils;
+import com.android.net.module.util.NetworkIdentityUtils;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
@@ -2162,13 +2163,14 @@
if (template.matches(probeIdent)) {
if (LOGD) {
Slog.d(TAG, "Found template " + template + " which matches subscriber "
- + NetworkIdentity.scrubSubscriberId(subscriberId));
+ + NetworkIdentityUtils.scrubSubscriberId(subscriberId));
}
return false;
}
}
- Slog.i(TAG, "No policy for subscriber " + NetworkIdentity.scrubSubscriberId(subscriberId)
+ Slog.i(TAG, "No policy for subscriber "
+ + NetworkIdentityUtils.scrubSubscriberId(subscriberId)
+ "; generating default policy");
final NetworkPolicy policy = buildDefaultMobilePolicy(subId, subscriberId);
addNetworkPolicyAL(policy);
@@ -3596,14 +3598,15 @@
final int subId = mSubIdToSubscriberId.keyAt(i);
final String subscriberId = mSubIdToSubscriberId.valueAt(i);
- fout.println(subId + "=" + NetworkIdentity.scrubSubscriberId(subscriberId));
+ fout.println(subId + "="
+ + NetworkIdentityUtils.scrubSubscriberId(subscriberId));
}
fout.decreaseIndent();
fout.println();
for (String[] mergedSubscribers : mMergedSubscriberIds) {
fout.println("Merged subscriptions: " + Arrays.toString(
- NetworkIdentity.scrubSubscriberId(mergedSubscribers)));
+ NetworkIdentityUtils.scrubSubscriberIds(mergedSubscribers)));
}
fout.println();
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 3dfb99e..bba5dcb 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -976,7 +976,7 @@
AudioPortConfig sourceConfig = mAudioSource.activeConfig();
List<AudioPortConfig> sinkConfigs = new ArrayList<>();
AudioPatch[] audioPatchArray = new AudioPatch[] { mAudioPatch };
- boolean shouldRecreateAudioPatch = sourceUpdated || sinkUpdated;
+ boolean shouldRecreateAudioPatch = sourceUpdated || sinkUpdated || mAudioPatch == null;
for (AudioDevicePort audioSink : mAudioSink) {
AudioPortConfig sinkConfig = audioSink.activeConfig();
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index 0ae10b6..a3cadf3 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -88,7 +88,6 @@
}
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
- ps->giveThreadPoolName();
// sm->addService increments the reference count, and now we're OK with returning the pointer.
return self.get();
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 3a9896a..a42e364 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4124,6 +4124,13 @@
*/
public static final String KEY_USE_ACS_FOR_RCS_BOOL = "use_acs_for_rcs_bool";
+ /**
+ * Indicates temporarily unmetered mobile data is supported by the carrier.
+ * @hide
+ */
+ public static final String KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL =
+ "network_temp_not_metered_supported_bool";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -4673,6 +4680,7 @@
sDefaults.putString(KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING, "");
sDefaults.putBoolean(KEY_USE_LOWER_MTU_VALUE_IF_BOTH_RECEIVED, false);
sDefaults.putBoolean(KEY_USE_ACS_FOR_RCS_BOOL, false);
+ sDefaults.putBoolean(KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL, false);
sDefaults.putInt(KEY_DEFAULT_RTT_MODE_INT, 0);
}
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index 8507d85..706e3cb 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -344,6 +344,7 @@
// TODO: Instead of doing this, we should create a formal way for cloning cell identity.
// Cell identity is not an immutable object so we have to deep copy it.
mCellIdentity = CellIdentity.CREATOR.createFromParcel(p);
+ p.recycle();
}
if (nri.mVoiceSpecificInfo != null) {
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index e630da0..ffde68e 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -36,7 +36,7 @@
"libvndksupport",
"libziparchive",
"libz",
- "netd_aidl_interface-cpp",
+ "netd_aidl_interface-V5-cpp",
],
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 4c658e1..b0cc7f1 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -132,6 +132,7 @@
import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.NotificationManager;
@@ -252,6 +253,7 @@
import com.android.internal.util.WakeupMessage;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.net.module.util.ArrayTrackRecord;
import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
import com.android.server.connectivity.ConnectivityConstants;
import com.android.server.connectivity.MockableSystemProperties;
@@ -906,28 +908,69 @@
}
/**
- * A NetworkFactory that allows tests to wait until any in-flight NetworkRequest add or remove
- * operations have been processed. Before ConnectivityService can add or remove any requests,
- * the factory must be told to expect those operations by calling expectAddRequestsWithScores or
- * expectRemoveRequests.
+ * A NetworkFactory that allows to wait until any in-flight NetworkRequest add or remove
+ * operations have been processed and test for them.
*/
private static class MockNetworkFactory extends NetworkFactory {
private final ConditionVariable mNetworkStartedCV = new ConditionVariable();
private final ConditionVariable mNetworkStoppedCV = new ConditionVariable();
private final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
- // Used to expect that requests be removed or added on a separate thread, without sleeping.
- // Callers can call either expectAddRequestsWithScores() or expectRemoveRequests() exactly
- // once, then cause some other thread to add or remove requests, then call
- // waitForRequests().
- // It is not possible to wait for both add and remove requests. When adding, the queue
- // contains the expected score. When removing, the value is unused, all matters is the
- // number of objects in the queue.
- private final LinkedBlockingQueue<Integer> mExpectations;
+ static class RequestEntry {
+ @NonNull
+ public final NetworkRequest request;
- // Whether we are currently expecting requests to be added or removed. Valid only if
- // mExpectations is non-empty.
- private boolean mExpectingAdditions;
+ RequestEntry(@NonNull final NetworkRequest request) {
+ this.request = request;
+ }
+
+ static final class Add extends RequestEntry {
+ public final int factorySerialNumber;
+
+ Add(@NonNull final NetworkRequest request, final int factorySerialNumber) {
+ super(request);
+ this.factorySerialNumber = factorySerialNumber;
+ }
+ }
+
+ static final class Remove extends RequestEntry {
+ Remove(@NonNull final NetworkRequest request) {
+ super(request);
+ }
+ }
+ }
+
+ // History of received requests adds and removes.
+ private final ArrayTrackRecord<RequestEntry>.ReadHead mRequestHistory =
+ new ArrayTrackRecord<RequestEntry>().newReadHead();
+
+ private static <T> T failIfNull(@Nullable final T obj, @Nullable final String message) {
+ if (null == obj) fail(null != message ? message : "Must not be null");
+ return obj;
+ }
+
+
+ public RequestEntry.Add expectRequestAdd() {
+ return failIfNull((RequestEntry.Add) mRequestHistory.poll(TIMEOUT_MS,
+ it -> it instanceof RequestEntry.Add), "Expected request add");
+ }
+
+ public void expectRequestAdds(final int count) {
+ for (int i = count; i > 0; --i) {
+ expectRequestAdd();
+ }
+ }
+
+ public RequestEntry.Remove expectRequestRemove() {
+ return failIfNull((RequestEntry.Remove) mRequestHistory.poll(TIMEOUT_MS,
+ it -> it instanceof RequestEntry.Remove), "Expected request remove");
+ }
+
+ public void expectRequestRemoves(final int count) {
+ for (int i = count; i > 0; --i) {
+ expectRequestRemove();
+ }
+ }
// Used to collect the networks requests managed by this factory. This is a duplicate of
// the internal information stored in the NetworkFactory (which is private).
@@ -936,7 +979,6 @@
public MockNetworkFactory(Looper looper, Context context, String logTag,
NetworkCapabilities filter) {
super(looper, context, logTag, filter);
- mExpectations = new LinkedBlockingQueue<>();
}
public int getMyRequestCount() {
@@ -970,95 +1012,33 @@
@Override
protected void handleAddRequest(NetworkRequest request, int score,
int factorySerialNumber) {
- synchronized (mExpectations) {
- final Integer expectedScore = mExpectations.poll(); // null if the queue is empty
-
- assertNotNull("Added more requests than expected (" + request + " score : "
- + score + ")", expectedScore);
- // If we're expecting anything, we must be expecting additions.
- if (!mExpectingAdditions) {
- fail("Can't add requests while expecting requests to be removed");
- }
- if (expectedScore != score) {
- fail("Expected score was " + expectedScore + " but actual was " + score
- + " in added request");
- }
-
- // Add the request.
- mNetworkRequests.put(request.requestId, request);
- super.handleAddRequest(request, score, factorySerialNumber);
- mExpectations.notify();
- }
+ mNetworkRequests.put(request.requestId, request);
+ super.handleAddRequest(request, score, factorySerialNumber);
+ mRequestHistory.add(new RequestEntry.Add(request, factorySerialNumber));
}
@Override
protected void handleRemoveRequest(NetworkRequest request) {
- synchronized (mExpectations) {
- final Integer expectedScore = mExpectations.poll(); // null if the queue is empty
+ mNetworkRequests.remove(request.requestId);
+ super.handleRemoveRequest(request);
+ mRequestHistory.add(new RequestEntry.Remove(request));
+ }
- assertTrue("Removed more requests than expected", expectedScore != null);
- // If we're expecting anything, we must be expecting removals.
- if (mExpectingAdditions) {
- fail("Can't remove requests while expecting requests to be added");
- }
+ public void assertRequestCountEquals(final int count) {
+ assertEquals(count, getMyRequestCount());
+ }
- // Remove the request.
- mNetworkRequests.remove(request.requestId);
- super.handleRemoveRequest(request);
- mExpectations.notify();
- }
+ @Override
+ public void terminate() {
+ super.terminate();
+ // Make sure there are no remaining requests unaccounted for.
+ assertNull(mRequestHistory.poll(TIMEOUT_MS, r -> true));
}
// Trigger releasing the request as unfulfillable
public void triggerUnfulfillable(NetworkRequest r) {
super.releaseRequestAsUnfulfillableByAnyFactory(r);
}
-
- private void assertNoExpectations() {
- if (mExpectations.size() != 0) {
- fail("Can't add expectation, " + mExpectations.size() + " already pending");
- }
- }
-
- // Expects that requests with the specified scores will be added.
- public void expectAddRequestsWithScores(final int... scores) {
- assertNoExpectations();
- mExpectingAdditions = true;
- for (int score : scores) {
- mExpectations.add(score);
- }
- }
-
- // Expects that count requests will be removed.
- public void expectRemoveRequests(final int count) {
- assertNoExpectations();
- mExpectingAdditions = false;
- for (int i = 0; i < count; ++i) {
- mExpectations.add(0); // For removals the score is ignored so any value will do.
- }
- }
-
- // Waits for the expected request additions or removals to happen within a timeout.
- public void waitForRequests() throws InterruptedException {
- final long deadline = SystemClock.elapsedRealtime() + TIMEOUT_MS;
- synchronized (mExpectations) {
- while (mExpectations.size() > 0 && SystemClock.elapsedRealtime() < deadline) {
- mExpectations.wait(deadline - SystemClock.elapsedRealtime());
- }
- }
- final long count = mExpectations.size();
- final String msg = count + " requests still not " +
- (mExpectingAdditions ? "added" : "removed") +
- " after " + TIMEOUT_MS + " ms";
- assertEquals(msg, 0, count);
- }
-
- public SparseArray<NetworkRequest> waitForNetworkRequests(final int count)
- throws InterruptedException {
- waitForRequests();
- assertEquals(count, getMyRequestCount());
- return mNetworkRequests;
- }
}
private Set<UidRange> uidRangesForUid(int uid) {
@@ -2595,12 +2575,6 @@
callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
}
- private int[] makeIntArray(final int size, final int value) {
- final int[] array = new int[size];
- Arrays.fill(array, value);
- return array;
- }
-
private void tryNetworkFactoryRequests(int capability) throws Exception {
// Verify NOT_RESTRICTED is set appropriately
final NetworkCapabilities nc = new NetworkRequest.Builder().addCapability(capability)
@@ -2622,9 +2596,9 @@
mServiceContext, "testFactory", filter);
testFactory.setScoreFilter(40);
ConditionVariable cv = testFactory.getNetworkStartedCV();
- testFactory.expectAddRequestsWithScores(0);
testFactory.register();
- testFactory.waitForNetworkRequests(1);
+ testFactory.expectRequestAdd();
+ testFactory.assertRequestCountEquals(1);
int expectedRequestCount = 1;
NetworkCallback networkCallback = null;
// For non-INTERNET capabilities we cannot rely on the default request being present, so
@@ -2633,13 +2607,12 @@
assertFalse(testFactory.getMyStartRequested());
NetworkRequest request = new NetworkRequest.Builder().addCapability(capability).build();
networkCallback = new NetworkCallback();
- testFactory.expectAddRequestsWithScores(0); // New request
mCm.requestNetwork(request, networkCallback);
expectedRequestCount++;
- testFactory.waitForNetworkRequests(expectedRequestCount);
+ testFactory.expectRequestAdd();
}
waitFor(cv);
- assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
+ testFactory.assertRequestCountEquals(expectedRequestCount);
assertTrue(testFactory.getMyStartRequested());
// Now bring in a higher scored network.
@@ -2653,15 +2626,14 @@
// When testAgent connects, ConnectivityService will re-send us all current requests with
// the new score. There are expectedRequestCount such requests, and we must wait for all of
// them.
- testFactory.expectAddRequestsWithScores(makeIntArray(expectedRequestCount, 50));
testAgent.connect(false);
testAgent.addCapability(capability);
waitFor(cv);
- testFactory.waitForNetworkRequests(expectedRequestCount);
+ testFactory.expectRequestAdds(expectedRequestCount);
+ testFactory.assertRequestCountEquals(expectedRequestCount);
assertFalse(testFactory.getMyStartRequested());
// Bring in a bunch of requests.
- testFactory.expectAddRequestsWithScores(makeIntArray(10, 50));
assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
ConnectivityManager.NetworkCallback[] networkCallbacks =
new ConnectivityManager.NetworkCallback[10];
@@ -2671,24 +2643,24 @@
builder.addCapability(capability);
mCm.requestNetwork(builder.build(), networkCallbacks[i]);
}
- testFactory.waitForNetworkRequests(10 + expectedRequestCount);
+ testFactory.expectRequestAdds(10);
+ testFactory.assertRequestCountEquals(10 + expectedRequestCount);
assertFalse(testFactory.getMyStartRequested());
// Remove the requests.
- testFactory.expectRemoveRequests(10);
for (int i = 0; i < networkCallbacks.length; i++) {
mCm.unregisterNetworkCallback(networkCallbacks[i]);
}
- testFactory.waitForNetworkRequests(expectedRequestCount);
+ testFactory.expectRequestRemoves(10);
+ testFactory.assertRequestCountEquals(expectedRequestCount);
assertFalse(testFactory.getMyStartRequested());
// Drop the higher scored network.
cv = testFactory.getNetworkStartedCV();
- // With the default network disconnecting, the requests are sent with score 0 to factories.
- testFactory.expectAddRequestsWithScores(makeIntArray(expectedRequestCount, 0));
testAgent.disconnect();
waitFor(cv);
- testFactory.waitForNetworkRequests(expectedRequestCount);
+ testFactory.expectRequestAdds(expectedRequestCount);
+ testFactory.assertRequestCountEquals(expectedRequestCount);
assertEquals(expectedRequestCount, testFactory.getMyRequestCount());
assertTrue(testFactory.getMyStartRequested());
@@ -2731,9 +2703,8 @@
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
mServiceContext, "testFactory", filter);
// Register the factory and don't be surprised when the default request arrives.
- testFactory.expectAddRequestsWithScores(0);
testFactory.register();
- testFactory.waitForNetworkRequests(1);
+ testFactory.expectRequestAdd();
testFactory.setScoreFilter(42);
testFactory.terminate();
@@ -3876,38 +3847,37 @@
testFactory.setScoreFilter(40);
// Register the factory and expect it to start looking for a network.
- testFactory.expectAddRequestsWithScores(0); // Score 0 as the request is not served yet.
testFactory.register();
try {
- testFactory.waitForNetworkRequests(1);
+ testFactory.expectRequestAdd();
+ testFactory.assertRequestCountEquals(1);
assertTrue(testFactory.getMyStartRequested());
// Bring up wifi. The factory stops looking for a network.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
// Score 60 - 40 penalty for not validated yet, then 60 when it validates
- testFactory.expectAddRequestsWithScores(20, 60);
mWiFiNetworkAgent.connect(true);
- testFactory.waitForRequests();
+ // Default request and mobile always on request
+ testFactory.expectRequestAdds(2);
assertFalse(testFactory.getMyStartRequested());
- ContentResolver cr = mServiceContext.getContentResolver();
-
// Turn on mobile data always on. The factory starts looking again.
- testFactory.expectAddRequestsWithScores(0); // Always on requests comes up with score 0
setAlwaysOnNetworks(true);
- testFactory.waitForNetworkRequests(2);
+ testFactory.expectRequestAdd();
+ testFactory.assertRequestCountEquals(2);
+
assertTrue(testFactory.getMyStartRequested());
// Bring up cell data and check that the factory stops looking.
assertLength(1, mCm.getAllNetworks());
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
- testFactory.expectAddRequestsWithScores(10, 50); // Unvalidated, then validated
mCellNetworkAgent.connect(true);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- testFactory.waitForNetworkRequests(2);
- assertFalse(
- testFactory.getMyStartRequested()); // Because the cell network outscores us.
+ testFactory.expectRequestAdds(2); // Unvalidated and validated
+ testFactory.assertRequestCountEquals(2);
+ // The cell network outscores the factory filter, so start is not requested.
+ assertFalse(testFactory.getMyStartRequested());
// Check that cell data stays up.
waitForIdle();
@@ -3915,9 +3885,8 @@
assertLength(2, mCm.getAllNetworks());
// Turn off mobile data always on and expect the request to disappear...
- testFactory.expectRemoveRequests(1);
setAlwaysOnNetworks(false);
- testFactory.waitForNetworkRequests(1);
+ testFactory.expectRequestRemove();
// ... and cell data to be torn down.
cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
@@ -4224,46 +4193,33 @@
testFactory.setScoreFilter(40);
// Register the factory and expect it to receive the default request.
- testFactory.expectAddRequestsWithScores(0);
testFactory.register();
- SparseArray<NetworkRequest> requests = testFactory.waitForNetworkRequests(1);
-
- assertEquals(1, requests.size()); // have 1 request at this point
- int origRequestId = requests.valueAt(0).requestId;
+ testFactory.expectRequestAdd();
// Now file the test request and expect it.
- testFactory.expectAddRequestsWithScores(0);
mCm.requestNetwork(nr, networkCallback);
- requests = testFactory.waitForNetworkRequests(2); // have 2 requests at this point
+ final NetworkRequest newRequest = testFactory.expectRequestAdd().request;
- int newRequestId = 0;
- for (int i = 0; i < requests.size(); ++i) {
- if (requests.valueAt(i).requestId != origRequestId) {
- newRequestId = requests.valueAt(i).requestId;
- break;
- }
- }
-
- testFactory.expectRemoveRequests(1);
if (preUnregister) {
mCm.unregisterNetworkCallback(networkCallback);
// Simulate the factory releasing the request as unfulfillable: no-op since
// the callback has already been unregistered (but a test that no exceptions are
// thrown).
- testFactory.triggerUnfulfillable(requests.get(newRequestId));
+ testFactory.triggerUnfulfillable(newRequest);
} else {
// Simulate the factory releasing the request as unfulfillable and expect onUnavailable!
- testFactory.triggerUnfulfillable(requests.get(newRequestId));
+ testFactory.triggerUnfulfillable(newRequest);
networkCallback.expectCallback(CallbackEntry.UNAVAILABLE, (Network) null);
- testFactory.waitForRequests();
// unregister network callback - a no-op (since already freed by the
// on-unavailable), but should not fail or throw exceptions.
mCm.unregisterNetworkCallback(networkCallback);
}
+ testFactory.expectRequestRemove();
+
testFactory.terminate();
handlerThread.quit();
}
diff --git a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
index a10a3c8..e590fb7 100644
--- a/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
+++ b/tests/net/java/com/android/server/LegacyTypeTrackerTest.kt
@@ -55,7 +55,7 @@
private val supportedTypes = arrayOf(TYPE_MOBILE, TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_SUPL)
private val mMockService = mock(ConnectivityService::class.java).apply {
- doReturn(false).`when`(this).isDefaultNetwork(any())
+ doReturn(false).`when`(this).isFallbackNetwork(any())
}
private val mTracker = LegacyTypeTracker(mMockService).apply {
supportedTypes.forEach {
@@ -126,11 +126,11 @@
fun testBroadcastOnDisconnect() {
val mobileNai1 = mock(NetworkAgentInfo::class.java)
val mobileNai2 = mock(NetworkAgentInfo::class.java)
- doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai1)
+ doReturn(false).`when`(mMockService).isFallbackNetwork(mobileNai1)
mTracker.add(TYPE_MOBILE, mobileNai1)
verify(mMockService).sendLegacyNetworkBroadcast(mobileNai1, CONNECTED, TYPE_MOBILE)
reset(mMockService)
- doReturn(false).`when`(mMockService).isDefaultNetwork(mobileNai2)
+ doReturn(false).`when`(mMockService).isFallbackNetwork(mobileNai2)
mTracker.add(TYPE_MOBILE, mobileNai2)
verify(mMockService, never()).sendLegacyNetworkBroadcast(any(), any(), anyInt())
mTracker.remove(TYPE_MOBILE, mobileNai1, false /* wasDefault */)
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 68aaaed..f478282 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -148,6 +148,7 @@
managedProfileA.profileGroupId = primaryUser.id;
}
+ static final Network EGRESS_NETWORK = new Network(101);
static final String EGRESS_IFACE = "wlan0";
static final String TEST_VPN_PKG = "com.testvpn.vpn";
private static final String TEST_VPN_SERVER = "1.2.3.4";
@@ -963,7 +964,7 @@
InetAddresses.parseNumericAddress("192.0.2.0"), EGRESS_IFACE);
lp.addRoute(defaultRoute);
- vpn.startLegacyVpn(vpnProfile, mKeyStore, lp);
+ vpn.startLegacyVpn(vpnProfile, mKeyStore, EGRESS_NETWORK, lp);
return vpn;
}