Merge "Add getter for the fields of NetworkStats.Entry"
diff --git a/Android.bp b/Android.bp
index 36ed865..310db95 100644
--- a/Android.bp
+++ b/Android.bp
@@ -419,7 +419,6 @@
name: "framework-ike-shared-srcs",
visibility: ["//packages/modules/IPsec"],
srcs: [
- "core/java/android/net/annotations/PolicyDirection.java",
"core/java/com/android/internal/util/HexDump.java",
"core/java/com/android/internal/util/WakeupMessage.java",
"services/core/java/com/android/server/vcn/util/PersistableBundleUtils.java",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 31fecd1..14da6fb 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -177,6 +177,7 @@
last_released: {
api_file: ":android-non-updatable.api.module-lib.latest",
removed_api_file: ":android-non-updatable-removed.api.module-lib.latest",
+ baseline_file: ":android-non-updatable-incompatibilities.api.module-lib.latest",
},
api_lint: {
enabled: true,
diff --git a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
index a1a46af..161a317 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
@@ -235,7 +235,6 @@
public static final int REASON_LOCKED_BOOT_COMPLETED = 202;
/**
* All Bluetooth broadcasts.
- * @hide
*/
public static final int REASON_BLUETOOTH_BROADCAST = 203;
/**
diff --git a/api/api.go b/api/api.go
index 976b140..74cbece 100644
--- a/api/api.go
+++ b/api/api.go
@@ -30,22 +30,10 @@
// The properties of the combined_apis module type.
type CombinedApisProperties struct {
- // Module libraries that have public APIs
- Public []string
- // Module libraries that have system APIs
- System []string
- // Module libraries that have module_library APIs
- Module_lib []string
- // Module libraries that have system_server APIs
- System_server []string
- // ART module library. The only API library not removed from the filtered api database, because
- // 1) ART apis are available by default to all modules, while other module-to-module deps are
- // explicit and probably receive more scrutiny anyway
- // 2) The number of ART/libcore APIs is large, so not linting them would create a large gap
- // 3) It's a compromise. Ideally we wouldn't be filtering out any module APIs, and have
- // per-module lint databases that excludes just that module's APIs. Alas, that's more
- // difficult to achieve.
- Art_module string
+ // Module libraries in the bootclasspath
+ Bootclasspath []string
+ // Module libraries in system server
+ System_server_classpath []string
}
type CombinedApis struct {
@@ -105,7 +93,7 @@
props := genruleProps{}
props.Name = proptools.StringPtr(ctx.ModuleName() + "-" + filename)
props.Tools = []string{"metalava"}
- props.Out = []string{txt.TxtFilename}
+ props.Out = []string{filename}
props.Cmd = proptools.StringPtr(metalavaCmd + "$(in) --api $(out)")
props.Srcs = createSrcs(txt.BaseTxt, txt.Modules, txt.ModuleTag)
props.Dists = []android.Dist{
@@ -170,33 +158,38 @@
func createMergedTxts(ctx android.LoadHookContext, props CombinedApisProperties) {
var textFiles []MergedTxtDefinition
+ // Two module libraries currently do not support @SystemApi so only have the public scope.
+ bcpWithSystemApi := props.Bootclasspath
+ bcpWithSystemApi = remove(bcpWithSystemApi, "conscrypt.module.public.api")
+ bcpWithSystemApi = remove(bcpWithSystemApi, "i18n.module.public.api")
+
tagSuffix := []string{".api.txt}", ".removed-api.txt}"}
for i, f := range []string{"current.txt", "removed.txt"} {
textFiles = append(textFiles, MergedTxtDefinition{
TxtFilename: f,
BaseTxt: ":non-updatable-" + f,
- Modules: props.Public,
+ Modules: props.Bootclasspath,
ModuleTag: "{.public" + tagSuffix[i],
Scope: "public",
})
textFiles = append(textFiles, MergedTxtDefinition{
TxtFilename: f,
BaseTxt: ":non-updatable-system-" + f,
- Modules: props.System,
+ Modules: bcpWithSystemApi,
ModuleTag: "{.system" + tagSuffix[i],
Scope: "system",
})
textFiles = append(textFiles, MergedTxtDefinition{
TxtFilename: f,
BaseTxt: ":non-updatable-module-lib-" + f,
- Modules: props.Module_lib,
+ Modules: bcpWithSystemApi,
ModuleTag: "{.module-lib" + tagSuffix[i],
Scope: "module-lib",
})
textFiles = append(textFiles, MergedTxtDefinition{
TxtFilename: f,
BaseTxt: ":non-updatable-system-server-" + f,
- Modules: props.System_server,
+ Modules: props.System_server_classpath,
ModuleTag: "{.system-server" + tagSuffix[i],
Scope: "system-server",
})
@@ -209,10 +202,18 @@
func (a *CombinedApis) createInternalModules(ctx android.LoadHookContext) {
createMergedTxts(ctx, a.properties)
- createMergedStubsSrcjar(ctx, a.properties.Public)
+ createMergedStubsSrcjar(ctx, a.properties.Bootclasspath)
- // For the filtered api versions, we prune all APIs except art module's APIs.
- createFilteredApiVersions(ctx, remove(a.properties.Public, a.properties.Art_module))
+ // For the filtered api versions, we prune all APIs except art module's APIs. because
+ // 1) ART apis are available by default to all modules, while other module-to-module deps are
+ // explicit and probably receive more scrutiny anyway
+ // 2) The number of ART/libcore APIs is large, so not linting them would create a large gap
+ // 3) It's a compromise. Ideally we wouldn't be filtering out any module APIs, and have
+ // per-module lint databases that excludes just that module's APIs. Alas, that's more
+ // difficult to achieve.
+ filteredModules := a.properties.Bootclasspath
+ filteredModules = remove(filteredModules, "art.module.public.api")
+ createFilteredApiVersions(ctx, filteredModules)
}
func combinedApisModuleFactory() android.Module {
diff --git a/core/api/current.txt b/core/api/current.txt
index 95435f7..d696bc7 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -17980,10 +17980,12 @@
ctor public BiometricPrompt.CryptoObject(@NonNull java.security.Signature);
ctor public BiometricPrompt.CryptoObject(@NonNull javax.crypto.Cipher);
ctor public BiometricPrompt.CryptoObject(@NonNull javax.crypto.Mac);
- ctor public BiometricPrompt.CryptoObject(@NonNull android.security.identity.IdentityCredential);
+ ctor @Deprecated public BiometricPrompt.CryptoObject(@NonNull android.security.identity.IdentityCredential);
+ ctor public BiometricPrompt.CryptoObject(@NonNull android.security.identity.PresentationSession);
method public javax.crypto.Cipher getCipher();
- method @Nullable public android.security.identity.IdentityCredential getIdentityCredential();
+ method @Deprecated @Nullable public android.security.identity.IdentityCredential getIdentityCredential();
method public javax.crypto.Mac getMac();
+ method @Nullable public android.security.identity.PresentationSession getPresentationSession();
method public java.security.Signature getSignature();
}
@@ -27290,6 +27292,8 @@
ctor public VcnCellUnderlyingNetworkTemplate.Builder();
method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate build();
method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMetered(int);
+ method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMinDownstreamBandwidthKbps(int, int);
+ method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setMinUpstreamBandwidthKbps(int, int);
method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setOperatorPlmnIds(@NonNull java.util.Set<java.lang.String>);
method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setOpportunistic(int);
method @NonNull public android.net.vcn.VcnCellUnderlyingNetworkTemplate.Builder setRoaming(int);
@@ -27350,6 +27354,10 @@
public abstract class VcnUnderlyingNetworkTemplate {
method public int getMetered();
+ method public int getMinEntryDownstreamBandwidthKbps();
+ method public int getMinEntryUpstreamBandwidthKbps();
+ method public int getMinExitDownstreamBandwidthKbps();
+ method public int getMinExitUpstreamBandwidthKbps();
field public static final int MATCH_ANY = 0; // 0x0
field public static final int MATCH_FORBIDDEN = 2; // 0x2
field public static final int MATCH_REQUIRED = 1; // 0x1
@@ -27363,6 +27371,8 @@
ctor public VcnWifiUnderlyingNetworkTemplate.Builder();
method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate build();
method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setMetered(int);
+ method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setMinDownstreamBandwidthKbps(int, int);
+ method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setMinUpstreamBandwidthKbps(int, int);
method @NonNull public android.net.vcn.VcnWifiUnderlyingNetworkTemplate.Builder setSsids(@NonNull java.util.Set<java.lang.String>);
}
@@ -37542,6 +37552,51 @@
ctor public CipherSuiteNotSupportedException(@NonNull String, @NonNull Throwable);
}
+ public class CredentialDataRequest {
+ method @NonNull public java.util.Map<java.lang.String,java.util.Collection<java.lang.String>> getDeviceSignedEntriesToRequest();
+ method @NonNull public java.util.Map<java.lang.String,java.util.Collection<java.lang.String>> getIssuerSignedEntriesToRequest();
+ method @Nullable public byte[] getReaderSignature();
+ method @Nullable public byte[] getRequestMessage();
+ method public boolean isAllowUsingExhaustedKeys();
+ method public boolean isAllowUsingExpiredKeys();
+ method public boolean isIncrementUseCount();
+ }
+
+ public static final class CredentialDataRequest.Builder {
+ ctor public CredentialDataRequest.Builder();
+ method @NonNull public android.security.identity.CredentialDataRequest build();
+ method @NonNull public android.security.identity.CredentialDataRequest.Builder setAllowUsingExhaustedKeys(boolean);
+ method @NonNull public android.security.identity.CredentialDataRequest.Builder setAllowUsingExpiredKeys(boolean);
+ method @NonNull public android.security.identity.CredentialDataRequest.Builder setDeviceSignedEntriesToRequest(@NonNull java.util.Map<java.lang.String,java.util.Collection<java.lang.String>>);
+ method @NonNull public android.security.identity.CredentialDataRequest.Builder setIncrementUseCount(boolean);
+ method @NonNull public android.security.identity.CredentialDataRequest.Builder setIssuerSignedEntriesToRequest(@NonNull java.util.Map<java.lang.String,java.util.Collection<java.lang.String>>);
+ method @NonNull public android.security.identity.CredentialDataRequest.Builder setReaderSignature(@NonNull byte[]);
+ method @NonNull public android.security.identity.CredentialDataRequest.Builder setRequestMessage(@NonNull byte[]);
+ }
+
+ public abstract class CredentialDataResult {
+ method @Nullable public abstract byte[] getDeviceMac();
+ method @NonNull public abstract byte[] getDeviceNameSpaces();
+ method @NonNull public abstract android.security.identity.CredentialDataResult.Entries getDeviceSignedEntries();
+ method @NonNull public abstract android.security.identity.CredentialDataResult.Entries getIssuerSignedEntries();
+ method @NonNull public abstract byte[] getStaticAuthenticationData();
+ }
+
+ public static interface CredentialDataResult.Entries {
+ method @Nullable public byte[] getEntry(@NonNull String, @NonNull String);
+ method @NonNull public java.util.Collection<java.lang.String> getEntryNames(@NonNull String);
+ method @NonNull public java.util.Collection<java.lang.String> getNamespaces();
+ method @NonNull public java.util.Collection<java.lang.String> getRetrievedEntryNames(@NonNull String);
+ method public int getStatus(@NonNull String, @NonNull String);
+ field public static final int STATUS_NOT_IN_REQUEST_MESSAGE = 3; // 0x3
+ field public static final int STATUS_NOT_REQUESTED = 2; // 0x2
+ field public static final int STATUS_NO_ACCESS_CONTROL_PROFILES = 6; // 0x6
+ field public static final int STATUS_NO_SUCH_ENTRY = 1; // 0x1
+ field public static final int STATUS_OK = 0; // 0x0
+ field public static final int STATUS_READER_AUTHENTICATION_FAILED = 5; // 0x5
+ field public static final int STATUS_USER_AUTHENTICATION_FAILED = 4; // 0x4
+ }
+
public class DocTypeNotSupportedException extends android.security.identity.IdentityCredentialException {
ctor public DocTypeNotSupportedException(@NonNull String);
ctor public DocTypeNotSupportedException(@NonNull String, @NonNull Throwable);
@@ -37553,19 +37608,19 @@
}
public abstract class IdentityCredential {
- method @NonNull public abstract java.security.KeyPair createEphemeralKeyPair();
- method @NonNull public abstract byte[] decryptMessageFromReader(@NonNull byte[]) throws android.security.identity.MessageDecryptionException;
+ method @Deprecated @NonNull public abstract java.security.KeyPair createEphemeralKeyPair();
+ method @Deprecated @NonNull public abstract byte[] decryptMessageFromReader(@NonNull byte[]) throws android.security.identity.MessageDecryptionException;
method @NonNull public byte[] delete(@NonNull byte[]);
- method @NonNull public abstract byte[] encryptMessageToReader(@NonNull byte[]);
+ method @Deprecated @NonNull public abstract byte[] encryptMessageToReader(@NonNull byte[]);
method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getAuthKeysNeedingCertification();
method @NonNull public abstract int[] getAuthenticationDataUsageCount();
method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getCredentialKeyCertificateChain();
- method @NonNull public abstract android.security.identity.ResultData getEntries(@Nullable byte[], @NonNull java.util.Map<java.lang.String,java.util.Collection<java.lang.String>>, @Nullable byte[], @Nullable byte[]) throws android.security.identity.EphemeralPublicKeyNotFoundException, android.security.identity.InvalidReaderSignatureException, android.security.identity.InvalidRequestMessageException, android.security.identity.NoAuthenticationKeyAvailableException, android.security.identity.SessionTranscriptMismatchException;
+ method @Deprecated @NonNull public abstract android.security.identity.ResultData getEntries(@Nullable byte[], @NonNull java.util.Map<java.lang.String,java.util.Collection<java.lang.String>>, @Nullable byte[], @Nullable byte[]) throws android.security.identity.EphemeralPublicKeyNotFoundException, android.security.identity.InvalidReaderSignatureException, android.security.identity.InvalidRequestMessageException, android.security.identity.NoAuthenticationKeyAvailableException, android.security.identity.SessionTranscriptMismatchException;
method @NonNull public byte[] proveOwnership(@NonNull byte[]);
- method public abstract void setAllowUsingExhaustedKeys(boolean);
- method public void setAllowUsingExpiredKeys(boolean);
+ method @Deprecated public abstract void setAllowUsingExhaustedKeys(boolean);
+ method @Deprecated public void setAllowUsingExpiredKeys(boolean);
method public abstract void setAvailableAuthenticationKeys(int, int);
- method public abstract void setReaderEphemeralPublicKey(@NonNull java.security.PublicKey) throws java.security.InvalidKeyException;
+ method @Deprecated public abstract void setReaderEphemeralPublicKey(@NonNull java.security.PublicKey) throws java.security.InvalidKeyException;
method @Deprecated public abstract void storeStaticAuthenticationData(@NonNull java.security.cert.X509Certificate, @NonNull byte[]) throws android.security.identity.UnknownAuthenticationKeyException;
method public void storeStaticAuthenticationData(@NonNull java.security.cert.X509Certificate, @NonNull java.time.Instant, @NonNull byte[]) throws android.security.identity.UnknownAuthenticationKeyException;
method @NonNull public byte[] update(@NonNull android.security.identity.PersonalizationData);
@@ -37578,6 +37633,7 @@
public abstract class IdentityCredentialStore {
method @NonNull public abstract android.security.identity.WritableIdentityCredential createCredential(@NonNull String, @NonNull String) throws android.security.identity.AlreadyPersonalizedException, android.security.identity.DocTypeNotSupportedException;
+ method @NonNull public android.security.identity.PresentationSession createPresentationSession(int) throws android.security.identity.CipherSuiteNotSupportedException;
method @Deprecated @Nullable public abstract byte[] deleteCredentialByName(@NonNull String);
method @Nullable public abstract android.security.identity.IdentityCredential getCredentialByName(@NonNull String, int) throws android.security.identity.CipherSuiteNotSupportedException;
method @Nullable public static android.security.identity.IdentityCredentialStore getDirectAccessInstance(@NonNull android.content.Context);
@@ -37616,22 +37672,29 @@
method @NonNull public android.security.identity.PersonalizationData.Builder putEntry(@NonNull String, @NonNull String, @NonNull java.util.Collection<android.security.identity.AccessControlProfileId>, @NonNull byte[]);
}
- public abstract class ResultData {
- method @NonNull public abstract byte[] getAuthenticatedData();
- method @Nullable public abstract byte[] getEntry(@NonNull String, @NonNull String);
- method @Nullable public abstract java.util.Collection<java.lang.String> getEntryNames(@NonNull String);
- method @Nullable public abstract byte[] getMessageAuthenticationCode();
- method @NonNull public abstract java.util.Collection<java.lang.String> getNamespaces();
- method @Nullable public abstract java.util.Collection<java.lang.String> getRetrievedEntryNames(@NonNull String);
- method @NonNull public abstract byte[] getStaticAuthenticationData();
- method public abstract int getStatus(@NonNull String, @NonNull String);
- field public static final int STATUS_NOT_IN_REQUEST_MESSAGE = 3; // 0x3
- field public static final int STATUS_NOT_REQUESTED = 2; // 0x2
- field public static final int STATUS_NO_ACCESS_CONTROL_PROFILES = 6; // 0x6
- field public static final int STATUS_NO_SUCH_ENTRY = 1; // 0x1
- field public static final int STATUS_OK = 0; // 0x0
- field public static final int STATUS_READER_AUTHENTICATION_FAILED = 5; // 0x5
- field public static final int STATUS_USER_AUTHENTICATION_FAILED = 4; // 0x4
+ public abstract class PresentationSession {
+ method @Nullable public abstract android.security.identity.CredentialDataResult getCredentialData(@NonNull String, @NonNull android.security.identity.CredentialDataRequest) throws android.security.identity.EphemeralPublicKeyNotFoundException, android.security.identity.InvalidReaderSignatureException, android.security.identity.InvalidRequestMessageException, android.security.identity.NoAuthenticationKeyAvailableException;
+ method @NonNull public abstract java.security.KeyPair getEphemeralKeyPair();
+ method public abstract void setReaderEphemeralPublicKey(@NonNull java.security.PublicKey) throws java.security.InvalidKeyException;
+ method public abstract void setSessionTranscript(@NonNull byte[]);
+ }
+
+ @Deprecated public abstract class ResultData {
+ method @Deprecated @NonNull public abstract byte[] getAuthenticatedData();
+ method @Deprecated @Nullable public abstract byte[] getEntry(@NonNull String, @NonNull String);
+ method @Deprecated @Nullable public abstract java.util.Collection<java.lang.String> getEntryNames(@NonNull String);
+ method @Deprecated @Nullable public abstract byte[] getMessageAuthenticationCode();
+ method @Deprecated @NonNull public abstract java.util.Collection<java.lang.String> getNamespaces();
+ method @Deprecated @Nullable public abstract java.util.Collection<java.lang.String> getRetrievedEntryNames(@NonNull String);
+ method @Deprecated @NonNull public abstract byte[] getStaticAuthenticationData();
+ method @Deprecated public abstract int getStatus(@NonNull String, @NonNull String);
+ field @Deprecated public static final int STATUS_NOT_IN_REQUEST_MESSAGE = 3; // 0x3
+ field @Deprecated public static final int STATUS_NOT_REQUESTED = 2; // 0x2
+ field @Deprecated public static final int STATUS_NO_ACCESS_CONTROL_PROFILES = 6; // 0x6
+ field @Deprecated public static final int STATUS_NO_SUCH_ENTRY = 1; // 0x1
+ field @Deprecated public static final int STATUS_OK = 0; // 0x0
+ field @Deprecated public static final int STATUS_READER_AUTHENTICATION_FAILED = 5; // 0x5
+ field @Deprecated public static final int STATUS_USER_AUTHENTICATION_FAILED = 4; // 0x4
}
public class SessionTranscriptMismatchException extends android.security.identity.IdentityCredentialException {
@@ -41254,6 +41317,7 @@
field public static final int EPDG_ADDRESS_PCO = 2; // 0x2
field public static final int EPDG_ADDRESS_PLMN = 1; // 0x1
field public static final int EPDG_ADDRESS_STATIC = 0; // 0x0
+ field public static final int EPDG_ADDRESS_VISITED_COUNTRY = 4; // 0x4
field public static final int ID_TYPE_FQDN = 2; // 0x2
field public static final int ID_TYPE_KEY_ID = 11; // 0xb
field public static final int ID_TYPE_RFC822_ADDR = 3; // 0x3
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index d13170bf..b380e6d 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -71,6 +71,14 @@
field public static final String TEST_NETWORK_SERVICE = "test_network";
}
+ public class Intent implements java.lang.Cloneable android.os.Parcelable {
+ field public static final String ACTION_SETTING_RESTORED = "android.os.action.SETTING_RESTORED";
+ field public static final String EXTRA_SETTING_NAME = "setting_name";
+ field public static final String EXTRA_SETTING_NEW_VALUE = "new_value";
+ field public static final String EXTRA_SETTING_PREVIOUS_VALUE = "previous_value";
+ field public static final String EXTRA_SETTING_RESTORED_FROM_SDK_INT = "restored_from_sdk_int";
+ }
+
}
package android.content.pm {
@@ -127,6 +135,7 @@
public final class BtProfileConnectionInfo implements android.os.Parcelable {
method @NonNull public static android.media.BtProfileConnectionInfo a2dpInfo(boolean, int);
+ method @NonNull public static android.media.BtProfileConnectionInfo a2dpSinkInfo(int);
method public int describeContents();
method public boolean getIsLeOutput();
method public int getProfile();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 8ace816..8556011 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -138,6 +138,7 @@
field public static final String MANAGE_APP_PREDICTIONS = "android.permission.MANAGE_APP_PREDICTIONS";
field public static final String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
field public static final String MANAGE_AUTO_FILL = "android.permission.MANAGE_AUTO_FILL";
+ field public static final String MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED = "android.permission.MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED";
field public static final String MANAGE_CARRIER_OEM_UNLOCK_STATE = "android.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE";
field public static final String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
field public static final String MANAGE_CONTENT_CAPTURE = "android.permission.MANAGE_CONTENT_CAPTURE";
@@ -5880,6 +5881,7 @@
public static final class TvInputManager.Hardware {
method public void overrideAudioSink(int, String, int, int, int);
+ method public void overrideAudioSink(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) int, int, int);
method public void setStreamVolume(float);
method public boolean setSurface(android.view.Surface, android.media.tv.TvStreamConfig);
}
@@ -8517,6 +8519,7 @@
field public static final int EVENT_UNSPECIFIED = 0; // 0x0
field public static final int REASON_ACCOUNT_TRANSFER = 104; // 0x68
field public static final int REASON_ACTIVITY_RECOGNITION = 103; // 0x67
+ field public static final int REASON_BLUETOOTH_BROADCAST = 203; // 0xcb
field public static final int REASON_GEOFENCING = 100; // 0x64
field public static final int REASON_LOCATION_PROVIDER = 312; // 0x138
field public static final int REASON_OTHER = 1; // 0x1
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index c6c64b0..f94ee85 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -28,8 +28,7 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.app.PropertyInvalidatedCache;
+import android.annotation.SystemApi; //import android.app.PropertyInvalidatedCache;
import android.bluetooth.BluetoothDevice.Transport;
import android.bluetooth.BluetoothProfile.ConnectionPolicy;
import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission;
@@ -676,14 +675,15 @@
"android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED";
/** The profile is in disconnected state */
- public static final int STATE_DISCONNECTED = BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTED;
+ public static final int STATE_DISCONNECTED =
+ 0; //BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTED;
/** The profile is in connecting state */
- public static final int STATE_CONNECTING = BluetoothProtoEnums.CONNECTION_STATE_CONNECTING;
+ public static final int STATE_CONNECTING = 1; //BluetoothProtoEnums.CONNECTION_STATE_CONNECTING;
/** The profile is in connected state */
- public static final int STATE_CONNECTED = BluetoothProtoEnums.CONNECTION_STATE_CONNECTED;
+ public static final int STATE_CONNECTED = 2; //BluetoothProtoEnums.CONNECTION_STATE_CONNECTED;
/** The profile is in disconnecting state */
public static final int STATE_DISCONNECTING =
- BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTING;
+ 3; //BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTING;
/** @hide */
public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager";
@@ -1044,6 +1044,7 @@
return false;
}
+ /*
private static final String BLUETOOTH_GET_STATE_CACHE_PROPERTY = "cache_key.bluetooth.get_state";
private final PropertyInvalidatedCache<Void, Integer> mBluetoothGetStateCache =
@@ -1059,17 +1060,22 @@
}
}
};
+ */
/** @hide */
+ /*
@RequiresNoPermission
public void disableBluetoothGetStateCache() {
mBluetoothGetStateCache.disableLocal();
}
+ */
/** @hide */
+ /*
public static void invalidateBluetoothGetStateCache() {
PropertyInvalidatedCache.invalidateCache(BLUETOOTH_GET_STATE_CACHE_PROPERTY);
}
+ */
/**
* Fetch the current bluetooth state. If the service is down, return
@@ -1081,14 +1087,12 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- state = mBluetoothGetStateCache.query(null);
+ //state = mBluetoothGetStateCache.query(null);
+ state = mService.getState();
}
- } catch (RuntimeException e) {
- if (e.getCause() instanceof RemoteException) {
- Log.e(TAG, "", e.getCause());
- } else {
- throw e;
- }
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ e.rethrowFromSystemServer();
} finally {
mServiceLock.readLock().unlock();
}
@@ -2100,6 +2104,7 @@
}
}
+ /*
private static final String BLUETOOTH_FILTERING_CACHE_PROPERTY =
"cache_key.bluetooth.is_offloaded_filtering_supported";
private final PropertyInvalidatedCache<Void, Boolean> mBluetoothFilteringCache =
@@ -2122,17 +2127,22 @@
}
};
+ */
/** @hide */
+ /*
@RequiresNoPermission
public void disableIsOffloadedFilteringSupportedCache() {
mBluetoothFilteringCache.disableLocal();
}
+ */
/** @hide */
+ /*
public static void invalidateIsOffloadedFilteringSupportedCache() {
PropertyInvalidatedCache.invalidateCache(BLUETOOTH_FILTERING_CACHE_PROPERTY);
}
+ */
/**
* Return true if offloaded filters are supported
@@ -2145,7 +2155,18 @@
if (!getLeAccess()) {
return false;
}
- return mBluetoothFilteringCache.query(null);
+ //return mBluetoothFilteringCache.query(null);
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) {
+ return mService.isOffloadedFilteringSupported();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return false;
}
/**
@@ -2551,15 +2572,13 @@
return supportedProfiles;
}
+ /*
private static final String BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY =
"cache_key.bluetooth.get_adapter_connection_state";
private final PropertyInvalidatedCache<Void, Integer>
mBluetoothGetAdapterConnectionStateCache =
new PropertyInvalidatedCache<Void, Integer> (
8, BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY) {
- /**
- * This method must not be called when mService is null.
- */
@Override
@SuppressLint("AndroidFrameworkRequiresPermission")
protected Integer recompute(Void query) {
@@ -2570,18 +2589,23 @@
}
}
};
+ */
/** @hide */
+ /*
@RequiresNoPermission
public void disableGetAdapterConnectionStateCache() {
mBluetoothGetAdapterConnectionStateCache.disableLocal();
}
+ */
/** @hide */
+ /*
public static void invalidateGetAdapterConnectionStateCache() {
PropertyInvalidatedCache.invalidateCache(
BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY);
}
+ */
/**
* Get the current connection state of the local Bluetooth adapter.
@@ -2605,20 +2629,18 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mBluetoothGetAdapterConnectionStateCache.query(null);
+ return mService.getAdapterConnectionState();
}
- } catch (RuntimeException e) {
- if (e.getCause() instanceof RemoteException) {
- Log.e(TAG, "getConnectionState:", e.getCause());
- } else {
- throw e;
- }
+ //return mBluetoothGetAdapterConnectionStateCache.query(null);
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to getConnectionState, error: ", e);
} finally {
mServiceLock.readLock().unlock();
}
return BluetoothAdapter.STATE_DISCONNECTED;
}
+ /*
private static final String BLUETOOTH_PROFILE_CACHE_PROPERTY =
"cache_key.bluetooth.get_profile_connection_state";
private final PropertyInvalidatedCache<Integer, Integer>
@@ -2646,17 +2668,22 @@
query);
}
};
+ */
/** @hide */
+ /*
@RequiresNoPermission
public void disableGetProfileConnectionStateCache() {
mGetProfileConnectionStateCache.disableLocal();
}
+ */
/** @hide */
+ /*
public static void invalidateGetProfileConnectionStateCache() {
PropertyInvalidatedCache.invalidateCache(BLUETOOTH_PROFILE_CACHE_PROPERTY);
}
+ */
/**
* Get the current connection state of a profile.
@@ -2678,7 +2705,18 @@
if (getState() != STATE_ON) {
return BluetoothProfile.STATE_DISCONNECTED;
}
- return mGetProfileConnectionStateCache.query(new Integer(profile));
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) {
+ mService.getProfileConnectionState(profile);
+ }
+ //return mGetProfileConnectionStateCache.query(new Integer(profile));
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to getProfileConnectionState, error: ", e);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return BluetoothProfile.STATE_DISCONNECTED;
}
/**
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 93f0268..1edf5cc 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -23,8 +23,7 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.app.PropertyInvalidatedCache;
+import android.annotation.SystemApi; //import android.app.PropertyInvalidatedCache;
import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
import android.bluetooth.annotations.RequiresBluetoothScanPermission;
@@ -1597,6 +1596,7 @@
return false;
}
+ /*
private static final String BLUETOOTH_BONDING_CACHE_PROPERTY =
"cache_key.bluetooth.get_bond_state";
private final PropertyInvalidatedCache<BluetoothDevice, Integer> mBluetoothBondCache =
@@ -1612,16 +1612,19 @@
}
}
};
+ */
/** @hide */
- public void disableBluetoothGetBondStateCache() {
+ /* public void disableBluetoothGetBondStateCache() {
mBluetoothBondCache.disableLocal();
- }
+ } */
/** @hide */
+ /*
public static void invalidateBluetoothGetBondStateCache() {
PropertyInvalidatedCache.invalidateCache(BLUETOOTH_BONDING_CACHE_PROPERTY);
}
+ */
/**
* Get the bond state of the remote device.
@@ -1643,13 +1646,11 @@
return BOND_NONE;
}
try {
- return mBluetoothBondCache.query(this);
- } catch (RuntimeException e) {
- if (e.getCause() instanceof RemoteException) {
- Log.e(TAG, "", e);
- } else {
- throw e;
- }
+ //return mBluetoothBondCache.query(this);
+ return sService.getBondState(this, mAttributionSource);
+ } catch (RemoteException e) {
+ Log.e(TAG, "failed to ", e);
+ e.rethrowFromSystemServer();
}
return BOND_NONE;
}
diff --git a/core/java/android/bluetooth/OWNERS b/core/java/android/bluetooth/OWNERS
index fbee577..8e9d7b7 100644
--- a/core/java/android/bluetooth/OWNERS
+++ b/core/java/android/bluetooth/OWNERS
@@ -1,6 +1,4 @@
# Bug component: 27441
-rahulsabnis@google.com
sattiraju@google.com
-siyuanh@google.com
-zachoverflow@google.com
+baligh@google.com
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9659df6..8a5e097 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4206,9 +4206,9 @@
* restored from (corresponds to {@link android.os.Build.VERSION#SDK_INT}). The first three
* values are represented as strings, the fourth one as int.
*
- * <p>This broadcast is sent only for settings provider entries known to require special handling
- * around restore time. These entries are found in the BROADCAST_ON_RESTORE table within
- * the provider's backup agent implementation.
+ * <p>This broadcast is sent only for settings provider entries known to require special
+ * handling around restore time to specific receivers. These entries are found in the
+ * BROADCAST_ON_RESTORE table within the provider's backup agent implementation.
*
* @see #EXTRA_SETTING_NAME
* @see #EXTRA_SETTING_PREVIOUS_VALUE
@@ -4216,15 +4216,46 @@
* @see #EXTRA_SETTING_RESTORED_FROM_SDK_INT
* {@hide}
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SuppressLint("ActionValue")
public static final String ACTION_SETTING_RESTORED = "android.os.action.SETTING_RESTORED";
- /** {@hide} */
+ /**
+ * String intent extra to be used with {@link ACTION_SETTING_RESTORED}.
+ * Contain the name of the restored setting.
+ * {@hide}
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SuppressLint("ActionValue")
public static final String EXTRA_SETTING_NAME = "setting_name";
- /** {@hide} */
+
+ /**
+ * String intent extra to be used with {@link ACTION_SETTING_RESTORED}.
+ * Contain the value of the {@link EXTRA_SETTING_NAME} settings entry prior to the restore
+ * operation.
+ * {@hide}
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SuppressLint("ActionValue")
public static final String EXTRA_SETTING_PREVIOUS_VALUE = "previous_value";
- /** {@hide} */
+
+ /**
+ * String intent extra to be used with {@link ACTION_SETTING_RESTORED}.
+ * Contain the value of the {@link EXTRA_SETTING_NAME} settings entry being restored.
+ * {@hide}
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SuppressLint("ActionValue")
public static final String EXTRA_SETTING_NEW_VALUE = "new_value";
- /** {@hide} */
+
+ /**
+ * Int intent extra to be used with {@link ACTION_SETTING_RESTORED}.
+ * Contain the version of the SDK that the setting has been restored from (corresponds to
+ * {@link android.os.Build.VERSION#SDK_INT}).
+ * {@hide}
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SuppressLint("ActionValue")
public static final String EXTRA_SETTING_RESTORED_FROM_SDK_INT = "restored_from_sdk_int";
/**
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 2ed00b5..7cd7e7ac 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2485,6 +2485,8 @@
* API shipped in Android 11.
* <li><code>202101</code>: corresponds to the features included in the Identity Credential
* API shipped in Android 12.
+ * <li><code>202201</code>: corresponds to the features included in the Identity Credential
+ * API shipped in Android 13.
* </ul>
*/
@SdkConstant(SdkConstantType.FEATURE)
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index c8c122d..9fb70d6 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -38,6 +38,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.security.identity.IdentityCredential;
+import android.security.identity.PresentationSession;
import android.security.keystore.KeyProperties;
import android.text.TextUtils;
import android.util.Log;
@@ -653,8 +654,8 @@
/**
* A wrapper class for the cryptographic operations supported by BiometricPrompt.
*
- * <p>Currently the framework supports {@link Signature}, {@link Cipher}, {@link Mac}, and
- * {@link IdentityCredential}.
+ * <p>Currently the framework supports {@link Signature}, {@link Cipher}, {@link Mac},
+ * {@link IdentityCredential}, and {@link PresentationSession}.
*
* <p>Cryptographic operations in Android can be split into two categories: auth-per-use and
* time-based. This is specified during key creation via the timeout parameter of the
@@ -684,10 +685,21 @@
super(mac);
}
+ /**
+ * Create from a {@link IdentityCredential} object.
+ *
+ * @param credential a {@link IdentityCredential} object.
+ * @deprecated Use {@link PresentationSession} instead of {@link IdentityCredential}.
+ */
+ @Deprecated
public CryptoObject(@NonNull IdentityCredential credential) {
super(credential);
}
+ public CryptoObject(@NonNull PresentationSession session) {
+ super(session);
+ }
+
/**
* Get {@link Signature} object.
* @return {@link Signature} object or null if this doesn't contain one.
@@ -715,10 +727,20 @@
/**
* Get {@link IdentityCredential} object.
* @return {@link IdentityCredential} object or null if this doesn't contain one.
+ * @deprecated Use {@link PresentationSession} instead of {@link IdentityCredential}.
*/
+ @Deprecated
public @Nullable IdentityCredential getIdentityCredential() {
return super.getIdentityCredential();
}
+
+ /**
+ * Get {@link PresentationSession} object.
+ * @return {@link PresentationSession} object or null if this doesn't contain one.
+ */
+ public @Nullable PresentationSession getPresentationSession() {
+ return super.getPresentationSession();
+ }
}
/**
diff --git a/core/java/android/hardware/biometrics/CryptoObject.java b/core/java/android/hardware/biometrics/CryptoObject.java
index 7648cf2..d415706 100644
--- a/core/java/android/hardware/biometrics/CryptoObject.java
+++ b/core/java/android/hardware/biometrics/CryptoObject.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.security.identity.IdentityCredential;
+import android.security.identity.PresentationSession;
import android.security.keystore2.AndroidKeyStoreProvider;
import java.security.Signature;
@@ -27,8 +28,8 @@
/**
* A wrapper class for the crypto objects supported by BiometricPrompt and FingerprintManager.
- * Currently the framework supports {@link Signature}, {@link Cipher}, {@link Mac} and
- * {@link IdentityCredential} objects.
+ * Currently the framework supports {@link Signature}, {@link Cipher}, {@link Mac},
+ * {@link IdentityCredential}, and {@link PresentationSession} objects.
* @hide
*/
public class CryptoObject {
@@ -46,10 +47,21 @@
mCrypto = mac;
}
+ /**
+ * Create from a {@link IdentityCredential} object.
+ *
+ * @param credential a {@link IdentityCredential} object.
+ * @deprecated Use {@link PresentationSession} instead of {@link IdentityCredential}.
+ */
+ @Deprecated
public CryptoObject(@NonNull IdentityCredential credential) {
mCrypto = credential;
}
+ public CryptoObject(@NonNull PresentationSession session) {
+ mCrypto = session;
+ }
+
/**
* Get {@link Signature} object.
* @return {@link Signature} object or null if this doesn't contain one.
@@ -77,12 +89,22 @@
/**
* Get {@link IdentityCredential} object.
* @return {@link IdentityCredential} object or null if this doesn't contain one.
+ * @deprecated Use {@link PresentationSession} instead of {@link IdentityCredential}.
*/
+ @Deprecated
public IdentityCredential getIdentityCredential() {
return mCrypto instanceof IdentityCredential ? (IdentityCredential) mCrypto : null;
}
/**
+ * Get {@link PresentationSession} object.
+ * @return {@link PresentationSession} object or null if this doesn't contain one.
+ */
+ public PresentationSession getPresentationSession() {
+ return mCrypto instanceof PresentationSession ? (PresentationSession) mCrypto : null;
+ }
+
+ /**
* @hide
* @return the opId associated with this object or 0 if none
*/
@@ -91,6 +113,8 @@
return 0;
} else if (mCrypto instanceof IdentityCredential) {
return ((IdentityCredential) mCrypto).getCredstoreOperationHandle();
+ } else if (mCrypto instanceof PresentationSession) {
+ return ((PresentationSession) mCrypto).getCredstoreOperationHandle();
}
return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto);
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index a3d595c..480923e 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -58,6 +58,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.security.identity.IdentityCredential;
+import android.security.identity.PresentationSession;
import android.util.Slog;
import android.view.Surface;
@@ -264,10 +265,21 @@
* Get {@link IdentityCredential} object.
* @return {@link IdentityCredential} object or null if this doesn't contain one.
* @hide
+ * @deprecated Use {@link PresentationSession} instead of {@link IdentityCredential}.
*/
+ @Deprecated
public IdentityCredential getIdentityCredential() {
return super.getIdentityCredential();
}
+
+ /**
+ * Get {@link PresentationSession} object.
+ * @return {@link PresentationSession} object or null if this doesn't contain one.
+ * @hide
+ */
+ public PresentationSession getPresentationSession() {
+ return super.getPresentationSession();
+ }
}
/**
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index f50aa99..147138e 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -69,6 +69,8 @@
int getMultipathPreference(in Network network);
+ SubscriptionPlan getSubscriptionPlan(in NetworkTemplate template);
+ void onStatsProviderWarningOrLimitReached();
SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage);
void setSubscriptionPlans(int subId, in SubscriptionPlan[] plans, String callingPackage);
String getSubscriptionPlansOwner(int subId);
diff --git a/core/java/android/net/InternalNetworkUpdateRequest.java b/core/java/android/net/InternalNetworkUpdateRequest.java
index 6f09383..f42c4b7 100644
--- a/core/java/android/net/InternalNetworkUpdateRequest.java
+++ b/core/java/android/net/InternalNetworkUpdateRequest.java
@@ -17,7 +17,6 @@
package android.net;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -27,7 +26,7 @@
public final class InternalNetworkUpdateRequest implements Parcelable {
@NonNull
private final StaticIpConfiguration mIpConfig;
- @Nullable
+ @NonNull
private final NetworkCapabilities mNetworkCapabilities;
@NonNull
@@ -37,20 +36,16 @@
@NonNull
public NetworkCapabilities getNetworkCapabilities() {
- return mNetworkCapabilities == null
- ? null : new NetworkCapabilities(mNetworkCapabilities);
+ return new NetworkCapabilities(mNetworkCapabilities);
}
/** @hide */
public InternalNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig,
- @Nullable final NetworkCapabilities networkCapabilities) {
+ @NonNull final NetworkCapabilities networkCapabilities) {
Objects.requireNonNull(ipConfig);
+ Objects.requireNonNull(networkCapabilities);
mIpConfig = new StaticIpConfiguration(ipConfig);
- if (null == networkCapabilities) {
- mNetworkCapabilities = null;
- } else {
- mNetworkCapabilities = new NetworkCapabilities(networkCapabilities);
- }
+ mNetworkCapabilities = new NetworkCapabilities(networkCapabilities);
}
private InternalNetworkUpdateRequest(@NonNull final Parcel source) {
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 7ebb646..426fc61 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -535,6 +535,46 @@
}
/**
+ * Get subscription plan for the given networkTemplate.
+ *
+ * @param template the networkTemplate to get the subscription plan for.
+ * @return the active {@link SubscriptionPlan} for the given template, or
+ * {@code null} if not found.
+ * @hide
+ */
+ @Nullable
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_STACK})
+ // @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public SubscriptionPlan getSubscriptionPlan(@NonNull NetworkTemplate template) {
+ try {
+ return mService.getSubscriptionPlan(template);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Notifies that the specified {@link NetworkStatsProvider} has reached its quota
+ * which was set through {@link NetworkStatsProvider#onSetLimit(String, long)} or
+ * {@link NetworkStatsProvider#onSetWarningAndLimit(String, long, long)}.
+ *
+ * @hide
+ */
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_STACK})
+ // @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public void onStatsProviderWarningOrLimitReached() {
+ try {
+ mService.onStatsProviderWarningOrLimitReached();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Resets network policy settings back to factory defaults.
*
* @hide
diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
index 5c28553..3193826 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -96,6 +96,141 @@
*/
public static final String NOTIFICATION_CHANNEL_VPN = "VPN";
+ /**
+ * Action sent in the intent when an error occurred.
+ *
+ * @hide
+ */
+ public static final String ACTION_VPN_MANAGER_ERROR = "android.net.action.VPN_MANAGER_ERROR";
+
+ /**
+ * An IKE protocol error. Codes are the codes from IkeProtocolException, RFC 7296.
+ *
+ * @hide
+ */
+ public static final String CATEGORY_ERROR_IKE = "android.net.category.ERROR_IKE";
+
+ /**
+ * User deactivated the VPN, either by turning it off or selecting a different VPN provider.
+ * The error code is always 0.
+ *
+ * @hide
+ */
+ public static final String CATEGORY_ERROR_USER_DEACTIVATED =
+ "android.net.category.ERROR_USER_DEACTIVATED";
+
+ /**
+ * Network error. Error codes are ERROR_CODE_NETWORK_*.
+ *
+ * @hide
+ */
+ public static final String CATEGORY_ERROR_NETWORK = "android.net.category.ERROR_NETWORK";
+
+ /**
+ * The key of the session that experienced this error, as returned by
+ * startProvisionedVpnProfileSession.
+ *
+ * @hide
+ */
+ public static final String EXTRA_SESSION_KEY = "android.net.extra.SESSION_KEY";
+
+ /**
+ * Extra for the Network object that was the underlying network at the time of the failure, or
+ * null if none.
+ *
+ * @hide
+ */
+ public static final String EXTRA_UNDERLYING_NETWORK = "android.net.extra.UNDERLYING_NETWORK";
+
+ /**
+ * The NetworkCapabilities of the underlying network.
+ *
+ * @hide
+ */
+ public static final String EXTRA_UNDERLYING_NETWORK_CAPABILITIES =
+ "android.net.extra.UNDERLYING_NETWORK_CAPABILITIES";
+
+ /**
+ * The LinkProperties of the underlying network.
+ *
+ * @hide
+ */
+ public static final String EXTRA_UNDERLYING_LINK_PROPERTIES =
+ "android.net.extra.UNDERLYING_LINK_PROPERTIES";
+
+ /**
+ * A long timestamp with SystemClock.elapsedRealtime base for when the event happened.
+ *
+ * @hide
+ */
+ public static final String EXTRA_TIMESTAMP = "android.net.extra.TIMESTAMP";
+
+ /**
+ * Extra for the error type. This is ERROR_NOT_RECOVERABLE or ERROR_RECOVERABLE.
+ *
+ * @hide
+ */
+ public static final String EXTRA_ERROR_TYPE = "android.net.extra.ERROR_TYPE";
+
+ /**
+ * Extra for the error code. The value will be 0 for CATEGORY_ERROR_USER_DEACTIVATED, one of
+ * ERROR_CODE_NETWORK_* for ERROR_CATEGORY_NETWORK or one of values defined in
+ * IkeProtocolException#ErrorType for CATEGORY_ERROR_IKE.
+ *
+ * @hide
+ */
+ public static final String EXTRA_ERROR_CODE = "android.net.extra.ERROR_CODE";
+
+ /**
+ * This error is fatal, e.g. the VPN was disabled or configuration error. The stack will not
+ * retry connection.
+ *
+ * @hide
+ */
+ public static final int ERROR_NOT_RECOVERABLE = 1;
+
+ /**
+ * The stack experienced an error but will retry with exponential backoff, e.g. network timeout.
+ *
+ * @hide
+ */
+ public static final int ERROR_RECOVERABLE = 2;
+
+ /**
+ * An error code to indicate that there was an UnknownHostException.
+ *
+ * @hide
+ */
+ public static final int ERROR_CODE_NETWORK_UNKNOWN_HOST = 0;
+
+ /**
+ * An error code to indicate that there is a SocketTimeoutException.
+ *
+ * @hide
+ */
+ public static final int ERROR_CODE_NETWORK_TIMEOUT = 1;
+
+ /**
+ * An error code to indicate that the connection is refused.
+ *
+ * @hide
+ */
+ public static final int ERROR_CODE_NETWORK_CONNECT = 2;
+
+ /**
+ * An error code to indicate the connection was reset. (e.g. SocketException)
+ *
+ * @hide
+ */
+ public static final int ERROR_CODE_NETWORK_CONNECTION_RESET = 3;
+
+ /**
+ * An error code to indicate that there is an IOException.
+ *
+ * @hide
+ */
+ public static final int ERROR_CODE_NETWORK_IO = 4;
+
/** @hide */
@IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM, TYPE_VPN_LEGACY,
TYPE_VPN_OEM})
diff --git a/core/java/android/net/annotations/PolicyDirection.java b/core/java/android/net/annotations/PolicyDirection.java
index febd9b4..3f7521a 100644
--- a/core/java/android/net/annotations/PolicyDirection.java
+++ b/core/java/android/net/annotations/PolicyDirection.java
@@ -24,10 +24,6 @@
/**
* IPsec traffic direction.
- *
- * <p>Mainline modules cannot reference hidden @IntDef. Moving this annotation to a separate class
- * to allow others to statically include it.
- *
* @hide
*/
@IntDef(value = {IpSecManager.DIRECTION_IN, IpSecManager.DIRECTION_OUT})
diff --git a/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java b/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java
index 125b573..69e6313 100644
--- a/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java
+++ b/core/java/android/net/vcn/VcnCellUnderlyingNetworkTemplate.java
@@ -63,13 +63,22 @@
private final int mOpportunisticMatchCriteria;
private VcnCellUnderlyingNetworkTemplate(
- int networkQuality,
int meteredMatchCriteria,
+ int minEntryUpstreamBandwidthKbps,
+ int minExitUpstreamBandwidthKbps,
+ int minEntryDownstreamBandwidthKbps,
+ int minExitDownstreamBandwidthKbps,
Set<String> allowedNetworkPlmnIds,
Set<Integer> allowedSpecificCarrierIds,
int roamingMatchCriteria,
int opportunisticMatchCriteria) {
- super(NETWORK_PRIORITY_TYPE_CELL, networkQuality, meteredMatchCriteria);
+ super(
+ NETWORK_PRIORITY_TYPE_CELL,
+ meteredMatchCriteria,
+ minEntryUpstreamBandwidthKbps,
+ minExitUpstreamBandwidthKbps,
+ minEntryDownstreamBandwidthKbps,
+ minExitDownstreamBandwidthKbps);
mAllowedNetworkPlmnIds = new ArraySet<>(allowedNetworkPlmnIds);
mAllowedSpecificCarrierIds = new ArraySet<>(allowedSpecificCarrierIds);
mRoamingMatchCriteria = roamingMatchCriteria;
@@ -109,9 +118,17 @@
@NonNull PersistableBundle in) {
Objects.requireNonNull(in, "PersistableBundle is null");
- final int networkQuality = in.getInt(NETWORK_QUALITY_KEY);
final int meteredMatchCriteria = in.getInt(METERED_MATCH_KEY);
+ final int minEntryUpstreamBandwidthKbps =
+ in.getInt(MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS);
+ final int minExitUpstreamBandwidthKbps =
+ in.getInt(MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS);
+ final int minEntryDownstreamBandwidthKbps =
+ in.getInt(MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS);
+ final int minExitDownstreamBandwidthKbps =
+ in.getInt(MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS);
+
final PersistableBundle plmnIdsBundle =
in.getPersistableBundle(ALLOWED_NETWORK_PLMN_IDS_KEY);
Objects.requireNonNull(plmnIdsBundle, "plmnIdsBundle is null");
@@ -131,8 +148,11 @@
final int opportunisticMatchCriteria = in.getInt(OPPORTUNISTIC_MATCH_KEY);
return new VcnCellUnderlyingNetworkTemplate(
- networkQuality,
meteredMatchCriteria,
+ minEntryUpstreamBandwidthKbps,
+ minExitUpstreamBandwidthKbps,
+ minEntryDownstreamBandwidthKbps,
+ minExitDownstreamBandwidthKbps,
allowedNetworkPlmnIds,
allowedSpecificCarrierIds,
roamingMatchCriteria,
@@ -243,7 +263,6 @@
/** This class is used to incrementally build VcnCellUnderlyingNetworkTemplate objects. */
public static final class Builder {
- private int mNetworkQuality = NETWORK_QUALITY_ANY;
private int mMeteredMatchCriteria = MATCH_ANY;
@NonNull private final Set<String> mAllowedNetworkPlmnIds = new ArraySet<>();
@@ -252,29 +271,15 @@
private int mRoamingMatchCriteria = MATCH_ANY;
private int mOpportunisticMatchCriteria = MATCH_ANY;
+ private int mMinEntryUpstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS;
+ private int mMinExitUpstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS;
+ private int mMinEntryDownstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS;
+ private int mMinExitDownstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS;
+
/** Construct a Builder object. */
public Builder() {}
/**
- * Set the required network quality to match this template.
- *
- * <p>Network quality is a aggregation of multiple signals that reflect the network link
- * metrics. For example, the network validation bit (see {@link
- * NetworkCapabilities#NET_CAPABILITY_VALIDATED}), estimated first hop transport bandwidth
- * and signal strength.
- *
- * @param networkQuality the required network quality. Defaults to NETWORK_QUALITY_ANY
- * @hide
- */
- @NonNull
- public Builder setNetworkQuality(@NetworkQuality int networkQuality) {
- validateNetworkQuality(networkQuality);
-
- mNetworkQuality = networkQuality;
- return this;
- }
-
- /**
* Set the matching criteria for metered networks.
*
* <p>A template where setMetered(MATCH_REQUIRED) will only match metered networks (one
@@ -369,12 +374,92 @@
return this;
}
+ /**
+ * Set the minimum upstream bandwidths that this template will match.
+ *
+ * <p>This template will not match a network that does not provide at least the bandwidth
+ * passed as the entry bandwidth, except in the case that the network is selected as the VCN
+ * Gateway Connection's underlying network, where it will continue to match until the
+ * bandwidth drops under the exit bandwidth.
+ *
+ * <p>The entry criteria MUST be greater than, or equal to the exit criteria to avoid the
+ * invalid case where a network fulfills the entry criteria, but at the same time fails the
+ * exit criteria.
+ *
+ * <p>Estimated bandwidth of a network is provided by the transport layer, and reported in
+ * {@link NetworkCapabilities}. The provided estimates will be used without modification.
+ *
+ * @param minEntryUpstreamBandwidthKbps the minimum accepted upstream bandwidth for networks
+ * that ARE NOT the already-selected underlying network, or {@code 0} to disable this
+ * requirement. Disabled by default.
+ * @param minExitUpstreamBandwidthKbps the minimum accepted upstream bandwidth for a network
+ * that IS the already-selected underlying network, or {@code 0} to disable this
+ * requirement. Disabled by default.
+ * @return this {@link Builder} instance, for chaining
+ */
+ @NonNull
+ // The getter for the two integers are separated, and in the superclass. Please see {@link
+ // VcnUnderlyingNetworkTemplate#getMinEntryUpstreamBandwidthKbps()} and {@link
+ // VcnUnderlyingNetworkTemplate#getMinExitUpstreamBandwidthKbps()}
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public Builder setMinUpstreamBandwidthKbps(
+ int minEntryUpstreamBandwidthKbps, int minExitUpstreamBandwidthKbps) {
+ validateMinBandwidthKbps(minEntryUpstreamBandwidthKbps, minExitUpstreamBandwidthKbps);
+
+ mMinEntryUpstreamBandwidthKbps = minEntryUpstreamBandwidthKbps;
+ mMinExitUpstreamBandwidthKbps = minExitUpstreamBandwidthKbps;
+
+ return this;
+ }
+
+ /**
+ * Set the minimum upstream bandwidths that this template will match.
+ *
+ * <p>This template will not match a network that does not provide at least the bandwidth
+ * passed as the entry bandwidth, except in the case that the network is selected as the VCN
+ * Gateway Connection's underlying network, where it will continue to match until the
+ * bandwidth drops under the exit bandwidth.
+ *
+ * <p>The entry criteria MUST be greater than, or equal to the exit criteria to avoid the
+ * invalid case where a network fulfills the entry criteria, but at the same time fails the
+ * exit criteria.
+ *
+ * <p>Estimated bandwidth of a network is provided by the transport layer, and reported in
+ * {@link NetworkCapabilities}. The provided estimates will be used without modification.
+ *
+ * @param minEntryDownstreamBandwidthKbps the minimum accepted downstream bandwidth for
+ * networks that ARE NOT the already-selected underlying network, or {@code 0} to
+ * disable this requirement. Disabled by default.
+ * @param minExitDownstreamBandwidthKbps the minimum accepted downstream bandwidth for a
+ * network that IS the already-selected underlying network, or {@code 0} to disable this
+ * requirement. Disabled by default.
+ * @return this {@link Builder} instance, for chaining
+ */
+ @NonNull
+ // The getter for the two integers are separated, and in the superclass. Please see {@link
+ // VcnUnderlyingNetworkTemplate#getMinEntryDownstreamBandwidthKbps()} and {@link
+ // VcnUnderlyingNetworkTemplate#getMinExitDownstreamBandwidthKbps()}
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public Builder setMinDownstreamBandwidthKbps(
+ int minEntryDownstreamBandwidthKbps, int minExitDownstreamBandwidthKbps) {
+ validateMinBandwidthKbps(
+ minEntryDownstreamBandwidthKbps, minExitDownstreamBandwidthKbps);
+
+ mMinEntryDownstreamBandwidthKbps = minEntryDownstreamBandwidthKbps;
+ mMinExitDownstreamBandwidthKbps = minExitDownstreamBandwidthKbps;
+
+ return this;
+ }
+
/** Build the VcnCellUnderlyingNetworkTemplate. */
@NonNull
public VcnCellUnderlyingNetworkTemplate build() {
return new VcnCellUnderlyingNetworkTemplate(
- mNetworkQuality,
mMeteredMatchCriteria,
+ mMinEntryUpstreamBandwidthKbps,
+ mMinExitUpstreamBandwidthKbps,
+ mMinEntryDownstreamBandwidthKbps,
+ mMinExitDownstreamBandwidthKbps,
mAllowedNetworkPlmnIds,
mAllowedSpecificCarrierIds,
mRoamingMatchCriteria,
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index 92956e8..a6830b7 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -17,7 +17,6 @@
import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
-import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK;
import static com.android.internal.annotations.VisibleForTesting.Visibility;
@@ -169,18 +168,15 @@
static {
DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add(
new VcnCellUnderlyingNetworkTemplate.Builder()
- .setNetworkQuality(NETWORK_QUALITY_OK)
.setOpportunistic(MATCH_REQUIRED)
.build());
DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add(
new VcnWifiUnderlyingNetworkTemplate.Builder()
- .setNetworkQuality(NETWORK_QUALITY_OK)
.build());
DEFAULT_UNDERLYING_NETWORK_TEMPLATES.add(
new VcnCellUnderlyingNetworkTemplate.Builder()
- .setNetworkQuality(NETWORK_QUALITY_OK)
.build());
}
diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkTemplate.java b/core/java/android/net/vcn/VcnUnderlyingNetworkTemplate.java
index 60fc936..3a9ca3e 100644
--- a/core/java/android/net/vcn/VcnUnderlyingNetworkTemplate.java
+++ b/core/java/android/net/vcn/VcnUnderlyingNetworkTemplate.java
@@ -48,23 +48,6 @@
/** @hide */
static final int NETWORK_PRIORITY_TYPE_CELL = 2;
- /** Denotes that any network quality is acceptable. @hide */
- public static final int NETWORK_QUALITY_ANY = 0;
- /** Denotes that network quality needs to be OK. @hide */
- public static final int NETWORK_QUALITY_OK = 100000;
-
- private static final SparseArray<String> NETWORK_QUALITY_TO_STRING_MAP = new SparseArray<>();
-
- static {
- NETWORK_QUALITY_TO_STRING_MAP.put(NETWORK_QUALITY_ANY, "NETWORK_QUALITY_ANY");
- NETWORK_QUALITY_TO_STRING_MAP.put(NETWORK_QUALITY_OK, "NETWORK_QUALITY_OK");
- }
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({NETWORK_QUALITY_OK, NETWORK_QUALITY_ANY})
- public @interface NetworkQuality {}
-
/**
* Used to configure the matching criteria of a network characteristic. This may include network
* capabilities, or cellular subscription information. Denotes that networks with or without the
@@ -103,44 +86,73 @@
private final int mNetworkPriorityType;
/** @hide */
- static final String NETWORK_QUALITY_KEY = "mNetworkQuality";
-
- private final int mNetworkQuality;
-
- /** @hide */
static final String METERED_MATCH_KEY = "mMeteredMatchCriteria";
private final int mMeteredMatchCriteria;
/** @hide */
+ public static final int DEFAULT_MIN_BANDWIDTH_KBPS = 0;
+
+ /** @hide */
+ static final String MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS_KEY = "mMinEntryUpstreamBandwidthKbps";
+
+ private final int mMinEntryUpstreamBandwidthKbps;
+
+ /** @hide */
+ static final String MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS_KEY = "mMinExitUpstreamBandwidthKbps";
+
+ private final int mMinExitUpstreamBandwidthKbps;
+
+ /** @hide */
+ static final String MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS_KEY =
+ "mMinEntryDownstreamBandwidthKbps";
+
+ private final int mMinEntryDownstreamBandwidthKbps;
+
+ /** @hide */
+ static final String MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS_KEY = "mMinExitDownstreamBandwidthKbps";
+
+ private final int mMinExitDownstreamBandwidthKbps;
+
+ /** @hide */
VcnUnderlyingNetworkTemplate(
- int networkPriorityType, int networkQuality, int meteredMatchCriteria) {
+ int networkPriorityType,
+ int meteredMatchCriteria,
+ int minEntryUpstreamBandwidthKbps,
+ int minExitUpstreamBandwidthKbps,
+ int minEntryDownstreamBandwidthKbps,
+ int minExitDownstreamBandwidthKbps) {
mNetworkPriorityType = networkPriorityType;
- mNetworkQuality = networkQuality;
mMeteredMatchCriteria = meteredMatchCriteria;
+ mMinEntryUpstreamBandwidthKbps = minEntryUpstreamBandwidthKbps;
+ mMinExitUpstreamBandwidthKbps = minExitUpstreamBandwidthKbps;
+ mMinEntryDownstreamBandwidthKbps = minEntryDownstreamBandwidthKbps;
+ mMinExitDownstreamBandwidthKbps = minExitDownstreamBandwidthKbps;
}
/** @hide */
- static void validateNetworkQuality(int networkQuality) {
+ static void validateMatchCriteria(int matchCriteria, String matchingCapability) {
Preconditions.checkArgument(
- networkQuality == NETWORK_QUALITY_ANY || networkQuality == NETWORK_QUALITY_OK,
- "Invalid networkQuality:" + networkQuality);
+ MATCH_CRITERIA_TO_STRING_MAP.contains(matchCriteria),
+ "Invalid matching criteria: " + matchCriteria + " for " + matchingCapability);
}
/** @hide */
- static void validateMatchCriteria(int meteredMatchCriteria, String matchingCapability) {
+ static void validateMinBandwidthKbps(int minEntryBandwidth, int minExitBandwidth) {
Preconditions.checkArgument(
- MATCH_CRITERIA_TO_STRING_MAP.contains(meteredMatchCriteria),
- "Invalid matching criteria: "
- + meteredMatchCriteria
- + " for "
- + matchingCapability);
+ minEntryBandwidth >= 0, "Invalid minEntryBandwidth, must be >= 0");
+ Preconditions.checkArgument(
+ minExitBandwidth >= 0, "Invalid minExitBandwidth, must be >= 0");
+ Preconditions.checkArgument(
+ minEntryBandwidth >= minExitBandwidth,
+ "Minimum entry bandwidth must be >= exit bandwidth");
}
/** @hide */
protected void validate() {
- validateNetworkQuality(mNetworkQuality);
validateMatchCriteria(mMeteredMatchCriteria, "mMeteredMatchCriteria");
+ validateMinBandwidthKbps(mMinEntryUpstreamBandwidthKbps, mMinExitUpstreamBandwidthKbps);
+ validateMinBandwidthKbps(mMinEntryDownstreamBandwidthKbps, mMinExitDownstreamBandwidthKbps);
}
/** @hide */
@@ -168,15 +180,24 @@
final PersistableBundle result = new PersistableBundle();
result.putInt(NETWORK_PRIORITY_TYPE_KEY, mNetworkPriorityType);
- result.putInt(NETWORK_QUALITY_KEY, mNetworkQuality);
result.putInt(METERED_MATCH_KEY, mMeteredMatchCriteria);
+ result.putInt(MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS_KEY, mMinEntryUpstreamBandwidthKbps);
+ result.putInt(MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS_KEY, mMinExitUpstreamBandwidthKbps);
+ result.putInt(MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS_KEY, mMinEntryDownstreamBandwidthKbps);
+ result.putInt(MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS_KEY, mMinExitDownstreamBandwidthKbps);
return result;
}
@Override
public int hashCode() {
- return Objects.hash(mNetworkPriorityType, mNetworkQuality, mMeteredMatchCriteria);
+ return Objects.hash(
+ mNetworkPriorityType,
+ mMeteredMatchCriteria,
+ mMinEntryUpstreamBandwidthKbps,
+ mMinExitUpstreamBandwidthKbps,
+ mMinEntryDownstreamBandwidthKbps,
+ mMinExitDownstreamBandwidthKbps);
}
@Override
@@ -187,8 +208,11 @@
final VcnUnderlyingNetworkTemplate rhs = (VcnUnderlyingNetworkTemplate) other;
return mNetworkPriorityType == rhs.mNetworkPriorityType
- && mNetworkQuality == rhs.mNetworkQuality
- && mMeteredMatchCriteria == rhs.mMeteredMatchCriteria;
+ && mMeteredMatchCriteria == rhs.mMeteredMatchCriteria
+ && mMinEntryUpstreamBandwidthKbps == rhs.mMinEntryUpstreamBandwidthKbps
+ && mMinExitUpstreamBandwidthKbps == rhs.mMinExitUpstreamBandwidthKbps
+ && mMinEntryDownstreamBandwidthKbps == rhs.mMinEntryDownstreamBandwidthKbps
+ && mMinExitDownstreamBandwidthKbps == rhs.mMinExitDownstreamBandwidthKbps;
}
/** @hide */
@@ -197,8 +221,8 @@
}
/** @hide */
- static String getMatchCriteriaString(int meteredMatchCriteria) {
- return getNameString(MATCH_CRITERIA_TO_STRING_MAP, meteredMatchCriteria);
+ static String getMatchCriteriaString(int matchCriteria) {
+ return getNameString(MATCH_CRITERIA_TO_STRING_MAP, matchCriteria);
}
/** @hide */
@@ -213,34 +237,63 @@
pw.println(this.getClass().getSimpleName() + ":");
pw.increaseIndent();
- pw.println(
- "mNetworkQuality: "
- + getNameString(NETWORK_QUALITY_TO_STRING_MAP, mNetworkQuality));
pw.println("mMeteredMatchCriteria: " + getMatchCriteriaString(mMeteredMatchCriteria));
+ pw.println("mMinEntryUpstreamBandwidthKbps: " + mMinEntryUpstreamBandwidthKbps);
+ pw.println("mMinExitUpstreamBandwidthKbps: " + mMinExitUpstreamBandwidthKbps);
+ pw.println("mMinEntryDownstreamBandwidthKbps: " + mMinEntryDownstreamBandwidthKbps);
+ pw.println("mMinExitDownstreamBandwidthKbps: " + mMinExitDownstreamBandwidthKbps);
dumpTransportSpecificFields(pw);
pw.decreaseIndent();
}
/**
- * Retrieve the required network quality to match this template.
- *
- * @see Builder#setNetworkQuality(int)
- * @hide
- */
- @NetworkQuality
- public int getNetworkQuality() {
- return mNetworkQuality;
- }
-
- /**
* Return the matching criteria for metered networks.
*
* @see VcnWifiUnderlyingNetworkTemplate.Builder#setMetered(int)
* @see VcnCellUnderlyingNetworkTemplate.Builder#setMetered(int)
*/
- @MatchCriteria
public int getMetered() {
return mMeteredMatchCriteria;
}
+
+ /**
+ * Returns the minimum entry upstream bandwidth allowed by this template.
+ *
+ * @see VcnWifiUnderlyingNetworkTemplate.Builder#setMinUpstreamBandwidthKbps(int, int)
+ * @see VcnCellUnderlyingNetworkTemplate.Builder#setMinUpstreamBandwidthKbps(int, int)
+ */
+ public int getMinEntryUpstreamBandwidthKbps() {
+ return mMinEntryUpstreamBandwidthKbps;
+ }
+
+ /**
+ * Returns the minimum exit upstream bandwidth allowed by this template.
+ *
+ * @see VcnWifiUnderlyingNetworkTemplate.Builder#setMinUpstreamBandwidthKbps(int, int)
+ * @see VcnCellUnderlyingNetworkTemplate.Builder#setMinUpstreamBandwidthKbps(int, int)
+ */
+ public int getMinExitUpstreamBandwidthKbps() {
+ return mMinExitUpstreamBandwidthKbps;
+ }
+
+ /**
+ * Returns the minimum entry downstream bandwidth allowed by this template.
+ *
+ * @see VcnWifiUnderlyingNetworkTemplate.Builder#setMinDownstreamBandwidthKbps(int, int)
+ * @see VcnCellUnderlyingNetworkTemplate.Builder#setMinDownstreamBandwidthKbps(int, int)
+ */
+ public int getMinEntryDownstreamBandwidthKbps() {
+ return mMinEntryDownstreamBandwidthKbps;
+ }
+
+ /**
+ * Returns the minimum exit downstream bandwidth allowed by this template.
+ *
+ * @see VcnWifiUnderlyingNetworkTemplate.Builder#setMinDownstreamBandwidthKbps(int, int)
+ * @see VcnCellUnderlyingNetworkTemplate.Builder#setMinDownstreamBandwidthKbps(int, int)
+ */
+ public int getMinExitDownstreamBandwidthKbps() {
+ return mMinExitDownstreamBandwidthKbps;
+ }
}
diff --git a/core/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java b/core/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java
index 272ca9d..23a07ab 100644
--- a/core/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java
+++ b/core/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplate.java
@@ -46,8 +46,19 @@
@Nullable private final Set<String> mSsids;
private VcnWifiUnderlyingNetworkTemplate(
- int networkQuality, int meteredMatchCriteria, Set<String> ssids) {
- super(NETWORK_PRIORITY_TYPE_WIFI, networkQuality, meteredMatchCriteria);
+ int meteredMatchCriteria,
+ int minEntryUpstreamBandwidthKbps,
+ int minExitUpstreamBandwidthKbps,
+ int minEntryDownstreamBandwidthKbps,
+ int minExitDownstreamBandwidthKbps,
+ Set<String> ssids) {
+ super(
+ NETWORK_PRIORITY_TYPE_WIFI,
+ meteredMatchCriteria,
+ minEntryUpstreamBandwidthKbps,
+ minExitUpstreamBandwidthKbps,
+ minEntryDownstreamBandwidthKbps,
+ minExitDownstreamBandwidthKbps);
mSsids = new ArraySet<>(ssids);
validate();
@@ -75,15 +86,29 @@
@NonNull PersistableBundle in) {
Objects.requireNonNull(in, "PersistableBundle is null");
- final int networkQuality = in.getInt(NETWORK_QUALITY_KEY);
final int meteredMatchCriteria = in.getInt(METERED_MATCH_KEY);
+ final int minEntryUpstreamBandwidthKbps =
+ in.getInt(MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS);
+ final int minExitUpstreamBandwidthKbps =
+ in.getInt(MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS);
+ final int minEntryDownstreamBandwidthKbps =
+ in.getInt(MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS);
+ final int minExitDownstreamBandwidthKbps =
+ in.getInt(MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS_KEY, DEFAULT_MIN_BANDWIDTH_KBPS);
+
final PersistableBundle ssidsBundle = in.getPersistableBundle(SSIDS_KEY);
Objects.requireNonNull(ssidsBundle, "ssidsBundle is null");
final Set<String> ssids =
new ArraySet<String>(
PersistableBundleUtils.toList(ssidsBundle, STRING_DESERIALIZER));
- return new VcnWifiUnderlyingNetworkTemplate(networkQuality, meteredMatchCriteria, ssids);
+ return new VcnWifiUnderlyingNetworkTemplate(
+ meteredMatchCriteria,
+ minEntryUpstreamBandwidthKbps,
+ minExitUpstreamBandwidthKbps,
+ minEntryDownstreamBandwidthKbps,
+ minExitDownstreamBandwidthKbps,
+ ssids);
}
/** @hide */
@@ -137,33 +162,18 @@
/** This class is used to incrementally build VcnWifiUnderlyingNetworkTemplate objects. */
public static final class Builder {
- private int mNetworkQuality = NETWORK_QUALITY_ANY;
private int mMeteredMatchCriteria = MATCH_ANY;
@NonNull private final Set<String> mSsids = new ArraySet<>();
+ private int mMinEntryUpstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS;
+ private int mMinExitUpstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS;
+ private int mMinEntryDownstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS;
+ private int mMinExitDownstreamBandwidthKbps = DEFAULT_MIN_BANDWIDTH_KBPS;
+
/** Construct a Builder object. */
public Builder() {}
/**
- * Set the required network quality to match this template.
- *
- * <p>Network quality is a aggregation of multiple signals that reflect the network link
- * metrics. For example, the network validation bit (see {@link
- * NetworkCapabilities#NET_CAPABILITY_VALIDATED}), estimated first hop transport bandwidth
- * and signal strength.
- *
- * @param networkQuality the required network quality. Defaults to NETWORK_QUALITY_ANY
- * @hide
- */
- @NonNull
- public Builder setNetworkQuality(@NetworkQuality int networkQuality) {
- validateNetworkQuality(networkQuality);
-
- mNetworkQuality = networkQuality;
- return this;
- }
-
- /**
* Set the matching criteria for metered networks.
*
* <p>A template where setMetered(MATCH_REQUIRED) will only match metered networks (one
@@ -200,11 +210,93 @@
return this;
}
+ /**
+ * Set the minimum upstream bandwidths that this template will match.
+ *
+ * <p>This template will not match a network that does not provide at least the bandwidth
+ * passed as the entry bandwidth, except in the case that the network is selected as the VCN
+ * Gateway Connection's underlying network, where it will continue to match until the
+ * bandwidth drops under the exit bandwidth.
+ *
+ * <p>The entry criteria MUST be greater than, or equal to the exit criteria to avoid the
+ * invalid case where a network fulfills the entry criteria, but at the same time fails the
+ * exit criteria.
+ *
+ * <p>Estimated bandwidth of a network is provided by the transport layer, and reported in
+ * {@link NetworkCapabilities}. The provided estimates will be used without modification.
+ *
+ * @param minEntryUpstreamBandwidthKbps the minimum accepted upstream bandwidth for networks
+ * that ARE NOT the already-selected underlying network, or {@code 0} to disable this
+ * requirement. Disabled by default.
+ * @param minExitUpstreamBandwidthKbps the minimum accepted upstream bandwidth for a network
+ * that IS the already-selected underlying network, or {@code 0} to disable this
+ * requirement. Disabled by default.
+ * @return this {@link Builder} instance, for chaining
+ */
+ @NonNull
+ // The getter for the two integers are separated, and in the superclass. Please see {@link
+ // VcnUnderlyingNetworkTemplate#getMinEntryUpstreamBandwidthKbps()} and {@link
+ // VcnUnderlyingNetworkTemplate#getMinExitUpstreamBandwidthKbps()}
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public Builder setMinUpstreamBandwidthKbps(
+ int minEntryUpstreamBandwidthKbps, int minExitUpstreamBandwidthKbps) {
+ validateMinBandwidthKbps(minEntryUpstreamBandwidthKbps, minExitUpstreamBandwidthKbps);
+
+ mMinEntryUpstreamBandwidthKbps = minEntryUpstreamBandwidthKbps;
+ mMinExitUpstreamBandwidthKbps = minExitUpstreamBandwidthKbps;
+
+ return this;
+ }
+
+ /**
+ * Set the minimum upstream bandwidths that this template will match.
+ *
+ * <p>This template will not match a network that does not provide at least the bandwidth
+ * passed as the entry bandwidth, except in the case that the network is selected as the VCN
+ * Gateway Connection's underlying network, where it will continue to match until the
+ * bandwidth drops under the exit bandwidth.
+ *
+ * <p>The entry criteria MUST be greater than, or equal to the exit criteria to avoid the
+ * invalid case where a network fulfills the entry criteria, but at the same time fails the
+ * exit criteria.
+ *
+ * <p>Estimated bandwidth of a network is provided by the transport layer, and reported in
+ * {@link NetworkCapabilities}. The provided estimates will be used without modification.
+ *
+ * @param minEntryDownstreamBandwidthKbps the minimum accepted downstream bandwidth for
+ * networks that ARE NOT the already-selected underlying network, or {@code 0} to
+ * disable this requirement. Disabled by default.
+ * @param minExitDownstreamBandwidthKbps the minimum accepted downstream bandwidth for a
+ * network that IS the already-selected underlying network, or {@code 0} to disable this
+ * requirement. Disabled by default.
+ * @return this {@link Builder} instance, for chaining
+ */
+ @NonNull
+ // The getter for the two integers are separated, and in the superclass. Please see {@link
+ // VcnUnderlyingNetworkTemplate#getMinEntryDownstreamBandwidthKbps()} and {@link
+ // VcnUnderlyingNetworkTemplate#getMinExitDownstreamBandwidthKbps()}
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public Builder setMinDownstreamBandwidthKbps(
+ int minEntryDownstreamBandwidthKbps, int minExitDownstreamBandwidthKbps) {
+ validateMinBandwidthKbps(
+ minEntryDownstreamBandwidthKbps, minExitDownstreamBandwidthKbps);
+
+ mMinEntryDownstreamBandwidthKbps = minEntryDownstreamBandwidthKbps;
+ mMinExitDownstreamBandwidthKbps = minExitDownstreamBandwidthKbps;
+
+ return this;
+ }
+
/** Build the VcnWifiUnderlyingNetworkTemplate. */
@NonNull
public VcnWifiUnderlyingNetworkTemplate build() {
return new VcnWifiUnderlyingNetworkTemplate(
- mNetworkQuality, mMeteredMatchCriteria, mSsids);
+ mMeteredMatchCriteria,
+ mMinEntryUpstreamBandwidthKbps,
+ mMinExitUpstreamBandwidthKbps,
+ mMinEntryDownstreamBandwidthKbps,
+ mMinExitDownstreamBandwidthKbps,
+ mSsids);
}
}
}
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 9eaaa91..542de3f 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -131,6 +131,7 @@
mContext.getAttributionTag(), callback);
} catch (RemoteException ex) {
// system server crash
+ throw ex.rethrowFromSystemServer();
}
}
@@ -152,6 +153,7 @@
mSubscriptionChangedListenerMap.remove(listener);
} catch (RemoteException ex) {
// system server crash
+ throw ex.rethrowFromSystemServer();
}
}
@@ -194,6 +196,7 @@
mContext.getAttributionTag(), callback);
} catch (RemoteException ex) {
// system server crash
+ throw ex.rethrowFromSystemServer();
}
}
@@ -216,6 +219,7 @@
mOpportunisticSubscriptionChangedListenerMap.remove(listener);
} catch (RemoteException ex) {
// system server crash
+ throw ex.rethrowFromSystemServer();
}
}
@@ -304,6 +308,7 @@
sRegistry.notifyCarrierNetworkChange(active);
} catch (RemoteException ex) {
// system server crash
+ throw ex.rethrowFromSystemServer();
}
}
@@ -329,6 +334,7 @@
sRegistry.notifyCarrierNetworkChangeWithSubId(subscriptionId, active);
} catch (RemoteException ex) {
// system server crash
+ throw ex.rethrowFromSystemServer();
}
}
@@ -347,6 +353,7 @@
sRegistry.notifyCallState(slotIndex, subId, state, incomingNumber);
} catch (RemoteException ex) {
// system server crash
+ throw ex.rethrowFromSystemServer();
}
}
@@ -364,6 +371,7 @@
sRegistry.notifyCallStateForAllSubs(state, incomingNumber);
} catch (RemoteException ex) {
// system server crash
+ throw ex.rethrowFromSystemServer();
}
}
@@ -376,6 +384,7 @@
sRegistry.notifySubscriptionInfoChanged();
} catch (RemoteException ex) {
// system server crash
+ throw ex.rethrowFromSystemServer();
}
}
@@ -388,6 +397,7 @@
sRegistry.notifyOpportunisticSubscriptionInfoChanged();
} catch (RemoteException ex) {
// system server crash
+ throw ex.rethrowFromSystemServer();
}
}
@@ -404,6 +414,7 @@
sRegistry.notifyServiceStateForPhoneId(slotIndex, subId, state);
} catch (RemoteException ex) {
// system server crash
+ throw ex.rethrowFromSystemServer();
}
}
@@ -421,6 +432,7 @@
sRegistry.notifySignalStrengthForPhoneId(slotIndex, subId, signalStrength);
} catch (RemoteException ex) {
// system server crash
+ throw ex.rethrowFromSystemServer();
}
}
@@ -439,6 +451,7 @@
sRegistry.notifyMessageWaitingChangedForPhoneId(slotIndex, subId, msgWaitingInd);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -454,6 +467,7 @@
sRegistry.notifyCallForwardingChangedForSubscriber(subId, callForwardInd);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -469,6 +483,7 @@
sRegistry.notifyDataActivityForSubscriber(subId, dataActivityType);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -490,6 +505,7 @@
slotIndex, subId, preciseState);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -508,6 +524,7 @@
sRegistry.notifyCallQualityChanged(callQuality, slotIndex, subId, networkType);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -523,6 +540,7 @@
sRegistry.notifyEmergencyNumberList(slotIndex, subId);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -538,6 +556,7 @@
sRegistry.notifyOutgoingEmergencyCall(phoneId, subId, emergencyNumber);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -553,6 +572,7 @@
sRegistry.notifyOutgoingEmergencySms(phoneId, subId, emergencyNumber);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -570,6 +590,7 @@
sRegistry.notifyRadioPowerStateChanged(slotIndex, subId, radioPowerState);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -583,6 +604,7 @@
sRegistry.notifyPhoneCapabilityChanged(phoneCapability);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -615,6 +637,7 @@
SIM_ACTIVATION_TYPE_DATA, activationState);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -634,6 +657,7 @@
SIM_ACTIVATION_TYPE_VOICE, activationState);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -651,6 +675,7 @@
sRegistry.notifyUserMobileDataStateChangedForPhoneId(slotIndex, subId, state);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -669,6 +694,7 @@
sRegistry.notifyDisplayInfoChanged(slotIndex, subscriptionId, telephonyDisplayInfo);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -683,6 +709,7 @@
sRegistry.notifyImsDisconnectCause(subId, imsReasonInfo);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -698,6 +725,7 @@
sRegistry.notifySrvccStateChanged(subId, state);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -721,6 +749,7 @@
foregroundCallPreciseState, backgroundCallPreciseState);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -741,6 +770,7 @@
sRegistry.notifyDisconnectCause(slotIndex, subId, cause, preciseCause);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -755,6 +785,7 @@
sRegistry.notifyCellLocationForSubscriber(subId, cellLocation);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -769,7 +800,7 @@
try {
sRegistry.notifyCellInfoForSubscriber(subId, cellInfo);
} catch (RemoteException ex) {
-
+ throw ex.rethrowFromSystemServer();
}
}
@@ -781,7 +812,7 @@
try {
sRegistry.notifyActiveDataSubIdChanged(activeDataSubId);
} catch (RemoteException ex) {
-
+ throw ex.rethrowFromSystemServer();
}
}
@@ -814,6 +845,7 @@
sRegistry.notifyRegistrationFailed(slotIndex, subId, cellIdentity,
chosenPlmn, domain, causeCode, additionalCauseCode);
} catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
}
}
@@ -830,6 +862,7 @@
sRegistry.notifyBarringInfoChanged(slotIndex, subId, barringInfo);
} catch (RemoteException ex) {
// system server crash
+ throw ex.rethrowFromSystemServer();
}
}
@@ -846,6 +879,7 @@
sRegistry.notifyPhysicalChannelConfigForSubscriber(slotIndex, subId, configs);
} catch (RemoteException ex) {
// system server crash
+ throw ex.rethrowFromSystemServer();
}
}
@@ -862,6 +896,7 @@
sRegistry.notifyDataEnabled(slotIndex, subId, enabled, reason);
} catch (RemoteException ex) {
// system server crash
+ throw ex.rethrowFromSystemServer();
}
}
@@ -880,6 +915,7 @@
allowedNetworkType);
} catch (RemoteException ex) {
// system process is dead
+ throw ex.rethrowFromSystemServer();
}
}
@@ -895,6 +931,7 @@
sRegistry.notifyLinkCapacityEstimateChanged(slotIndex, subId, linkCapacityEstimateList);
} catch (RemoteException ex) {
// system server crash
+ throw ex.rethrowFromSystemServer();
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 0f1c6f3..270b5d6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -25,6 +25,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.usage.NetworkStatsManager;
import android.bluetooth.BluetoothActivityEnergyInfo;
import android.bluetooth.UidTraffic;
import android.compat.annotation.UnsupportedAppUsage;
@@ -36,7 +37,6 @@
import android.database.ContentObserver;
import android.hardware.usb.UsbManager;
import android.location.GnssSignalQuality;
-import android.net.INetworkStatsService;
import android.net.NetworkStats;
import android.net.Uri;
import android.net.wifi.WifiManager;
@@ -136,7 +136,9 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Queue;
+import java.util.Set;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
@@ -11539,19 +11541,11 @@
private NetworkStats mLastModemNetworkStats = new NetworkStats(0, -1);
@VisibleForTesting
- protected NetworkStats readNetworkStatsLocked(String[] ifaces) {
- try {
- if (!ArrayUtils.isEmpty(ifaces)) {
- INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
- if (statsService != null) {
- return statsService.getDetailedUidStats(ifaces);
- } else {
- Slog.e(TAG, "Failed to get networkStatsService ");
- }
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "failed to read network stats for ifaces: " + Arrays.toString(ifaces) + e);
+ protected NetworkStats readNetworkStatsLocked(@NonNull NetworkStatsManager networkStatsManager,
+ String[] ifaces) {
+ Objects.requireNonNull(networkStatsManager);
+ if (!ArrayUtils.isEmpty(ifaces)) {
+ return networkStatsManager.getDetailedUidStats(Set.of(ifaces));
}
return null;
}
@@ -11561,7 +11555,8 @@
* @param info The energy information from the WiFi controller.
*/
public void updateWifiState(@Nullable final WifiActivityEnergyInfo info,
- final long consumedChargeUC, long elapsedRealtimeMs, long uptimeMs) {
+ final long consumedChargeUC, long elapsedRealtimeMs, long uptimeMs,
+ @NonNull NetworkStatsManager networkStatsManager) {
if (DEBUG_ENERGY) {
Slog.d(TAG, "Updating wifi stats: " + Arrays.toString(mWifiIfaces));
}
@@ -11569,7 +11564,8 @@
// Grab a separate lock to acquire the network stats, which may do I/O.
NetworkStats delta = null;
synchronized (mWifiNetworkLock) {
- final NetworkStats latestStats = readNetworkStatsLocked(mWifiIfaces);
+ final NetworkStats latestStats = readNetworkStatsLocked(networkStatsManager,
+ mWifiIfaces);
if (latestStats != null) {
delta = NetworkStats.subtract(latestStats, mLastWifiNetworkStats, null, null,
mNetworkStatsPool.acquire());
@@ -11921,7 +11917,8 @@
* Distribute Cell radio energy info and network traffic to apps.
*/
public void noteModemControllerActivity(@Nullable final ModemActivityInfo activityInfo,
- final long consumedChargeUC, long elapsedRealtimeMs, long uptimeMs) {
+ final long consumedChargeUC, long elapsedRealtimeMs, long uptimeMs,
+ @NonNull NetworkStatsManager networkStatsManager) {
if (DEBUG_ENERGY) {
Slog.d(TAG, "Updating mobile radio stats with " + activityInfo);
}
@@ -11935,7 +11932,8 @@
// Grab a separate lock to acquire the network stats, which may do I/O.
NetworkStats delta = null;
synchronized (mModemNetworkLock) {
- final NetworkStats latestStats = readNetworkStatsLocked(mModemIfaces);
+ final NetworkStats latestStats = readNetworkStatsLocked(networkStatsManager,
+ mModemIfaces);
if (latestStats != null) {
delta = NetworkStats.subtract(latestStats, mLastModemNetworkStats, null, null,
mNetworkStatsPool.acquire());
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 2cfec4b..07b16ed 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -242,6 +242,7 @@
"audioflinger-aidl-cpp",
"av-types-aidl-cpp",
"android.hardware.camera.device@3.2",
+ "libandroid_net",
"libandroidicu",
"libbpf_android",
"libnetdbpf",
diff --git a/core/jni/android_server_NetworkManagementSocketTagger.cpp b/core/jni/android_server_NetworkManagementSocketTagger.cpp
index afad08a..1be1873 100644
--- a/core/jni/android_server_NetworkManagementSocketTagger.cpp
+++ b/core/jni/android_server_NetworkManagementSocketTagger.cpp
@@ -15,24 +15,23 @@
*/
#define LOG_TAG "NMST_QTagUidNative"
-#include <utils/Log.h>
-#include <nativehelper/JNIPlatformHelp.h>
-
-#include "jni.h"
-#include <utils/misc.h>
+#include <android/multinetwork.h>
#include <cutils/qtaguid.h>
-
#include <errno.h>
#include <fcntl.h>
-#include <sys/types.h>
+#include <nativehelper/JNIPlatformHelp.h>
#include <sys/socket.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+#include <utils/misc.h>
+
+#include "jni.h"
namespace android {
-static jint QTagUid_tagSocketFd(JNIEnv* env, jclass,
- jobject fileDescriptor,
- jint tagNum, jint uid) {
+static jint tagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor,
+ jint tagNum, jint uid) {
int userFd = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (env->ExceptionCheck()) {
@@ -40,15 +39,14 @@
return (jint)-1;
}
- int res = qtaguid_tagSocket(userFd, tagNum, uid);
+ int res = android_tag_socket_with_uid(userFd, tagNum, uid);
if (res < 0) {
return (jint)-errno;
}
return (jint)res;
}
-static jint QTagUid_untagSocketFd(JNIEnv* env, jclass,
- jobject fileDescriptor) {
+static jint untagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor) {
int userFd = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (env->ExceptionCheck()) {
@@ -56,16 +54,14 @@
return (jint)-1;
}
- int res = qtaguid_untagSocket(userFd);
+ int res = android_untag_socket(userFd);
if (res < 0) {
return (jint)-errno;
}
return (jint)res;
}
-static jint QTagUid_setCounterSet(JNIEnv* env, jclass,
- jint setNum, jint uid) {
-
+static jint setCounterSet(JNIEnv* env, jclass, jint setNum, jint uid) {
int res = qtaguid_setCounterSet(setNum, uid);
if (res < 0) {
return (jint)-errno;
@@ -73,9 +69,7 @@
return (jint)res;
}
-static jint QTagUid_deleteTagData(JNIEnv* env, jclass,
- jint tagNum, jint uid) {
-
+static jint deleteTagData(JNIEnv* env, jclass, jint tagNum, jint uid) {
int res = qtaguid_deleteTagData(tagNum, uid);
if (res < 0) {
return (jint)-errno;
@@ -84,10 +78,10 @@
}
static const JNINativeMethod gQTagUidMethods[] = {
- { "native_tagSocketFd", "(Ljava/io/FileDescriptor;II)I", (void*)QTagUid_tagSocketFd},
- { "native_untagSocketFd", "(Ljava/io/FileDescriptor;)I", (void*)QTagUid_untagSocketFd},
- { "native_setCounterSet", "(II)I", (void*)QTagUid_setCounterSet},
- { "native_deleteTagData", "(II)I", (void*)QTagUid_deleteTagData},
+ { "native_tagSocketFd", "(Ljava/io/FileDescriptor;II)I", (void*)tagSocketFd},
+ { "native_untagSocketFd", "(Ljava/io/FileDescriptor;)I", (void*)untagSocketFd},
+ { "native_setCounterSet", "(II)I", (void*)setCounterSet},
+ { "native_deleteTagData", "(II)I", (void*)deleteTagData},
};
int register_android_server_NetworkManagementSocketTagger(JNIEnv* env) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6ecfcec..c11502f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2114,8 +2114,9 @@
<permission android:name="android.permission.NFC_HANDOVER_STATUS"
android:protectionLevel="signature|privileged" />
- <!-- @hide Allows internal management of Bluetooth state when on wireless consent mode.
- <p>Not for use by third-party applications. -->
+ <!-- @SystemApi Allows internal management of Bluetooth state when on wireless consent mode.
+ <p>Not for use by third-party applications.
+ @hide -->
<permission android:name="android.permission.MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED"
android:protectionLevel="signature" />
@@ -6234,6 +6235,11 @@
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
+ <service android:name="com.android.server.SmartStorageMaintIdler"
+ android:exported="true"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
+
<service android:name="com.android.server.ZramWriteback"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE" >
diff --git a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
index 48a1da1..1cc1894 100644
--- a/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/MobileRadioPowerCalculatorTest.java
@@ -23,6 +23,7 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import android.app.usage.NetworkStatsManager;
import android.net.NetworkCapabilities;
import android.net.NetworkStats;
import android.os.BatteryConsumer;
@@ -40,12 +41,15 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class MobileRadioPowerCalculatorTest {
private static final double PRECISION = 0.00001;
private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+ @Mock
+ NetworkStatsManager mNetworkStatsManager;
@Rule
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
@@ -90,7 +94,8 @@
ModemActivityInfo mai = new ModemActivityInfo(10000, 2000, 3000,
new int[] {100, 200, 300, 400, 500}, 600);
- stats.noteModemControllerActivity(mai, POWER_DATA_UNAVAILABLE, 10000, 10000);
+ stats.noteModemControllerActivity(mai, POWER_DATA_UNAVAILABLE, 10000, 10000,
+ mNetworkStatsManager);
mStatsRule.setTime(12_000_000, 12_000_000);
@@ -150,7 +155,7 @@
ModemActivityInfo mai = new ModemActivityInfo(10000, 2000, 3000,
new int[] {100, 200, 300, 400, 500}, 600);
- stats.noteModemControllerActivity(mai, 10_000_000, 10000, 10000);
+ stats.noteModemControllerActivity(mai, 10_000_000, 10000, 10000, mNetworkStatsManager);
mStatsRule.setTime(12_000_000, 12_000_000);
diff --git a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
index cee1a03..db0c934 100644
--- a/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
+++ b/core/tests/coretests/src/com/android/internal/os/MockBatteryStatsImpl.java
@@ -16,6 +16,8 @@
package com.android.internal.os;
+import android.annotation.NonNull;
+import android.app.usage.NetworkStatsManager;
import android.net.NetworkStats;
import android.os.Handler;
import android.os.Looper;
@@ -105,7 +107,8 @@
}
@Override
- protected NetworkStats readNetworkStatsLocked(String[] ifaces) {
+ protected NetworkStats readNetworkStatsLocked(@NonNull NetworkStatsManager networkStatsManager,
+ String[] ifaces) {
return mNetworkStats;
}
diff --git a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
index fc44ddc..e7ce9a0 100644
--- a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
@@ -21,6 +21,7 @@
import static com.google.common.truth.Truth.assertThat;
+import android.app.usage.NetworkStatsManager;
import android.net.NetworkCapabilities;
import android.net.NetworkStats;
import android.os.BatteryConsumer;
@@ -35,6 +36,7 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -43,6 +45,9 @@
private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
+ @Mock
+ NetworkStatsManager mNetworkStatsManager;
+
@Rule
public final BatteryUsageStatsRule mStatsRule = new BatteryUsageStatsRule()
.setAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE, 360.0)
@@ -80,7 +85,8 @@
final BatteryStatsImpl batteryStats = setupTestNetworkNumbers();
final WifiActivityEnergyInfo energyInfo = setupPowerControllerBasedModelEnergyNumbersInfo();
- batteryStats.updateWifiState(energyInfo, POWER_DATA_UNAVAILABLE, 1000, 1000);
+ batteryStats.updateWifiState(energyInfo, POWER_DATA_UNAVAILABLE, 1000, 1000,
+ mNetworkStatsManager);
WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
@@ -113,7 +119,7 @@
final BatteryStatsImpl batteryStats = setupTestNetworkNumbers();
final WifiActivityEnergyInfo energyInfo = setupPowerControllerBasedModelEnergyNumbersInfo();
- batteryStats.updateWifiState(energyInfo, 1_000_000, 1000, 1000);
+ batteryStats.updateWifiState(energyInfo, 1_000_000, 1000, 1000, mNetworkStatsManager);
WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(calculator);
@@ -160,7 +166,8 @@
// Don't pass WifiActivityEnergyInfo, making WifiPowerCalculator rely exclusively
// on the packet counts.
- batteryStats.updateWifiState(/* energyInfo */ null, POWER_DATA_UNAVAILABLE, 1000, 1000);
+ batteryStats.updateWifiState(/* energyInfo */ null, POWER_DATA_UNAVAILABLE, 1000, 1000,
+ mNetworkStatsManager);
WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(BatteryUsageStatsRule.POWER_PROFILE_MODEL_ONLY, calculator);
@@ -180,7 +187,8 @@
// Don't pass WifiActivityEnergyInfo, making WifiPowerCalculator rely exclusively
// on the packet counts.
- batteryStats.updateWifiState(/* energyInfo */ null, 1_000_000, 1000, 1000);
+ batteryStats.updateWifiState(/* energyInfo */ null, 1_000_000, 1000, 1000,
+ mNetworkStatsManager);
WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
mStatsRule.apply(calculator);
diff --git a/identity/java/android/security/identity/CredentialDataRequest.java b/identity/java/android/security/identity/CredentialDataRequest.java
new file mode 100644
index 0000000..2a47a02
--- /dev/null
+++ b/identity/java/android/security/identity/CredentialDataRequest.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * An object representing a request for credential data.
+ */
+public class CredentialDataRequest {
+ CredentialDataRequest() {}
+
+ /**
+ * Gets the device-signed entries to request.
+ *
+ * @return the device-signed entries to request.
+ */
+ public @NonNull Map<String, Collection<String>> getDeviceSignedEntriesToRequest() {
+ return mDeviceSignedEntriesToRequest;
+ }
+
+ /**
+ * Gets the issuer-signed entries to request.
+ *
+ * @return the issuer-signed entries to request.
+ */
+ public @NonNull Map<String, Collection<String>> getIssuerSignedEntriesToRequest() {
+ return mIssuerSignedEntriesToRequest;
+ }
+
+ /**
+ * Gets whether to allow using an authentication key which use count has been exceeded.
+ *
+ * <p>By default this is set to true.
+ *
+ * @return whether to allow using an authentication key which use
+ * count has been exceeded if no other key is available.
+ */
+ public boolean isAllowUsingExhaustedKeys() {
+ return mAllowUsingExhaustedKeys;
+ }
+
+ /**
+ * Gets whether to allow using an authentication key which is expired.
+ *
+ * <p>By default this is set to false.
+ *
+ * @return whether to allow using an authentication key which is
+ * expired if no other key is available.
+ */
+ public boolean isAllowUsingExpiredKeys() {
+ return mAllowUsingExpiredKeys;
+ }
+
+ /**
+ * Gets whether to increment the use-count for the authentication key used.
+ *
+ * <p>By default this is set to true.
+ *
+ * @return whether to increment the use count of the authentication key used.
+ */
+ public boolean isIncrementUseCount() {
+ return mIncrementUseCount;
+ }
+
+ /**
+ * Gets the request message CBOR.
+ *
+ * <p>This data structure is described in the documentation for the
+ * {@link PresentationSession#getCredentialData(String, CredentialDataRequest)} method.
+ *
+ * @return the request message CBOR as described above.
+ */
+ public @Nullable byte[] getRequestMessage() {
+ return mRequestMessage;
+ }
+
+ /**
+ * Gets the reader signature.
+ *
+ * <p>This data structure is described in the documentation for the
+ * {@link PresentationSession#getCredentialData(String, CredentialDataRequest)} method.
+ *
+ * @return a {@code COSE_Sign1} structure as described above.
+ */
+ public @Nullable byte[] getReaderSignature() {
+ return mReaderSignature;
+ }
+
+ Map<String, Collection<String>> mDeviceSignedEntriesToRequest = new LinkedHashMap<>();
+ Map<String, Collection<String>> mIssuerSignedEntriesToRequest = new LinkedHashMap<>();
+ boolean mAllowUsingExhaustedKeys = true;
+ boolean mAllowUsingExpiredKeys = false;
+ boolean mIncrementUseCount = true;
+ byte[] mRequestMessage = null;
+ byte[] mReaderSignature = null;
+
+ /**
+ * A builder for {@link CredentialDataRequest}.
+ */
+ public static final class Builder {
+ private CredentialDataRequest mData;
+
+ /**
+ * Creates a new builder.
+ */
+ public Builder() {
+ mData = new CredentialDataRequest();
+ }
+
+ /**
+ * Sets the device-signed entries to request.
+ *
+ * @param entriesToRequest the device-signed entries to request.
+ */
+ public @NonNull Builder setDeviceSignedEntriesToRequest(
+ @NonNull Map<String, Collection<String>> entriesToRequest) {
+ mData.mDeviceSignedEntriesToRequest = entriesToRequest;
+ return this;
+ }
+
+ /**
+ * Sets the issuer-signed entries to request.
+ *
+ * @param entriesToRequest the issuer-signed entries to request.
+ * @return the builder.
+ */
+ public @NonNull Builder setIssuerSignedEntriesToRequest(
+ @NonNull Map<String, Collection<String>> entriesToRequest) {
+ mData.mIssuerSignedEntriesToRequest = entriesToRequest;
+ return this;
+ }
+
+ /**
+ * Sets whether to allow using an authentication key which use count has been exceeded.
+ *
+ * By default this is set to true.
+ *
+ * @param allowUsingExhaustedKeys whether to allow using an authentication key which use
+ * count has been exceeded if no other key is available.
+ * @return the builder.
+ */
+ public @NonNull Builder setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys) {
+ mData.mAllowUsingExhaustedKeys = allowUsingExhaustedKeys;
+ return this;
+ }
+
+ /**
+ * Sets whether to allow using an authentication key which is expired.
+ *
+ * By default this is set to false.
+ *
+ * @param allowUsingExpiredKeys whether to allow using an authentication key which is
+ * expired if no other key is available.
+ * @return the builder.
+ */
+ public @NonNull Builder setAllowUsingExpiredKeys(boolean allowUsingExpiredKeys) {
+ mData.mAllowUsingExpiredKeys = allowUsingExpiredKeys;
+ return this;
+ }
+
+ /**
+ * Sets whether to increment the use-count for the authentication key used.
+ *
+ * By default this is set to true.
+ *
+ * @param incrementUseCount whether to increment the use count of the authentication
+ * key used.
+ * @return the builder.
+ */
+ public @NonNull Builder setIncrementUseCount(boolean incrementUseCount) {
+ mData.mIncrementUseCount = incrementUseCount;
+ return this;
+ }
+
+ /**
+ * Sets the request message CBOR.
+ *
+ * <p>This data structure is described in the documentation for the
+ * {@link PresentationSession#getCredentialData(String, CredentialDataRequest)} method.
+ *
+ * @param requestMessage the request message CBOR as described above.
+ * @return the builder.
+ */
+ public @NonNull Builder setRequestMessage(@NonNull byte[] requestMessage) {
+ mData.mRequestMessage = requestMessage;
+ return this;
+ }
+
+ /**
+ * Sets the reader signature.
+ *
+ * <p>This data structure is described in the documentation for the
+ * {@link PresentationSession#getCredentialData(String, CredentialDataRequest)} method.
+ *
+ * @param readerSignature a {@code COSE_Sign1} structure as described above.
+ * @return the builder.
+ */
+ public @NonNull Builder setReaderSignature(@NonNull byte[] readerSignature) {
+ mData.mReaderSignature = readerSignature;
+ return this;
+ }
+
+ /**
+ * Finishes building a {@link CredentialDataRequest}.
+ *
+ * @return the {@link CredentialDataRequest} object.
+ */
+ public @NonNull CredentialDataRequest build() {
+ return mData;
+ }
+ }
+}
diff --git a/identity/java/android/security/identity/CredentialDataResult.java b/identity/java/android/security/identity/CredentialDataResult.java
new file mode 100644
index 0000000..beb03af
--- /dev/null
+++ b/identity/java/android/security/identity/CredentialDataResult.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.lang.annotation.Retention;
+import java.util.Collection;
+
+
+/**
+ * An object that contains the result of retrieving data from a credential. This is used to return
+ * data requested in a {@link PresentationSession}.
+ */
+public abstract class CredentialDataResult {
+ /**
+ * @hide
+ */
+ protected CredentialDataResult() {}
+
+ /**
+ * Returns a CBOR structure containing the retrieved device-signed data.
+ *
+ * <p>This structure - along with the session transcript - may be cryptographically
+ * authenticated to prove to the reader that the data is from a trusted credential and
+ * {@link #getDeviceMac()} can be used to get a MAC.
+ *
+ * <p>The CBOR structure which is cryptographically authenticated is the
+ * {@code DeviceAuthenticationBytes} structure according to the following
+ * <a href="https://tools.ietf.org/html/rfc8610">CDDL</a> schema:
+ *
+ * <pre>
+ * DeviceAuthentication = [
+ * "DeviceAuthentication",
+ * SessionTranscript,
+ * DocType,
+ * DeviceNameSpacesBytes
+ * ]
+ *
+ * DocType = tstr
+ * SessionTranscript = any
+ * DeviceNameSpacesBytes = #6.24(bstr .cbor DeviceNameSpaces)
+ * DeviceAuthenticationBytes = #6.24(bstr .cbor DeviceAuthentication)
+ * </pre>
+ *
+ * <p>where
+ *
+ * <pre>
+ * DeviceNameSpaces = {
+ * * NameSpace => DeviceSignedItems
+ * }
+ *
+ * DeviceSignedItems = {
+ * + DataItemName => DataItemValue
+ * }
+ *
+ * NameSpace = tstr
+ * DataItemName = tstr
+ * DataItemValue = any
+ * </pre>
+ *
+ * <p>The returned data is the binary encoding of the {@code DeviceNameSpaces} structure
+ * as defined above.
+ *
+ * @return The bytes of the {@code DeviceNameSpaces} CBOR structure.
+ */
+ public abstract @NonNull byte[] getDeviceNameSpaces();
+
+ /**
+ * Returns a message authentication code over the {@code DeviceAuthenticationBytes} CBOR
+ * specified in {@link #getDeviceNameSpaces()}, to prove to the reader that the data
+ * is from a trusted credential.
+ *
+ * <p>The MAC proves to the reader that the data is from a trusted credential. This code is
+ * produced by using the key agreement and key derivation function from the ciphersuite
+ * with the authentication private key and the reader ephemeral public key to compute a
+ * shared message authentication code (MAC) key, then using the MAC function from the
+ * ciphersuite to compute a MAC of the authenticated data. See section 9.2.3.5 of
+ * ISO/IEC 18013-5 for details of this operation.
+ *
+ * <p>If the session transcript or reader ephemeral key wasn't set on the {@link
+ * PresentationSession} used to obtain this data no message authencation code will be produced
+ * and this method will return {@code null}.
+ *
+ * @return A COSE_Mac0 structure with the message authentication code as described above
+ * or {@code null} if the conditions specified above are not met.
+ */
+ public abstract @Nullable byte[] getDeviceMac();
+
+ /**
+ * Returns the static authentication data associated with the dynamic authentication
+ * key used to MAC the data returned by {@link #getDeviceNameSpaces()}.
+ *
+ * @return The static authentication data associated with dynamic authentication key used to
+ * MAC the data.
+ */
+ public abstract @NonNull byte[] getStaticAuthenticationData();
+
+ /**
+ * Gets the device-signed entries that was returned.
+ *
+ * @return an object to examine the entries returned.
+ */
+ public abstract @NonNull Entries getDeviceSignedEntries();
+
+ /**
+ * Gets the issuer-signed entries that was returned.
+ *
+ * @return an object to examine the entries returned.
+ */
+ public abstract @NonNull Entries getIssuerSignedEntries();
+
+ /**
+ * A class for representing data elements returned.
+ */
+ public interface Entries {
+ /** Value was successfully retrieved. */
+ int STATUS_OK = 0;
+
+ /** The entry does not exist. */
+ int STATUS_NO_SUCH_ENTRY = 1;
+
+ /** The entry was not requested. */
+ int STATUS_NOT_REQUESTED = 2;
+
+ /** The entry wasn't in the request message. */
+ int STATUS_NOT_IN_REQUEST_MESSAGE = 3;
+
+ /** The entry was not retrieved because user authentication failed. */
+ int STATUS_USER_AUTHENTICATION_FAILED = 4;
+
+ /** The entry was not retrieved because reader authentication failed. */
+ int STATUS_READER_AUTHENTICATION_FAILED = 5;
+
+ /**
+ * The entry was not retrieved because it was configured without any access
+ * control profile.
+ */
+ int STATUS_NO_ACCESS_CONTROL_PROFILES = 6;
+
+ /**
+ * Gets the names of namespaces with retrieved entries.
+ *
+ * @return collection of name of namespaces containing retrieved entries. May be empty if no
+ * data was retrieved.
+ */
+ @NonNull Collection<String> getNamespaces();
+
+ /**
+ * Get the names of all requested entries in a name space.
+ *
+ * <p>This includes the name of entries that wasn't successfully retrieved.
+ *
+ * @param namespaceName the namespace name to get entries for.
+ * @return A collection of names for the given namespace or the empty collection if no
+ * entries was returned for the given name space.
+ */
+ @NonNull Collection<String> getEntryNames(@NonNull String namespaceName);
+
+ /**
+ * Get the names of all entries that was successfully retrieved from a name space.
+ *
+ * <p>This only return entries for which {@link #getStatus(String, String)} will return
+ * {@link #STATUS_OK}.
+ *
+ * @param namespaceName the namespace name to get entries for.
+ * @return The entries in the given namespace that were successfully rerieved or the
+ * empty collection if no entries was returned for the given name space.
+ */
+ @NonNull Collection<String> getRetrievedEntryNames(@NonNull String namespaceName);
+
+ /**
+ * Gets the status of an entry.
+ *
+ * <p>This returns {@link #STATUS_OK} if the value was retrieved, {@link
+ * #STATUS_NO_SUCH_ENTRY} if the given entry wasn't retrieved, {@link
+ * #STATUS_NOT_REQUESTED} if it wasn't requested, {@link #STATUS_NOT_IN_REQUEST_MESSAGE} if
+ * the request message was set but the entry wasn't present in the request message, {@link
+ * #STATUS_USER_AUTHENTICATION_FAILED} if the value wasn't retrieved because the necessary
+ * user authentication wasn't performed, {@link #STATUS_READER_AUTHENTICATION_FAILED} if
+ * the supplied reader certificate chain didn't match the set of certificates the entry was
+ * provisioned with, or {@link #STATUS_NO_ACCESS_CONTROL_PROFILES} if the entry was
+ * configured without any access control profiles.
+ *
+ * @param namespaceName the namespace name of the entry.
+ * @param name the name of the entry to get the value for.
+ * @return the status indicating whether the value was retrieved and if not, why.
+ */
+ @Status int getStatus(@NonNull String namespaceName, @NonNull String name);
+
+ /**
+ * Gets the raw CBOR data for the value of an entry.
+ *
+ * <p>This should only be called on an entry for which the {@link #getStatus(String,
+ * String)} method returns {@link #STATUS_OK}.
+ *
+ * @param namespaceName the namespace name of the entry.
+ * @param name the name of the entry to get the value for.
+ * @return the raw CBOR data or {@code null} if no entry with the given name exists.
+ */
+ @Nullable byte[] getEntry(@NonNull String namespaceName, @NonNull String name);
+
+ /**
+ * The type of the entry status.
+ * @hide
+ */
+ @Retention(SOURCE)
+ @IntDef({STATUS_OK, STATUS_NO_SUCH_ENTRY, STATUS_NOT_REQUESTED,
+ STATUS_NOT_IN_REQUEST_MESSAGE, STATUS_USER_AUTHENTICATION_FAILED,
+ STATUS_READER_AUTHENTICATION_FAILED, STATUS_NO_ACCESS_CONTROL_PROFILES})
+ @interface Status {}
+ }
+
+}
diff --git a/identity/java/android/security/identity/CredstoreCredentialDataResult.java b/identity/java/android/security/identity/CredstoreCredentialDataResult.java
new file mode 100644
index 0000000..7afe3d4
--- /dev/null
+++ b/identity/java/android/security/identity/CredstoreCredentialDataResult.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+class CredstoreCredentialDataResult extends CredentialDataResult {
+
+ ResultData mDeviceSignedResult;
+ ResultData mIssuerSignedResult;
+ CredstoreEntries mDeviceSignedEntries;
+ CredstoreEntries mIssuerSignedEntries;
+
+ CredstoreCredentialDataResult(ResultData deviceSignedResult, ResultData issuerSignedResult) {
+ mDeviceSignedResult = deviceSignedResult;
+ mIssuerSignedResult = issuerSignedResult;
+ mDeviceSignedEntries = new CredstoreEntries(deviceSignedResult);
+ mIssuerSignedEntries = new CredstoreEntries(issuerSignedResult);
+ }
+
+ @Override
+ public @NonNull byte[] getDeviceNameSpaces() {
+ return mDeviceSignedResult.getAuthenticatedData();
+ }
+
+ @Override
+ public @Nullable byte[] getDeviceMac() {
+ return mDeviceSignedResult.getMessageAuthenticationCode();
+ }
+
+ @Override
+ public @NonNull byte[] getStaticAuthenticationData() {
+ return mDeviceSignedResult.getStaticAuthenticationData();
+ }
+
+ @Override
+ public @NonNull CredentialDataResult.Entries getDeviceSignedEntries() {
+ return mDeviceSignedEntries;
+ }
+
+ @Override
+ public @NonNull CredentialDataResult.Entries getIssuerSignedEntries() {
+ return mIssuerSignedEntries;
+ }
+
+ static class CredstoreEntries implements CredentialDataResult.Entries {
+ ResultData mResultData;
+
+ CredstoreEntries(ResultData resultData) {
+ mResultData = resultData;
+ }
+
+ @Override
+ public @NonNull Collection<String> getNamespaces() {
+ return mResultData.getNamespaces();
+ }
+
+ @Override
+ public @NonNull Collection<String> getEntryNames(@NonNull String namespaceName) {
+ Collection<String> ret = mResultData.getEntryNames(namespaceName);
+ if (ret == null) {
+ ret = new LinkedList<String>();
+ }
+ return ret;
+ }
+
+ @Override
+ public @NonNull Collection<String> getRetrievedEntryNames(@NonNull String namespaceName) {
+ Collection<String> ret = mResultData.getRetrievedEntryNames(namespaceName);
+ if (ret == null) {
+ ret = new LinkedList<String>();
+ }
+ return ret;
+ }
+
+ @Override
+ @Status
+ public int getStatus(@NonNull String namespaceName, @NonNull String name) {
+ return mResultData.getStatus(namespaceName, name);
+ }
+
+ @Override
+ public @Nullable byte[] getEntry(@NonNull String namespaceName, @NonNull String name) {
+ return mResultData.getEntry(namespaceName, name);
+ }
+ }
+
+}
diff --git a/identity/java/android/security/identity/CredstoreIdentityCredential.java b/identity/java/android/security/identity/CredstoreIdentityCredential.java
index 6398cee..8e01105 100644
--- a/identity/java/android/security/identity/CredstoreIdentityCredential.java
+++ b/identity/java/android/security/identity/CredstoreIdentityCredential.java
@@ -58,14 +58,17 @@
private @IdentityCredentialStore.Ciphersuite int mCipherSuite;
private Context mContext;
private ICredential mBinder;
+ private CredstorePresentationSession mSession;
CredstoreIdentityCredential(Context context, String credentialName,
@IdentityCredentialStore.Ciphersuite int cipherSuite,
- ICredential binder) {
+ ICredential binder,
+ @Nullable CredstorePresentationSession session) {
mContext = context;
mCredentialName = credentialName;
mCipherSuite = cipherSuite;
mBinder = binder;
+ mSession = session;
}
private KeyPair mEphemeralKeyPair = null;
@@ -239,6 +242,7 @@
private boolean mAllowUsingExhaustedKeys = true;
private boolean mAllowUsingExpiredKeys = false;
+ private boolean mIncrementKeyUsageCount = true;
@Override
public void setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys) {
@@ -250,6 +254,11 @@
mAllowUsingExpiredKeys = allowUsingExpiredKeys;
}
+ @Override
+ public void setIncrementKeyUsageCount(boolean incrementKeyUsageCount) {
+ mIncrementKeyUsageCount = incrementKeyUsageCount;
+ }
+
private boolean mOperationHandleSet = false;
private long mOperationHandle = 0;
@@ -264,7 +273,8 @@
if (!mOperationHandleSet) {
try {
mOperationHandle = mBinder.selectAuthKey(mAllowUsingExhaustedKeys,
- mAllowUsingExpiredKeys);
+ mAllowUsingExpiredKeys,
+ mIncrementKeyUsageCount);
mOperationHandleSet = true;
} catch (android.os.RemoteException e) {
throw new RuntimeException("Unexpected RemoteException ", e);
@@ -315,7 +325,8 @@
sessionTranscript != null ? sessionTranscript : new byte[0],
readerSignature != null ? readerSignature : new byte[0],
mAllowUsingExhaustedKeys,
- mAllowUsingExpiredKeys);
+ mAllowUsingExpiredKeys,
+ mIncrementKeyUsageCount);
} catch (android.os.RemoteException e) {
throw new RuntimeException("Unexpected RemoteException ", e);
} catch (android.os.ServiceSpecificException e) {
diff --git a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java
index d8d4742..fb0880c 100644
--- a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java
+++ b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java
@@ -126,7 +126,8 @@
ICredential credstoreCredential;
credstoreCredential = mStore.getCredentialByName(credentialName, cipherSuite);
return new CredstoreIdentityCredential(mContext, credentialName, cipherSuite,
- credstoreCredential);
+ credstoreCredential,
+ null);
} catch (android.os.RemoteException e) {
throw new RuntimeException("Unexpected RemoteException ", e);
} catch (android.os.ServiceSpecificException e) {
@@ -162,4 +163,23 @@
+ e.errorCode, e);
}
}
+
+ @Override
+ public @NonNull PresentationSession createPresentationSession(@Ciphersuite int cipherSuite)
+ throws CipherSuiteNotSupportedException {
+ try {
+ ISession credstoreSession = mStore.createPresentationSession(cipherSuite);
+ return new CredstorePresentationSession(mContext, cipherSuite, this, credstoreSession);
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ if (e.errorCode == ICredentialStore.ERROR_CIPHER_SUITE_NOT_SUPPORTED) {
+ throw new CipherSuiteNotSupportedException(e.getMessage(), e);
+ } else {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+ }
+
}
diff --git a/identity/java/android/security/identity/CredstorePresentationSession.java b/identity/java/android/security/identity/CredstorePresentationSession.java
new file mode 100644
index 0000000..e3c6689
--- /dev/null
+++ b/identity/java/android/security/identity/CredstorePresentationSession.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+class CredstorePresentationSession extends PresentationSession {
+ private static final String TAG = "CredstorePresentationSession";
+
+ private @IdentityCredentialStore.Ciphersuite int mCipherSuite;
+ private Context mContext;
+ private CredstoreIdentityCredentialStore mStore;
+ private ISession mBinder;
+ private Map<String, CredstoreIdentityCredential> mCredentialCache = new LinkedHashMap<>();
+ private KeyPair mEphemeralKeyPair = null;
+ private byte[] mSessionTranscript = null;
+ private boolean mOperationHandleSet = false;
+ private long mOperationHandle = 0;
+
+ CredstorePresentationSession(Context context,
+ @IdentityCredentialStore.Ciphersuite int cipherSuite,
+ CredstoreIdentityCredentialStore store,
+ ISession binder) {
+ mContext = context;
+ mCipherSuite = cipherSuite;
+ mStore = store;
+ mBinder = binder;
+ }
+
+ private void ensureEphemeralKeyPair() {
+ if (mEphemeralKeyPair != null) {
+ return;
+ }
+ try {
+ // This PKCS#12 blob is generated in credstore, using BoringSSL.
+ //
+ // The main reason for this convoluted approach and not just sending the decomposed
+ // key-pair is that this would require directly using (device-side) BouncyCastle which
+ // is tricky due to various API hiding efforts. So instead we have credstore generate
+ // this PKCS#12 blob. The blob is encrypted with no password (sadly, also, BoringSSL
+ // doesn't support not using encryption when building a PKCS#12 blob).
+ //
+ byte[] pkcs12 = mBinder.getEphemeralKeyPair();
+ String alias = "ephemeralKey";
+ char[] password = {};
+
+ KeyStore ks = KeyStore.getInstance("PKCS12");
+ ByteArrayInputStream bais = new ByteArrayInputStream(pkcs12);
+ ks.load(bais, password);
+ PrivateKey privKey = (PrivateKey) ks.getKey(alias, password);
+
+ Certificate cert = ks.getCertificate(alias);
+ PublicKey pubKey = cert.getPublicKey();
+
+ mEphemeralKeyPair = new KeyPair(pubKey, privKey);
+ } catch (android.os.ServiceSpecificException e) {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ } catch (android.os.RemoteException
+ | KeyStoreException
+ | CertificateException
+ | UnrecoverableKeyException
+ | NoSuchAlgorithmException
+ | IOException e) {
+ throw new RuntimeException("Unexpected exception ", e);
+ }
+ }
+
+ @Override
+ public @NonNull KeyPair getEphemeralKeyPair() {
+ ensureEphemeralKeyPair();
+ return mEphemeralKeyPair;
+ }
+
+ @Override
+ public void setReaderEphemeralPublicKey(@NonNull PublicKey readerEphemeralPublicKey)
+ throws InvalidKeyException {
+ try {
+ byte[] uncompressedForm =
+ Util.publicKeyEncodeUncompressedForm(readerEphemeralPublicKey);
+ mBinder.setReaderEphemeralPublicKey(uncompressedForm);
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+
+ @Override
+ public void setSessionTranscript(@NonNull byte[] sessionTranscript) {
+ try {
+ mBinder.setSessionTranscript(sessionTranscript);
+ mSessionTranscript = sessionTranscript;
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+
+ @Override
+ public @Nullable CredentialDataResult getCredentialData(@NonNull String credentialName,
+ @NonNull CredentialDataRequest request)
+ throws NoAuthenticationKeyAvailableException, InvalidReaderSignatureException,
+ InvalidRequestMessageException, EphemeralPublicKeyNotFoundException {
+ try {
+ // Cache the IdentityCredential to satisfy the property that AuthKey usage counts are
+ // incremented on only the _first_ getCredentialData() call.
+ //
+ CredstoreIdentityCredential credential = mCredentialCache.get(credentialName);
+ if (credential == null) {
+ ICredential credstoreCredential =
+ mBinder.getCredentialForPresentation(credentialName);
+ credential = new CredstoreIdentityCredential(mContext, credentialName,
+ mCipherSuite, credstoreCredential,
+ this);
+ mCredentialCache.put(credentialName, credential);
+
+ credential.setAllowUsingExhaustedKeys(request.isAllowUsingExhaustedKeys());
+ credential.setAllowUsingExpiredKeys(request.isAllowUsingExpiredKeys());
+ credential.setIncrementKeyUsageCount(request.isIncrementUseCount());
+ }
+
+ ResultData deviceSignedResult = credential.getEntries(
+ request.getRequestMessage(),
+ request.getDeviceSignedEntriesToRequest(),
+ mSessionTranscript,
+ request.getReaderSignature());
+
+ // By design this second getEntries() call consumes the same auth-key.
+
+ ResultData issuerSignedResult = credential.getEntries(
+ request.getRequestMessage(),
+ request.getIssuerSignedEntriesToRequest(),
+ mSessionTranscript,
+ request.getReaderSignature());
+
+ return new CredstoreCredentialDataResult(deviceSignedResult, issuerSignedResult);
+
+ } catch (SessionTranscriptMismatchException e) {
+ throw new RuntimeException("Unexpected ", e);
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ if (e.errorCode == ICredentialStore.ERROR_NO_SUCH_CREDENTIAL) {
+ return null;
+ } else {
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+ }
+
+ /**
+ * Called by android.hardware.biometrics.CryptoObject#getOpId() to get an
+ * operation handle.
+ *
+ * @hide
+ */
+ @Override
+ public long getCredstoreOperationHandle() {
+ if (!mOperationHandleSet) {
+ try {
+ mOperationHandle = mBinder.getAuthChallenge();
+ mOperationHandleSet = true;
+ } catch (android.os.RemoteException e) {
+ throw new RuntimeException("Unexpected RemoteException ", e);
+ } catch (android.os.ServiceSpecificException e) {
+ if (e.errorCode == ICredentialStore.ERROR_NO_AUTHENTICATION_KEY_AVAILABLE) {
+ // The NoAuthenticationKeyAvailableException will be thrown when
+ // the caller proceeds to call getEntries().
+ }
+ throw new RuntimeException("Unexpected ServiceSpecificException with code "
+ + e.errorCode, e);
+ }
+ }
+ return mOperationHandle;
+ }
+
+}
diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java
index 1e68585..cdf746f 100644
--- a/identity/java/android/security/identity/IdentityCredential.java
+++ b/identity/java/android/security/identity/IdentityCredential.java
@@ -48,7 +48,9 @@
* encryption".
*
* @return ephemeral key pair to use to establish a secure channel with a reader.
+ * @deprecated Use {@link PresentationSession} instead.
*/
+ @Deprecated
public @NonNull abstract KeyPair createEphemeralKeyPair();
/**
@@ -58,7 +60,9 @@
* @param readerEphemeralPublicKey The ephemeral public key provided by the reader to
* establish a secure session.
* @throws InvalidKeyException if the given key is invalid.
+ * @deprecated Use {@link PresentationSession} instead.
*/
+ @Deprecated
public abstract void setReaderEphemeralPublicKey(@NonNull PublicKey readerEphemeralPublicKey)
throws InvalidKeyException;
@@ -72,7 +76,10 @@
*
* @param messagePlaintext unencrypted message to encrypt.
* @return encrypted message.
+ * @deprecated Applications should use {@link PresentationSession} and
+ * implement encryption/decryption themselves.
*/
+ @Deprecated
public @NonNull abstract byte[] encryptMessageToReader(@NonNull byte[] messagePlaintext);
/**
@@ -86,7 +93,10 @@
* @param messageCiphertext encrypted message to decrypt.
* @return decrypted message.
* @throws MessageDecryptionException if the ciphertext couldn't be decrypted.
+ * @deprecated Applications should use {@link PresentationSession} and
+ * implement encryption/decryption themselves.
*/
+ @Deprecated
public @NonNull abstract byte[] decryptMessageFromReader(@NonNull byte[] messageCiphertext)
throws MessageDecryptionException;
@@ -111,7 +121,9 @@
*
* @param allowUsingExhaustedKeys whether to allow using an authentication key which use count
* has been exceeded if no other key is available.
+ * @deprecated Use {@link PresentationSession} instead.
*/
+ @Deprecated
public abstract void setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys);
/**
@@ -128,12 +140,36 @@
*
* @param allowUsingExpiredKeys whether to allow using an authentication key which use count
* has been exceeded if no other key is available.
+ * @deprecated Use {@link PresentationSession} instead.
*/
+ @Deprecated
public void setAllowUsingExpiredKeys(boolean allowUsingExpiredKeys) {
throw new UnsupportedOperationException();
}
/**
+ * @hide
+ *
+ * Sets whether the usage count of an authentication key should be increased. This must be
+ * called prior to calling
+ * {@link #getEntries(byte[], Map, byte[], byte[])} or using a
+ * {@link android.hardware.biometrics.BiometricPrompt.CryptoObject} which references this object.
+ *
+ * <p>By default this is set to true.
+ *
+ * <p>This is only implemented in feature version 202201 or later. If not implemented, the call
+ * fails with {@link UnsupportedOperationException}. See
+ * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known
+ * feature versions.
+ *
+ * @param incrementKeyUsageCount whether the usage count of the key should be increased.
+ * @deprecated Use {@link PresentationSession} instead.
+ */
+ public void setIncrementKeyUsageCount(boolean incrementKeyUsageCount) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
* Called by android.hardware.biometrics.CryptoObject#getOpId() to get an
* operation handle.
*
@@ -149,15 +185,19 @@
* by using the {@link ResultData#getStatus(String, String)} method on each of the requested
* entries.
*
- * <p>It is the responsibility of the calling application to know if authentication is needed
- * and use e.g. {@link android.hardware.biometrics.BiometricPrompt} to make the user
- * authenticate using a {@link android.hardware.biometrics.BiometricPrompt.CryptoObject} which
- * references this object. If needed, this must be done before calling
- * {@link #getEntries(byte[], Map, byte[], byte[])}.
- *
* <p>It is permissible to call this method multiple times using the same instance but if this
* is done, the {@code sessionTranscript} parameter must be identical for each call. If this is
* not the case, the {@link SessionTranscriptMismatchException} exception is thrown.
+ * Additionally, if this is done the same auth-key will be used.
+ *
+ * <p>The application should not make any assumptions on whether user authentication is needed.
+ * Instead, the application should request the data elements values first and then examine
+ * the returned {@link ResultData}. If {@link ResultData#STATUS_USER_AUTHENTICATION_FAILED}
+ * is returned the application should get a
+ * {@link android.hardware.biometrics.BiometricPrompt.CryptoObject} which references this
+ * object and use it with a {@link android.hardware.biometrics.BiometricPrompt}. Upon successful
+ * authentication the application may call {@link #getEntries(byte[], Map, byte[], byte[])}
+ * again.
*
* <p>If not {@code null} the {@code requestMessage} parameter must contain data for the request
* from the verifier. The content can be defined in the way appropriate for the credential, but
@@ -269,7 +309,9 @@
* @throws InvalidRequestMessageException if the requestMessage is malformed.
* @throws EphemeralPublicKeyNotFoundException if the ephemeral public key was not found in
* the session transcript.
+ * @deprecated Use {@link PresentationSession} instead.
*/
+ @Deprecated
public abstract @NonNull ResultData getEntries(
@Nullable byte[] requestMessage,
@NonNull Map<String, Collection<String>> entriesToRequest,
diff --git a/identity/java/android/security/identity/IdentityCredentialStore.java b/identity/java/android/security/identity/IdentityCredentialStore.java
index 6ccd0e8..dbb8aaa 100644
--- a/identity/java/android/security/identity/IdentityCredentialStore.java
+++ b/identity/java/android/security/identity/IdentityCredentialStore.java
@@ -209,6 +209,25 @@
@Deprecated
public abstract @Nullable byte[] deleteCredentialByName(@NonNull String credentialName);
+ /**
+ * Creates a new presentation session.
+ *
+ * <p>This method gets an object to be used for interaction with a remote verifier for
+ * presentation of one or more credentials.
+ *
+ * <p>This is only implemented in feature version 202201 or later. If not implemented, the call
+ * fails with {@link UnsupportedOperationException}. See
+ * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known
+ * feature versions.
+ *
+ * @param cipherSuite the cipher suite to use for communicating with the verifier.
+ * @return The presentation session.
+ */
+ public @NonNull PresentationSession createPresentationSession(@Ciphersuite int cipherSuite)
+ throws CipherSuiteNotSupportedException {
+ throw new UnsupportedOperationException();
+ }
+
/** @hide */
@IntDef(value = {CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256})
@Retention(RetentionPolicy.SOURCE)
diff --git a/identity/java/android/security/identity/PresentationSession.java b/identity/java/android/security/identity/PresentationSession.java
new file mode 100644
index 0000000..afaafce
--- /dev/null
+++ b/identity/java/android/security/identity/PresentationSession.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.identity;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.PublicKey;
+
+/**
+ * Class for presenting multiple documents to a remote verifier.
+ *
+ * Use {@link IdentityCredentialStore#createPresentationSession(int)} to create a {@link
+ * PresentationSession} instance.
+ */
+public abstract class PresentationSession {
+ /**
+ * @hide
+ */
+ protected PresentationSession() {}
+
+ /**
+ * Gets the ephemeral key pair to use to establish a secure channel with the verifier.
+ *
+ * <p>Applications should use this key-pair for the communications channel with the verifier
+ * using a protocol / cipher-suite appropriate for the application. One example of such a
+ * protocol is the one used for Mobile Driving Licenses, see ISO 18013-5.
+ *
+ * <p>The ephemeral key pair is tied to the {@link PresentationSession} instance so subsequent
+ * calls to this method will return the same key-pair.
+ *
+ * @return ephemeral key pair to use to establish a secure channel with a reader.
+ */
+ public @NonNull abstract KeyPair getEphemeralKeyPair();
+
+ /**
+ * Set the ephemeral public key provided by the verifier.
+ *
+ * <p>If called, this must be called before any calls to
+ * {@link #getCredentialData(String, CredentialDataRequest)}.
+ *
+ * <p>This method can only be called once per {@link PresentationSession} instance.
+ *
+ * @param readerEphemeralPublicKey The ephemeral public key provided by the reader to
+ * establish a secure session.
+ * @throws InvalidKeyException if the given key is invalid.
+ */
+ public abstract void setReaderEphemeralPublicKey(@NonNull PublicKey readerEphemeralPublicKey)
+ throws InvalidKeyException;
+
+ /**
+ * Set the session transcript.
+ *
+ * <p>If called, this must be called before any calls to
+ * {@link #getCredentialData(String, CredentialDataRequest)}.
+ *
+ * <p>The X and Y coordinates of the public part of the key-pair returned by {@link
+ * #getEphemeralKeyPair()} must appear somewhere in the bytes of the passed in CBOR. Each of
+ * these coordinates must appear encoded with the most significant bits first and use the exact
+ * amount of bits indicated by the key size of the ephemeral keys. For example, if the
+ * ephemeral key is using the P-256 curve then the 32 bytes for the X coordinate encoded with
+ * the most significant bits first must appear somewhere and ditto for the 32 bytes for the Y
+ * coordinate.
+ *
+ * <p>This method can only be called once per {@link PresentationSession} instance.
+ *
+ * @param sessionTranscript the session transcript.
+ */
+ public abstract void setSessionTranscript(@NonNull byte[] sessionTranscript);
+
+ /**
+ * Retrieves data from a named credential in the current presentation session.
+ *
+ * <p>If an access control check fails for one of the requested entries or if the entry
+ * doesn't exist, the entry is simply not returned. The application can detect this
+ * by using the {@link CredentialDataResult.Entries#getStatus(String, String)} method on
+ * each of the requested entries.
+ *
+ * <p>The application should not make any assumptions on whether user authentication is needed.
+ * Instead, the application should request the data elements values first and then examine
+ * the returned {@link CredentialDataResult.Entries}. If
+ * {@link CredentialDataResult.Entries#STATUS_USER_AUTHENTICATION_FAILED} is returned the
+ * application should get a
+ * {@link android.hardware.biometrics.BiometricPrompt.CryptoObject} which references this
+ * object and use it with a {@link android.hardware.biometrics.BiometricPrompt}. Upon successful
+ * authentication the application may call
+ * {@link #getCredentialData(String, CredentialDataRequest)} again.
+ *
+ * <p>It is permissible to call this method multiple times using the same credential name.
+ * If this is done the same auth-key will be used.
+ *
+ * <p>If the reader signature is set in the request parameter (via the
+ * {@link CredentialDataRequest.Builder#setReaderSignature(byte[])} method) it must contain
+ * the bytes of a {@code COSE_Sign1} structure as defined in RFC 8152. For the payload
+ * {@code nil} shall be used and the detached payload is the {@code ReaderAuthenticationBytes}
+ * CBOR described below.
+ * <pre>
+ * ReaderAuthentication = [
+ * "ReaderAuthentication",
+ * SessionTranscript,
+ * ItemsRequestBytes
+ * ]
+ *
+ * ItemsRequestBytes = #6.24(bstr .cbor ItemsRequest)
+ *
+ * ReaderAuthenticationBytes = #6.24(bstr .cbor ReaderAuthentication)
+ * </pre>
+ *
+ * <p>where {@code ItemsRequestBytes} are the bytes of the request message set in
+ * the request parameter (via the
+ * {@link CredentialDataRequest.Builder#setRequestMessage(byte[])} method).
+ *
+ * <p>The public key corresponding to the key used to make the signature, can be found in the
+ * {@code x5chain} unprotected header element of the {@code COSE_Sign1} structure (as as
+ * described in
+ * <a href="https://tools.ietf.org/html/draft-ietf-cose-x509-08">draft-ietf-cose-x509-08</a>).
+ * There will be at least one certificate in said element and there may be more (and if so,
+ * each certificate must be signed by its successor).
+ *
+ * <p>Data elements protected by reader authentication are returned if, and only if,
+ * {@code requestMessage} is signed by the top-most certificate in the reader's certificate
+ * chain, and the data element is configured with an {@link AccessControlProfile} configured
+ * with an X.509 certificate for a key which appear in the certificate chain.
+ *
+ * <p>Note that the request message CBOR is used only for enforcing reader authentication, it's
+ * not used for determining which entries this API will return. The application is expected to
+ * have parsed the request message and filtered it according to user preference and/or consent.
+ *
+ * @param credentialName the name of the credential to retrieve.
+ * @param request the data to retrieve from the credential
+ * @return If the credential wasn't found, returns null. Otherwise a
+ * {@link CredentialDataResult} object containing entry data organized by namespace and
+ * a cryptographically authenticated representation of the same data, bound to the
+ * current session.
+ * @throws NoAuthenticationKeyAvailableException if authentication keys were never
+ * provisioned for the credential or if they
+ * are expired or exhausted their use-count.
+ * @throws InvalidRequestMessageException if the requestMessage is malformed.
+ * @throws InvalidReaderSignatureException if the reader signature is invalid, or it
+ * doesn't contain a certificate chain, or if
+ * the signature failed to validate.
+ * @throws EphemeralPublicKeyNotFoundException if the ephemeral public key was not found in
+ * the session transcript.
+ */
+ public abstract @Nullable CredentialDataResult getCredentialData(
+ @NonNull String credentialName, @NonNull CredentialDataRequest request)
+ throws NoAuthenticationKeyAvailableException, InvalidReaderSignatureException,
+ InvalidRequestMessageException, EphemeralPublicKeyNotFoundException;
+
+ /**
+ * Called by android.hardware.biometrics.CryptoObject#getOpId() to get an
+ * operation handle.
+ *
+ * @hide
+ */
+ public abstract long getCredstoreOperationHandle();
+}
diff --git a/identity/java/android/security/identity/ResultData.java b/identity/java/android/security/identity/ResultData.java
index 71860d2..d46f985 100644
--- a/identity/java/android/security/identity/ResultData.java
+++ b/identity/java/android/security/identity/ResultData.java
@@ -28,7 +28,10 @@
/**
* An object that contains the result of retrieving data from a credential. This is used to return
* data requested from a {@link IdentityCredential}.
+ *
+ * @deprecated Use {@link PresentationSession} instead.
*/
+@Deprecated
public abstract class ResultData {
/** Value was successfully retrieved. */
diff --git a/libs/hwui/jni/NinePatch.cpp b/libs/hwui/jni/NinePatch.cpp
index 6942017..3ca457f 100644
--- a/libs/hwui/jni/NinePatch.cpp
+++ b/libs/hwui/jni/NinePatch.cpp
@@ -67,7 +67,7 @@
size_t chunkSize = env->GetArrayLength(obj);
if (chunkSize < (int) (sizeof(Res_png_9patch))) {
jniThrowRuntimeException(env, "Array too small for chunk.");
- return NULL;
+ return 0;
}
int8_t* storage = new int8_t[chunkSize];
diff --git a/libs/hwui/jni/android_util_PathParser.cpp b/libs/hwui/jni/android_util_PathParser.cpp
index 72995ef..8cbb70e 100644
--- a/libs/hwui/jni/android_util_PathParser.cpp
+++ b/libs/hwui/jni/android_util_PathParser.cpp
@@ -61,7 +61,7 @@
} else {
delete pathData;
doThrowIAE(env, result.failureMessage.c_str());
- return NULL;
+ return 0;
}
}
diff --git a/media/java/android/media/BtProfileConnectionInfo.java b/media/java/android/media/BtProfileConnectionInfo.java
index 19ea2de..d1bb41e 100644
--- a/media/java/android/media/BtProfileConnectionInfo.java
+++ b/media/java/android/media/BtProfileConnectionInfo.java
@@ -34,7 +34,7 @@
/** @hide */
@IntDef({
BluetoothProfile.A2DP,
- BluetoothProfile.A2DP_SINK, // Can only be set by BtHelper
+ BluetoothProfile.A2DP_SINK,
BluetoothProfile.HEADSET, // Can only be set by BtHelper
BluetoothProfile.HEARING_AID,
BluetoothProfile.LE_AUDIO,
@@ -105,6 +105,16 @@
}
/**
+ * Constructor for A2dp sink info
+ * The {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
+ *
+ * @param volume of device -1 to ignore value
+ */
+ public static @NonNull BtProfileConnectionInfo a2dpSinkInfo(int volume) {
+ return new BtProfileConnectionInfo(BluetoothProfile.A2DP_SINK, true, volume, false);
+ }
+
+ /**
* Constructor for hearing aid info
*
* @param suppressNoisyIntent if true the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY}
diff --git a/media/java/android/media/tv/OWNERS b/media/java/android/media/tv/OWNERS
index 33acd0d..fa04293 100644
--- a/media/java/android/media/tv/OWNERS
+++ b/media/java/android/media/tv/OWNERS
@@ -1,6 +1,6 @@
-nchalko@google.com
quxiangfang@google.com
shubang@google.com
+hgchen@google.com
# For android remote service
per-file ITvRemoteServiceInput.aidl = file:/media/lib/tvremote/OWNERS
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index efd9d10..420f4ef 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -18,6 +18,7 @@
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -27,6 +28,8 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
+import android.media.AudioDeviceInfo;
+import android.media.AudioFormat.Encoding;
import android.media.PlaybackParams;
import android.net.Uri;
import android.os.Binder;
@@ -59,6 +62,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -2998,6 +3002,16 @@
return false;
}
+ /**
+ * Override default audio sink from audio policy.
+ *
+ * @param audioType device type of the audio sink to override with.
+ * @param audioAddress device address of the audio sink to override with.
+ * @param samplingRate desired sampling rate. Use default when it's 0.
+ * @param channelMask desired channel mask. Use default when it's
+ * AudioFormat.CHANNEL_OUT_DEFAULT.
+ * @param format desired format. Use default when it's AudioFormat.ENCODING_DEFAULT.
+ */
public void overrideAudioSink(int audioType, String audioAddress, int samplingRate,
int channelMask, int format) {
try {
@@ -3007,5 +3021,27 @@
throw new RuntimeException(e);
}
}
+
+ /**
+ * Override default audio sink from audio policy.
+ *
+ * @param device {@link android.media.AudioDeviceInfo} to use.
+ * @param samplingRate desired sampling rate. Use default when it's 0.
+ * @param channelMask desired channel mask. Use default when it's
+ * AudioFormat.CHANNEL_OUT_DEFAULT.
+ * @param format desired format. Use default when it's AudioFormat.ENCODING_DEFAULT.
+ */
+ public void overrideAudioSink(@NonNull AudioDeviceInfo device,
+ @IntRange(from = 0) int samplingRate,
+ int channelMask, @Encoding int format) {
+ Objects.requireNonNull(device);
+ try {
+ mInterface.overrideAudioSink(
+ AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType()),
+ device.getAddress(), samplingRate, channelMask, format);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
}
}
diff --git a/media/java/android/media/tv/tunerresourcemanager/OWNER b/media/java/android/media/tv/tunerresourcemanager/OWNER
index 76b84d9..0eb1c31 100644
--- a/media/java/android/media/tv/tunerresourcemanager/OWNER
+++ b/media/java/android/media/tv/tunerresourcemanager/OWNER
@@ -1,4 +1,3 @@
-amyjojo@google.com
-nchalko@google.com
quxiangfang@google.com
-shubang@google.com
\ No newline at end of file
+shubang@google.com
+kemiyagi@google.com
\ No newline at end of file
diff --git a/media/tests/TunerTest/OWNERS b/media/tests/TunerTest/OWNERS
index 73ea663..7554889 100644
--- a/media/tests/TunerTest/OWNERS
+++ b/media/tests/TunerTest/OWNERS
@@ -1,4 +1,4 @@
-amyjojo@google.com
-nchalko@google.com
quxiangfang@google.com
shubang@google.com
+hgchen@google.com
+kemiyagi@google.com
\ No newline at end of file
diff --git a/native/android/libandroid_net.map.txt b/native/android/libandroid_net.map.txt
index a6c1b50..32fd734 100644
--- a/native/android/libandroid_net.map.txt
+++ b/native/android/libandroid_net.map.txt
@@ -18,6 +18,10 @@
android_getprocnetwork; # llndk
android_setprocdns; # llndk
android_getprocdns; # llndk
+ # These functions have been part of the NDK since API 33.
+ android_tag_socket_with_uid; # llndk
+ android_tag_socket; # llndk
+ android_untag_socket; # llndk
local:
*;
};
diff --git a/native/android/net.c b/native/android/net.c
index e2f36a7..d7c22e1 100644
--- a/native/android/net.c
+++ b/native/android/net.c
@@ -161,3 +161,15 @@
void android_res_cancel(int nsend_fd) {
resNetworkCancel(nsend_fd);
}
+
+int android_tag_socket_with_uid(int sockfd, int tag, uid_t uid) {
+ return tagSocket(sockfd, tag, uid);
+}
+
+int android_tag_socket(int sockfd, int tag) {
+ return tagSocket(sockfd, tag, -1);
+}
+
+int android_untag_socket(int sockfd) {
+ return untagSocket(sockfd);
+}
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
index f684a4d..d33666d 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStats.java
@@ -545,6 +545,15 @@
}
/**
+ * Collects tagged summary results and sets summary enumeration mode.
+ * @throws RemoteException
+ */
+ void startTaggedSummaryEnumeration() throws RemoteException {
+ mSummary = mSession.getTaggedSummaryForAllUid(mTemplate, mStartTimeStamp, mEndTimeStamp);
+ mEnumerationIndex = 0;
+ }
+
+ /**
* Collects history results for uid and resets history enumeration index.
*/
void startHistoryEnumeration(int uid, int tag, int state) {
diff --git a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
index a316b8a..f74edb1 100644
--- a/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/app/usage/NetworkStatsManager.java
@@ -54,6 +54,7 @@
import java.util.List;
import java.util.Objects;
+import java.util.Set;
/**
* Provides access to network usage history and statistics. Usage data is collected in
@@ -141,7 +142,15 @@
setAugmentWithSubscriptionPlan(true);
}
- /** @hide */
+ /**
+ * Set poll on open flag to indicate the poll is needed before service gets statistics
+ * result. This is default enabled. However, for any non-privileged caller, the poll might
+ * be omitted in case of rate limiting.
+ *
+ * @param pollOnOpen true if poll is needed.
+ * @hide
+ */
+ // @SystemApi(client = MODULE_LIBRARIES)
public void setPollOnOpen(boolean pollOnOpen) {
if (pollOnOpen) {
mFlags |= FLAG_POLL_ON_OPEN;
@@ -368,7 +377,7 @@
* @return Statistics which is described above.
* @hide
*/
- @Nullable
+ @NonNull
// @SystemApi(client = MODULE_LIBRARIES)
@WorkerThread
public NetworkStats querySummary(@NonNull NetworkTemplate template, long startTime,
@@ -385,6 +394,39 @@
}
/**
+ * Query tagged network usage statistics summaries.
+ *
+ * The results will only include tagged traffic made by UIDs belonging to the calling user
+ * profile. The results are aggregated over time, so that all buckets will have the same
+ * start and end timestamps as the passed arguments. Not aggregated over state, uid,
+ * default network, metered, or roaming.
+ * This may take a long time, and apps should avoid calling this on their main thread.
+ *
+ * @param template Template used to match networks. See {@link NetworkTemplate}.
+ * @param startTime Start of period, in milliseconds since the Unix epoch, see
+ * {@link System#currentTimeMillis}.
+ * @param endTime End of period, in milliseconds since the Unix epoch, see
+ * {@link System#currentTimeMillis}.
+ * @return Statistics which is described above.
+ * @hide
+ */
+ @NonNull
+ // @SystemApi(client = MODULE_LIBRARIES)
+ @WorkerThread
+ public NetworkStats queryTaggedSummary(@NonNull NetworkTemplate template, long startTime,
+ long endTime) throws SecurityException {
+ try {
+ NetworkStats result =
+ new NetworkStats(mContext, template, mFlags, startTime, endTime, mService);
+ result.startTaggedSummaryEnumeration();
+ return result;
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ return null; // To make the compiler happy.
+ }
+
+ /**
* Query network usage statistics details for a given uid.
* This may take a long time, and apps should avoid calling this on their main thread.
*
@@ -535,6 +577,31 @@
return result;
}
+ /**
+ * Query realtime network usage statistics details with interfaces constrains.
+ * Return snapshot of current UID statistics, including any {@link TrafficStats#UID_TETHERING},
+ * video calling data usage and count of network operations that set by
+ * {@link TrafficStats#incrementOperationCount}. The returned data doesn't include any
+ * statistics that is reported by {@link NetworkStatsProvider}.
+ *
+ * @param requiredIfaces A list of interfaces the stats should be restricted to, or
+ * {@link NetworkStats#INTERFACES_ALL}.
+ *
+ * @hide
+ */
+ //@SystemApi
+ @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
+ @NonNull public android.net.NetworkStats getDetailedUidStats(
+ @NonNull Set<String> requiredIfaces) {
+ Objects.requireNonNull(requiredIfaces, "requiredIfaces cannot be null");
+ try {
+ return mService.getDetailedUidStats(requiredIfaces.toArray(new String[0]));
+ } catch (RemoteException e) {
+ if (DBG) Log.d(TAG, "Remote exception when get detailed uid stats");
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/** @hide */
public void registerUsageCallback(NetworkTemplate template, int networkType,
long thresholdBytes, UsageCallback callback, @Nullable Handler handler) {
@@ -804,4 +871,74 @@
return msg.getData().getParcelable(key);
}
}
+
+ /**
+ * Mark given UID as being in foreground for stats purposes.
+ *
+ * @hide
+ */
+ // @SystemApi
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_STACK})
+ public void setUidForeground(int uid, boolean uidForeground) {
+ try {
+ mService.setUidForeground(uid, uidForeground);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Advise persistence threshold; may be overridden internally.
+ *
+ * @hide
+ */
+ // @SystemApi
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_STACK})
+ public void advisePersistThreshold(long thresholdBytes) {
+ try {
+ mService.advisePersistThreshold(thresholdBytes);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Force update of statistics.
+ *
+ * @hide
+ */
+ // @SystemApi
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_STACK})
+ public void forceUpdate() {
+ try {
+ mService.forceUpdate();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Set the warning and limit to all registered custom network stats providers.
+ * Note that invocation of any interface will be sent to all providers.
+ *
+ * @hide
+ */
+ // @SystemApi
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_STACK})
+ public void setStatsProviderWarningAndLimitAsync(@NonNull String iface, long warning,
+ long limit) {
+ try {
+ mService.setStatsProviderWarningAndLimitAsync(iface, warning, limit);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl b/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl
index 12937b5..a4babb5 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsService.aidl
@@ -94,4 +94,16 @@
/** Registers a network stats provider */
INetworkStatsProviderCallback registerNetworkStatsProvider(String tag,
in INetworkStatsProvider provider);
+
+ /** Mark given UID as being in foreground for stats purposes. */
+ void setUidForeground(int uid, boolean uidForeground);
+
+ /** Advise persistence threshold; may be overridden internally. */
+ void advisePersistThreshold(long thresholdBytes);
+
+ /**
+ * Set the warning and limit to all registered custom network stats providers.
+ * Note that invocation of any interface will be sent to all providers.
+ */
+ void setStatsProviderWarningAndLimitAsync(String iface, long warning, long limit);
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsSession.aidl b/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsSession.aidl
index dfedf66..babe0bf 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsSession.aidl
+++ b/packages/ConnectivityT/framework-t/src/android/net/INetworkStatsSession.aidl
@@ -46,6 +46,10 @@
*/
@UnsupportedAppUsage
NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags);
+
+ /** Return network layer usage summary per UID for tagged traffic that matches template. */
+ NetworkStats getTaggedSummaryForAllUid(in NetworkTemplate template, long start, long end);
+
/** Return historical network layer stats for specific UID traffic that matches template. */
@UnsupportedAppUsage
NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields);
diff --git a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
index 0d15dff..49aa99b 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/IpSecManager.java
@@ -17,6 +17,7 @@
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
@@ -25,7 +26,6 @@
import android.annotation.TestApi;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.net.annotations.PolicyDirection;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -41,6 +41,8 @@
import java.io.FileDescriptor;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
@@ -88,6 +90,11 @@
@SystemApi(client = MODULE_LIBRARIES)
public static final int DIRECTION_FWD = 2;
+ /** @hide */
+ @IntDef(value = {DIRECTION_IN, DIRECTION_OUT})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PolicyDirection {}
+
/**
* The Security Parameter Index (SPI) 0 indicates an unknown or invalid index.
*
diff --git a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
index 7935d28..9f9d73f 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/NetworkStatsCollection.java
@@ -46,8 +46,6 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastDataInput;
-import com.android.internal.util.FastDataOutput;
import com.android.internal.util.FileRotator;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.NetworkStatsUtils;
@@ -58,6 +56,7 @@
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
+import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -83,9 +82,6 @@
/** File header magic number: "ANET" */
private static final int FILE_MAGIC = 0x414E4554;
- /** Default buffer size from BufferedInputStream */
- private static final int BUFFER_SIZE = 8192;
-
private static final int VERSION_NETWORK_INIT = 1;
private static final int VERSION_UID_INIT = 1;
@@ -439,8 +435,7 @@
@Override
public void read(InputStream in) throws IOException {
- final FastDataInput dataIn = new FastDataInput(in, BUFFER_SIZE);
- read(dataIn);
+ read((DataInput) new DataInputStream(in));
}
private void read(DataInput in) throws IOException {
@@ -479,9 +474,8 @@
@Override
public void write(OutputStream out) throws IOException {
- final FastDataOutput dataOut = new FastDataOutput(out, BUFFER_SIZE);
- write(dataOut);
- dataOut.flush();
+ write((DataOutput) new DataOutputStream(out));
+ out.flush();
}
private void write(DataOutput out) throws IOException {
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsManagerInternal.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsManagerInternal.java
deleted file mode 100644
index 0e9a9da..0000000
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsManagerInternal.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.net;
-
-import android.annotation.NonNull;
-import android.net.NetworkStats;
-import android.net.NetworkTemplate;
-
-public abstract class NetworkStatsManagerInternal {
- /** Return network layer usage total for traffic that matches template. */
- public abstract long getNetworkTotalBytes(NetworkTemplate template, long start, long end);
-
- /** Return network layer usage per-UID for traffic that matches template. */
- public abstract NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end);
-
- /** Mark given UID as being in foreground for stats purposes. */
- public abstract void setUidForeground(int uid, boolean uidForeground);
-
- /** Advise persistance threshold; may be overridden internally. */
- public abstract void advisePersistThreshold(long thresholdBytes);
-
- /** Force update of statistics. */
- public abstract void forceUpdate();
-
- /**
- * Set the warning and limit to all registered custom network stats providers.
- * Note that invocation of any interface will be sent to all providers.
- */
- public abstract void setStatsProviderWarningAndLimitAsync(@NonNull String iface, long warning,
- long limit);
-}
diff --git a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
index 97281ed..e15acf3 100644
--- a/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/net/NetworkStatsService.java
@@ -44,6 +44,7 @@
import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
import static android.net.TrafficStats.KB_IN_BYTES;
import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.net.TrafficStats.UID_TETHERING;
import static android.net.TrafficStats.UNSUPPORTED;
import static android.os.Trace.TRACE_TAG_NETWORK;
import static android.provider.Settings.Global.NETSTATS_AUGMENT_ENABLED;
@@ -70,7 +71,7 @@
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import static com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport;
-import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
+import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT;
import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
@@ -89,13 +90,13 @@
import android.database.ContentObserver;
import android.net.DataUsageRequest;
import android.net.INetd;
-import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsService;
import android.net.INetworkStatsSession;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkIdentity;
import android.net.NetworkIdentitySet;
+import android.net.NetworkPolicyManager;
import android.net.NetworkSpecifier;
import android.net.NetworkStack;
import android.net.NetworkStateSnapshot;
@@ -106,6 +107,7 @@
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TelephonyNetworkSpecifier;
+import android.net.TetherStatsParcel;
import android.net.TetheringManager;
import android.net.TrafficStats;
import android.net.UnderlyingNetworkInfo;
@@ -120,12 +122,12 @@
import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IBinder;
-import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
@@ -148,12 +150,12 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FileRotator;
+import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
import com.android.net.module.util.BestClock;
import com.android.net.module.util.BinderUtils;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.NetworkStatsUtils;
import com.android.net.module.util.PermissionUtils;
-import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import java.io.File;
@@ -207,8 +209,15 @@
private static final String TAG_NETSTATS_ERROR = "netstats_error";
+ /**
+ * EventLog tags used when logging into the event log. Note the values must be sync with
+ * frameworks/base/services/core/java/com/android/server/EventLogTags.logtags to get correct
+ * name translation.
+ */
+ private static final int LOG_TAG_NETSTATS_MOBILE_SAMPLE = 51100;
+ private static final int LOG_TAG_NETSTATS_WIFI_SAMPLE = 51101;
+
private final Context mContext;
- private final INetworkManagementService mNetworkManager;
private final NetworkStatsFactory mStatsFactory;
private final AlarmManager mAlarmManager;
private final Clock mClock;
@@ -223,6 +232,9 @@
private final ContentObserver mContentObserver;
private final ContentResolver mContentResolver;
+ protected INetd mNetd;
+ private final AlertObserver mAlertObserver = new AlertObserver();
+
@VisibleForTesting
public static final String ACTION_NETWORK_STATS_POLL =
"com.android.server.action.NETWORK_STATS_POLL";
@@ -405,20 +417,20 @@
}
}
- public static NetworkStatsService create(Context context,
- INetworkManagementService networkManager) {
+ /** Creates a new NetworkStatsService */
+ public static NetworkStatsService create(Context context) {
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock =
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
final INetd netd = INetd.Stub.asInterface(
(IBinder) context.getSystemService(Context.NETD_SERVICE));
- final NetworkStatsService service = new NetworkStatsService(context, networkManager,
+ final NetworkStatsService service = new NetworkStatsService(context,
+ INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE)),
alarmManager, wakeLock, getDefaultClock(),
new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(netd),
new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(),
new Dependencies());
- service.registerLocalService();
return service;
}
@@ -426,14 +438,12 @@
// This must not be called outside of tests, even within the same package, as this constructor
// does not register the local service. Use the create() helper above.
@VisibleForTesting
- NetworkStatsService(Context context, INetworkManagementService networkManager,
- AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock,
- NetworkStatsSettings settings, NetworkStatsFactory factory,
- NetworkStatsObservers statsObservers, File systemDir, File baseDir,
- @NonNull Dependencies deps) {
+ NetworkStatsService(Context context, INetd netd, AlarmManager alarmManager,
+ PowerManager.WakeLock wakeLock, Clock clock, NetworkStatsSettings settings,
+ NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir,
+ File baseDir, @NonNull Dependencies deps) {
mContext = Objects.requireNonNull(context, "missing Context");
- mNetworkManager = Objects.requireNonNull(networkManager,
- "missing INetworkManagementService");
+ mNetd = Objects.requireNonNull(netd, "missing Netd");
mAlarmManager = Objects.requireNonNull(alarmManager, "missing AlarmManager");
mClock = Objects.requireNonNull(clock, "missing Clock");
mSettings = Objects.requireNonNull(settings, "missing NetworkStatsSettings");
@@ -501,9 +511,24 @@
}
}
- private void registerLocalService() {
- LocalServices.addService(NetworkStatsManagerInternal.class,
- new NetworkStatsManagerInternalImpl());
+ /**
+ * Observer that watches for {@link INetdUnsolicitedEventListener} alerts.
+ */
+ @VisibleForTesting
+ public class AlertObserver extends BaseNetdUnsolicitedEventListener {
+ @Override
+ public void onQuotaLimitReached(@NonNull String alertName, @NonNull String ifName) {
+ PermissionUtils.enforceNetworkStackPermission(mContext);
+
+ if (LIMIT_GLOBAL_ALERT.equals(alertName)) {
+ // kick off background poll to collect network stats unless there is already
+ // such a call pending; UID stats are handled during normal polling interval.
+ if (!mHandler.hasMessages(MSG_PERFORM_POLL_REGISTER_ALERT)) {
+ mHandler.sendEmptyMessageDelayed(MSG_PERFORM_POLL_REGISTER_ALERT,
+ mSettings.getPollDelay());
+ }
+ }
+ }
}
public void systemReady() {
@@ -551,9 +576,9 @@
mContext.registerReceiver(mShutdownReceiver, shutdownFilter);
try {
- mNetworkManager.registerObserver(mAlertObserver);
- } catch (RemoteException e) {
- // ignored; service lives in system_server
+ mNetd.registerUnsolicitedEventListener(mAlertObserver);
+ } catch (RemoteException | ServiceSpecificException e) {
+ Log.wtf(TAG, "Error registering event listener :", e);
}
// schedule periodic pall alarm based on {@link NetworkStatsSettings#getPollInterval()}.
@@ -641,13 +666,13 @@
}
/**
- * Register for a global alert that is delivered through {@link INetworkManagementEventObserver}
+ * Register for a global alert that is delivered through {@link AlertObserver}
* or {@link NetworkStatsProviderCallback#onAlertReached()} once a threshold amount of data has
* been transferred.
*/
private void registerGlobalAlert() {
try {
- mNetworkManager.setGlobalAlert(mGlobalAlertBytes);
+ mNetd.bandwidthSetGlobalAlert(mGlobalAlertBytes);
} catch (IllegalStateException e) {
Log.w(TAG, "problem registering for global alert: " + e);
} catch (RemoteException e) {
@@ -766,8 +791,18 @@
}
return stats;
} catch (NullPointerException e) {
- // TODO: Track down and fix the cause of this crash and remove this catch block.
- Log.wtf(TAG, "NullPointerException in getSummaryForAllUid", e);
+ throw e;
+ }
+ }
+
+ @Override
+ public NetworkStats getTaggedSummaryForAllUid(
+ NetworkTemplate template, long start, long end) {
+ try {
+ final NetworkStats tagStats = getUidTagComplete()
+ .getSummary(template, start, end, mAccessLevel, mCallingUid);
+ return tagStats;
+ } catch (NullPointerException e) {
throw e;
}
}
@@ -827,7 +862,7 @@
if (LOGD) Log.d(TAG, "Resolving plan for " + template);
final long token = Binder.clearCallingIdentity();
try {
- plan = LocalServices.getService(NetworkPolicyManagerInternal.class)
+ plan = mContext.getSystemService(NetworkPolicyManager.class)
.getSubscriptionPlan(template);
} finally {
Binder.restoreCallingIdentity(token);
@@ -922,6 +957,7 @@
@Override
public NetworkStats getDetailedUidStats(String[] requiredIfaces) {
+ enforceAnyPermissionOf(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
try {
final String[] ifacesToQuery =
mStatsFactory.augmentWithStackedInterfaces(requiredIfaces);
@@ -965,7 +1001,8 @@
}
@VisibleForTesting
- void setUidForeground(int uid, boolean uidForeground) {
+ public void setUidForeground(int uid, boolean uidForeground) {
+ PermissionUtils.enforceNetworkStackPermission(mContext);
synchronized (mStatsLock) {
final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT;
final int oldSet = mActiveUidCounterSet.get(uid, SET_DEFAULT);
@@ -1001,7 +1038,7 @@
@Override
public void forceUpdate() {
- mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+ PermissionUtils.enforceNetworkStackPermission(mContext);
final long token = Binder.clearCallingIdentity();
try {
@@ -1011,7 +1048,9 @@
}
}
- private void advisePersistThreshold(long thresholdBytes) {
+ /** Advise persistence threshold; may be overridden internally. */
+ public void advisePersistThreshold(long thresholdBytes) {
+ PermissionUtils.enforceNetworkStackPermission(mContext);
// clamp threshold into safe range
mPersistThreshold = NetworkStatsUtils.constrain(thresholdBytes,
128 * KB_IN_BYTES, 2 * MB_IN_BYTES);
@@ -1226,26 +1265,6 @@
};
/**
- * Observer that watches for {@link INetworkManagementService} alerts.
- */
- private final INetworkManagementEventObserver mAlertObserver = new BaseNetworkObserver() {
- @Override
- public void limitReached(String limitName, String iface) {
- // only someone like NMS should be calling us
- PermissionUtils.enforceNetworkStackPermission(mContext);
-
- if (LIMIT_GLOBAL_ALERT.equals(limitName)) {
- // kick off background poll to collect network stats unless there is already
- // such a call pending; UID stats are handled during normal polling interval.
- if (!mHandler.hasMessages(MSG_PERFORM_POLL_REGISTER_ALERT)) {
- mHandler.sendEmptyMessageDelayed(MSG_PERFORM_POLL_REGISTER_ALERT,
- mSettings.getPollDelay());
- }
- }
- }
- };
-
- /**
* Handle collapsed RAT type changed event.
*/
@VisibleForTesting
@@ -1610,7 +1629,7 @@
xtTotal = mXtRecorder.getTotalSinceBootLocked(template);
uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
- EventLogTags.writeNetstatsMobileSample(
+ EventLog.writeEvent(LOG_TAG_NETSTATS_MOBILE_SAMPLE,
devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
@@ -1622,7 +1641,7 @@
xtTotal = mXtRecorder.getTotalSinceBootLocked(template);
uidTotal = mUidRecorder.getTotalSinceBootLocked(template);
- EventLogTags.writeNetstatsWifiSample(
+ EventLog.writeEvent(LOG_TAG_NETSTATS_WIFI_SAMPLE,
devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets,
xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets,
uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets,
@@ -1668,52 +1687,19 @@
removeUidsLocked(CollectionUtils.toIntArray(uids));
}
- private class NetworkStatsManagerInternalImpl extends NetworkStatsManagerInternal {
- @Override
- public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
- Trace.traceBegin(TRACE_TAG_NETWORK, "getNetworkTotalBytes");
- try {
- return NetworkStatsService.this.getNetworkTotalBytes(template, start, end);
- } finally {
- Trace.traceEnd(TRACE_TAG_NETWORK);
- }
+ /**
+ * Set the warning and limit to all registered custom network stats providers.
+ * Note that invocation of any interface will be sent to all providers.
+ */
+ public void setStatsProviderWarningAndLimitAsync(
+ @NonNull String iface, long warning, long limit) {
+ PermissionUtils.enforceNetworkStackPermission(mContext);
+ if (LOGV) {
+ Log.v(TAG, "setStatsProviderWarningAndLimitAsync("
+ + iface + "," + warning + "," + limit + ")");
}
-
- @Override
- public NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) {
- Trace.traceBegin(TRACE_TAG_NETWORK, "getNetworkUidBytes");
- try {
- return NetworkStatsService.this.getNetworkUidBytes(template, start, end);
- } finally {
- Trace.traceEnd(TRACE_TAG_NETWORK);
- }
- }
-
- @Override
- public void setUidForeground(int uid, boolean uidForeground) {
- NetworkStatsService.this.setUidForeground(uid, uidForeground);
- }
-
- @Override
- public void advisePersistThreshold(long thresholdBytes) {
- NetworkStatsService.this.advisePersistThreshold(thresholdBytes);
- }
-
- @Override
- public void forceUpdate() {
- NetworkStatsService.this.forceUpdate();
- }
-
- @Override
- public void setStatsProviderWarningAndLimitAsync(
- @NonNull String iface, long warning, long limit) {
- if (LOGV) {
- Log.v(TAG, "setStatsProviderWarningAndLimitAsync("
- + iface + "," + warning + "," + limit + ")");
- }
- invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface,
- warning, limit));
- }
+ invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface,
+ warning, limit));
}
@Override
@@ -1956,13 +1942,29 @@
*/
// TODO: Remove this by implementing {@link NetworkStatsProvider} for non-offloaded
// tethering stats.
- private NetworkStats getNetworkStatsTethering(int how) throws RemoteException {
+ private @NonNull NetworkStats getNetworkStatsTethering(int how) throws RemoteException {
+ // We only need to return per-UID stats. Per-device stats are already counted by
+ // interface counters.
+ if (how != STATS_PER_UID) {
+ return new NetworkStats(SystemClock.elapsedRealtime(), 0);
+ }
+
+ final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
try {
- return mNetworkManager.getNetworkStatsTethering(how);
+ final TetherStatsParcel[] tetherStatsParcels = mNetd.tetherGetStats();
+ for (TetherStatsParcel tetherStats : tetherStatsParcels) {
+ try {
+ stats.combineValues(new NetworkStats.Entry(tetherStats.iface, UID_TETHERING,
+ SET_DEFAULT, TAG_NONE, tetherStats.rxBytes, tetherStats.rxPackets,
+ tetherStats.txBytes, tetherStats.txPackets, 0L));
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new IllegalStateException("invalid tethering stats " + e);
+ }
+ }
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem reading network stats", e);
- return new NetworkStats(0L, 10);
}
+ return stats;
}
// TODO: It is copied from ConnectivityService, consider refactor these check permission
@@ -2001,10 +2003,12 @@
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
Objects.requireNonNull(provider, "provider is null");
Objects.requireNonNull(tag, "tag is null");
+ final NetworkPolicyManager netPolicyManager = mContext
+ .getSystemService(NetworkPolicyManager.class);
try {
NetworkStatsProviderCallbackImpl callback = new NetworkStatsProviderCallbackImpl(
tag, provider, mStatsProviderSem, mAlertObserver,
- mStatsProviderCbList);
+ mStatsProviderCbList, netPolicyManager);
mStatsProviderCbList.add(callback);
Log.d(TAG, "registerNetworkStatsProvider from " + callback.mTag + " uid/pid="
+ getCallingUid() + "/" + getCallingPid());
@@ -2044,8 +2048,9 @@
@NonNull final INetworkStatsProvider mProvider;
@NonNull private final Semaphore mSemaphore;
- @NonNull final INetworkManagementEventObserver mAlertObserver;
+ @NonNull final AlertObserver mAlertObserver;
@NonNull final CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList;
+ @NonNull final NetworkPolicyManager mNetworkPolicyManager;
@NonNull private final Object mProviderStatsLock = new Object();
@@ -2058,8 +2063,9 @@
NetworkStatsProviderCallbackImpl(
@NonNull String tag, @NonNull INetworkStatsProvider provider,
@NonNull Semaphore semaphore,
- @NonNull INetworkManagementEventObserver alertObserver,
- @NonNull CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> cbList)
+ @NonNull AlertObserver alertObserver,
+ @NonNull CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> cbList,
+ @NonNull NetworkPolicyManager networkPolicyManager)
throws RemoteException {
mTag = tag;
mProvider = provider;
@@ -2067,6 +2073,7 @@
mSemaphore = semaphore;
mAlertObserver = alertObserver;
mStatsProviderCbList = cbList;
+ mNetworkPolicyManager = networkPolicyManager;
}
@NonNull
@@ -2106,15 +2113,14 @@
// This binder object can only have been obtained by a process that holds
// NETWORK_STATS_PROVIDER. Thus, no additional permission check is required.
BinderUtils.withCleanCallingIdentity(() ->
- mAlertObserver.limitReached(LIMIT_GLOBAL_ALERT, null /* unused */));
+ mAlertObserver.onQuotaLimitReached(LIMIT_GLOBAL_ALERT, null /* unused */));
}
@Override
public void notifyWarningOrLimitReached() {
Log.d(TAG, mTag + ": notifyWarningOrLimitReached");
BinderUtils.withCleanCallingIdentity(() ->
- LocalServices.getService(NetworkPolicyManagerInternal.class)
- .onStatsProviderWarningOrLimitReached(mTag));
+ mNetworkPolicyManager.onStatsProviderWarningOrLimitReached());
}
@Override
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index a2c2dbd..3951680 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -39,6 +39,8 @@
import static android.net.NetworkStats.TAG_NONE;
import static android.net.TrafficStats.UID_TETHERING;
+import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT;
+
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.content.Context;
@@ -133,12 +135,6 @@
private static final int MAX_UID_RANGES_PER_COMMAND = 10;
- /**
- * Name representing {@link #setGlobalAlert(long)} limit when delivered to
- * {@link INetworkManagementEventObserver#limitReached(String, String)}.
- */
- public static final String LIMIT_GLOBAL_ALERT = "globalAlert";
-
static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
static final boolean MODIFY_OPERATION_ADD = true;
diff --git a/services/core/java/com/android/server/SmartStorageMaintIdler.java b/services/core/java/com/android/server/SmartStorageMaintIdler.java
new file mode 100644
index 0000000..2dff72f
--- /dev/null
+++ b/services/core/java/com/android/server/SmartStorageMaintIdler.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.util.Slog;
+
+import java.util.concurrent.TimeUnit;
+
+public class SmartStorageMaintIdler extends JobService {
+ private static final String TAG = "SmartStorageMaintIdler";
+
+ private static final ComponentName SMART_STORAGE_MAINT_SERVICE =
+ new ComponentName("android", SmartStorageMaintIdler.class.getName());
+
+ private static final int SMART_MAINT_JOB_ID = 2808;
+
+ private boolean mStarted;
+ private JobParameters mJobParams;
+ private final Runnable mFinishCallback = new Runnable() {
+ @Override
+ public void run() {
+ Slog.i(TAG, "Got smart storage maintenance service completion callback");
+ if (mStarted) {
+ jobFinished(mJobParams, false);
+ mStarted = false;
+ }
+ // ... and try again in a next period
+ scheduleSmartIdlePass(SmartStorageMaintIdler.this,
+ StorageManagerService.SMART_IDLE_MAINT_PERIOD);
+ }
+ };
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ mJobParams = params;
+ StorageManagerService ms = StorageManagerService.sSelf;
+ if (ms != null) {
+ mStarted = true;
+ ms.runSmartIdleMaint(mFinishCallback);
+ }
+ return ms != null;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ mStarted = false;
+ return false;
+ }
+
+ /**
+ * Schedule the smart storage idle maintenance job
+ */
+ public static void scheduleSmartIdlePass(Context context, int nHours) {
+ StorageManagerService ms = StorageManagerService.sSelf;
+ if ((ms == null) || ms.isPassedLifetimeThresh()) {
+ return;
+ }
+
+ JobScheduler tm = context.getSystemService(JobScheduler.class);
+
+ long nextScheduleTime = TimeUnit.HOURS.toMillis(nHours);
+
+ JobInfo.Builder builder = new JobInfo.Builder(SMART_MAINT_JOB_ID,
+ SMART_STORAGE_MAINT_SERVICE);
+
+ builder.setMinimumLatency(nextScheduleTime);
+ tm.schedule(builder.build());
+ }
+}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 2d6170b..53c8635 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -79,6 +79,7 @@
import android.content.res.ObbInfo;
import android.database.ContentObserver;
import android.net.Uri;
+import android.os.BatteryManager;
import android.os.Binder;
import android.os.DropBoxManager;
import android.os.Environment;
@@ -158,6 +159,8 @@
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal.ScreenObserver;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
@@ -339,7 +342,44 @@
@Nullable public static String sMediaStoreAuthorityProcessName;
+ // Run period in hour for smart idle maintenance
+ static final int SMART_IDLE_MAINT_PERIOD = 1;
+
private final AtomicFile mSettingsFile;
+ private final AtomicFile mHourlyWriteFile;
+
+ private static final int MAX_HOURLY_WRITE_RECORDS = 72;
+
+ /**
+ * Default config values for smart idle maintenance
+ * Actual values will be controlled by DeviceConfig
+ */
+ // Decide whether smart idle maintenance is enabled or not
+ private static final boolean DEFAULT_SMART_IDLE_MAINT_ENABLED = false;
+ // Storage lifetime percentage threshold to decide to turn off the feature
+ private static final int DEFAULT_LIFETIME_PERCENT_THRESHOLD = 70;
+ // Minimum required number of dirty + free segments to trigger GC
+ private static final int DEFAULT_MIN_SEGMENTS_THRESHOLD = 512;
+ // Determine how much portion of current dirty segments will be GCed
+ private static final float DEFAULT_DIRTY_RECLAIM_RATE = 0.5F;
+ // Multiplier to amplify the target segment number for GC
+ private static final float DEFAULT_SEGMENT_RECLAIM_WEIGHT = 1.0F;
+ // Low battery level threshold to decide to turn off the feature
+ private static final float DEFAULT_LOW_BATTERY_LEVEL = 20F;
+ // Decide whether charging is required to turn on the feature
+ private static final boolean DEFAULT_CHARGING_REQUIRED = true;
+
+ private volatile int mLifetimePercentThreshold;
+ private volatile int mMinSegmentsThreshold;
+ private volatile float mDirtyReclaimRate;
+ private volatile float mSegmentReclaimWeight;
+ private volatile float mLowBatteryLevel;
+ private volatile boolean mChargingRequired;
+ private volatile boolean mNeedGC;
+
+ private volatile boolean mPassedLifetimeThresh;
+ // Tracking storage hourly write amounts
+ private volatile int[] mStorageHourlyWrites;
/**
* <em>Never</em> hold the lock while performing downcalls into vold, since
@@ -901,6 +941,10 @@
}
private void handleSystemReady() {
+ if (prepareSmartIdleMaint()) {
+ SmartStorageMaintIdler.scheduleSmartIdlePass(mContext, SMART_IDLE_MAINT_PERIOD);
+ }
+
// Start scheduling nominally-daily fstrim operations
MountServiceIdler.scheduleIdlePass(mContext);
@@ -1907,6 +1951,10 @@
mSettingsFile = new AtomicFile(
new File(Environment.getDataSystemDirectory(), "storage.xml"), "storage-settings");
+ mHourlyWriteFile = new AtomicFile(
+ new File(Environment.getDataSystemDirectory(), "storage-hourly-writes"));
+
+ mStorageHourlyWrites = new int[MAX_HOURLY_WRITE_RECORDS];
synchronized (mLock) {
readSettingsLocked();
@@ -2572,7 +2620,7 @@
// fstrim time is still updated. If file based checkpoints are used, we run
// idle maintenance (GC + fstrim) regardless of checkpoint status.
if (!needsCheckpoint() || !supportsBlockCheckpoint()) {
- mVold.runIdleMaint(new IVoldTaskListener.Stub() {
+ mVold.runIdleMaint(mNeedGC, new IVoldTaskListener.Stub() {
@Override
public void onStatus(int status, PersistableBundle extras) {
// Not currently used
@@ -2623,6 +2671,176 @@
abortIdleMaint(null);
}
+ private boolean prepareSmartIdleMaint() {
+ /**
+ * We can choose whether going with a new storage smart idle maintenance job
+ * or falling back to the traditional way using DeviceConfig
+ */
+ boolean smartIdleMaintEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "smart_idle_maint_enabled",
+ DEFAULT_SMART_IDLE_MAINT_ENABLED);
+ if (smartIdleMaintEnabled) {
+ mLifetimePercentThreshold = DeviceConfig.getInt(
+ DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "lifetime_threshold", DEFAULT_LIFETIME_PERCENT_THRESHOLD);
+ mMinSegmentsThreshold = DeviceConfig.getInt(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "min_segments_threshold", DEFAULT_MIN_SEGMENTS_THRESHOLD);
+ mDirtyReclaimRate = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "dirty_reclaim_rate", DEFAULT_DIRTY_RECLAIM_RATE);
+ mSegmentReclaimWeight = DeviceConfig.getFloat(
+ DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "segment_reclaim_weight", DEFAULT_SEGMENT_RECLAIM_WEIGHT);
+ mLowBatteryLevel = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "low_battery_level", DEFAULT_LOW_BATTERY_LEVEL);
+ mChargingRequired = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT,
+ "charging_required", DEFAULT_CHARGING_REQUIRED);
+
+ // If we use the smart idle maintenance, we need to turn off GC in the traditional idle
+ // maintenance to avoid the conflict
+ mNeedGC = false;
+
+ loadStorageHourlyWrites();
+ try {
+ mVold.refreshLatestWrite();
+ } catch (Exception e) {
+ Slog.wtf(TAG, e);
+ }
+ refreshLifetimeConstraint();
+ }
+ return smartIdleMaintEnabled;
+ }
+
+ // Return whether storage lifetime exceeds the threshold
+ public boolean isPassedLifetimeThresh() {
+ return mPassedLifetimeThresh;
+ }
+
+ private void loadStorageHourlyWrites() {
+ FileInputStream fis = null;
+
+ try {
+ fis = mHourlyWriteFile.openRead();
+ ObjectInputStream ois = new ObjectInputStream(fis);
+ mStorageHourlyWrites = (int[])ois.readObject();
+ } catch (FileNotFoundException e) {
+ // Missing data is okay, probably first boot
+ } catch (Exception e) {
+ Slog.wtf(TAG, "Failed reading write records", e);
+ } finally {
+ IoUtils.closeQuietly(fis);
+ }
+ }
+
+ private int getAverageHourlyWrite() {
+ return Arrays.stream(mStorageHourlyWrites).sum() / MAX_HOURLY_WRITE_RECORDS;
+ }
+
+ private void updateStorageHourlyWrites(int latestWrite) {
+ FileOutputStream fos = null;
+
+ System.arraycopy(mStorageHourlyWrites,0, mStorageHourlyWrites, 1,
+ MAX_HOURLY_WRITE_RECORDS - 1);
+ mStorageHourlyWrites[0] = latestWrite;
+ try {
+ fos = mHourlyWriteFile.startWrite();
+ ObjectOutputStream oos = new ObjectOutputStream(fos);
+ oos.writeObject(mStorageHourlyWrites);
+ mHourlyWriteFile.finishWrite(fos);
+ } catch (IOException e) {
+ if (fos != null) {
+ mHourlyWriteFile.failWrite(fos);
+ }
+ }
+ }
+
+ private boolean checkChargeStatus() {
+ IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+ Intent batteryStatus = mContext.registerReceiver(null, ifilter);
+
+ if (mChargingRequired) {
+ int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
+ if (status != BatteryManager.BATTERY_STATUS_CHARGING &&
+ status != BatteryManager.BATTERY_STATUS_FULL) {
+ Slog.w(TAG, "Battery is not being charged");
+ return false;
+ }
+ }
+
+ int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
+ int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
+ float chargePercent = level * 100f / (float)scale;
+
+ if (chargePercent < mLowBatteryLevel) {
+ Slog.w(TAG, "Battery level is " + chargePercent + ", which is lower than threshold: " +
+ mLowBatteryLevel);
+ return false;
+ }
+ return true;
+ }
+
+ private boolean refreshLifetimeConstraint() {
+ int storageLifeTime = 0;
+
+ try {
+ storageLifeTime = mVold.getStorageLifeTime();
+ } catch (Exception e) {
+ Slog.wtf(TAG, e);
+ return false;
+ }
+
+ if (storageLifeTime == -1) {
+ Slog.w(TAG, "Failed to get storage lifetime");
+ return false;
+ } else if (storageLifeTime > mLifetimePercentThreshold) {
+ Slog.w(TAG, "Ended smart idle maintenance, because of lifetime(" + storageLifeTime +
+ ")" + ", lifetime threshold(" + mLifetimePercentThreshold + ")");
+ mPassedLifetimeThresh = true;
+ return false;
+ }
+ Slog.i(TAG, "Storage lifetime: " + storageLifeTime);
+ return true;
+ }
+
+ void runSmartIdleMaint(Runnable callback) {
+ enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
+
+ try {
+ // Block based checkpoint process runs fstrim. So, if checkpoint is in progress
+ // (first boot after OTA), We skip the smart idle maintenance
+ if (!needsCheckpoint() || !supportsBlockCheckpoint()) {
+ if (!refreshLifetimeConstraint() || !checkChargeStatus()) {
+ return;
+ }
+
+ int latestHourlyWrite = mVold.getWriteAmount();
+ if (latestHourlyWrite == -1) {
+ Slog.w(TAG, "Failed to get storage hourly write");
+ return;
+ }
+
+ updateStorageHourlyWrites(latestHourlyWrite);
+ int avgHourlyWrite = getAverageHourlyWrite();
+
+ Slog.i(TAG, "Set smart idle maintenance: " + "latest hourly write: " +
+ latestHourlyWrite + ", average hourly write: " + avgHourlyWrite +
+ ", min segment threshold: " + mMinSegmentsThreshold +
+ ", dirty reclaim rate: " + mDirtyReclaimRate +
+ ", segment reclaim weight:" + mSegmentReclaimWeight);
+ mVold.setGCUrgentPace(avgHourlyWrite, mMinSegmentsThreshold, mDirtyReclaimRate,
+ mSegmentReclaimWeight);
+ } else {
+ Slog.i(TAG, "Skipping smart idle maintenance - block based checkpoint in progress");
+ }
+ } catch (Exception e) {
+ Slog.wtf(TAG, e);
+ } finally {
+ if (callback != null) {
+ callback.run();
+ }
+ }
+ }
+
@Override
public void setDebugFlags(int flags, int mask) {
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 7ba032f..c6bca19 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -16,6 +16,7 @@
package com.android.server.am;
import android.annotation.Nullable;
+import android.app.usage.NetworkStatsManager;
import android.bluetooth.BluetoothActivityEnergyInfo;
import android.bluetooth.BluetoothAdapter;
import android.content.Context;
@@ -702,8 +703,10 @@
if (wifiInfo.isValid()) {
final long wifiChargeUC = measuredEnergyDeltas != null ?
measuredEnergyDeltas.wifiChargeUC : MeasuredEnergySnapshot.UNAVAILABLE;
- mStats.updateWifiState(
- extractDeltaLocked(wifiInfo), wifiChargeUC, elapsedRealtime, uptime);
+ final NetworkStatsManager networkStatsManager = mInjector.getSystemService(
+ NetworkStatsManager.class);
+ mStats.updateWifiState(extractDeltaLocked(wifiInfo),
+ wifiChargeUC, elapsedRealtime, uptime, networkStatsManager);
} else {
Slog.w(TAG, "wifi info is invalid: " + wifiInfo);
}
@@ -712,8 +715,10 @@
if (modemInfo != null) {
final long mobileRadioChargeUC = measuredEnergyDeltas != null
? measuredEnergyDeltas.mobileRadioChargeUC : MeasuredEnergySnapshot.UNAVAILABLE;
+ final NetworkStatsManager networkStatsManager = mInjector.getSystemService(
+ NetworkStatsManager.class);
mStats.noteModemControllerActivity(modemInfo, mobileRadioChargeUC, elapsedRealtime,
- uptime);
+ uptime, networkStatsManager);
}
if (updateFlags == UPDATE_ALL) {
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 9a349ef..d75ddba 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -22,6 +22,7 @@
import android.annotation.NonNull;
import android.app.StatsManager;
+import android.app.usage.NetworkStatsManager;
import android.bluetooth.BluetoothActivityEnergyInfo;
import android.content.ContentResolver;
import android.content.Context;
@@ -2025,8 +2026,11 @@
synchronized (mLock) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
+ final NetworkStatsManager networkStatsManager = mContext.getSystemService(
+ NetworkStatsManager.class);
mHandler.post(() -> {
- mStats.updateWifiState(info, POWER_DATA_UNAVAILABLE, elapsedRealtime, uptime);
+ mStats.updateWifiState(info, POWER_DATA_UNAVAILABLE, elapsedRealtime, uptime,
+ networkStatsManager);
});
}
}
@@ -2063,9 +2067,11 @@
synchronized (mLock) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
+ final NetworkStatsManager networkStatsManager = mContext.getSystemService(
+ NetworkStatsManager.class);
mHandler.post(() -> {
mStats.noteModemControllerActivity(info, POWER_DATA_UNAVAILABLE, elapsedRealtime,
- uptime);
+ uptime, networkStatsManager);
});
}
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 0a114b9..fba8c05 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -1088,6 +1088,12 @@
private void makeLeAudioDeviceAvailable(String address, String name, int streamType, int device,
String eventSource) {
if (device != AudioSystem.DEVICE_NONE) {
+
+ /* Audio Policy sees Le Audio similar to A2DP. Let's make sure
+ * AUDIO_POLICY_FORCE_NO_BT_A2DP is not set
+ */
+ mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/, eventSource);
+
AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE,
address, name, AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address),
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 093ecd5..3d5abfe 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -535,9 +535,6 @@
mEmulatorClipboardMonitor.accept(clip);
final int userId = UserHandle.getUserId(uid);
- if (clip != null) {
- startClassificationLocked(clip, userId);
- }
// Update this user
setPrimaryClipInternalLocked(getClipboardLocked(userId), clip, uid, sourcePackage);
@@ -593,6 +590,17 @@
@GuardedBy("mLock")
private void setPrimaryClipInternalLocked(PerUserClipboard clipboard, @Nullable ClipData clip,
int uid, @Nullable String sourcePackage) {
+ final int userId = UserHandle.getUserId(uid);
+ if (clip != null) {
+ startClassificationLocked(clip, userId);
+ }
+
+ setPrimaryClipInternalNoClassifyLocked(clipboard, clip, uid, sourcePackage);
+ }
+
+ @GuardedBy("mLock")
+ private void setPrimaryClipInternalNoClassifyLocked(PerUserClipboard clipboard,
+ @Nullable ClipData clip, int uid, @Nullable String sourcePackage) {
revokeUris(clipboard);
clipboard.activePermissionOwners.clear();
if (clip == null && clipboard.primaryClip == null) {
diff --git a/services/core/java/com/android/server/media/OWNERS b/services/core/java/com/android/server/media/OWNERS
index 2e2d812..8097f4e 100644
--- a/services/core/java/com/android/server/media/OWNERS
+++ b/services/core/java/com/android/server/media/OWNERS
@@ -1,8 +1,6 @@
+# Bug component: 137631
elaurent@google.com
-hdmoon@google.com
-insun@google.com
-jaewan@google.com
-jinpark@google.com
-klhyun@google.com
lajos@google.com
-sungsoo@google.com
+
+# go/android-fwk-media-solutions for info on areas of ownership.
+include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
index 03a63b9..8ef42ff 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
@@ -16,11 +16,8 @@
package com.android.server.net;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.Network;
-import android.net.NetworkTemplate;
-import android.net.netstats.provider.NetworkStatsProvider;
import android.os.PowerExemptionManager.ReasonCode;
import android.telephony.SubscriptionPlan;
@@ -56,11 +53,6 @@
*/
public abstract SubscriptionPlan getSubscriptionPlan(Network network);
- /**
- * Return the active {@link SubscriptionPlan} for the given template.
- */
- public abstract SubscriptionPlan getSubscriptionPlan(NetworkTemplate template);
-
public static final int QUOTA_TYPE_JOBS = 1;
public static final int QUOTA_TYPE_MULTIPATH = 2;
@@ -99,13 +91,4 @@
*/
public abstract void setMeteredRestrictedPackagesAsync(
Set<String> packageNames, int userId);
-
- /**
- * Notifies that the specified {@link NetworkStatsProvider} has reached its quota
- * which was set through {@link NetworkStatsProvider#onSetLimit(String, long)} or
- * {@link NetworkStatsProvider#onSetWarningAndLimit(String, long, long)}.
- *
- * @param tag the human readable identifier of the custom network stats provider.
- */
- public abstract void onStatsProviderWarningOrLimitReached(@NonNull String tag);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 2ca057d..e1cbdb7 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -130,7 +130,7 @@
import static com.android.internal.util.XmlUtils.writeIntAttribute;
import static com.android.internal.util.XmlUtils.writeLongAttribute;
import static com.android.internal.util.XmlUtils.writeStringAttribute;
-import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
+import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT;
import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -151,6 +151,8 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.usage.NetworkStats;
+import android.app.usage.NetworkStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -181,7 +183,6 @@
import android.net.NetworkSpecifier;
import android.net.NetworkStack;
import android.net.NetworkStateSnapshot;
-import android.net.NetworkStats;
import android.net.NetworkTemplate;
import android.net.TelephonyNetworkSpecifier;
import android.net.TrafficStats;
@@ -443,7 +444,7 @@
private final Context mContext;
private final IActivityManager mActivityManager;
- private NetworkStatsManagerInternal mNetworkStats;
+ private NetworkStatsManager mNetworkStats;
private final INetworkManagementService mNetworkManager;
private UsageStatsManagerInternal mUsageStats;
private AppStandbyInternal mAppStandby;
@@ -455,6 +456,8 @@
private ConnectivityManager mConnManager;
private PowerManagerInternal mPowerManagerInternal;
private PowerWhitelistManager mPowerWhitelistManager;
+ @NonNull
+ private final Dependencies mDeps;
/** Current cached value of the current Battery Saver mode's setting for restrict background. */
@GuardedBy("mUidRulesFirstLock")
@@ -706,7 +709,7 @@
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
INetworkManagementService networkManagement) {
this(context, activityManager, networkManagement, AppGlobals.getPackageManager(),
- getDefaultClock(), getDefaultSystemDir(), false);
+ getDefaultClock(), getDefaultSystemDir(), false, new Dependencies(context));
}
private static @NonNull File getDefaultSystemDir() {
@@ -718,9 +721,59 @@
Clock.systemUTC());
}
+ static class Dependencies {
+ final Context mContext;
+ final NetworkStatsManager mNetworkStatsManager;
+ Dependencies(Context context) {
+ mContext = context;
+ mNetworkStatsManager = mContext.getSystemService(NetworkStatsManager.class);
+ // Query stats from NetworkStatsService will trigger a poll by default.
+ // But since NPMS listens stats updated event, and will query stats
+ // after the event. A polling -> updated -> query -> polling loop will be introduced
+ // if polls on open. Hence, while NPMS manages it's poll requests explicitly, set
+ // flag to false to prevent a polling loop.
+ mNetworkStatsManager.setPollOnOpen(false);
+ }
+
+ long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
+ Trace.traceBegin(TRACE_TAG_NETWORK, "getNetworkTotalBytes");
+ try {
+ final NetworkStats.Bucket ret = mNetworkStatsManager
+ .querySummaryForDevice(template, start, end);
+ return ret.getRxBytes() + ret.getTxBytes();
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failed to read network stats: " + e);
+ return 0;
+ } finally {
+ Trace.traceEnd(TRACE_TAG_NETWORK);
+ }
+ }
+
+ @NonNull
+ List<NetworkStats.Bucket> getNetworkUidBytes(
+ @NonNull NetworkTemplate template, long start, long end) {
+ Trace.traceBegin(TRACE_TAG_NETWORK, "getNetworkUidBytes");
+ final List<NetworkStats.Bucket> buckets = new ArrayList<>();
+ try {
+ final NetworkStats stats = mNetworkStatsManager.querySummary(template, start, end);
+ while (stats.hasNextBucket()) {
+ final NetworkStats.Bucket bucket = new NetworkStats.Bucket();
+ stats.getNextBucket(bucket);
+ buckets.add(bucket);
+ }
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failed to read network stats: " + e);
+ } finally {
+ Trace.traceEnd(TRACE_TAG_NETWORK);
+ }
+ return buckets;
+ }
+ }
+
+ @VisibleForTesting
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
INetworkManagementService networkManagement, IPackageManager pm, Clock clock,
- File systemDir, boolean suppressDefaultPolicy) {
+ File systemDir, boolean suppressDefaultPolicy, Dependencies deps) {
mContext = Objects.requireNonNull(context, "missing context");
mActivityManager = Objects.requireNonNull(activityManager, "missing activityManager");
mNetworkManager = Objects.requireNonNull(networkManagement, "missing networkManagement");
@@ -741,10 +794,12 @@
mUidEventHandler = new Handler(mUidEventThread.getLooper(), mUidEventHandlerCallback);
mSuppressDefaultPolicy = suppressDefaultPolicy;
+ mDeps = Objects.requireNonNull(deps, "missing Dependencies");
mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"), "net-policy");
mAppOps = context.getSystemService(AppOpsManager.class);
+ mNetworkStats = context.getSystemService(NetworkStatsManager.class);
mMultipathPolicyTracker = new MultipathPolicyTracker(mContext, mHandler);
// Expose private service for system components to use.
LocalServices.addService(NetworkPolicyManagerInternal.class,
@@ -844,7 +899,6 @@
mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
mAppStandby = LocalServices.getService(AppStandbyInternal.class);
- mNetworkStats = LocalServices.getService(NetworkStatsManagerInternal.class);
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
@@ -1167,21 +1221,34 @@
};
/**
- * Receiver that watches for {@link INetworkStatsService} updates, which we
+ * Receiver that watches for {@link NetworkStatsManager} updates, which we
* use to check against {@link NetworkPolicy#warningBytes}.
*/
- final private BroadcastReceiver mStatsReceiver = new BroadcastReceiver() {
+ private final NetworkStatsBroadcastReceiver mStatsReceiver =
+ new NetworkStatsBroadcastReceiver();
+ private class NetworkStatsBroadcastReceiver extends BroadcastReceiver {
+ private boolean mIsAnyIntentReceived = false;
@Override
public void onReceive(Context context, Intent intent) {
// on background handler thread, and verified
// READ_NETWORK_USAGE_HISTORY permission above.
+ mIsAnyIntentReceived = true;
+
synchronized (mNetworkPoliciesSecondLock) {
updateNetworkRulesNL();
updateNetworkEnabledNL();
updateNotificationsNL();
}
}
+
+ /**
+ * Return whether any {@code ACTION_NETWORK_STATS_UPDATED} intent is received.
+ * Used to determine if NetworkStatsService is ready.
+ */
+ public boolean isAnyIntentReceived() {
+ return mIsAnyIntentReceived;
+ }
};
/**
@@ -1405,15 +1472,17 @@
long maxBytes = 0;
int maxUid = 0;
- final NetworkStats stats = getNetworkUidBytes(template, start, end);
- NetworkStats.Entry entry = null;
- for (int i = 0; i < stats.size(); i++) {
- entry = stats.getValues(i, entry);
- final long bytes = entry.rxBytes + entry.txBytes;
+ // Skip if not ready. NetworkStatsService will block public API calls until it is
+ // ready. To prevent NPMS be blocked on that, skip and fail fast instead.
+ if (!mStatsReceiver.isAnyIntentReceived()) return null;
+
+ final List<NetworkStats.Bucket> stats = mDeps.getNetworkUidBytes(template, start, end);
+ for (final NetworkStats.Bucket entry : stats) {
+ final long bytes = entry.getRxBytes() + entry.getTxBytes();
totalBytes += bytes;
if (bytes > maxBytes) {
maxBytes = bytes;
- maxUid = entry.uid;
+ maxUid = entry.getUid();
}
}
@@ -3383,6 +3452,35 @@
return result;
}
+ /**
+ * Get subscription plan for the given networkTemplate.
+ *
+ * @param template the networkTemplate to get the subscription plan for.
+ */
+ @Override
+ public SubscriptionPlan getSubscriptionPlan(@NonNull NetworkTemplate template) {
+ enforceAnyPermissionOf(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
+ synchronized (mNetworkPoliciesSecondLock) {
+ final int subId = findRelevantSubIdNL(template);
+ return getPrimarySubscriptionPlanLocked(subId);
+ }
+ }
+
+ /**
+ * Notifies that the specified {@link NetworkStatsProvider} has reached its quota
+ * which was set through {@link NetworkStatsProvider#onSetLimit(String, long)} or
+ * {@link NetworkStatsProvider#onSetWarningAndLimit(String, long, long)}.
+ */
+ @Override
+ public void onStatsProviderWarningOrLimitReached() {
+ enforceAnyPermissionOf(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
+ // This API may be called before the system is ready.
+ synchronized (mNetworkPoliciesSecondLock) {
+ if (!mSystemReady) return;
+ }
+ mHandler.obtainMessage(MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED).sendToTarget();
+ }
+
@Override
public SubscriptionPlan[] getSubscriptionPlans(int subId, String callingPackage) {
enforceSubscriptionPlanAccess(subId, Binder.getCallingUid(), callingPackage);
@@ -5369,25 +5467,10 @@
@Deprecated
private long getTotalBytes(NetworkTemplate template, long start, long end) {
- return getNetworkTotalBytes(template, start, end);
- }
-
- private long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
- try {
- return mNetworkStats.getNetworkTotalBytes(template, start, end);
- } catch (RuntimeException e) {
- Slog.w(TAG, "Failed to read network stats: " + e);
- return 0;
- }
- }
-
- private NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) {
- try {
- return mNetworkStats.getNetworkUidBytes(template, start, end);
- } catch (RuntimeException e) {
- Slog.w(TAG, "Failed to read network stats: " + e);
- return new NetworkStats(SystemClock.elapsedRealtime(), 0);
- }
+ // Skip if not ready. NetworkStatsService will block public API calls until it is
+ // ready. To prevent NPMS be blocked on that, skip and fail fast instead.
+ if (!mStatsReceiver.isAnyIntentReceived()) return 0;
+ return mDeps.getNetworkTotalBytes(template, start, end);
}
private boolean isBandwidthControlEnabled() {
@@ -5607,14 +5690,6 @@
}
@Override
- public SubscriptionPlan getSubscriptionPlan(NetworkTemplate template) {
- synchronized (mNetworkPoliciesSecondLock) {
- final int subId = findRelevantSubIdNL(template);
- return getPrimarySubscriptionPlanLocked(subId);
- }
- }
-
- @Override
public long getSubscriptionOpportunisticQuota(Network network, int quotaType) {
final long quotaBytes;
synchronized (mNetworkPoliciesSecondLock) {
@@ -5656,12 +5731,6 @@
mHandler.obtainMessage(MSG_METERED_RESTRICTED_PACKAGES_CHANGED,
userId, 0, packageNames).sendToTarget();
}
-
- @Override
- public void onStatsProviderWarningOrLimitReached(@NonNull String tag) {
- Log.v(TAG, "onStatsProviderWarningOrLimitReached: " + tag);
- mHandler.obtainMessage(MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED).sendToTarget();
- }
}
private void setMeteredRestrictedPackagesInternal(Set<String> packageNames, int userId) {
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 0f37450..e7d05b6 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -527,12 +527,13 @@
callback.onFailure();
return;
}
- textClassifierServiceConsumer.accept(serviceState.mService);
+ consumeServiceNoExceptLocked(textClassifierServiceConsumer, serviceState.mService);
} else {
serviceState.mPendingRequests.add(
new PendingRequest(
methodName,
- () -> textClassifierServiceConsumer.accept(serviceState.mService),
+ () -> consumeServiceNoExceptLocked(
+ textClassifierServiceConsumer, serviceState.mService),
callback::onFailure, callback.asBinder(),
this,
serviceState,
@@ -541,6 +542,16 @@
}
}
+ private static void consumeServiceNoExceptLocked(
+ @NonNull ThrowingConsumer<ITextClassifierService> textClassifierServiceConsumer,
+ @Nullable ITextClassifierService service) {
+ try {
+ textClassifierServiceConsumer.accept(service);
+ } catch (RuntimeException | Error e) {
+ Slog.e(LOG_TAG, "Exception when consume textClassifierService: " + e);
+ }
+ }
+
private static ITextClassifierCallback wrap(ITextClassifierCallback orig) {
return new CallbackWrapper(orig);
}
diff --git a/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
index 6db25b7..c96c1ee 100644
--- a/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
+++ b/services/core/java/com/android/server/vcn/routeselection/NetworkPriorityClassifier.java
@@ -22,8 +22,6 @@
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN;
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
-import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_ANY;
-import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK;
import static com.android.server.VcnManagementService.LOCAL_LOG;
@@ -47,6 +45,7 @@
import com.android.server.vcn.VcnContext;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
/** @hide */
@@ -121,9 +120,10 @@
TelephonySubscriptionSnapshot snapshot,
UnderlyingNetworkRecord currentlySelected,
PersistableBundle carrierConfig) {
- // TODO: Check Network Quality reported by metric monitors/probers.
-
final NetworkCapabilities caps = networkRecord.networkCapabilities;
+ final boolean isSelectedUnderlyingNetwork =
+ currentlySelected != null
+ && Objects.equals(currentlySelected.network, networkRecord.network);
final int meteredMatch = networkPriority.getMetered();
final boolean isMetered = !caps.hasCapability(NET_CAPABILITY_NOT_METERED);
@@ -132,6 +132,23 @@
return false;
}
+ // Fails bandwidth requirements if either (a) less than exit threshold, or (b), not
+ // selected, but less than entry threshold
+ if (caps.getLinkUpstreamBandwidthKbps() < networkPriority.getMinExitUpstreamBandwidthKbps()
+ || (caps.getLinkUpstreamBandwidthKbps()
+ < networkPriority.getMinEntryUpstreamBandwidthKbps()
+ && !isSelectedUnderlyingNetwork)) {
+ return false;
+ }
+
+ if (caps.getLinkDownstreamBandwidthKbps()
+ < networkPriority.getMinExitDownstreamBandwidthKbps()
+ || (caps.getLinkDownstreamBandwidthKbps()
+ < networkPriority.getMinEntryDownstreamBandwidthKbps()
+ && !isSelectedUnderlyingNetwork)) {
+ return false;
+ }
+
if (vcnContext.isInTestMode() && caps.hasTransport(TRANSPORT_TEST)) {
return true;
}
@@ -172,8 +189,7 @@
}
// TODO: Move the Network Quality check to the network metric monitor framework.
- if (networkPriority.getNetworkQuality()
- > getWifiQuality(networkRecord, currentlySelected, carrierConfig)) {
+ if (!isWifiRssiAcceptable(networkRecord, currentlySelected, carrierConfig)) {
return false;
}
@@ -185,7 +201,7 @@
return true;
}
- private static int getWifiQuality(
+ private static boolean isWifiRssiAcceptable(
UnderlyingNetworkRecord networkRecord,
UnderlyingNetworkRecord currentlySelected,
PersistableBundle carrierConfig) {
@@ -196,14 +212,14 @@
if (isSelectedNetwork
&& caps.getSignalStrength() >= getWifiExitRssiThreshold(carrierConfig)) {
- return NETWORK_QUALITY_OK;
+ return true;
}
if (caps.getSignalStrength() >= getWifiEntryRssiThreshold(carrierConfig)) {
- return NETWORK_QUALITY_OK;
+ return true;
}
- return NETWORK_QUALITY_ANY;
+ return false;
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 0792d9b..df98390 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -231,6 +231,7 @@
import android.net.ConnectivityManager;
import android.net.ConnectivitySettingsManager;
import android.net.IIpConnectivityMetrics;
+import android.net.ProfileNetworkPreference;
import android.net.ProxyInfo;
import android.net.Uri;
import android.net.VpnManager;
@@ -17538,10 +17539,14 @@
}
int networkPreference = preferentialNetworkServiceEnabled
? PROFILE_NETWORK_PREFERENCE_ENTERPRISE : PROFILE_NETWORK_PREFERENCE_DEFAULT;
+ ProfileNetworkPreference.Builder preferenceBuilder =
+ new ProfileNetworkPreference.Builder();
+ preferenceBuilder.setPreference(networkPreference);
+ List<ProfileNetworkPreference> preferences = new ArrayList<>();
+ preferences.add(preferenceBuilder.build());
mInjector.binderWithCleanCallingIdentity(() ->
- mInjector.getConnectivityManager().setProfileNetworkPreference(
- UserHandle.of(userId),
- networkPreference,
+ mInjector.getConnectivityManager().setProfileNetworkPreferences(
+ UserHandle.of(userId), preferences,
null /* executor */, null /* listener */));
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2aee778..2303495 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1837,7 +1837,7 @@
t.traceBegin("StartNetworkStatsService");
try {
- networkStats = NetworkStatsService.create(context, networkManagement);
+ networkStats = NetworkStatsService.create(context);
ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
} catch (Throwable e) {
reportWtf("starting NetworkStats Service", e);
diff --git a/services/midi/OWNERS b/services/midi/OWNERS
new file mode 100644
index 0000000..f4d51f9
--- /dev/null
+++ b/services/midi/OWNERS
@@ -0,0 +1 @@
+philburk@google.com
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index bcb2cf8..187b012 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -93,6 +93,7 @@
<uses-permission android:name="android.permission.CONTROL_DEVICE_STATE"/>
<uses-permission android:name="android.permission.READ_PROJECTION_STATE"/>
<uses-permission android:name="android.permission.KILL_UID"/>
+ <uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK"/>
<uses-permission
android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 3ac30d02..a63aa6a 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -37,6 +37,8 @@
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.PasswordMetrics.computeForPasswordOrPin;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
+import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
+import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
import static android.net.InetAddresses.parseNumericAddress;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
@@ -99,7 +101,7 @@
import android.content.pm.UserInfo;
import android.graphics.Color;
import android.hardware.usb.UsbManager;
-import android.net.ConnectivityManager;
+import android.net.ProfileNetworkPreference;
import android.net.Uri;
import android.os.Build.VERSION_CODES;
import android.os.Bundle;
@@ -4044,12 +4046,15 @@
mServiceContext.permissions.add(permission.INTERACT_ACROSS_USERS_FULL);
dpms.handleStartUser(managedProfileUserId);
- verify(getServices().connectivityManager, times(1)).setProfileNetworkPreference(
- eq(UserHandle.of(managedProfileUserId)),
- anyInt(),
- any(),
- any()
- );
+ ProfileNetworkPreference preferenceDetails =
+ new ProfileNetworkPreference.Builder()
+ .setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT)
+ .build();
+ List<ProfileNetworkPreference> preferences = new ArrayList<>();
+ preferences.add(preferenceDetails);
+ verify(getServices().connectivityManager, times(1))
+ .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences,
+ null, null);
}
@Test
@@ -4061,12 +4066,15 @@
mServiceContext.permissions.add(permission.INTERACT_ACROSS_USERS_FULL);
dpms.handleStopUser(managedProfileUserId);
- verify(getServices().connectivityManager, times(1)).setProfileNetworkPreference(
- eq(UserHandle.of(managedProfileUserId)),
- eq(ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT),
- any(),
- any()
- );
+ ProfileNetworkPreference preferenceDetails =
+ new ProfileNetworkPreference.Builder()
+ .setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT)
+ .build();
+ List<ProfileNetworkPreference> preferences = new ArrayList<>();
+ preferences.add(preferenceDetails);
+ verify(getServices().connectivityManager, times(1))
+ .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences,
+ null, null);
}
@Test
@@ -4084,21 +4092,29 @@
dpm.setPreferentialNetworkServiceEnabled(false);
assertThat(dpm.isPreferentialNetworkServiceEnabled()).isFalse();
- verify(getServices().connectivityManager, times(1)).setProfileNetworkPreference(
- eq(UserHandle.of(managedProfileUserId)),
- eq(ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT),
- any(),
- any()
- );
+
+ ProfileNetworkPreference preferenceDetails =
+ new ProfileNetworkPreference.Builder()
+ .setPreference(PROFILE_NETWORK_PREFERENCE_DEFAULT)
+ .build();
+ List<ProfileNetworkPreference> preferences = new ArrayList<>();
+ preferences.add(preferenceDetails);
+ verify(getServices().connectivityManager, times(1))
+ .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences,
+ null, null);
dpm.setPreferentialNetworkServiceEnabled(true);
assertThat(dpm.isPreferentialNetworkServiceEnabled()).isTrue();
- verify(getServices().connectivityManager, times(1)).setProfileNetworkPreference(
- eq(UserHandle.of(managedProfileUserId)),
- eq(ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE),
- any(),
- any()
- );
+
+ ProfileNetworkPreference preferenceDetails2 =
+ new ProfileNetworkPreference.Builder()
+ .setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE)
+ .build();
+ List<ProfileNetworkPreference> preferences2 = new ArrayList<>();
+ preferences2.add(preferenceDetails);
+ verify(getServices().connectivityManager, times(1))
+ .setProfileNetworkPreferences(UserHandle.of(managedProfileUserId), preferences2,
+ null, null);
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index b811e28..9a6f61e 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -49,12 +49,8 @@
import static android.net.NetworkPolicyManager.uidPoliciesToString;
import static android.net.NetworkPolicyManager.uidRulesToString;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
-import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.METERED_NO;
import static android.net.NetworkStats.METERED_YES;
-import static android.net.NetworkStats.SET_ALL;
-import static android.net.NetworkStats.TAG_ALL;
-import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkTemplate.buildTemplateCarrierMetered;
import static android.net.NetworkTemplate.buildTemplateWifi;
import static android.net.TrafficStats.MB_IN_BYTES;
@@ -75,6 +71,7 @@
import static com.android.server.net.NetworkPolicyManagerService.TYPE_RAPID;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
import static com.android.server.net.NetworkPolicyManagerService.UidBlockedState.getEffectiveBlockedReasons;
+import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_UPDATED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -108,6 +105,8 @@
import android.app.IUidObserver;
import android.app.Notification;
import android.app.NotificationManager;
+import android.app.usage.NetworkStats;
+import android.app.usage.NetworkStatsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.Context;
import android.content.Intent;
@@ -125,8 +124,6 @@
import android.net.NetworkCapabilities;
import android.net.NetworkPolicy;
import android.net.NetworkStateSnapshot;
-import android.net.NetworkStats;
-import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TelephonyNetworkSpecifier;
import android.net.wifi.WifiInfo;
@@ -138,7 +135,6 @@
import android.os.PowerSaveState;
import android.os.RemoteException;
import android.os.SimpleClock;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
@@ -263,12 +259,13 @@
private @Mock CarrierConfigManager mCarrierConfigManager;
private @Mock TelephonyManager mTelephonyManager;
private @Mock UserManager mUserManager;
+ private @Mock NetworkStatsManager mStatsManager;
+ private TestDependencies mDeps;
private ArgumentCaptor<ConnectivityManager.NetworkCallback> mNetworkCallbackCaptor =
ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
private ActivityManagerInternal mActivityManagerInternal;
- private NetworkStatsManagerInternal mStatsService;
private IUidObserver mUidObserver;
private INetworkManagementEventObserver mNetworkObserver;
@@ -335,8 +332,47 @@
.setBatterySaverEnabled(false).build();
final PowerManagerInternal pmInternal = addLocalServiceMock(PowerManagerInternal.class);
when(pmInternal.getLowPowerState(anyInt())).thenReturn(state);
+ }
- mStatsService = addLocalServiceMock(NetworkStatsManagerInternal.class);
+ private class TestDependencies extends NetworkPolicyManagerService.Dependencies {
+ private final SparseArray<NetworkStats.Bucket> mMockedStats = new SparseArray<>();
+
+ TestDependencies(Context context) {
+ super(context);
+ }
+
+ @Override
+ long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
+ int total = 0;
+ for (int i = 0; i < mMockedStats.size(); i++) {
+ NetworkStats.Bucket bucket = mMockedStats.valueAt(i);
+ total += bucket.getRxBytes() + bucket.getTxBytes();
+ }
+ return total;
+ }
+
+ @Override
+ List<NetworkStats.Bucket> getNetworkUidBytes(NetworkTemplate template, long start,
+ long end) {
+ final List<NetworkStats.Bucket> ret = new ArrayList<>();
+ for (int i = 0; i < mMockedStats.size(); i++) {
+ ret.add(mMockedStats.valueAt(i));
+ }
+ return ret;
+ }
+
+ private void setMockedTotalBytes(int uid, long rxBytes, long txBytes) {
+ final NetworkStats.Bucket bucket = mock(NetworkStats.Bucket.class);
+ when(bucket.getUid()).thenReturn(uid);
+ when(bucket.getRxBytes()).thenReturn(rxBytes);
+ when(bucket.getTxBytes()).thenReturn(txBytes);
+ mMockedStats.set(uid, bucket);
+ }
+
+ private void increaseMockedTotalBytes(int uid, long rxBytes, long txBytes) {
+ final NetworkStats.Bucket bucket = mMockedStats.get(uid);
+ setMockedTotalBytes(uid, bucket.getRxBytes() + rxBytes, bucket.getTxBytes() + txBytes);
+ }
}
@Before
@@ -376,6 +412,8 @@
return mConnManager;
case Context.USER_SERVICE:
return mUserManager;
+ case Context.NETWORK_STATS_SERVICE:
+ return mStatsManager;
default:
return super.getSystemService(name);
}
@@ -400,8 +438,9 @@
}).when(mActivityManager).registerUidObserver(any(), anyInt(), anyInt(), any(String.class));
mFutureIntent = newRestrictBackgroundChangedFuture();
+ mDeps = new TestDependencies(mServiceContext);
mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager,
- mNetworkManager, mIpm, mClock, mPolicyDir, true);
+ mNetworkManager, mIpm, mClock, mPolicyDir, true, mDeps);
mService.bindConnectivityManager();
mPolicyListener = new NetworkPolicyListenerAnswer(mService);
@@ -456,6 +495,9 @@
verify(mNetworkManager).registerObserver(networkObserver.capture());
mNetworkObserver = networkObserver.getValue();
+ // Simulate NetworkStatsService broadcast stats updated to signal its readiness.
+ mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_UPDATED));
+
NetworkPolicy defaultPolicy = mService.buildDefaultCarrierPolicy(0, "");
mDefaultWarningBytes = defaultPolicy.warningBytes;
mDefaultLimitBytes = defaultPolicy.limitBytes;
@@ -479,7 +521,6 @@
LocalServices.removeServiceForTest(DeviceIdleInternal.class);
LocalServices.removeServiceForTest(AppStandbyInternal.class);
LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
- LocalServices.removeServiceForTest(NetworkStatsManagerInternal.class);
}
@After
@@ -1108,10 +1149,7 @@
when(mConnManager.getAllNetworkStateSnapshots()).thenReturn(snapshots);
// pretend that 512 bytes total have happened
- stats = new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 256L, 2L, 256L, 2L);
- when(mStatsService.getNetworkTotalBytes(sTemplateWifi, CYCLE_START, CYCLE_END))
- .thenReturn(stats.getTotalBytes());
+ mDeps.setMockedTotalBytes(UID_A, 256L, 256L);
mPolicyListener.expect().onMeteredIfacesChanged(any());
setNetworkPolicies(new NetworkPolicy(
@@ -1124,26 +1162,6 @@
@Test
public void testNotificationWarningLimitSnooze() throws Exception {
- // Create a place to store fake usage
- final NetworkStatsHistory history = new NetworkStatsHistory(TimeUnit.HOURS.toMillis(1));
- final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
- when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
- .thenAnswer(new Answer<Long>() {
- @Override
- public Long answer(InvocationOnMock invocation) throws Throwable {
- final NetworkStatsHistory.Entry entry = history.getValues(
- invocation.getArgument(1), invocation.getArgument(2), null);
- return entry.rxBytes + entry.txBytes;
- }
- });
- when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
- .thenAnswer(new Answer<NetworkStats>() {
- @Override
- public NetworkStats answer(InvocationOnMock invocation) throws Throwable {
- return stats;
- }
- });
-
// Get active mobile network in place
expectMobileDefaults();
mService.updateNetworks();
@@ -1161,9 +1179,7 @@
// Normal usage means no notification
{
- history.clear();
- history.recordData(start, end,
- new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(360), 0L, 0L, 0L, 0));
+ mDeps.setMockedTotalBytes(UID_A, DataUnit.MEGABYTES.toBytes(360), 0);
reset(mTelephonyManager, mNetworkManager, mNotifManager);
TelephonyManager tmSub = expectMobileDefaults();
@@ -1178,9 +1194,7 @@
// Push over warning
{
- history.clear();
- history.recordData(start, end,
- new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1799), 0L, 0L, 0L, 0));
+ mDeps.setMockedTotalBytes(UID_A, DataUnit.MEGABYTES.toBytes(1799), 0);
reset(mTelephonyManager, mNetworkManager, mNotifManager);
TelephonyManager tmSub = expectMobileDefaults();
@@ -1196,9 +1210,7 @@
// Push over warning, but with a config that isn't from an identified carrier
{
- history.clear();
- history.recordData(start, end,
- new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1799), 0L, 0L, 0L, 0));
+ mDeps.setMockedTotalBytes(UID_A, DataUnit.MEGABYTES.toBytes(1799), 0);
reset(mTelephonyManager, mNetworkManager, mNotifManager);
TelephonyManager tmSub = expectMobileDefaults();
@@ -1215,9 +1227,7 @@
// Push over limit
{
- history.clear();
- history.recordData(start, end,
- new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1810), 0L, 0L, 0L, 0));
+ mDeps.setMockedTotalBytes(UID_A, DataUnit.MEGABYTES.toBytes(1810), 0);
reset(mTelephonyManager, mNetworkManager, mNotifManager);
TelephonyManager tmSub = expectMobileDefaults();
@@ -1248,26 +1258,6 @@
@Test
public void testNotificationRapid() throws Exception {
- // Create a place to store fake usage
- final NetworkStatsHistory history = new NetworkStatsHistory(TimeUnit.HOURS.toMillis(1));
- final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
- when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
- .thenAnswer(new Answer<Long>() {
- @Override
- public Long answer(InvocationOnMock invocation) throws Throwable {
- final NetworkStatsHistory.Entry entry = history.getValues(
- invocation.getArgument(1), invocation.getArgument(2), null);
- return entry.rxBytes + entry.txBytes;
- }
- });
- when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
- .thenAnswer(new Answer<NetworkStats>() {
- @Override
- public NetworkStats answer(InvocationOnMock invocation) throws Throwable {
- return stats;
- }
- });
-
// Get active mobile network in place
expectMobileDefaults();
mService.updateNetworks();
@@ -1285,9 +1275,7 @@
// Using 20% data in 20% time is normal
{
- history.clear();
- history.recordData(start, end,
- new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(360), 0L, 0L, 0L, 0));
+ mDeps.setMockedTotalBytes(UID_A, DataUnit.MEGABYTES.toBytes(360), 0);
reset(mNotifManager);
mService.updateNetworks();
@@ -1297,16 +1285,9 @@
// Using 80% data in 20% time is alarming; but spread equally among
// three UIDs means we get generic alert
{
- history.clear();
- history.recordData(start, end,
- new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1440), 0L, 0L, 0L, 0));
- stats.clear();
- stats.insertEntry(IFACE_ALL, UID_A, SET_ALL, TAG_ALL,
- DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
- stats.insertEntry(IFACE_ALL, UID_B, SET_ALL, TAG_ALL,
- DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
- stats.insertEntry(IFACE_ALL, UID_C, SET_ALL, TAG_ALL,
- DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
+ mDeps.setMockedTotalBytes(UID_A, DataUnit.MEGABYTES.toBytes(480), 0);
+ mDeps.setMockedTotalBytes(UID_B, DataUnit.MEGABYTES.toBytes(480), 0);
+ mDeps.setMockedTotalBytes(UID_C, DataUnit.MEGABYTES.toBytes(480), 0);
reset(mNotifManager);
mService.updateNetworks();
@@ -1325,14 +1306,9 @@
// Using 80% data in 20% time is alarming; but mostly done by one UID
// means we get specific alert
{
- history.clear();
- history.recordData(start, end,
- new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1440), 0L, 0L, 0L, 0));
- stats.clear();
- stats.insertEntry(IFACE_ALL, UID_A, SET_ALL, TAG_ALL,
- DataUnit.MEGABYTES.toBytes(960), 0, 0, 0, 0);
- stats.insertEntry(IFACE_ALL, UID_B, SET_ALL, TAG_ALL,
- DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0);
+ mDeps.setMockedTotalBytes(UID_A, DataUnit.MEGABYTES.toBytes(960), 0);
+ mDeps.setMockedTotalBytes(UID_B, DataUnit.MEGABYTES.toBytes(480), 0);
+ mDeps.setMockedTotalBytes(UID_C, 0, 0);
reset(mNotifManager);
mService.updateNetworks();
@@ -1362,13 +1338,10 @@
// bring up wifi network with metered policy
snapshots = List.of(buildWifi());
- stats = new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 0L, 0L, 0L, 0L);
+ mDeps.setMockedTotalBytes(UID_A, 0L, 0L);
{
when(mConnManager.getAllNetworkStateSnapshots()).thenReturn(snapshots);
- when(mStatsService.getNetworkTotalBytes(sTemplateWifi, TIME_FEB_15,
- currentTimeMillis())).thenReturn(stats.getTotalBytes());
mPolicyListener.expect().onMeteredIfacesChanged(any());
setNetworkPolicies(new NetworkPolicy(
@@ -1647,18 +1620,6 @@
final NetworkPolicyManagerInternal internal = LocalServices
.getService(NetworkPolicyManagerInternal.class);
- // Create a place to store fake usage
- final NetworkStatsHistory history = new NetworkStatsHistory(TimeUnit.HOURS.toMillis(1));
- final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
- when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
- .thenAnswer(invocation -> {
- final NetworkStatsHistory.Entry entry = history.getValues(
- invocation.getArgument(1), invocation.getArgument(2), null);
- return entry.rxBytes + entry.txBytes;
- });
- when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
- .thenReturn(stats);
-
// Get active mobile network in place
expectMobileDefaults();
mService.updateNetworks();
@@ -1669,9 +1630,7 @@
setCurrentTimeMillis(end);
// Get some data usage in place
- history.clear();
- history.recordData(start, end,
- new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(360), 0L, 0L, 0L, 0));
+ mDeps.setMockedTotalBytes(UID_A, DataUnit.MEGABYTES.toBytes(360), 0);
// No data plan
{
@@ -1786,22 +1745,11 @@
true);
}
- private void increaseMockedTotalBytes(NetworkStats stats, long rxBytes, long txBytes) {
- stats.insertEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE,
- rxBytes, 1, txBytes, 1, 0);
- when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
- .thenReturn(stats.getTotalBytes());
- when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
- .thenReturn(stats);
- }
-
private void triggerOnStatsProviderWarningOrLimitReached() throws InterruptedException {
- final NetworkPolicyManagerInternal npmi = LocalServices
- .getService(NetworkPolicyManagerInternal.class);
- npmi.onStatsProviderWarningOrLimitReached("TEST");
+ mService.onStatsProviderWarningOrLimitReached();
// Wait for processing of MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED.
postMsgAndWaitForCompletion();
- verify(mStatsService).forceUpdate();
+ verify(mStatsManager).forceUpdate();
// Wait for processing of MSG_*_INTERFACE_QUOTAS.
postMsgAndWaitForCompletion();
}
@@ -1814,13 +1762,12 @@
public void testStatsProviderWarningAndLimitReached() throws Exception {
final int CYCLE_DAY = 15;
- final NetworkStats stats = new NetworkStats(0L, 1);
- increaseMockedTotalBytes(stats, 2999, 2000);
+ mDeps.setMockedTotalBytes(UID_A, 2999, 2000);
// Get active mobile network in place
expectMobileDefaults();
mService.updateNetworks();
- verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, Long.MAX_VALUE,
+ verify(mStatsManager).setStatsProviderWarningAndLimitAsync(TEST_IFACE, Long.MAX_VALUE,
Long.MAX_VALUE);
// Set warning to 7KB and limit to 10KB.
@@ -1830,32 +1777,32 @@
postMsgAndWaitForCompletion();
// Verifies that remaining quotas are set to providers.
- verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, 2001L, 5001L);
- reset(mStatsService);
+ verify(mStatsManager).setStatsProviderWarningAndLimitAsync(TEST_IFACE, 2001L, 5001L);
+ reset(mStatsManager);
// Increase the usage and simulates that limit reached fires earlier by provider,
// but actually the quota is not yet reached. Verifies that the limit reached leads to
// a force update and new quotas should be set.
- increaseMockedTotalBytes(stats, 1000, 999);
+ mDeps.increaseMockedTotalBytes(UID_A, 1000, 999);
triggerOnStatsProviderWarningOrLimitReached();
- verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, 2L, 3002L);
- reset(mStatsService);
+ verify(mStatsManager).setStatsProviderWarningAndLimitAsync(TEST_IFACE, 2L, 3002L);
+ reset(mStatsManager);
// Increase the usage and simulate warning reached, the new warning should be unlimited
// since service will disable warning quota to stop lower layer from keep triggering
// warning reached event.
- increaseMockedTotalBytes(stats, 1000L, 1000);
+ mDeps.increaseMockedTotalBytes(UID_A, 1000L, 1000);
triggerOnStatsProviderWarningOrLimitReached();
- verify(mStatsService).setStatsProviderWarningAndLimitAsync(
+ verify(mStatsManager).setStatsProviderWarningAndLimitAsync(
TEST_IFACE, Long.MAX_VALUE, 1002L);
- reset(mStatsService);
+ reset(mStatsManager);
// Increase the usage that over the warning and limit, the new limit should set to 1 to
// block the network traffic.
- increaseMockedTotalBytes(stats, 1000L, 1000);
+ mDeps.increaseMockedTotalBytes(UID_A, 1000L, 1000);
triggerOnStatsProviderWarningOrLimitReached();
- verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, Long.MAX_VALUE, 1L);
- reset(mStatsService);
+ verify(mStatsManager).setStatsProviderWarningAndLimitAsync(TEST_IFACE, Long.MAX_VALUE, 1L);
+ reset(mStatsManager);
}
private void enableRestrictedMode(boolean enable) throws Exception {
@@ -2145,7 +2092,7 @@
}
private void verifyAdvisePersistThreshold() throws Exception {
- verify(mStatsService).advisePersistThreshold(anyLong());
+ verify(mStatsManager).advisePersistThreshold(anyLong());
}
private static class TestAbstractFuture<T> extends AbstractFuture<T> {
diff --git a/services/tests/servicestests/src/com/android/server/wm/OWNERS b/services/tests/servicestests/src/com/android/server/wm/OWNERS
new file mode 100644
index 0000000..361760d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/services/core/java/com/android/server/wm/OWNERS
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index b109c46..de97730 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4724,7 +4724,7 @@
/**
* A priority list of ePDG addresses to be used. Possible values are {@link
* #EPDG_ADDRESS_STATIC}, {@link #EPDG_ADDRESS_PLMN}, {@link #EPDG_ADDRESS_PCO}, {@link
- * #EPDG_ADDRESS_CELLULAR_LOC}
+ * #EPDG_ADDRESS_CELLULAR_LOC}, {@link #EPDG_ADDRESS_VISITED_COUNTRY}
*/
public static final String KEY_EPDG_ADDRESS_PRIORITY_INT_ARRAY =
KEY_PREFIX + "epdg_address_priority_int_array";
@@ -4899,7 +4899,8 @@
EPDG_ADDRESS_STATIC,
EPDG_ADDRESS_PLMN,
EPDG_ADDRESS_PCO,
- EPDG_ADDRESS_CELLULAR_LOC
+ EPDG_ADDRESS_CELLULAR_LOC,
+ EPDG_ADDRESS_VISITED_COUNTRY
})
public @interface EpdgAddressType {}
@@ -4913,6 +4914,8 @@
public static final int EPDG_ADDRESS_PCO = 2;
/** Use cellular location to chose epdg server */
public static final int EPDG_ADDRESS_CELLULAR_LOC = 3;
+ /* Use Visited Country FQDN rule*/
+ public static final int EPDG_ADDRESS_VISITED_COUNTRY = 4;
/** @hide */
@IntDef({ID_TYPE_FQDN, ID_TYPE_RFC822_ADDR, ID_TYPE_KEY_ID})
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index ba95841..39ab7eb 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -592,6 +592,7 @@
int RIL_UNSOL_UNTHROTTLE_APN = 1052;
int RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_CHANGED = 1053;
int RIL_UNSOL_RESPONSE_SIM_PHONEBOOK_RECORDS_RECEIVED = 1054;
+ int RIL_UNSOL_SLICING_CONFIG_CHANGED = 1055;
/* The following unsols are not defined in RIL.h */
int RIL_UNSOL_HAL_NON_RIL_BASE = 1100;
diff --git a/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java b/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java
index 4a724b7..2fbcf9d 100644
--- a/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnCellUnderlyingNetworkTemplateTest.java
@@ -18,25 +18,29 @@
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY;
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN;
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
-import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_ANY;
-import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
import org.junit.Test;
import java.util.HashSet;
import java.util.Set;
-public class VcnCellUnderlyingNetworkTemplateTest {
+public class VcnCellUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTemplateTestBase {
private static final Set<String> ALLOWED_PLMN_IDS = new HashSet<>();
private static final Set<Integer> ALLOWED_CARRIER_IDS = new HashSet<>();
// Package private for use in VcnGatewayConnectionConfigTest
static VcnCellUnderlyingNetworkTemplate getTestNetworkTemplate() {
return new VcnCellUnderlyingNetworkTemplate.Builder()
- .setNetworkQuality(NETWORK_QUALITY_OK)
.setMetered(MATCH_FORBIDDEN)
+ .setMinUpstreamBandwidthKbps(
+ TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS)
+ .setMinDownstreamBandwidthKbps(
+ TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS)
.setOperatorPlmnIds(ALLOWED_PLMN_IDS)
.setSimSpecificCarrierIds(ALLOWED_CARRIER_IDS)
.setRoaming(MATCH_FORBIDDEN)
@@ -47,8 +51,19 @@
@Test
public void testBuilderAndGetters() {
final VcnCellUnderlyingNetworkTemplate networkPriority = getTestNetworkTemplate();
- assertEquals(NETWORK_QUALITY_OK, networkPriority.getNetworkQuality());
assertEquals(MATCH_FORBIDDEN, networkPriority.getMetered());
+ assertEquals(
+ TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS,
+ networkPriority.getMinEntryUpstreamBandwidthKbps());
+ assertEquals(
+ TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS,
+ networkPriority.getMinExitUpstreamBandwidthKbps());
+ assertEquals(
+ TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS,
+ networkPriority.getMinEntryDownstreamBandwidthKbps());
+ assertEquals(
+ TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS,
+ networkPriority.getMinExitDownstreamBandwidthKbps());
assertEquals(ALLOWED_PLMN_IDS, networkPriority.getOperatorPlmnIds());
assertEquals(ALLOWED_CARRIER_IDS, networkPriority.getSimSpecificCarrierIds());
assertEquals(MATCH_FORBIDDEN, networkPriority.getRoaming());
@@ -59,8 +74,14 @@
public void testBuilderAndGettersForDefaultValues() {
final VcnCellUnderlyingNetworkTemplate networkPriority =
new VcnCellUnderlyingNetworkTemplate.Builder().build();
- assertEquals(NETWORK_QUALITY_ANY, networkPriority.getNetworkQuality());
assertEquals(MATCH_ANY, networkPriority.getMetered());
+
+ // Explicitly expect 0, as documented in Javadoc on setter methods.
+ assertEquals(0, networkPriority.getMinEntryUpstreamBandwidthKbps());
+ assertEquals(0, networkPriority.getMinExitUpstreamBandwidthKbps());
+ assertEquals(0, networkPriority.getMinEntryDownstreamBandwidthKbps());
+ assertEquals(0, networkPriority.getMinExitDownstreamBandwidthKbps());
+
assertEquals(new HashSet<String>(), networkPriority.getOperatorPlmnIds());
assertEquals(new HashSet<Integer>(), networkPriority.getSimSpecificCarrierIds());
assertEquals(MATCH_ANY, networkPriority.getRoaming());
@@ -68,6 +89,29 @@
}
@Test
+ public void testBuilderRequiresStricterEntryCriteria() {
+ try {
+ new VcnCellUnderlyingNetworkTemplate.Builder()
+ .setMinUpstreamBandwidthKbps(
+ TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS);
+
+ fail("Expected IAE for exit threshold > entry threshold");
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ new VcnCellUnderlyingNetworkTemplate.Builder()
+ .setMinDownstreamBandwidthKbps(
+ TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS);
+
+ fail("Expected IAE for exit threshold > entry threshold");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
public void testPersistableBundle() {
final VcnCellUnderlyingNetworkTemplate networkPriority = getTestNetworkTemplate();
assertEquals(
diff --git a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkTemplateTestBase.java b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkTemplateTestBase.java
new file mode 100644
index 0000000..399e136
--- /dev/null
+++ b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkTemplateTestBase.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net.vcn;
+
+public class VcnUnderlyingNetworkTemplateTestBase {
+ // Public for use in NetworkPriorityClassifierTest
+ public static final int TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS = 200;
+ public static final int TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS = 100;
+ public static final int TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS = 400;
+ public static final int TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS = 300;
+}
diff --git a/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java b/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java
index cb5b47b..4063178 100644
--- a/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnWifiUnderlyingNetworkTemplateTest.java
@@ -17,8 +17,6 @@
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_ANY;
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN;
-import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_ANY;
-import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -28,15 +26,19 @@
import java.util.Set;
-public class VcnWifiUnderlyingNetworkTemplateTest {
+public class VcnWifiUnderlyingNetworkTemplateTest extends VcnUnderlyingNetworkTemplateTestBase {
private static final String SSID = "TestWifi";
- private static final int INVALID_NETWORK_QUALITY = -1;
// Package private for use in VcnGatewayConnectionConfigTest
static VcnWifiUnderlyingNetworkTemplate getTestNetworkTemplate() {
return new VcnWifiUnderlyingNetworkTemplate.Builder()
- .setNetworkQuality(NETWORK_QUALITY_OK)
.setMetered(MATCH_FORBIDDEN)
+ .setMinUpstreamBandwidthKbps(
+ TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS)
+ .setMinDownstreamBandwidthKbps(
+ TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS)
.setSsids(Set.of(SSID))
.build();
}
@@ -44,8 +46,19 @@
@Test
public void testBuilderAndGetters() {
final VcnWifiUnderlyingNetworkTemplate networkPriority = getTestNetworkTemplate();
- assertEquals(NETWORK_QUALITY_OK, networkPriority.getNetworkQuality());
assertEquals(MATCH_FORBIDDEN, networkPriority.getMetered());
+ assertEquals(
+ TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS,
+ networkPriority.getMinEntryUpstreamBandwidthKbps());
+ assertEquals(
+ TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS,
+ networkPriority.getMinExitUpstreamBandwidthKbps());
+ assertEquals(
+ TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS,
+ networkPriority.getMinEntryDownstreamBandwidthKbps());
+ assertEquals(
+ TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS,
+ networkPriority.getMinExitDownstreamBandwidthKbps());
assertEquals(Set.of(SSID), networkPriority.getSsids());
}
@@ -53,18 +66,37 @@
public void testBuilderAndGettersForDefaultValues() {
final VcnWifiUnderlyingNetworkTemplate networkPriority =
new VcnWifiUnderlyingNetworkTemplate.Builder().build();
- assertEquals(NETWORK_QUALITY_ANY, networkPriority.getNetworkQuality());
assertEquals(MATCH_ANY, networkPriority.getMetered());
+
+ // Explicitly expect 0, as documented in Javadoc on setter methods..
+ assertEquals(0, networkPriority.getMinEntryUpstreamBandwidthKbps());
+ assertEquals(0, networkPriority.getMinExitUpstreamBandwidthKbps());
+ assertEquals(0, networkPriority.getMinEntryDownstreamBandwidthKbps());
+ assertEquals(0, networkPriority.getMinExitDownstreamBandwidthKbps());
+
assertTrue(networkPriority.getSsids().isEmpty());
}
@Test
- public void testBuildWithInvalidNetworkQuality() {
+ public void testBuilderRequiresStricterEntryCriteria() {
try {
new VcnWifiUnderlyingNetworkTemplate.Builder()
- .setNetworkQuality(INVALID_NETWORK_QUALITY);
- fail("Expected to fail due to the invalid network quality");
- } catch (Exception expected) {
+ .setMinUpstreamBandwidthKbps(
+ TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS);
+
+ fail("Expected IAE for exit threshold > entry threshold");
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ new VcnWifiUnderlyingNetworkTemplate.Builder()
+ .setMinDownstreamBandwidthKbps(
+ TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS);
+
+ fail("Expected IAE for exit threshold > entry threshold");
+ } catch (IllegalArgumentException expected) {
}
}
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
index 4bb7de8..6c849b5 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
@@ -18,7 +18,10 @@
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_FORBIDDEN;
import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED;
-import static android.net.vcn.VcnUnderlyingNetworkTemplate.NETWORK_QUALITY_OK;
+import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS;
+import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS;
+import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS;
+import static android.net.vcn.VcnUnderlyingNetworkTemplateTestBase.TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS;
import static com.android.server.vcn.VcnTestUtils.setupSystemService;
import static com.android.server.vcn.routeselection.NetworkPriorityClassifier.PRIORITY_ANY;
@@ -76,6 +79,12 @@
private static final int CARRIER_ID = 1;
private static final int CARRIER_ID_OTHER = 2;
+ private static final int LINK_UPSTREAM_BANDWIDTH_KBPS = 1024;
+ private static final int LINK_DOWNSTREAM_BANDWIDTH_KBPS = 2048;
+
+ private static final int TEST_MIN_UPSTREAM_BANDWIDTH_KBPS = 100;
+ private static final int TEST_MIN_DOWNSTREAM_BANDWIDTH_KBPS = 200;
+
private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0));
private static final NetworkCapabilities WIFI_NETWORK_CAPABILITIES =
@@ -83,6 +92,8 @@
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.setSignalStrength(WIFI_RSSI)
.setSsid(SSID)
+ .setLinkUpstreamBandwidthKbps(LINK_UPSTREAM_BANDWIDTH_KBPS)
+ .setLinkDownstreamBandwidthKbps(LINK_DOWNSTREAM_BANDWIDTH_KBPS)
.build();
private static final TelephonyNetworkSpecifier TEL_NETWORK_SPECIFIER =
@@ -93,6 +104,8 @@
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.setSubscriptionIds(Set.of(SUB_ID))
.setNetworkSpecifier(TEL_NETWORK_SPECIFIER)
+ .setLinkUpstreamBandwidthKbps(LINK_UPSTREAM_BANDWIDTH_KBPS)
+ .setLinkDownstreamBandwidthKbps(LINK_DOWNSTREAM_BANDWIDTH_KBPS)
.build();
private static final LinkProperties LINK_PROPERTIES = getLinkPropertiesWithName("test_iface");
@@ -146,7 +159,6 @@
public void testMatchWithoutNotMeteredBit() {
final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority =
new VcnWifiUnderlyingNetworkTemplate.Builder()
- .setNetworkQuality(NETWORK_QUALITY_OK)
.setMetered(MATCH_FORBIDDEN)
.build();
@@ -161,11 +173,133 @@
null /* carrierConfig */));
}
+ private void verifyMatchesPriorityRuleForUpstreamBandwidth(
+ int entryUpstreamBandwidth,
+ int exitUpstreamBandwidth,
+ UnderlyingNetworkRecord currentlySelected,
+ boolean expectMatch) {
+ final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority =
+ new VcnWifiUnderlyingNetworkTemplate.Builder()
+ .setMinUpstreamBandwidthKbps(entryUpstreamBandwidth, exitUpstreamBandwidth)
+ .build();
+
+ assertEquals(
+ expectMatch,
+ checkMatchesPriorityRule(
+ mVcnContext,
+ wifiNetworkPriority,
+ mWifiNetworkRecord,
+ SUB_GROUP,
+ mSubscriptionSnapshot,
+ currentlySelected,
+ null /* carrierConfig */));
+ }
+
+ private void verifyMatchesPriorityRuleForDownstreamBandwidth(
+ int entryDownstreamBandwidth,
+ int exitDownstreamBandwidth,
+ UnderlyingNetworkRecord currentlySelected,
+ boolean expectMatch) {
+ final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority =
+ new VcnWifiUnderlyingNetworkTemplate.Builder()
+ .setMinDownstreamBandwidthKbps(
+ entryDownstreamBandwidth, exitDownstreamBandwidth)
+ .build();
+
+ assertEquals(
+ expectMatch,
+ checkMatchesPriorityRule(
+ mVcnContext,
+ wifiNetworkPriority,
+ mWifiNetworkRecord,
+ SUB_GROUP,
+ mSubscriptionSnapshot,
+ currentlySelected,
+ null /* carrierConfig */));
+ }
+
+ @Test
+ public void testMatchWithEntryUpstreamBandwidthEquals() {
+ verifyMatchesPriorityRuleForUpstreamBandwidth(
+ TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS,
+ null /* currentlySelected */,
+ true);
+ }
+
+ @Test
+ public void testMatchWithEntryUpstreamBandwidthTooLow() {
+ verifyMatchesPriorityRuleForUpstreamBandwidth(
+ LINK_UPSTREAM_BANDWIDTH_KBPS + 1,
+ LINK_UPSTREAM_BANDWIDTH_KBPS + 1,
+ null /* currentlySelected */,
+ false);
+ }
+
+ @Test
+ public void testMatchWithEntryDownstreamBandwidthEquals() {
+ verifyMatchesPriorityRuleForDownstreamBandwidth(
+ TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS,
+ null /* currentlySelected */,
+ true);
+ }
+
+ @Test
+ public void testMatchWithEntryDownstreamBandwidthTooLow() {
+ verifyMatchesPriorityRuleForDownstreamBandwidth(
+ LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1,
+ LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1,
+ null /* currentlySelected */,
+ false);
+ }
+
+ @Test
+ public void testMatchWithExitUpstreamBandwidthEquals() {
+ verifyMatchesPriorityRuleForUpstreamBandwidth(
+ TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS,
+ mWifiNetworkRecord,
+ true);
+ }
+
+ @Test
+ public void testMatchWithExitUpstreamBandwidthTooLow() {
+ verifyMatchesPriorityRuleForUpstreamBandwidth(
+ LINK_UPSTREAM_BANDWIDTH_KBPS + 1,
+ LINK_UPSTREAM_BANDWIDTH_KBPS + 1,
+ mWifiNetworkRecord,
+ false);
+ }
+
+ @Test
+ public void testMatchWithExitDownstreamBandwidthEquals() {
+ verifyMatchesPriorityRuleForDownstreamBandwidth(
+ TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS,
+ mWifiNetworkRecord,
+ true);
+ }
+
+ @Test
+ public void testMatchWithExitDownstreamBandwidthTooLow() {
+ verifyMatchesPriorityRuleForDownstreamBandwidth(
+ LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1,
+ LINK_DOWNSTREAM_BANDWIDTH_KBPS + 1,
+ mWifiNetworkRecord,
+ false);
+ }
+
private void verifyMatchWifi(
boolean isSelectedNetwork, PersistableBundle carrierConfig, boolean expectMatch) {
final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority =
new VcnWifiUnderlyingNetworkTemplate.Builder()
- .setNetworkQuality(NETWORK_QUALITY_OK)
+ .setMinUpstreamBandwidthKbps(
+ TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS)
+ .setMinDownstreamBandwidthKbps(
+ TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS)
.build();
final UnderlyingNetworkRecord selectedNetworkRecord =
isSelectedNetwork ? mWifiNetworkRecord : null;
@@ -214,7 +348,12 @@
final String nwPrioritySsid = useMatchedSsid ? SSID : SSID_OTHER;
final VcnWifiUnderlyingNetworkTemplate wifiNetworkPriority =
new VcnWifiUnderlyingNetworkTemplate.Builder()
- .setNetworkQuality(NETWORK_QUALITY_OK)
+ .setMinUpstreamBandwidthKbps(
+ TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS)
+ .setMinDownstreamBandwidthKbps(
+ TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS)
.setSsids(Set.of(nwPrioritySsid))
.build();
@@ -238,7 +377,13 @@
}
private static VcnCellUnderlyingNetworkTemplate.Builder getCellNetworkPriorityBuilder() {
- return new VcnCellUnderlyingNetworkTemplate.Builder().setNetworkQuality(NETWORK_QUALITY_OK);
+ return new VcnCellUnderlyingNetworkTemplate.Builder()
+ .setMinUpstreamBandwidthKbps(
+ TEST_MIN_ENTRY_UPSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_EXIT_UPSTREAM_BANDWIDTH_KBPS)
+ .setMinDownstreamBandwidthKbps(
+ TEST_MIN_ENTRY_DOWNSTREAM_BANDWIDTH_KBPS,
+ TEST_MIN_EXIT_DOWNSTREAM_BANDWIDTH_KBPS);
}
@Test
diff --git a/tools/aosp/aosp_sha.sh b/tools/aosp/aosp_sha.sh
index 36bea57..95b43cd 100755
--- a/tools/aosp/aosp_sha.sh
+++ b/tools/aosp/aosp_sha.sh
@@ -1,7 +1,7 @@
#!/bin/bash
LOCAL_DIR="$( dirname "${BASH_SOURCE}" )"
-if git branch -vv | grep -q -E "^\*[^\[]+\[aosp/"; then
+if git log -n 1 --format='%D' HEAD@{upstream} | grep -q aosp/; then
# Change appears to be in AOSP
exit 0
elif git log -n 1 --format='%B' $1 | grep -q -E "^Ignore-AOSP-First: .+" ; then