Merge "Use Ble scan for Fast Pair" into tm-dev
diff --git a/framework-t/api/system-current.txt b/framework-t/api/system-current.txt
index c59fb68..755bf1c 100644
--- a/framework-t/api/system-current.txt
+++ b/framework-t/api/system-current.txt
@@ -51,208 +51,6 @@
field @NonNull public static final android.os.Parcelable.Creator<android.nearby.DataElement> CREATOR;
}
- public class FastPairAccountKeyDeviceMetadata {
- method @Nullable public byte[] getDeviceAccountKey();
- method @Nullable public android.nearby.FastPairDeviceMetadata getFastPairDeviceMetadata();
- method @Nullable public android.nearby.FastPairDiscoveryItem getFastPairDiscoveryItem();
- method @Nullable public byte[] getSha256DeviceAccountKeyPublicAddress();
- }
-
- public static final class FastPairAccountKeyDeviceMetadata.Builder {
- ctor public FastPairAccountKeyDeviceMetadata.Builder();
- method @NonNull public android.nearby.FastPairAccountKeyDeviceMetadata build();
- method @NonNull public android.nearby.FastPairAccountKeyDeviceMetadata.Builder setDeviceAccountKey(@Nullable byte[]);
- method @NonNull public android.nearby.FastPairAccountKeyDeviceMetadata.Builder setFastPairDeviceMetadata(@Nullable android.nearby.FastPairDeviceMetadata);
- method @NonNull public android.nearby.FastPairAccountKeyDeviceMetadata.Builder setFastPairDiscoveryItem(@Nullable android.nearby.FastPairDiscoveryItem);
- method @NonNull public android.nearby.FastPairAccountKeyDeviceMetadata.Builder setSha256DeviceAccountKeyPublicAddress(@Nullable byte[]);
- }
-
- public class FastPairAntispoofKeyDeviceMetadata {
- method @Nullable public byte[] getAntispoofPublicKey();
- method @Nullable public android.nearby.FastPairDeviceMetadata getFastPairDeviceMetadata();
- }
-
- public static final class FastPairAntispoofKeyDeviceMetadata.Builder {
- ctor public FastPairAntispoofKeyDeviceMetadata.Builder();
- method @NonNull public android.nearby.FastPairAntispoofKeyDeviceMetadata build();
- method @NonNull public android.nearby.FastPairAntispoofKeyDeviceMetadata.Builder setAntispoofPublicKey(@Nullable byte[]);
- method @NonNull public android.nearby.FastPairAntispoofKeyDeviceMetadata.Builder setFastPairDeviceMetadata(@Nullable android.nearby.FastPairDeviceMetadata);
- }
-
- public abstract class FastPairDataProviderService extends android.app.Service {
- ctor public FastPairDataProviderService(@NonNull String);
- method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
- method public abstract void onLoadFastPairAccountDevicesMetadata(@NonNull android.nearby.FastPairDataProviderService.FastPairAccountDevicesMetadataRequest, @NonNull android.nearby.FastPairDataProviderService.FastPairAccountDevicesMetadataCallback);
- method public abstract void onLoadFastPairAntispoofKeyDeviceMetadata(@NonNull android.nearby.FastPairDataProviderService.FastPairAntispoofKeyDeviceMetadataRequest, @NonNull android.nearby.FastPairDataProviderService.FastPairAntispoofKeyDeviceMetadataCallback);
- method public abstract void onLoadFastPairEligibleAccounts(@NonNull android.nearby.FastPairDataProviderService.FastPairEligibleAccountsRequest, @NonNull android.nearby.FastPairDataProviderService.FastPairEligibleAccountsCallback);
- method public abstract void onManageFastPairAccount(@NonNull android.nearby.FastPairDataProviderService.FastPairManageAccountRequest, @NonNull android.nearby.FastPairDataProviderService.FastPairManageActionCallback);
- method public abstract void onManageFastPairAccountDevice(@NonNull android.nearby.FastPairDataProviderService.FastPairManageAccountDeviceRequest, @NonNull android.nearby.FastPairDataProviderService.FastPairManageActionCallback);
- field public static final String ACTION_FAST_PAIR_DATA_PROVIDER = "android.nearby.action.FAST_PAIR_DATA_PROVIDER";
- field public static final int ERROR_CODE_BAD_REQUEST = 0; // 0x0
- field public static final int ERROR_CODE_INTERNAL_ERROR = 1; // 0x1
- field public static final int MANAGE_REQUEST_ADD = 0; // 0x0
- field public static final int MANAGE_REQUEST_REMOVE = 1; // 0x1
- }
-
- public static interface FastPairDataProviderService.FastPairAccountDevicesMetadataCallback {
- method public void onError(int, @Nullable String);
- method public void onFastPairAccountDevicesMetadataReceived(@NonNull java.util.Collection<android.nearby.FastPairAccountKeyDeviceMetadata>);
- }
-
- public static class FastPairDataProviderService.FastPairAccountDevicesMetadataRequest {
- method @NonNull public android.accounts.Account getAccount();
- method @NonNull public java.util.Collection<byte[]> getDeviceAccountKeys();
- }
-
- public static interface FastPairDataProviderService.FastPairAntispoofKeyDeviceMetadataCallback {
- method public void onError(int, @Nullable String);
- method public void onFastPairAntispoofKeyDeviceMetadataReceived(@NonNull android.nearby.FastPairAntispoofKeyDeviceMetadata);
- }
-
- public static class FastPairDataProviderService.FastPairAntispoofKeyDeviceMetadataRequest {
- method @NonNull public byte[] getModelId();
- }
-
- public static interface FastPairDataProviderService.FastPairEligibleAccountsCallback {
- method public void onError(int, @Nullable String);
- method public void onFastPairEligibleAccountsReceived(@NonNull java.util.Collection<android.nearby.FastPairEligibleAccount>);
- }
-
- public static class FastPairDataProviderService.FastPairEligibleAccountsRequest {
- }
-
- public static class FastPairDataProviderService.FastPairManageAccountDeviceRequest {
- method @NonNull public android.accounts.Account getAccount();
- method @NonNull public android.nearby.FastPairAccountKeyDeviceMetadata getAccountKeyDeviceMetadata();
- method public int getRequestType();
- }
-
- public static class FastPairDataProviderService.FastPairManageAccountRequest {
- method @NonNull public android.accounts.Account getAccount();
- method public int getRequestType();
- }
-
- public static interface FastPairDataProviderService.FastPairManageActionCallback {
- method public void onError(int, @Nullable String);
- method public void onSuccess();
- }
-
- public class FastPairDeviceMetadata {
- method public int getBleTxPower();
- method @Nullable public String getConnectSuccessCompanionAppInstalled();
- method @Nullable public String getConnectSuccessCompanionAppNotInstalled();
- method public int getDeviceType();
- method @Nullable public String getDownloadCompanionAppDescription();
- method @Nullable public String getFailConnectGoToSettingsDescription();
- method @Nullable public byte[] getImage();
- method @Nullable public String getImageUrl();
- method @Nullable public String getInitialNotificationDescription();
- method @Nullable public String getInitialNotificationDescriptionNoAccount();
- method @Nullable public String getInitialPairingDescription();
- method @Nullable public String getIntentUri();
- method @Nullable public String getName();
- method @Nullable public String getOpenCompanionAppDescription();
- method @Nullable public String getRetroactivePairingDescription();
- method @Nullable public String getSubsequentPairingDescription();
- method public float getTriggerDistance();
- method @Nullable public String getTrueWirelessImageUrlCase();
- method @Nullable public String getTrueWirelessImageUrlLeftBud();
- method @Nullable public String getTrueWirelessImageUrlRightBud();
- method @Nullable public String getUnableToConnectDescription();
- method @Nullable public String getUnableToConnectTitle();
- method @Nullable public String getUpdateCompanionAppDescription();
- method @Nullable public String getWaitLaunchCompanionAppDescription();
- }
-
- public static final class FastPairDeviceMetadata.Builder {
- ctor public FastPairDeviceMetadata.Builder();
- method @NonNull public android.nearby.FastPairDeviceMetadata build();
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setBleTxPower(int);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setConnectSuccessCompanionAppInstalled(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setConnectSuccessCompanionAppNotInstalled(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setDeviceType(int);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setDownloadCompanionAppDescription(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setFailConnectGoToSettingsDescription(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setImage(@Nullable byte[]);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setImageUrl(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setInitialNotificationDescription(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setInitialNotificationDescriptionNoAccount(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setInitialPairingDescription(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setIntentUri(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setName(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setOpenCompanionAppDescription(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setRetroactivePairingDescription(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setSubsequentPairingDescription(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setTriggerDistance(float);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setTrueWirelessImageUrlCase(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setTrueWirelessImageUrlLeftBud(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setTrueWirelessImageUrlRightBud(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setUnableToConnectDescription(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setUnableToConnectTitle(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setUpdateCompanionAppDescription(@Nullable String);
- method @NonNull public android.nearby.FastPairDeviceMetadata.Builder setWaitLaunchCompanionAppDescription(@Nullable String);
- }
-
- public class FastPairDiscoveryItem {
- method @Nullable public String getActionUrl();
- method public int getActionUrlType();
- method @Nullable public String getAppName();
- method @Nullable public byte[] getAuthenticationPublicKeySecp256r1();
- method @Nullable public String getDescription();
- method @Nullable public String getDeviceName();
- method @Nullable public String getDisplayUrl();
- method public long getFirstObservationTimestampMillis();
- method @Nullable public String getIconFfeUrl();
- method @Nullable public byte[] getIconPng();
- method @Nullable public String getId();
- method public long getLastObservationTimestampMillis();
- method @Nullable public String getMacAddress();
- method @Nullable public String getPackageName();
- method public long getPendingAppInstallTimestampMillis();
- method public int getRssi();
- method public int getState();
- method @Nullable public String getTitle();
- method @Nullable public String getTriggerId();
- method public int getTxPower();
- }
-
- public static final class FastPairDiscoveryItem.Builder {
- ctor public FastPairDiscoveryItem.Builder();
- method @NonNull public android.nearby.FastPairDiscoveryItem build();
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setActionUrl(@Nullable String);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setActionUrlType(int);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setAppName(@Nullable String);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setAuthenticationPublicKeySecp256r1(@Nullable byte[]);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setDescription(@Nullable String);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setDeviceName(@Nullable String);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setDisplayUrl(@Nullable String);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setFirstObservationTimestampMillis(long);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setIconFfeUrl(@Nullable String);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setIconPng(@Nullable byte[]);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setId(@Nullable String);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setLastObservationTimestampMillis(long);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setMacAddress(@Nullable String);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setPackageName(@Nullable String);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setPendingAppInstallTimestampMillis(long);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setRssi(int);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setState(int);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setTitle(@Nullable String);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setTriggerId(@Nullable String);
- method @NonNull public android.nearby.FastPairDiscoveryItem.Builder setTxPower(int);
- }
-
- public class FastPairEligibleAccount {
- method @Nullable public android.accounts.Account getAccount();
- method public boolean isOptIn();
- }
-
- public static final class FastPairEligibleAccount.Builder {
- ctor public FastPairEligibleAccount.Builder();
- method @NonNull public android.nearby.FastPairEligibleAccount build();
- method @NonNull public android.nearby.FastPairEligibleAccount.Builder setAccount(@Nullable android.accounts.Account);
- method @NonNull public android.nearby.FastPairEligibleAccount.Builder setOptIn(boolean);
- }
-
public abstract class NearbyDevice {
method @NonNull public java.util.List<java.lang.Integer> getMediums();
method @Nullable public String getName();
diff --git a/nearby/framework/java/android/nearby/FastPairAccountKeyDeviceMetadata.java b/nearby/framework/java/android/nearby/FastPairAccountKeyDeviceMetadata.java
index 160ad75..d42fbf4 100644
--- a/nearby/framework/java/android/nearby/FastPairAccountKeyDeviceMetadata.java
+++ b/nearby/framework/java/android/nearby/FastPairAccountKeyDeviceMetadata.java
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.nearby.aidl.FastPairAccountKeyDeviceMetadataParcel;
/**
@@ -26,7 +25,6 @@
*
* @hide
*/
-@SystemApi
public class FastPairAccountKeyDeviceMetadata {
FastPairAccountKeyDeviceMetadataParcel mMetadataParcel;
@@ -42,7 +40,6 @@
* @return 16-byte Account Key.
* @hide
*/
- @SystemApi
@Nullable
public byte[] getDeviceAccountKey() {
return mMetadataParcel.deviceAccountKey;
@@ -55,7 +52,6 @@
* @return 32-byte Sha256 hash value.
* @hide
*/
- @SystemApi
@Nullable
public byte[] getSha256DeviceAccountKeyPublicAddress() {
return mMetadataParcel.sha256DeviceAccountKeyPublicAddress;
@@ -66,7 +62,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public FastPairDeviceMetadata getFastPairDeviceMetadata() {
if (mMetadataParcel.metadata == null) {
@@ -80,7 +75,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public FastPairDiscoveryItem getFastPairDiscoveryItem() {
if (mMetadataParcel.discoveryItem == null) {
@@ -94,7 +88,6 @@
*
* @hide
*/
- @SystemApi
public static final class Builder {
private final FastPairAccountKeyDeviceMetadataParcel mBuilderParcel;
@@ -104,7 +97,6 @@
*
* @hide
*/
- @SystemApi
public Builder() {
mBuilderParcel = new FastPairAccountKeyDeviceMetadataParcel();
mBuilderParcel.deviceAccountKey = null;
@@ -121,7 +113,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setDeviceAccountKey(@Nullable byte[] deviceAccountKey) {
mBuilderParcel.deviceAccountKey = deviceAccountKey;
@@ -136,7 +127,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setSha256DeviceAccountKeyPublicAddress(
@Nullable byte[] sha256DeviceAccountKeyPublicAddress) {
@@ -153,7 +143,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setFastPairDeviceMetadata(@Nullable FastPairDeviceMetadata metadata) {
if (metadata == null) {
@@ -171,7 +160,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setFastPairDiscoveryItem(@Nullable FastPairDiscoveryItem discoveryItem) {
if (discoveryItem == null) {
@@ -187,7 +175,6 @@
*
* @hide
*/
- @SystemApi
@NonNull
public FastPairAccountKeyDeviceMetadata build() {
return new FastPairAccountKeyDeviceMetadata(mBuilderParcel);
diff --git a/nearby/framework/java/android/nearby/FastPairAntispoofKeyDeviceMetadata.java b/nearby/framework/java/android/nearby/FastPairAntispoofKeyDeviceMetadata.java
index 1837671..74831d5 100644
--- a/nearby/framework/java/android/nearby/FastPairAntispoofKeyDeviceMetadata.java
+++ b/nearby/framework/java/android/nearby/FastPairAntispoofKeyDeviceMetadata.java
@@ -17,7 +17,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.nearby.aidl.FastPairAntispoofKeyDeviceMetadataParcel;
/**
@@ -25,7 +24,6 @@
*
* @hide
*/
-@SystemApi
public class FastPairAntispoofKeyDeviceMetadata {
FastPairAntispoofKeyDeviceMetadataParcel mMetadataParcel;
@@ -39,7 +37,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public byte[] getAntispoofPublicKey() {
return this.mMetadataParcel.antispoofPublicKey;
@@ -50,7 +47,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public FastPairDeviceMetadata getFastPairDeviceMetadata() {
if (this.mMetadataParcel.deviceMetadata == null) {
@@ -64,7 +60,6 @@
*
* @hide
*/
- @SystemApi
public static final class Builder {
private final FastPairAntispoofKeyDeviceMetadataParcel mBuilderParcel;
@@ -74,7 +69,6 @@
*
* @hide
*/
- @SystemApi
public Builder() {
mBuilderParcel = new FastPairAntispoofKeyDeviceMetadataParcel();
mBuilderParcel.antispoofPublicKey = null;
@@ -88,7 +82,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setAntispoofPublicKey(@Nullable byte[] antispoofPublicKey) {
mBuilderParcel.antispoofPublicKey = antispoofPublicKey;
@@ -103,7 +96,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setFastPairDeviceMetadata(@Nullable FastPairDeviceMetadata metadata) {
if (metadata != null) {
@@ -119,7 +111,6 @@
*
* @hide
*/
- @SystemApi
@NonNull
public FastPairAntispoofKeyDeviceMetadata build() {
return new FastPairAntispoofKeyDeviceMetadata(mBuilderParcel);
diff --git a/nearby/framework/java/android/nearby/FastPairDataProviderService.java b/nearby/framework/java/android/nearby/FastPairDataProviderService.java
index b6c840d..f1d5074 100644
--- a/nearby/framework/java/android/nearby/FastPairDataProviderService.java
+++ b/nearby/framework/java/android/nearby/FastPairDataProviderService.java
@@ -20,7 +20,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.app.Service;
import android.content.Intent;
import android.nearby.aidl.ByteArrayParcel;
@@ -59,7 +58,6 @@
*
* @hide
*/
-@SystemApi
public abstract class FastPairDataProviderService extends Service {
/**
* The action the wrapping service should have in its intent filter to implement the
@@ -67,7 +65,6 @@
*
* @hide
*/
- @SystemApi
public static final String ACTION_FAST_PAIR_DATA_PROVIDER =
"android.nearby.action.FAST_PAIR_DATA_PROVIDER";
@@ -76,7 +73,6 @@
*
* @hide
*/
- @SystemApi
public static final int MANAGE_REQUEST_ADD = 0;
/**
@@ -84,7 +80,6 @@
*
* @hide
*/
- @SystemApi
public static final int MANAGE_REQUEST_REMOVE = 1;
/**
@@ -101,7 +96,6 @@
*
* @hide
*/
- @SystemApi
public static final int ERROR_CODE_BAD_REQUEST = 0;
/**
@@ -109,7 +103,6 @@
*
* @hide
*/
- @SystemApi
public static final int ERROR_CODE_INTERNAL_ERROR = 1;
/**
@@ -130,7 +123,6 @@
* @param tag TAG for on device logging.
* @hide
*/
- @SystemApi
public FastPairDataProviderService(@NonNull String tag) {
mBinder = new Service();
mTag = tag;
@@ -147,7 +139,6 @@
*
* @hide
*/
- @SystemApi
public interface FastPairAntispoofKeyDeviceMetadataCallback {
/**
@@ -155,7 +146,6 @@
*
* @hide
*/
- @SystemApi
void onFastPairAntispoofKeyDeviceMetadataReceived(
@NonNull FastPairAntispoofKeyDeviceMetadata metadata);
@@ -163,7 +153,6 @@
*
* @hide
*/
- @SystemApi
void onError(@ErrorCode int code, @Nullable String message);
}
@@ -172,7 +161,6 @@
*
* @hide
*/
- @SystemApi
public interface FastPairAccountDevicesMetadataCallback {
/**
@@ -180,7 +168,6 @@
*
* @hide
*/
- @SystemApi
void onFastPairAccountDevicesMetadataReceived(
@NonNull Collection<FastPairAccountKeyDeviceMetadata> metadatas);
/**
@@ -188,7 +175,6 @@
*
* @hide
*/
- @SystemApi
void onError(@ErrorCode int code, @Nullable String message);
}
@@ -197,7 +183,6 @@
*
* @hide
*/
- @SystemApi
public interface FastPairEligibleAccountsCallback {
/**
@@ -205,7 +190,6 @@
*
* @hide
*/
- @SystemApi
void onFastPairEligibleAccountsReceived(
@NonNull Collection<FastPairEligibleAccount> accounts);
/**
@@ -213,7 +197,6 @@
*
* @hide
*/
- @SystemApi
void onError(@ErrorCode int code, @Nullable String message);
}
@@ -222,7 +205,6 @@
*
* @hide
*/
- @SystemApi
public interface FastPairManageActionCallback {
/**
@@ -230,14 +212,12 @@
*
* @hide
*/
- @SystemApi
void onSuccess();
/**
* Invoked in case of error.
*
* @hide
*/
- @SystemApi
void onError(@ErrorCode int code, @Nullable String message);
}
@@ -247,7 +227,6 @@
*
* @hide
*/
- @SystemApi
public abstract void onLoadFastPairAntispoofKeyDeviceMetadata(
@NonNull FastPairAntispoofKeyDeviceMetadataRequest request,
@NonNull FastPairAntispoofKeyDeviceMetadataCallback callback);
@@ -258,7 +237,6 @@
*
* @hide
*/
- @SystemApi
public abstract void onLoadFastPairAccountDevicesMetadata(
@NonNull FastPairAccountDevicesMetadataRequest request,
@NonNull FastPairAccountDevicesMetadataCallback callback);
@@ -269,7 +247,6 @@
*
* @hide
*/
- @SystemApi
public abstract void onLoadFastPairEligibleAccounts(
@NonNull FastPairEligibleAccountsRequest request,
@NonNull FastPairEligibleAccountsCallback callback);
@@ -279,7 +256,6 @@
*
* @hide
*/
- @SystemApi
public abstract void onManageFastPairAccount(
@NonNull FastPairManageAccountRequest request,
@NonNull FastPairManageActionCallback callback);
@@ -289,7 +265,6 @@
*
* @hide
*/
- @SystemApi
public abstract void onManageFastPairAccountDevice(
@NonNull FastPairManageAccountDeviceRequest request,
@NonNull FastPairManageActionCallback callback);
@@ -301,7 +276,6 @@
*
* @hide
*/
- @SystemApi
public static class FastPairAntispoofKeyDeviceMetadataRequest {
private final FastPairAntispoofKeyDeviceMetadataRequestParcel mMetadataRequestParcel;
@@ -321,7 +295,6 @@
* time.
* @hide
*/
- @SystemApi
public @NonNull byte[] getModelId() {
return this.mMetadataRequestParcel.modelId;
}
@@ -342,7 +315,6 @@
* needs to set account with a non-empty allow list.
* @hide
*/
- @SystemApi
public static class FastPairAccountDevicesMetadataRequest {
private final FastPairAccountDevicesMetadataRequestParcel mMetadataRequestParcel;
@@ -358,7 +330,6 @@
* @return a FastPair account.
* @hide
*/
- @SystemApi
public @NonNull Account getAccount() {
return this.mMetadataRequestParcel.account;
}
@@ -373,7 +344,6 @@
* @return allowlist of Fast Pair devices using a collection of deviceAccountKeys.
* @hide
*/
- @SystemApi
public @NonNull Collection<byte[]> getDeviceAccountKeys() {
if (this.mMetadataRequestParcel.deviceAccountKeys == null) {
return new ArrayList<byte[]>(0);
@@ -393,7 +363,6 @@
*
* @hide
*/
- @SystemApi
public static class FastPairEligibleAccountsRequest {
@SuppressWarnings("UnusedVariable")
private final FastPairEligibleAccountsRequestParcel mAccountsRequestParcel;
@@ -412,7 +381,6 @@
*
* @hide
*/
- @SystemApi
public static class FastPairManageAccountRequest {
private final FastPairManageAccountRequestParcel mAccountRequestParcel;
@@ -427,7 +395,6 @@
*
* @hide
*/
- @SystemApi
public @ManageRequestType int getRequestType() {
return this.mAccountRequestParcel.requestType;
}
@@ -436,7 +403,6 @@
*
* @hide
*/
- @SystemApi
public @NonNull Account getAccount() {
return this.mAccountRequestParcel.account;
}
@@ -450,7 +416,6 @@
*
* @hide
*/
- @SystemApi
public static class FastPairManageAccountDeviceRequest {
private final FastPairManageAccountDeviceRequestParcel mRequestParcel;
@@ -465,7 +430,6 @@
*
* @hide
*/
- @SystemApi
public @ManageRequestType int getRequestType() {
return this.mRequestParcel.requestType;
}
@@ -474,7 +438,6 @@
*
* @hide
*/
- @SystemApi
public @NonNull Account getAccount() {
return this.mRequestParcel.account;
}
@@ -483,7 +446,6 @@
*
* @hide
*/
- @SystemApi
public @NonNull FastPairAccountKeyDeviceMetadata getAccountKeyDeviceMetadata() {
return new FastPairAccountKeyDeviceMetadata(
this.mRequestParcel.accountKeyDeviceMetadata);
diff --git a/nearby/framework/java/android/nearby/FastPairDeviceMetadata.java b/nearby/framework/java/android/nearby/FastPairDeviceMetadata.java
index 04845c0..0e2e79d 100644
--- a/nearby/framework/java/android/nearby/FastPairDeviceMetadata.java
+++ b/nearby/framework/java/android/nearby/FastPairDeviceMetadata.java
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.nearby.aidl.FastPairDeviceMetadataParcel;
/**
@@ -26,7 +25,6 @@
*
* @hide
*/
-@SystemApi
public class FastPairDeviceMetadata {
FastPairDeviceMetadataParcel mMetadataParcel;
@@ -41,7 +39,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getImageUrl() {
return mMetadataParcel.imageUrl;
@@ -52,7 +49,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getIntentUri() {
return mMetadataParcel.intentUri;
@@ -64,7 +60,6 @@
*
* @hide
*/
- @SystemApi
public int getBleTxPower() {
return mMetadataParcel.bleTxPower;
}
@@ -74,7 +69,6 @@
*
* @hide
*/
- @SystemApi
public float getTriggerDistance() {
return mMetadataParcel.triggerDistance;
}
@@ -86,7 +80,6 @@
* @return Fast Pair device image in 32-bit PNG with dimensions of 512px by 512px.
* @hide
*/
- @SystemApi
@Nullable
public byte[] getImage() {
return mMetadataParcel.image;
@@ -99,7 +92,6 @@
* TRUE_WIRELESS_HEADPHONES = 7;
* @hide
*/
- @SystemApi
public int getDeviceType() {
return mMetadataParcel.deviceType;
}
@@ -109,7 +101,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getName() {
return mMetadataParcel.name;
@@ -120,7 +111,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getTrueWirelessImageUrlLeftBud() {
return mMetadataParcel.trueWirelessImageUrlLeftBud;
@@ -131,7 +121,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getTrueWirelessImageUrlRightBud() {
return mMetadataParcel.trueWirelessImageUrlRightBud;
@@ -142,7 +131,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getTrueWirelessImageUrlCase() {
return mMetadataParcel.trueWirelessImageUrlCase;
@@ -154,7 +142,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getInitialNotificationDescription() {
return mMetadataParcel.initialNotificationDescription;
@@ -166,7 +153,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getInitialNotificationDescriptionNoAccount() {
return mMetadataParcel.initialNotificationDescriptionNoAccount;
@@ -178,7 +164,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getOpenCompanionAppDescription() {
return mMetadataParcel.openCompanionAppDescription;
@@ -190,7 +175,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getUpdateCompanionAppDescription() {
return mMetadataParcel.updateCompanionAppDescription;
@@ -202,7 +186,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getDownloadCompanionAppDescription() {
return mMetadataParcel.downloadCompanionAppDescription;
@@ -223,7 +206,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getUnableToConnectDescription() {
return mMetadataParcel.unableToConnectDescription;
@@ -235,7 +217,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getInitialPairingDescription() {
return mMetadataParcel.initialPairingDescription;
@@ -247,7 +228,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getConnectSuccessCompanionAppInstalled() {
return mMetadataParcel.connectSuccessCompanionAppInstalled;
@@ -259,7 +239,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getConnectSuccessCompanionAppNotInstalled() {
return mMetadataParcel.connectSuccessCompanionAppNotInstalled;
@@ -271,7 +250,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getSubsequentPairingDescription() {
return mMetadataParcel.subsequentPairingDescription;
@@ -283,7 +261,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getRetroactivePairingDescription() {
return mMetadataParcel.retroactivePairingDescription;
@@ -295,7 +272,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getWaitLaunchCompanionAppDescription() {
return mMetadataParcel.waitLaunchCompanionAppDescription;
@@ -307,7 +283,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getFailConnectGoToSettingsDescription() {
return mMetadataParcel.failConnectGoToSettingsDescription;
@@ -318,7 +293,6 @@
*
* @hide
*/
- @SystemApi
public static final class Builder {
private final FastPairDeviceMetadataParcel mBuilderParcel;
@@ -328,7 +302,6 @@
*
* @hide
*/
- @SystemApi
public Builder() {
mBuilderParcel = new FastPairDeviceMetadataParcel();
mBuilderParcel.imageUrl = null;
@@ -364,7 +337,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setImageUrl(@Nullable String imageUrl) {
mBuilderParcel.imageUrl = imageUrl;
@@ -378,7 +350,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setIntentUri(@Nullable String intentUri) {
mBuilderParcel.intentUri = intentUri;
@@ -392,7 +363,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setName(@Nullable String name) {
mBuilderParcel.name = name;
@@ -406,7 +376,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setBleTxPower(int bleTxPower) {
mBuilderParcel.bleTxPower = bleTxPower;
@@ -420,7 +389,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setTriggerDistance(float triggerDistance) {
mBuilderParcel.triggerDistance = triggerDistance;
@@ -436,7 +404,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setImage(@Nullable byte[] image) {
mBuilderParcel.image = image;
@@ -450,7 +417,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setDeviceType(int deviceType) {
mBuilderParcel.deviceType = deviceType;
@@ -464,7 +430,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setTrueWirelessImageUrlLeftBud(
@Nullable String trueWirelessImageUrlLeftBud) {
@@ -479,7 +444,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setTrueWirelessImageUrlRightBud(
@Nullable String trueWirelessImageUrlRightBud) {
@@ -494,7 +458,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setTrueWirelessImageUrlCase(@Nullable String trueWirelessImageUrlCase) {
mBuilderParcel.trueWirelessImageUrlCase = trueWirelessImageUrlCase;
@@ -508,7 +471,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setInitialNotificationDescription(
@Nullable String initialNotificationDescription) {
@@ -524,7 +486,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setInitialNotificationDescriptionNoAccount(
@Nullable String initialNotificationDescriptionNoAccount) {
@@ -540,7 +501,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setOpenCompanionAppDescription(
@Nullable String openCompanionAppDescription) {
@@ -555,7 +515,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setUpdateCompanionAppDescription(
@Nullable String updateCompanionAppDescription) {
@@ -570,7 +529,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setDownloadCompanionAppDescription(
@Nullable String downloadCompanionAppDescription) {
@@ -585,7 +543,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setUnableToConnectTitle(@Nullable String unableToConnectTitle) {
mBuilderParcel.unableToConnectTitle = unableToConnectTitle;
@@ -600,7 +557,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setUnableToConnectDescription(
@Nullable String unableToConnectDescription) {
@@ -615,7 +571,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setInitialPairingDescription(@Nullable String initialPairingDescription) {
mBuilderParcel.initialPairingDescription = initialPairingDescription;
@@ -630,7 +585,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setConnectSuccessCompanionAppInstalled(
@Nullable String connectSuccessCompanionAppInstalled) {
@@ -647,7 +601,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setConnectSuccessCompanionAppNotInstalled(
@Nullable String connectSuccessCompanionAppNotInstalled) {
@@ -664,7 +617,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setSubsequentPairingDescription(
@Nullable String subsequentPairingDescription) {
@@ -679,7 +631,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setRetroactivePairingDescription(
@Nullable String retroactivePairingDescription) {
@@ -695,7 +646,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setWaitLaunchCompanionAppDescription(
@Nullable String waitLaunchCompanionAppDescription) {
@@ -712,7 +662,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setFailConnectGoToSettingsDescription(
@Nullable String failConnectGoToSettingsDescription) {
@@ -726,7 +675,6 @@
*
* @hide
*/
- @SystemApi
@NonNull
public FastPairDeviceMetadata build() {
return new FastPairDeviceMetadata(mBuilderParcel);
diff --git a/nearby/framework/java/android/nearby/FastPairDiscoveryItem.java b/nearby/framework/java/android/nearby/FastPairDiscoveryItem.java
index ce7413a..d8dfe29 100644
--- a/nearby/framework/java/android/nearby/FastPairDiscoveryItem.java
+++ b/nearby/framework/java/android/nearby/FastPairDiscoveryItem.java
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.nearby.aidl.FastPairDiscoveryItemParcel;
/**
@@ -26,7 +25,6 @@
*
* @hide
*/
-@SystemApi
public class FastPairDiscoveryItem {
FastPairDiscoveryItemParcel mMetadataParcel;
@@ -41,7 +39,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getId() {
return mMetadataParcel.id;
@@ -52,7 +49,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getMacAddress() {
return mMetadataParcel.macAddress;
@@ -63,7 +59,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getActionUrl() {
return mMetadataParcel.actionUrl;
@@ -74,7 +69,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getDeviceName() {
return mMetadataParcel.deviceName;
@@ -85,7 +79,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getTitle() {
return mMetadataParcel.title;
@@ -96,7 +89,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getDescription() {
return mMetadataParcel.description;
@@ -107,7 +99,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getDisplayUrl() {
return mMetadataParcel.displayUrl;
@@ -118,7 +109,6 @@
*
* @hide
*/
- @SystemApi
public long getLastObservationTimestampMillis() {
return mMetadataParcel.lastObservationTimestampMillis;
}
@@ -128,7 +118,6 @@
*
* @hide
*/
- @SystemApi
public long getFirstObservationTimestampMillis() {
return mMetadataParcel.firstObservationTimestampMillis;
}
@@ -138,7 +127,6 @@
*
* @hide
*/
- @SystemApi
public int getState() {
return mMetadataParcel.state;
}
@@ -148,7 +136,6 @@
*
* @hide
*/
- @SystemApi
public int getActionUrlType() {
return mMetadataParcel.actionUrlType;
}
@@ -158,7 +145,6 @@
*
* @hide
*/
- @SystemApi
public int getRssi() {
return mMetadataParcel.rssi;
}
@@ -168,7 +154,6 @@
*
* @hide
*/
- @SystemApi
public long getPendingAppInstallTimestampMillis() {
return mMetadataParcel.pendingAppInstallTimestampMillis;
}
@@ -178,7 +163,6 @@
*
* @hide
*/
- @SystemApi
public int getTxPower() {
return mMetadataParcel.txPower;
}
@@ -188,7 +172,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getAppName() {
return mMetadataParcel.appName;
@@ -199,7 +182,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getPackageName() {
return mMetadataParcel.packageName;
@@ -210,7 +192,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getTriggerId() {
return mMetadataParcel.triggerId;
@@ -223,7 +204,6 @@
* @return IconPng in 32-bit PNG with dimensions of 512px by 512px.
* @hide
*/
- @SystemApi
@Nullable
public byte[] getIconPng() {
return mMetadataParcel.iconPng;
@@ -234,7 +214,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public String getIconFfeUrl() {
return mMetadataParcel.iconFifeUrl;
@@ -247,7 +226,6 @@
* @return 64-byte authenticationPublicKeySecp256r1.
* @hide
*/
- @SystemApi
@Nullable
public byte[] getAuthenticationPublicKeySecp256r1() {
return mMetadataParcel.authenticationPublicKeySecp256r1;
@@ -258,7 +236,6 @@
*
* @hide
*/
- @SystemApi
public static final class Builder {
private final FastPairDiscoveryItemParcel mBuilderParcel;
@@ -268,7 +245,6 @@
*
* @hide
*/
- @SystemApi
public Builder() {
mBuilderParcel = new FastPairDiscoveryItemParcel();
}
@@ -281,7 +257,6 @@
*
* @hide
*/
- @SystemApi
@NonNull
public Builder setId(@Nullable String id) {
mBuilderParcel.id = id;
@@ -295,7 +270,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setMacAddress(@Nullable String macAddress) {
mBuilderParcel.macAddress = macAddress;
@@ -309,7 +283,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setActionUrl(@Nullable String actionUrl) {
mBuilderParcel.actionUrl = actionUrl;
@@ -322,7 +295,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setDeviceName(@Nullable String deviceName) {
mBuilderParcel.deviceName = deviceName;
@@ -336,7 +308,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setTitle(@Nullable String title) {
mBuilderParcel.title = title;
@@ -350,7 +321,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setDescription(@Nullable String description) {
mBuilderParcel.description = description;
@@ -364,7 +334,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setDisplayUrl(@Nullable String displayUrl) {
mBuilderParcel.displayUrl = displayUrl;
@@ -379,7 +348,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setLastObservationTimestampMillis(
long lastObservationTimestampMillis) {
@@ -395,7 +363,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setFirstObservationTimestampMillis(
long firstObservationTimestampMillis) {
@@ -410,7 +377,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setState(int state) {
mBuilderParcel.state = state;
@@ -424,7 +390,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setActionUrlType(int actionUrlType) {
mBuilderParcel.actionUrlType = actionUrlType;
@@ -438,7 +403,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setRssi(int rssi) {
mBuilderParcel.rssi = rssi;
@@ -453,7 +417,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setPendingAppInstallTimestampMillis(long pendingAppInstallTimestampMillis) {
mBuilderParcel.pendingAppInstallTimestampMillis = pendingAppInstallTimestampMillis;
@@ -467,7 +430,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setTxPower(int txPower) {
mBuilderParcel.txPower = txPower;
@@ -481,7 +443,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setAppName(@Nullable String appName) {
mBuilderParcel.appName = appName;
@@ -495,7 +456,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setPackageName(@Nullable String packageName) {
mBuilderParcel.packageName = packageName;
@@ -509,7 +469,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setTriggerId(@Nullable String triggerId) {
mBuilderParcel.triggerId = triggerId;
@@ -523,7 +482,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setIconPng(@Nullable byte[] iconPng) {
mBuilderParcel.iconPng = iconPng;
@@ -537,7 +495,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setIconFfeUrl(@Nullable String iconFifeUrl) {
mBuilderParcel.iconFifeUrl = iconFifeUrl;
@@ -552,7 +509,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setAuthenticationPublicKeySecp256r1(
@Nullable byte[] authenticationPublicKeySecp256r1) {
@@ -565,7 +521,6 @@
*
* @hide
*/
- @SystemApi
@NonNull
public FastPairDiscoveryItem build() {
return new FastPairDiscoveryItem(mBuilderParcel);
diff --git a/nearby/framework/java/android/nearby/FastPairEligibleAccount.java b/nearby/framework/java/android/nearby/FastPairEligibleAccount.java
index e6c3047..8be4cca 100644
--- a/nearby/framework/java/android/nearby/FastPairEligibleAccount.java
+++ b/nearby/framework/java/android/nearby/FastPairEligibleAccount.java
@@ -19,7 +19,6 @@
import android.accounts.Account;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.nearby.aidl.FastPairEligibleAccountParcel;
/**
@@ -27,7 +26,6 @@
*
* @hide
*/
-@SystemApi
public class FastPairEligibleAccount {
FastPairEligibleAccountParcel mAccountParcel;
@@ -41,7 +39,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
public Account getAccount() {
return this.mAccountParcel.account;
@@ -52,7 +49,6 @@
*
* @hide
*/
- @SystemApi
public boolean isOptIn() {
return this.mAccountParcel.optIn;
}
@@ -62,7 +58,6 @@
*
* @hide
*/
- @SystemApi
public static final class Builder {
private final FastPairEligibleAccountParcel mBuilderParcel;
@@ -72,7 +67,6 @@
*
* @hide
*/
- @SystemApi
public Builder() {
mBuilderParcel = new FastPairEligibleAccountParcel();
mBuilderParcel.account = null;
@@ -86,7 +80,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setAccount(@Nullable Account account) {
mBuilderParcel.account = account;
@@ -100,7 +93,6 @@
* @return The builder, to facilitate chaining {@code builder.setXXX(..).setXXX(..)}.
* @hide
*/
- @SystemApi
@NonNull
public Builder setOptIn(boolean optIn) {
mBuilderParcel.optIn = optIn;
@@ -112,7 +104,6 @@
*
* @hide
*/
- @SystemApi
@NonNull
public FastPairEligibleAccount build() {
return new FastPairEligibleAccount(mBuilderParcel);
diff --git a/nearby/service/Android.bp b/nearby/service/Android.bp
index 802e2c8..7112bb1 100644
--- a/nearby/service/Android.bp
+++ b/nearby/service/Android.bp
@@ -41,6 +41,39 @@
sdk_version: "module_current",
}
+// Common lib for nearby end-to-end testing.
+java_library {
+ name: "nearby-common-lib",
+ srcs: [
+ "java/com/android/server/nearby/common/bloomfilter/*.java",
+ "java/com/android/server/nearby/common/bluetooth/*.java",
+ "java/com/android/server/nearby/common/bluetooth/fastpair/AesCtrMultipleBlockEncryption.java",
+ "java/com/android/server/nearby/common/bluetooth/fastpair/AesEcbSingleBlockEncryption.java",
+ "java/com/android/server/nearby/common/bluetooth/fastpair/BluetoothAddress.java",
+ "java/com/android/server/nearby/common/bluetooth/fastpair/BluetoothUuids.java",
+ "java/com/android/server/nearby/common/bluetooth/fastpair/Bytes.java",
+ "java/com/android/server/nearby/common/bluetooth/fastpair/Constants.java",
+ "java/com/android/server/nearby/common/bluetooth/fastpair/EllipticCurveDiffieHellmanExchange.java",
+ "java/com/android/server/nearby/common/bluetooth/fastpair/HmacSha256.java",
+ "java/com/android/server/nearby/common/bluetooth/fastpair/Ltv.java",
+ "java/com/android/server/nearby/common/bluetooth/fastpair/MessageStreamHmacEncoder.java",
+ "java/com/android/server/nearby/common/bluetooth/fastpair/NamingEncoder.java",
+ "java/com/android/server/nearby/common/bluetooth/testability/**/*.java",
+ "java/com/android/server/nearby/common/bluetooth/gatt/*.java",
+ "java/com/android/server/nearby/common/bluetooth/util/*.java",
+ ],
+ libs: [
+ "androidx.annotation_annotation",
+ "androidx.core_core",
+ "error_prone_annotations",
+ "framework-bluetooth",
+ "guava",
+ ],
+ sdk_version: "module_current",
+ visibility: [
+ "//packages/modules/Connectivity/nearby/tests/multidevices/clients/test_support/fastpair_provider",
+ ],
+}
// Main lib for nearby services.
java_library {
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/FastPairAntispoofKeyDeviceMetadataTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/FastPairAntispoofKeyDeviceMetadataTest.java
deleted file mode 100644
index 65c061b..0000000
--- a/nearby/tests/cts/fastpair/src/android/nearby/cts/FastPairAntispoofKeyDeviceMetadataTest.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.nearby.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.nearby.FastPairAntispoofKeyDeviceMetadata;
-import android.nearby.FastPairDeviceMetadata;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SdkSuppress;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class FastPairAntispoofKeyDeviceMetadataTest {
-
- private static final String ASSISTANT_SETUP_HALFSHEET = "ASSISTANT_SETUP_HALFSHEET";
- private static final String ASSISTANT_SETUP_NOTIFICATION = "ASSISTANT_SETUP_NOTIFICATION";
- private static final int BLE_TX_POWER = 5;
- private static final String CONFIRM_PIN_DESCRIPTION = "CONFIRM_PIN_DESCRIPTION";
- private static final String CONFIRM_PIN_TITLE = "CONFIRM_PIN_TITLE";
- private static final String CONNECT_SUCCESS_COMPANION_APP_INSTALLED =
- "CONNECT_SUCCESS_COMPANION_APP_INSTALLED";
- private static final String CONNECT_SUCCESS_COMPANION_APP_NOT_INSTALLED =
- "CONNECT_SUCCESS_COMPANION_APP_NOT_INSTALLED";
- private static final float DELTA = 0.001f;
- private static final int DEVICE_TYPE = 7;
- private static final String DOWNLOAD_COMPANION_APP_DESCRIPTION =
- "DOWNLOAD_COMPANION_APP_DESCRIPTION";
- private static final String FAIL_CONNECT_GOTO_SETTINGS_DESCRIPTION =
- "FAIL_CONNECT_GOTO_SETTINGS_DESCRIPTION";
- private static final String FAST_PAIR_TV_CONNECT_DEVICE_NO_ACCOUNT_DESCRIPTION =
- "FAST_PAIR_TV_CONNECT_DEVICE_NO_ACCOUNT_DESCRIPTION";
- private static final byte[] IMAGE = new byte[] {7, 9};
- private static final String IMAGE_URL = "IMAGE_URL";
- private static final String INITIAL_NOTIFICATION_DESCRIPTION =
- "INITIAL_NOTIFICATION_DESCRIPTION";
- private static final String INITIAL_NOTIFICATION_DESCRIPTION_NO_ACCOUNT =
- "INITIAL_NOTIFICATION_DESCRIPTION_NO_ACCOUNT";
- private static final String INITIAL_PAIRING_DESCRIPTION = "INITIAL_PAIRING_DESCRIPTION";
- private static final String INTENT_URI = "INTENT_URI";
- private static final String LOCALE = "LOCALE";
- private static final String OPEN_COMPANION_APP_DESCRIPTION = "OPEN_COMPANION_APP_DESCRIPTION";
- private static final String RETRO_ACTIVE_PAIRING_DESCRIPTION =
- "RETRO_ACTIVE_PAIRING_DESCRIPTION";
- private static final String SUBSEQUENT_PAIRING_DESCRIPTION = "SUBSEQUENT_PAIRING_DESCRIPTION";
- private static final String SYNC_CONTACT_DESCRPTION = "SYNC_CONTACT_DESCRPTION";
- private static final String SYNC_CONTACTS_TITLE = "SYNC_CONTACTS_TITLE";
- private static final String SYNC_SMS_DESCRIPTION = "SYNC_SMS_DESCRIPTION";
- private static final String SYNC_SMS_TITLE = "SYNC_SMS_TITLE";
- private static final float TRIGGER_DISTANCE = 111;
- private static final String TRUE_WIRELESS_IMAGE_URL_CASE = "TRUE_WIRELESS_IMAGE_URL_CASE";
- private static final String TRUE_WIRELESS_IMAGE_URL_LEFT_BUD =
- "TRUE_WIRELESS_IMAGE_URL_LEFT_BUD";
- private static final String TRUE_WIRELESS_IMAGE_URL_RIGHT_BUD =
- "TRUE_WIRELESS_IMAGE_URL_RIGHT_BUD";
- private static final String UNABLE_TO_CONNECT_DESCRIPTION = "UNABLE_TO_CONNECT_DESCRIPTION";
- private static final String UNABLE_TO_CONNECT_TITLE = "UNABLE_TO_CONNECT_TITLE";
- private static final String UPDATE_COMPANION_APP_DESCRIPTION =
- "UPDATE_COMPANION_APP_DESCRIPTION";
- private static final String WAIT_LAUNCH_COMPANION_APP_DESCRIPTION =
- "WAIT_LAUNCH_COMPANION_APP_DESCRIPTION";
- private static final byte[] ANTI_SPOOFING_KEY = new byte[] {4, 5, 6};
- private static final String NAME = "NAME";
-
- @Test
- @SdkSuppress(minSdkVersion = 32, codeName = "T")
- public void testSetGetFastPairAntispoofKeyDeviceMetadataNotNull() {
- FastPairDeviceMetadata fastPairDeviceMetadata = genFastPairDeviceMetadata();
- FastPairAntispoofKeyDeviceMetadata fastPairAntispoofKeyDeviceMetadata =
- genFastPairAntispoofKeyDeviceMetadata(ANTI_SPOOFING_KEY, fastPairDeviceMetadata);
-
- assertThat(fastPairAntispoofKeyDeviceMetadata.getAntispoofPublicKey()).isEqualTo(
- ANTI_SPOOFING_KEY);
- ensureFastPairDeviceMetadataAsExpected(
- fastPairAntispoofKeyDeviceMetadata.getFastPairDeviceMetadata());
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 32, codeName = "T")
- public void testSetGetFastPairAntispoofKeyDeviceMetadataNull() {
- FastPairAntispoofKeyDeviceMetadata fastPairAntispoofKeyDeviceMetadata =
- genFastPairAntispoofKeyDeviceMetadata(null, null);
- assertThat(fastPairAntispoofKeyDeviceMetadata.getAntispoofPublicKey()).isEqualTo(
- null);
- assertThat(fastPairAntispoofKeyDeviceMetadata.getFastPairDeviceMetadata()).isEqualTo(
- null);
- }
-
- /* Verifies DeviceMetadata. */
- private static void ensureFastPairDeviceMetadataAsExpected(FastPairDeviceMetadata metadata) {
- assertThat(metadata.getBleTxPower()).isEqualTo(BLE_TX_POWER);
- assertThat(metadata.getConnectSuccessCompanionAppInstalled())
- .isEqualTo(CONNECT_SUCCESS_COMPANION_APP_INSTALLED);
- assertThat(metadata.getConnectSuccessCompanionAppNotInstalled())
- .isEqualTo(CONNECT_SUCCESS_COMPANION_APP_NOT_INSTALLED);
- assertThat(metadata.getDeviceType()).isEqualTo(DEVICE_TYPE);
- assertThat(metadata.getDownloadCompanionAppDescription())
- .isEqualTo(DOWNLOAD_COMPANION_APP_DESCRIPTION);
- assertThat(metadata.getFailConnectGoToSettingsDescription())
- .isEqualTo(FAIL_CONNECT_GOTO_SETTINGS_DESCRIPTION);
- assertThat(metadata.getImage()).isEqualTo(IMAGE);
- assertThat(metadata.getImageUrl()).isEqualTo(IMAGE_URL);
- assertThat(metadata.getInitialNotificationDescription())
- .isEqualTo(INITIAL_NOTIFICATION_DESCRIPTION);
- assertThat(metadata.getInitialNotificationDescriptionNoAccount())
- .isEqualTo(INITIAL_NOTIFICATION_DESCRIPTION_NO_ACCOUNT);
- assertThat(metadata.getInitialPairingDescription()).isEqualTo(INITIAL_PAIRING_DESCRIPTION);
- assertThat(metadata.getIntentUri()).isEqualTo(INTENT_URI);
- assertThat(metadata.getName()).isEqualTo(NAME);
- assertThat(metadata.getOpenCompanionAppDescription())
- .isEqualTo(OPEN_COMPANION_APP_DESCRIPTION);
- assertThat(metadata.getRetroactivePairingDescription())
- .isEqualTo(RETRO_ACTIVE_PAIRING_DESCRIPTION);
- assertThat(metadata.getSubsequentPairingDescription())
- .isEqualTo(SUBSEQUENT_PAIRING_DESCRIPTION);
- assertThat(metadata.getTriggerDistance()).isWithin(DELTA).of(TRIGGER_DISTANCE);
- assertThat(metadata.getTrueWirelessImageUrlCase()).isEqualTo(TRUE_WIRELESS_IMAGE_URL_CASE);
- assertThat(metadata.getTrueWirelessImageUrlLeftBud())
- .isEqualTo(TRUE_WIRELESS_IMAGE_URL_LEFT_BUD);
- assertThat(metadata.getTrueWirelessImageUrlRightBud())
- .isEqualTo(TRUE_WIRELESS_IMAGE_URL_RIGHT_BUD);
- assertThat(metadata.getUnableToConnectDescription())
- .isEqualTo(UNABLE_TO_CONNECT_DESCRIPTION);
- assertThat(metadata.getUnableToConnectTitle()).isEqualTo(UNABLE_TO_CONNECT_TITLE);
- assertThat(metadata.getUpdateCompanionAppDescription())
- .isEqualTo(UPDATE_COMPANION_APP_DESCRIPTION);
- assertThat(metadata.getWaitLaunchCompanionAppDescription())
- .isEqualTo(WAIT_LAUNCH_COMPANION_APP_DESCRIPTION);
- }
-
- /* Generates FastPairAntispoofKeyDeviceMetadata. */
- private static FastPairAntispoofKeyDeviceMetadata genFastPairAntispoofKeyDeviceMetadata(
- byte[] antispoofPublicKey, FastPairDeviceMetadata deviceMetadata) {
- FastPairAntispoofKeyDeviceMetadata.Builder builder =
- new FastPairAntispoofKeyDeviceMetadata.Builder();
- builder.setAntispoofPublicKey(antispoofPublicKey);
- builder.setFastPairDeviceMetadata(deviceMetadata);
-
- return builder.build();
- }
-
- /* Generates FastPairDeviceMetadata. */
- private static FastPairDeviceMetadata genFastPairDeviceMetadata() {
- FastPairDeviceMetadata.Builder builder = new FastPairDeviceMetadata.Builder();
- builder.setBleTxPower(BLE_TX_POWER);
- builder.setConnectSuccessCompanionAppInstalled(CONNECT_SUCCESS_COMPANION_APP_INSTALLED);
- builder.setConnectSuccessCompanionAppNotInstalled(
- CONNECT_SUCCESS_COMPANION_APP_NOT_INSTALLED);
- builder.setDeviceType(DEVICE_TYPE);
- builder.setDownloadCompanionAppDescription(DOWNLOAD_COMPANION_APP_DESCRIPTION);
- builder.setFailConnectGoToSettingsDescription(FAIL_CONNECT_GOTO_SETTINGS_DESCRIPTION);
- builder.setImage(IMAGE);
- builder.setImageUrl(IMAGE_URL);
- builder.setInitialNotificationDescription(INITIAL_NOTIFICATION_DESCRIPTION);
- builder.setInitialNotificationDescriptionNoAccount(
- INITIAL_NOTIFICATION_DESCRIPTION_NO_ACCOUNT);
- builder.setInitialPairingDescription(INITIAL_PAIRING_DESCRIPTION);
- builder.setIntentUri(INTENT_URI);
- builder.setName(NAME);
- builder.setOpenCompanionAppDescription(OPEN_COMPANION_APP_DESCRIPTION);
- builder.setRetroactivePairingDescription(RETRO_ACTIVE_PAIRING_DESCRIPTION);
- builder.setSubsequentPairingDescription(SUBSEQUENT_PAIRING_DESCRIPTION);
- builder.setTriggerDistance(TRIGGER_DISTANCE);
- builder.setTrueWirelessImageUrlCase(TRUE_WIRELESS_IMAGE_URL_CASE);
- builder.setTrueWirelessImageUrlLeftBud(TRUE_WIRELESS_IMAGE_URL_LEFT_BUD);
- builder.setTrueWirelessImageUrlRightBud(TRUE_WIRELESS_IMAGE_URL_RIGHT_BUD);
- builder.setUnableToConnectDescription(UNABLE_TO_CONNECT_DESCRIPTION);
- builder.setUnableToConnectTitle(UNABLE_TO_CONNECT_TITLE);
- builder.setUpdateCompanionAppDescription(UPDATE_COMPANION_APP_DESCRIPTION);
- builder.setWaitLaunchCompanionAppDescription(WAIT_LAUNCH_COMPANION_APP_DESCRIPTION);
-
- return builder.build();
- }
-}
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/FastPairDataProviderServiceTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/FastPairDataProviderServiceTest.java
deleted file mode 100644
index 160da56..0000000
--- a/nearby/tests/cts/fastpair/src/android/nearby/cts/FastPairDataProviderServiceTest.java
+++ /dev/null
@@ -1,994 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.nearby.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.MockitoAnnotations.initMocks;
-
-import android.accounts.Account;
-import android.content.Intent;
-import android.nearby.FastPairAccountKeyDeviceMetadata;
-import android.nearby.FastPairAntispoofKeyDeviceMetadata;
-import android.nearby.FastPairDataProviderService;
-import android.nearby.FastPairDeviceMetadata;
-import android.nearby.FastPairDiscoveryItem;
-import android.nearby.FastPairEligibleAccount;
-import android.nearby.aidl.ByteArrayParcel;
-import android.nearby.aidl.FastPairAccountDevicesMetadataRequestParcel;
-import android.nearby.aidl.FastPairAccountKeyDeviceMetadataParcel;
-import android.nearby.aidl.FastPairAntispoofKeyDeviceMetadataParcel;
-import android.nearby.aidl.FastPairAntispoofKeyDeviceMetadataRequestParcel;
-import android.nearby.aidl.FastPairDeviceMetadataParcel;
-import android.nearby.aidl.FastPairDiscoveryItemParcel;
-import android.nearby.aidl.FastPairEligibleAccountParcel;
-import android.nearby.aidl.FastPairEligibleAccountsRequestParcel;
-import android.nearby.aidl.FastPairManageAccountDeviceRequestParcel;
-import android.nearby.aidl.FastPairManageAccountRequestParcel;
-import android.nearby.aidl.IFastPairAccountDevicesMetadataCallback;
-import android.nearby.aidl.IFastPairAntispoofKeyDeviceMetadataCallback;
-import android.nearby.aidl.IFastPairDataProvider;
-import android.nearby.aidl.IFastPairEligibleAccountsCallback;
-import android.nearby.aidl.IFastPairManageAccountCallback;
-import android.nearby.aidl.IFastPairManageAccountDeviceCallback;
-
-import androidx.annotation.NonNull;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SdkSuppress;
-
-import com.google.common.collect.ImmutableList;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Captor;
-import org.mockito.Mock;
-
-@RunWith(AndroidJUnit4.class)
-public class FastPairDataProviderServiceTest {
-
- private static final String TAG = "FastPairDataProviderServiceTest";
-
- private static final String ASSISTANT_SETUP_HALFSHEET = "ASSISTANT_SETUP_HALFSHEET";
- private static final String ASSISTANT_SETUP_NOTIFICATION = "ASSISTANT_SETUP_NOTIFICATION";
- private static final int BLE_TX_POWER = 5;
- private static final String CONFIRM_PIN_DESCRIPTION = "CONFIRM_PIN_DESCRIPTION";
- private static final String CONFIRM_PIN_TITLE = "CONFIRM_PIN_TITLE";
- private static final String CONNECT_SUCCESS_COMPANION_APP_INSTALLED =
- "CONNECT_SUCCESS_COMPANION_APP_INSTALLED";
- private static final String CONNECT_SUCCESS_COMPANION_APP_NOT_INSTALLED =
- "CONNECT_SUCCESS_COMPANION_APP_NOT_INSTALLED";
- private static final float DELTA = 0.001f;
- private static final int DEVICE_TYPE = 7;
- private static final String DOWNLOAD_COMPANION_APP_DESCRIPTION =
- "DOWNLOAD_COMPANION_APP_DESCRIPTION";
- private static final Account ELIGIBLE_ACCOUNT_1 = new Account("abc@google.com", "type1");
- private static final boolean ELIGIBLE_ACCOUNT_1_OPT_IN = true;
- private static final Account ELIGIBLE_ACCOUNT_2 = new Account("def@gmail.com", "type2");
- private static final boolean ELIGIBLE_ACCOUNT_2_OPT_IN = false;
- private static final Account MANAGE_ACCOUNT = new Account("ghi@gmail.com", "type3");
- private static final Account ACCOUNTDEVICES_METADATA_ACCOUNT =
- new Account("jk@gmail.com", "type4");
- private static final int NUM_ACCOUNT_DEVICES = 2;
-
- private static final int ERROR_CODE_BAD_REQUEST =
- FastPairDataProviderService.ERROR_CODE_BAD_REQUEST;
- private static final int MANAGE_ACCOUNT_REQUEST_TYPE =
- FastPairDataProviderService.MANAGE_REQUEST_ADD;
- private static final String ERROR_STRING = "ERROR_STRING";
- private static final String FAIL_CONNECT_GOTO_SETTINGS_DESCRIPTION =
- "FAIL_CONNECT_GOTO_SETTINGS_DESCRIPTION";
- private static final String FAST_PAIR_TV_CONNECT_DEVICE_NO_ACCOUNT_DESCRIPTION =
- "FAST_PAIR_TV_CONNECT_DEVICE_NO_ACCOUNT_DESCRIPTION";
- private static final byte[] IMAGE = new byte[] {7, 9};
- private static final String IMAGE_URL = "IMAGE_URL";
- private static final String INITIAL_NOTIFICATION_DESCRIPTION =
- "INITIAL_NOTIFICATION_DESCRIPTION";
- private static final String INITIAL_NOTIFICATION_DESCRIPTION_NO_ACCOUNT =
- "INITIAL_NOTIFICATION_DESCRIPTION_NO_ACCOUNT";
- private static final String INITIAL_PAIRING_DESCRIPTION = "INITIAL_PAIRING_DESCRIPTION";
- private static final String INTENT_URI = "INTENT_URI";
- private static final String LOCALE = "LOCALE";
- private static final String OPEN_COMPANION_APP_DESCRIPTION = "OPEN_COMPANION_APP_DESCRIPTION";
- private static final String RETRO_ACTIVE_PAIRING_DESCRIPTION =
- "RETRO_ACTIVE_PAIRING_DESCRIPTION";
- private static final String SUBSEQUENT_PAIRING_DESCRIPTION = "SUBSEQUENT_PAIRING_DESCRIPTION";
- private static final String SYNC_CONTACT_DESCRPTION = "SYNC_CONTACT_DESCRPTION";
- private static final String SYNC_CONTACTS_TITLE = "SYNC_CONTACTS_TITLE";
- private static final String SYNC_SMS_DESCRIPTION = "SYNC_SMS_DESCRIPTION";
- private static final String SYNC_SMS_TITLE = "SYNC_SMS_TITLE";
- private static final float TRIGGER_DISTANCE = 111;
- private static final String TRUE_WIRELESS_IMAGE_URL_CASE = "TRUE_WIRELESS_IMAGE_URL_CASE";
- private static final String TRUE_WIRELESS_IMAGE_URL_LEFT_BUD =
- "TRUE_WIRELESS_IMAGE_URL_LEFT_BUD";
- private static final String TRUE_WIRELESS_IMAGE_URL_RIGHT_BUD =
- "TRUE_WIRELESS_IMAGE_URL_RIGHT_BUD";
- private static final String UNABLE_TO_CONNECT_DESCRIPTION = "UNABLE_TO_CONNECT_DESCRIPTION";
- private static final String UNABLE_TO_CONNECT_TITLE = "UNABLE_TO_CONNECT_TITLE";
- private static final String UPDATE_COMPANION_APP_DESCRIPTION =
- "UPDATE_COMPANION_APP_DESCRIPTION";
- private static final String WAIT_LAUNCH_COMPANION_APP_DESCRIPTION =
- "WAIT_LAUNCH_COMPANION_APP_DESCRIPTION";
- private static final byte[] ACCOUNT_KEY = new byte[] {3};
- private static final byte[] ACCOUNT_KEY_2 = new byte[] {9, 3};
- private static final byte[] SHA256_ACCOUNT_KEY_PUBLIC_ADDRESS = new byte[] {2, 8};
- private static final byte[] REQUEST_MODEL_ID = new byte[] {1, 2, 3};
- private static final byte[] ANTI_SPOOFING_KEY = new byte[] {4, 5, 6};
- private static final String ACTION_URL = "ACTION_URL";
- private static final int ACTION_URL_TYPE = 5;
- private static final String APP_NAME = "APP_NAME";
- private static final int ATTACHMENT_TYPE = 8;
- private static final byte[] AUTHENTICATION_PUBLIC_KEY_SEC_P256R1 = new byte[] {5, 7};
- private static final byte[] BLE_RECORD_BYTES = new byte[]{2, 4};
- private static final int DEBUG_CATEGORY = 9;
- private static final String DEBUG_MESSAGE = "DEBUG_MESSAGE";
- private static final String DESCRIPTION = "DESCRIPTION";
- private static final String DEVICE_NAME = "DEVICE_NAME";
- private static final String DISPLAY_URL = "DISPLAY_URL";
- private static final String ENTITY_ID = "ENTITY_ID";
- private static final String FEATURE_GRAPHIC_URL = "FEATURE_GRAPHIC_URL";
- private static final long FIRST_OBSERVATION_TIMESTAMP_MILLIS = 8393L;
- private static final String GROUP_ID = "GROUP_ID";
- private static final String ICON_FIFE_URL = "ICON_FIFE_URL";
- private static final byte[] ICON_PNG = new byte[]{2, 5};
- private static final String ID = "ID";
- private static final long LAST_OBSERVATION_TIMESTAMP_MILLIS = 934234L;
- private static final int LAST_USER_EXPERIENCE = 93;
- private static final long LOST_MILLIS = 393284L;
- private static final String MAC_ADDRESS = "MAC_ADDRESS";
- private static final String NAME = "NAME";
- private static final String PACKAGE_NAME = "PACKAGE_NAME";
- private static final long PENDING_APP_INSTALL_TIMESTAMP_MILLIS = 832393L;
- private static final int RSSI = 9;
- private static final int STATE = 63;
- private static final String TITLE = "TITLE";
- private static final String TRIGGER_ID = "TRIGGER_ID";
- private static final int TX_POWER = 62;
- private static final int TYPE = 73;
- private static final String BLE_ADDRESS = "BLE_ADDRESS";
-
- private static final int ELIGIBLE_ACCOUNTS_NUM = 2;
- private static final ImmutableList<FastPairEligibleAccount> ELIGIBLE_ACCOUNTS =
- ImmutableList.of(
- genHappyPathFastPairEligibleAccount(ELIGIBLE_ACCOUNT_1,
- ELIGIBLE_ACCOUNT_1_OPT_IN),
- genHappyPathFastPairEligibleAccount(ELIGIBLE_ACCOUNT_2,
- ELIGIBLE_ACCOUNT_2_OPT_IN));
- private static final int ACCOUNTKEY_DEVICE_NUM = 2;
- private static final ImmutableList<FastPairAccountKeyDeviceMetadata>
- FAST_PAIR_ACCOUNT_DEVICES_METADATA =
- ImmutableList.of(
- genHappyPathFastPairAccountkeyDeviceMetadata(),
- genHappyPathFastPairAccountkeyDeviceMetadata());
-
- private static final FastPairAntispoofKeyDeviceMetadataRequestParcel
- FAST_PAIR_ANTI_SPOOF_KEY_DEVICE_METADATA_REQUEST_PARCEL =
- genFastPairAntispoofKeyDeviceMetadataRequestParcel();
- private static final FastPairAccountDevicesMetadataRequestParcel
- FAST_PAIR_ACCOUNT_DEVICES_METADATA_REQUEST_PARCEL =
- genFastPairAccountDevicesMetadataRequestParcel();
- private static final FastPairEligibleAccountsRequestParcel
- FAST_PAIR_ELIGIBLE_ACCOUNTS_REQUEST_PARCEL =
- genFastPairEligibleAccountsRequestParcel();
- private static final FastPairManageAccountRequestParcel
- FAST_PAIR_MANAGE_ACCOUNT_REQUEST_PARCEL =
- genFastPairManageAccountRequestParcel();
- private static final FastPairManageAccountDeviceRequestParcel
- FAST_PAIR_MANAGE_ACCOUNT_DEVICE_REQUEST_PARCEL =
- genFastPairManageAccountDeviceRequestParcel();
- private static final FastPairAntispoofKeyDeviceMetadata
- HAPPY_PATH_FAST_PAIR_ANTI_SPOOF_KEY_DEVICE_METADATA =
- genHappyPathFastPairAntispoofKeyDeviceMetadata();
-
- @Captor private ArgumentCaptor<FastPairEligibleAccountParcel[]>
- mFastPairEligibleAccountParcelsArgumentCaptor;
- @Captor private ArgumentCaptor<FastPairAccountKeyDeviceMetadataParcel[]>
- mFastPairAccountKeyDeviceMetadataParcelsArgumentCaptor;
-
- @Mock private FastPairDataProviderService mMockFastPairDataProviderService;
- @Mock private IFastPairAntispoofKeyDeviceMetadataCallback.Stub
- mAntispoofKeyDeviceMetadataCallback;
- @Mock private IFastPairAccountDevicesMetadataCallback.Stub mAccountDevicesMetadataCallback;
- @Mock private IFastPairEligibleAccountsCallback.Stub mEligibleAccountsCallback;
- @Mock private IFastPairManageAccountCallback.Stub mManageAccountCallback;
- @Mock private IFastPairManageAccountDeviceCallback.Stub mManageAccountDeviceCallback;
-
- private MyHappyPathProvider mHappyPathFastPairDataProvider;
- private MyErrorPathProvider mErrorPathFastPairDataProvider;
-
- @Before
- public void setUp() throws Exception {
- initMocks(this);
-
- mHappyPathFastPairDataProvider =
- new MyHappyPathProvider(TAG, mMockFastPairDataProviderService);
- mErrorPathFastPairDataProvider =
- new MyErrorPathProvider(TAG, mMockFastPairDataProviderService);
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 32, codeName = "T")
- public void testHappyPathLoadFastPairAntispoofKeyDeviceMetadata() throws Exception {
- // AOSP sends calls to OEM via Parcelable.
- mHappyPathFastPairDataProvider.asProvider().loadFastPairAntispoofKeyDeviceMetadata(
- FAST_PAIR_ANTI_SPOOF_KEY_DEVICE_METADATA_REQUEST_PARCEL,
- mAntispoofKeyDeviceMetadataCallback);
-
- // OEM receives request and verifies that it is as expected.
- final ArgumentCaptor<FastPairDataProviderService.FastPairAntispoofKeyDeviceMetadataRequest>
- fastPairAntispoofKeyDeviceMetadataRequestCaptor =
- ArgumentCaptor.forClass(
- FastPairDataProviderService.FastPairAntispoofKeyDeviceMetadataRequest.class
- );
- verify(mMockFastPairDataProviderService).onLoadFastPairAntispoofKeyDeviceMetadata(
- fastPairAntispoofKeyDeviceMetadataRequestCaptor.capture(),
- any(FastPairDataProviderService.FastPairAntispoofKeyDeviceMetadataCallback.class));
- ensureHappyPathAsExpected(fastPairAntispoofKeyDeviceMetadataRequestCaptor.getValue());
-
- // AOSP receives responses and verifies that it is as expected.
- final ArgumentCaptor<FastPairAntispoofKeyDeviceMetadataParcel>
- fastPairAntispoofKeyDeviceMetadataParcelCaptor =
- ArgumentCaptor.forClass(FastPairAntispoofKeyDeviceMetadataParcel.class);
- verify(mAntispoofKeyDeviceMetadataCallback).onFastPairAntispoofKeyDeviceMetadataReceived(
- fastPairAntispoofKeyDeviceMetadataParcelCaptor.capture());
- ensureHappyPathAsExpected(fastPairAntispoofKeyDeviceMetadataParcelCaptor.getValue());
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 32, codeName = "T")
- public void testHappyPathLoadFastPairAccountDevicesMetadata() throws Exception {
- // AOSP sends calls to OEM via Parcelable.
- mHappyPathFastPairDataProvider.asProvider().loadFastPairAccountDevicesMetadata(
- FAST_PAIR_ACCOUNT_DEVICES_METADATA_REQUEST_PARCEL,
- mAccountDevicesMetadataCallback);
-
- // OEM receives request and verifies that it is as expected.
- final ArgumentCaptor<FastPairDataProviderService.FastPairAccountDevicesMetadataRequest>
- fastPairAccountDevicesMetadataRequestCaptor =
- ArgumentCaptor.forClass(
- FastPairDataProviderService.FastPairAccountDevicesMetadataRequest.class);
- verify(mMockFastPairDataProviderService).onLoadFastPairAccountDevicesMetadata(
- fastPairAccountDevicesMetadataRequestCaptor.capture(),
- any(FastPairDataProviderService.FastPairAccountDevicesMetadataCallback.class));
- ensureHappyPathAsExpected(fastPairAccountDevicesMetadataRequestCaptor.getValue());
-
- // AOSP receives responses and verifies that it is as expected.
- verify(mAccountDevicesMetadataCallback).onFastPairAccountDevicesMetadataReceived(
- mFastPairAccountKeyDeviceMetadataParcelsArgumentCaptor.capture());
- ensureHappyPathAsExpected(
- mFastPairAccountKeyDeviceMetadataParcelsArgumentCaptor.getValue());
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 32, codeName = "T")
- public void testHappyPathLoadFastPairEligibleAccounts() throws Exception {
- // AOSP sends calls to OEM via Parcelable.
- mHappyPathFastPairDataProvider.asProvider().loadFastPairEligibleAccounts(
- FAST_PAIR_ELIGIBLE_ACCOUNTS_REQUEST_PARCEL,
- mEligibleAccountsCallback);
-
- // OEM receives request and verifies that it is as expected.
- final ArgumentCaptor<FastPairDataProviderService.FastPairEligibleAccountsRequest>
- fastPairEligibleAccountsRequestCaptor =
- ArgumentCaptor.forClass(
- FastPairDataProviderService.FastPairEligibleAccountsRequest.class);
- verify(mMockFastPairDataProviderService).onLoadFastPairEligibleAccounts(
- fastPairEligibleAccountsRequestCaptor.capture(),
- any(FastPairDataProviderService.FastPairEligibleAccountsCallback.class));
- ensureHappyPathAsExpected(fastPairEligibleAccountsRequestCaptor.getValue());
-
- // AOSP receives responses and verifies that it is as expected.
- verify(mEligibleAccountsCallback).onFastPairEligibleAccountsReceived(
- mFastPairEligibleAccountParcelsArgumentCaptor.capture());
- ensureHappyPathAsExpected(mFastPairEligibleAccountParcelsArgumentCaptor.getValue());
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 32, codeName = "T")
- public void testHappyPathManageFastPairAccount() throws Exception {
- // AOSP sends calls to OEM via Parcelable.
- mHappyPathFastPairDataProvider.asProvider().manageFastPairAccount(
- FAST_PAIR_MANAGE_ACCOUNT_REQUEST_PARCEL,
- mManageAccountCallback);
-
- // OEM receives request and verifies that it is as expected.
- final ArgumentCaptor<FastPairDataProviderService.FastPairManageAccountRequest>
- fastPairManageAccountRequestCaptor =
- ArgumentCaptor.forClass(
- FastPairDataProviderService.FastPairManageAccountRequest.class);
- verify(mMockFastPairDataProviderService).onManageFastPairAccount(
- fastPairManageAccountRequestCaptor.capture(),
- any(FastPairDataProviderService.FastPairManageActionCallback.class));
- ensureHappyPathAsExpected(fastPairManageAccountRequestCaptor.getValue());
-
- // AOSP receives SUCCESS response.
- verify(mManageAccountCallback).onSuccess();
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 32, codeName = "T")
- public void testHappyPathManageFastPairAccountDevice() throws Exception {
- // AOSP sends calls to OEM via Parcelable.
- mHappyPathFastPairDataProvider.asProvider().manageFastPairAccountDevice(
- FAST_PAIR_MANAGE_ACCOUNT_DEVICE_REQUEST_PARCEL,
- mManageAccountDeviceCallback);
-
- // OEM receives request and verifies that it is as expected.
- final ArgumentCaptor<FastPairDataProviderService.FastPairManageAccountDeviceRequest>
- fastPairManageAccountDeviceRequestCaptor =
- ArgumentCaptor.forClass(
- FastPairDataProviderService.FastPairManageAccountDeviceRequest.class);
- verify(mMockFastPairDataProviderService).onManageFastPairAccountDevice(
- fastPairManageAccountDeviceRequestCaptor.capture(),
- any(FastPairDataProviderService.FastPairManageActionCallback.class));
- ensureHappyPathAsExpected(fastPairManageAccountDeviceRequestCaptor.getValue());
-
- // AOSP receives SUCCESS response.
- verify(mManageAccountDeviceCallback).onSuccess();
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 32, codeName = "T")
- public void testErrorPathLoadFastPairAntispoofKeyDeviceMetadata() throws Exception {
- mErrorPathFastPairDataProvider.asProvider().loadFastPairAntispoofKeyDeviceMetadata(
- FAST_PAIR_ANTI_SPOOF_KEY_DEVICE_METADATA_REQUEST_PARCEL,
- mAntispoofKeyDeviceMetadataCallback);
- verify(mMockFastPairDataProviderService).onLoadFastPairAntispoofKeyDeviceMetadata(
- any(FastPairDataProviderService.FastPairAntispoofKeyDeviceMetadataRequest.class),
- any(FastPairDataProviderService.FastPairAntispoofKeyDeviceMetadataCallback.class));
- verify(mAntispoofKeyDeviceMetadataCallback).onError(
- eq(ERROR_CODE_BAD_REQUEST), eq(ERROR_STRING));
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 32, codeName = "T")
- public void testErrorPathLoadFastPairAccountDevicesMetadata() throws Exception {
- mErrorPathFastPairDataProvider.asProvider().loadFastPairAccountDevicesMetadata(
- FAST_PAIR_ACCOUNT_DEVICES_METADATA_REQUEST_PARCEL,
- mAccountDevicesMetadataCallback);
- verify(mMockFastPairDataProviderService).onLoadFastPairAccountDevicesMetadata(
- any(FastPairDataProviderService.FastPairAccountDevicesMetadataRequest.class),
- any(FastPairDataProviderService.FastPairAccountDevicesMetadataCallback.class));
- verify(mAccountDevicesMetadataCallback).onError(
- eq(ERROR_CODE_BAD_REQUEST), eq(ERROR_STRING));
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 32, codeName = "T")
- public void testErrorPathLoadFastPairEligibleAccounts() throws Exception {
- mErrorPathFastPairDataProvider.asProvider().loadFastPairEligibleAccounts(
- FAST_PAIR_ELIGIBLE_ACCOUNTS_REQUEST_PARCEL,
- mEligibleAccountsCallback);
- verify(mMockFastPairDataProviderService).onLoadFastPairEligibleAccounts(
- any(FastPairDataProviderService.FastPairEligibleAccountsRequest.class),
- any(FastPairDataProviderService.FastPairEligibleAccountsCallback.class));
- verify(mEligibleAccountsCallback).onError(
- eq(ERROR_CODE_BAD_REQUEST), eq(ERROR_STRING));
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 32, codeName = "T")
- public void testErrorPathManageFastPairAccount() throws Exception {
- mErrorPathFastPairDataProvider.asProvider().manageFastPairAccount(
- FAST_PAIR_MANAGE_ACCOUNT_REQUEST_PARCEL,
- mManageAccountCallback);
- verify(mMockFastPairDataProviderService).onManageFastPairAccount(
- any(FastPairDataProviderService.FastPairManageAccountRequest.class),
- any(FastPairDataProviderService.FastPairManageActionCallback.class));
- verify(mManageAccountCallback).onError(eq(ERROR_CODE_BAD_REQUEST), eq(ERROR_STRING));
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 32, codeName = "T")
- public void testErrorPathManageFastPairAccountDevice() throws Exception {
- mErrorPathFastPairDataProvider.asProvider().manageFastPairAccountDevice(
- FAST_PAIR_MANAGE_ACCOUNT_DEVICE_REQUEST_PARCEL,
- mManageAccountDeviceCallback);
- verify(mMockFastPairDataProviderService).onManageFastPairAccountDevice(
- any(FastPairDataProviderService.FastPairManageAccountDeviceRequest.class),
- any(FastPairDataProviderService.FastPairManageActionCallback.class));
- verify(mManageAccountDeviceCallback).onError(eq(ERROR_CODE_BAD_REQUEST), eq(ERROR_STRING));
- }
-
- public static class MyHappyPathProvider extends FastPairDataProviderService {
-
- private final FastPairDataProviderService mMockFastPairDataProviderService;
-
- public MyHappyPathProvider(@NonNull String tag, FastPairDataProviderService mock) {
- super(tag);
- mMockFastPairDataProviderService = mock;
- }
-
- public IFastPairDataProvider asProvider() {
- Intent intent = new Intent();
- return IFastPairDataProvider.Stub.asInterface(onBind(intent));
- }
-
- @Override
- public void onLoadFastPairAntispoofKeyDeviceMetadata(
- @NonNull FastPairAntispoofKeyDeviceMetadataRequest request,
- @NonNull FastPairAntispoofKeyDeviceMetadataCallback callback) {
- mMockFastPairDataProviderService.onLoadFastPairAntispoofKeyDeviceMetadata(
- request, callback);
- callback.onFastPairAntispoofKeyDeviceMetadataReceived(
- HAPPY_PATH_FAST_PAIR_ANTI_SPOOF_KEY_DEVICE_METADATA);
- }
-
- @Override
- public void onLoadFastPairAccountDevicesMetadata(
- @NonNull FastPairAccountDevicesMetadataRequest request,
- @NonNull FastPairAccountDevicesMetadataCallback callback) {
- mMockFastPairDataProviderService.onLoadFastPairAccountDevicesMetadata(
- request, callback);
- callback.onFastPairAccountDevicesMetadataReceived(FAST_PAIR_ACCOUNT_DEVICES_METADATA);
- }
-
- @Override
- public void onLoadFastPairEligibleAccounts(
- @NonNull FastPairEligibleAccountsRequest request,
- @NonNull FastPairEligibleAccountsCallback callback) {
- mMockFastPairDataProviderService.onLoadFastPairEligibleAccounts(
- request, callback);
- callback.onFastPairEligibleAccountsReceived(ELIGIBLE_ACCOUNTS);
- }
-
- @Override
- public void onManageFastPairAccount(
- @NonNull FastPairManageAccountRequest request,
- @NonNull FastPairManageActionCallback callback) {
- mMockFastPairDataProviderService.onManageFastPairAccount(request, callback);
- callback.onSuccess();
- }
-
- @Override
- public void onManageFastPairAccountDevice(
- @NonNull FastPairManageAccountDeviceRequest request,
- @NonNull FastPairManageActionCallback callback) {
- mMockFastPairDataProviderService.onManageFastPairAccountDevice(request, callback);
- callback.onSuccess();
- }
- }
-
- public static class MyErrorPathProvider extends FastPairDataProviderService {
-
- private final FastPairDataProviderService mMockFastPairDataProviderService;
-
- public MyErrorPathProvider(@NonNull String tag, FastPairDataProviderService mock) {
- super(tag);
- mMockFastPairDataProviderService = mock;
- }
-
- public IFastPairDataProvider asProvider() {
- Intent intent = new Intent();
- return IFastPairDataProvider.Stub.asInterface(onBind(intent));
- }
-
- @Override
- public void onLoadFastPairAntispoofKeyDeviceMetadata(
- @NonNull FastPairAntispoofKeyDeviceMetadataRequest request,
- @NonNull FastPairAntispoofKeyDeviceMetadataCallback callback) {
- mMockFastPairDataProviderService.onLoadFastPairAntispoofKeyDeviceMetadata(
- request, callback);
- callback.onError(ERROR_CODE_BAD_REQUEST, ERROR_STRING);
- }
-
- @Override
- public void onLoadFastPairAccountDevicesMetadata(
- @NonNull FastPairAccountDevicesMetadataRequest request,
- @NonNull FastPairAccountDevicesMetadataCallback callback) {
- mMockFastPairDataProviderService.onLoadFastPairAccountDevicesMetadata(
- request, callback);
- callback.onError(ERROR_CODE_BAD_REQUEST, ERROR_STRING);
- }
-
- @Override
- public void onLoadFastPairEligibleAccounts(
- @NonNull FastPairEligibleAccountsRequest request,
- @NonNull FastPairEligibleAccountsCallback callback) {
- mMockFastPairDataProviderService.onLoadFastPairEligibleAccounts(request, callback);
- callback.onError(ERROR_CODE_BAD_REQUEST, ERROR_STRING);
- }
-
- @Override
- public void onManageFastPairAccount(
- @NonNull FastPairManageAccountRequest request,
- @NonNull FastPairManageActionCallback callback) {
- mMockFastPairDataProviderService.onManageFastPairAccount(request, callback);
- callback.onError(ERROR_CODE_BAD_REQUEST, ERROR_STRING);
- }
-
- @Override
- public void onManageFastPairAccountDevice(
- @NonNull FastPairManageAccountDeviceRequest request,
- @NonNull FastPairManageActionCallback callback) {
- mMockFastPairDataProviderService.onManageFastPairAccountDevice(request, callback);
- callback.onError(ERROR_CODE_BAD_REQUEST, ERROR_STRING);
- }
- }
-
- /* Generates AntispoofKeyDeviceMetadataRequestParcel. */
- private static FastPairAntispoofKeyDeviceMetadataRequestParcel
- genFastPairAntispoofKeyDeviceMetadataRequestParcel() {
- FastPairAntispoofKeyDeviceMetadataRequestParcel requestParcel =
- new FastPairAntispoofKeyDeviceMetadataRequestParcel();
- requestParcel.modelId = REQUEST_MODEL_ID;
-
- return requestParcel;
- }
-
- /* Generates AccountDevicesMetadataRequestParcel. */
- private static FastPairAccountDevicesMetadataRequestParcel
- genFastPairAccountDevicesMetadataRequestParcel() {
- FastPairAccountDevicesMetadataRequestParcel requestParcel =
- new FastPairAccountDevicesMetadataRequestParcel();
-
- requestParcel.account = ACCOUNTDEVICES_METADATA_ACCOUNT;
- requestParcel.deviceAccountKeys = new ByteArrayParcel[NUM_ACCOUNT_DEVICES];
- requestParcel.deviceAccountKeys[0] = new ByteArrayParcel();
- requestParcel.deviceAccountKeys[1] = new ByteArrayParcel();
- requestParcel.deviceAccountKeys[0].byteArray = ACCOUNT_KEY;
- requestParcel.deviceAccountKeys[1].byteArray = ACCOUNT_KEY_2;
-
- return requestParcel;
- }
-
- /* Generates FastPairEligibleAccountsRequestParcel. */
- private static FastPairEligibleAccountsRequestParcel
- genFastPairEligibleAccountsRequestParcel() {
- FastPairEligibleAccountsRequestParcel requestParcel =
- new FastPairEligibleAccountsRequestParcel();
- // No fields since FastPairEligibleAccountsRequestParcel is just a place holder now.
- return requestParcel;
- }
-
- /* Generates FastPairManageAccountRequestParcel. */
- private static FastPairManageAccountRequestParcel
- genFastPairManageAccountRequestParcel() {
- FastPairManageAccountRequestParcel requestParcel =
- new FastPairManageAccountRequestParcel();
- requestParcel.account = MANAGE_ACCOUNT;
- requestParcel.requestType = MANAGE_ACCOUNT_REQUEST_TYPE;
-
- return requestParcel;
- }
-
- /* Generates FastPairManageAccountDeviceRequestParcel. */
- private static FastPairManageAccountDeviceRequestParcel
- genFastPairManageAccountDeviceRequestParcel() {
- FastPairManageAccountDeviceRequestParcel requestParcel =
- new FastPairManageAccountDeviceRequestParcel();
- requestParcel.account = MANAGE_ACCOUNT;
- requestParcel.requestType = MANAGE_ACCOUNT_REQUEST_TYPE;
- requestParcel.accountKeyDeviceMetadata =
- genHappyPathFastPairAccountkeyDeviceMetadataParcel();
-
- return requestParcel;
- }
-
- /* Generates Happy Path AntispoofKeyDeviceMetadata. */
- private static FastPairAntispoofKeyDeviceMetadata
- genHappyPathFastPairAntispoofKeyDeviceMetadata() {
- FastPairAntispoofKeyDeviceMetadata.Builder builder =
- new FastPairAntispoofKeyDeviceMetadata.Builder();
- builder.setAntispoofPublicKey(ANTI_SPOOFING_KEY);
- builder.setFastPairDeviceMetadata(genHappyPathFastPairDeviceMetadata());
-
- return builder.build();
- }
-
- /* Generates Happy Path FastPairAccountKeyDeviceMetadata. */
- private static FastPairAccountKeyDeviceMetadata
- genHappyPathFastPairAccountkeyDeviceMetadata() {
- FastPairAccountKeyDeviceMetadata.Builder builder =
- new FastPairAccountKeyDeviceMetadata.Builder();
- builder.setDeviceAccountKey(ACCOUNT_KEY);
- builder.setFastPairDeviceMetadata(genHappyPathFastPairDeviceMetadata());
- builder.setSha256DeviceAccountKeyPublicAddress(SHA256_ACCOUNT_KEY_PUBLIC_ADDRESS);
- builder.setFastPairDiscoveryItem(genHappyPathFastPairDiscoveryItem());
-
- return builder.build();
- }
-
- /* Generates Happy Path FastPairAccountKeyDeviceMetadataParcel. */
- private static FastPairAccountKeyDeviceMetadataParcel
- genHappyPathFastPairAccountkeyDeviceMetadataParcel() {
- FastPairAccountKeyDeviceMetadataParcel parcel =
- new FastPairAccountKeyDeviceMetadataParcel();
- parcel.deviceAccountKey = ACCOUNT_KEY;
- parcel.metadata = genHappyPathFastPairDeviceMetadataParcel();
- parcel.sha256DeviceAccountKeyPublicAddress = SHA256_ACCOUNT_KEY_PUBLIC_ADDRESS;
- parcel.discoveryItem = genHappyPathFastPairDiscoveryItemParcel();
-
- return parcel;
- }
-
- /* Generates Happy Path DiscoveryItem. */
- private static FastPairDiscoveryItem genHappyPathFastPairDiscoveryItem() {
- FastPairDiscoveryItem.Builder builder = new FastPairDiscoveryItem.Builder();
-
- builder.setActionUrl(ACTION_URL);
- builder.setActionUrlType(ACTION_URL_TYPE);
- builder.setAppName(APP_NAME);
- builder.setAuthenticationPublicKeySecp256r1(AUTHENTICATION_PUBLIC_KEY_SEC_P256R1);
- builder.setDescription(DESCRIPTION);
- builder.setDeviceName(DEVICE_NAME);
- builder.setDisplayUrl(DISPLAY_URL);
- builder.setFirstObservationTimestampMillis(FIRST_OBSERVATION_TIMESTAMP_MILLIS);
- builder.setIconFfeUrl(ICON_FIFE_URL);
- builder.setIconPng(ICON_PNG);
- builder.setId(ID);
- builder.setLastObservationTimestampMillis(LAST_OBSERVATION_TIMESTAMP_MILLIS);
- builder.setMacAddress(MAC_ADDRESS);
- builder.setPackageName(PACKAGE_NAME);
- builder.setPendingAppInstallTimestampMillis(PENDING_APP_INSTALL_TIMESTAMP_MILLIS);
- builder.setRssi(RSSI);
- builder.setState(STATE);
- builder.setTitle(TITLE);
- builder.setTriggerId(TRIGGER_ID);
- builder.setTxPower(TX_POWER);
-
- return builder.build();
- }
-
- /* Generates Happy Path DiscoveryItemParcel. */
- private static FastPairDiscoveryItemParcel genHappyPathFastPairDiscoveryItemParcel() {
- FastPairDiscoveryItemParcel parcel = new FastPairDiscoveryItemParcel();
-
- parcel.actionUrl = ACTION_URL;
- parcel.actionUrlType = ACTION_URL_TYPE;
- parcel.appName = APP_NAME;
- parcel.authenticationPublicKeySecp256r1 = AUTHENTICATION_PUBLIC_KEY_SEC_P256R1;
- parcel.description = DESCRIPTION;
- parcel.deviceName = DEVICE_NAME;
- parcel.displayUrl = DISPLAY_URL;
- parcel.firstObservationTimestampMillis = FIRST_OBSERVATION_TIMESTAMP_MILLIS;
- parcel.iconFifeUrl = ICON_FIFE_URL;
- parcel.iconPng = ICON_PNG;
- parcel.id = ID;
- parcel.lastObservationTimestampMillis = LAST_OBSERVATION_TIMESTAMP_MILLIS;
- parcel.macAddress = MAC_ADDRESS;
- parcel.packageName = PACKAGE_NAME;
- parcel.pendingAppInstallTimestampMillis = PENDING_APP_INSTALL_TIMESTAMP_MILLIS;
- parcel.rssi = RSSI;
- parcel.state = STATE;
- parcel.title = TITLE;
- parcel.triggerId = TRIGGER_ID;
- parcel.txPower = TX_POWER;
-
- return parcel;
- }
-
- /* Generates Happy Path DeviceMetadata. */
- private static FastPairDeviceMetadata genHappyPathFastPairDeviceMetadata() {
- FastPairDeviceMetadata.Builder builder = new FastPairDeviceMetadata.Builder();
- builder.setBleTxPower(BLE_TX_POWER);
- builder.setConnectSuccessCompanionAppInstalled(CONNECT_SUCCESS_COMPANION_APP_INSTALLED);
- builder.setConnectSuccessCompanionAppNotInstalled(
- CONNECT_SUCCESS_COMPANION_APP_NOT_INSTALLED);
- builder.setDeviceType(DEVICE_TYPE);
- builder.setDownloadCompanionAppDescription(DOWNLOAD_COMPANION_APP_DESCRIPTION);
- builder.setFailConnectGoToSettingsDescription(FAIL_CONNECT_GOTO_SETTINGS_DESCRIPTION);
- builder.setImage(IMAGE);
- builder.setImageUrl(IMAGE_URL);
- builder.setInitialNotificationDescription(INITIAL_NOTIFICATION_DESCRIPTION);
- builder.setInitialNotificationDescriptionNoAccount(
- INITIAL_NOTIFICATION_DESCRIPTION_NO_ACCOUNT);
- builder.setInitialPairingDescription(INITIAL_PAIRING_DESCRIPTION);
- builder.setIntentUri(INTENT_URI);
- builder.setName(NAME);
- builder.setOpenCompanionAppDescription(OPEN_COMPANION_APP_DESCRIPTION);
- builder.setRetroactivePairingDescription(RETRO_ACTIVE_PAIRING_DESCRIPTION);
- builder.setSubsequentPairingDescription(SUBSEQUENT_PAIRING_DESCRIPTION);
- builder.setTriggerDistance(TRIGGER_DISTANCE);
- builder.setTrueWirelessImageUrlCase(TRUE_WIRELESS_IMAGE_URL_CASE);
- builder.setTrueWirelessImageUrlLeftBud(TRUE_WIRELESS_IMAGE_URL_LEFT_BUD);
- builder.setTrueWirelessImageUrlRightBud(TRUE_WIRELESS_IMAGE_URL_RIGHT_BUD);
- builder.setUnableToConnectDescription(UNABLE_TO_CONNECT_DESCRIPTION);
- builder.setUnableToConnectTitle(UNABLE_TO_CONNECT_TITLE);
- builder.setUpdateCompanionAppDescription(UPDATE_COMPANION_APP_DESCRIPTION);
- builder.setWaitLaunchCompanionAppDescription(WAIT_LAUNCH_COMPANION_APP_DESCRIPTION);
-
- return builder.build();
- }
-
- /* Generates Happy Path DeviceMetadataParcel. */
- private static FastPairDeviceMetadataParcel genHappyPathFastPairDeviceMetadataParcel() {
- FastPairDeviceMetadataParcel parcel = new FastPairDeviceMetadataParcel();
-
- parcel.bleTxPower = BLE_TX_POWER;
- parcel.connectSuccessCompanionAppInstalled = CONNECT_SUCCESS_COMPANION_APP_INSTALLED;
- parcel.connectSuccessCompanionAppNotInstalled =
- CONNECT_SUCCESS_COMPANION_APP_NOT_INSTALLED;
- parcel.deviceType = DEVICE_TYPE;
- parcel.downloadCompanionAppDescription = DOWNLOAD_COMPANION_APP_DESCRIPTION;
- parcel.failConnectGoToSettingsDescription = FAIL_CONNECT_GOTO_SETTINGS_DESCRIPTION;
- parcel.image = IMAGE;
- parcel.imageUrl = IMAGE_URL;
- parcel.initialNotificationDescription = INITIAL_NOTIFICATION_DESCRIPTION;
- parcel.initialNotificationDescriptionNoAccount =
- INITIAL_NOTIFICATION_DESCRIPTION_NO_ACCOUNT;
- parcel.initialPairingDescription = INITIAL_PAIRING_DESCRIPTION;
- parcel.intentUri = INTENT_URI;
- parcel.name = NAME;
- parcel.openCompanionAppDescription = OPEN_COMPANION_APP_DESCRIPTION;
- parcel.retroactivePairingDescription = RETRO_ACTIVE_PAIRING_DESCRIPTION;
- parcel.subsequentPairingDescription = SUBSEQUENT_PAIRING_DESCRIPTION;
- parcel.triggerDistance = TRIGGER_DISTANCE;
- parcel.trueWirelessImageUrlCase = TRUE_WIRELESS_IMAGE_URL_CASE;
- parcel.trueWirelessImageUrlLeftBud = TRUE_WIRELESS_IMAGE_URL_LEFT_BUD;
- parcel.trueWirelessImageUrlRightBud = TRUE_WIRELESS_IMAGE_URL_RIGHT_BUD;
- parcel.unableToConnectDescription = UNABLE_TO_CONNECT_DESCRIPTION;
- parcel.unableToConnectTitle = UNABLE_TO_CONNECT_TITLE;
- parcel.updateCompanionAppDescription = UPDATE_COMPANION_APP_DESCRIPTION;
- parcel.waitLaunchCompanionAppDescription = WAIT_LAUNCH_COMPANION_APP_DESCRIPTION;
-
- return parcel;
- }
-
- /* Generates Happy Path FastPairEligibleAccount. */
- private static FastPairEligibleAccount genHappyPathFastPairEligibleAccount(
- Account account, boolean optIn) {
- FastPairEligibleAccount.Builder builder = new FastPairEligibleAccount.Builder();
- builder.setAccount(account);
- builder.setOptIn(optIn);
-
- return builder.build();
- }
-
- /* Verifies Happy Path AntispoofKeyDeviceMetadataRequest. */
- private static void ensureHappyPathAsExpected(
- FastPairDataProviderService.FastPairAntispoofKeyDeviceMetadataRequest request) {
- assertThat(request.getModelId()).isEqualTo(REQUEST_MODEL_ID);
- }
-
- /* Verifies Happy Path AccountDevicesMetadataRequest. */
- private static void ensureHappyPathAsExpected(
- FastPairDataProviderService.FastPairAccountDevicesMetadataRequest request) {
- assertThat(request.getAccount()).isEqualTo(ACCOUNTDEVICES_METADATA_ACCOUNT);
- assertThat(request.getDeviceAccountKeys().size()).isEqualTo(ACCOUNTKEY_DEVICE_NUM);
- assertThat(request.getDeviceAccountKeys()).contains(ACCOUNT_KEY);
- assertThat(request.getDeviceAccountKeys()).contains(ACCOUNT_KEY_2);
- }
-
- /* Verifies Happy Path FastPairEligibleAccountsRequest. */
- @SuppressWarnings("UnusedVariable")
- private static void ensureHappyPathAsExpected(
- FastPairDataProviderService.FastPairEligibleAccountsRequest request) {
- // No fields since FastPairEligibleAccountsRequest is just a place holder now.
- }
-
- /* Verifies Happy Path FastPairManageAccountRequest. */
- private static void ensureHappyPathAsExpected(
- FastPairDataProviderService.FastPairManageAccountRequest request) {
- assertThat(request.getAccount()).isEqualTo(MANAGE_ACCOUNT);
- assertThat(request.getRequestType()).isEqualTo(MANAGE_ACCOUNT_REQUEST_TYPE);
- }
-
- /* Verifies Happy Path FastPairManageAccountDeviceRequest. */
- private static void ensureHappyPathAsExpected(
- FastPairDataProviderService.FastPairManageAccountDeviceRequest request) {
- assertThat(request.getAccount()).isEqualTo(MANAGE_ACCOUNT);
- assertThat(request.getRequestType()).isEqualTo(MANAGE_ACCOUNT_REQUEST_TYPE);
- ensureHappyPathAsExpected(request.getAccountKeyDeviceMetadata());
- }
-
- /* Verifies Happy Path AntispoofKeyDeviceMetadataParcel. */
- private static void ensureHappyPathAsExpected(
- FastPairAntispoofKeyDeviceMetadataParcel metadataParcel) {
- assertThat(metadataParcel).isNotNull();
- assertThat(metadataParcel.antispoofPublicKey).isEqualTo(ANTI_SPOOFING_KEY);
- ensureHappyPathAsExpected(metadataParcel.deviceMetadata);
- }
-
- /* Verifies Happy Path FastPairAccountKeyDeviceMetadataParcel[]. */
- private static void ensureHappyPathAsExpected(
- FastPairAccountKeyDeviceMetadataParcel[] metadataParcels) {
- assertThat(metadataParcels).isNotNull();
- assertThat(metadataParcels).hasLength(ACCOUNTKEY_DEVICE_NUM);
- for (FastPairAccountKeyDeviceMetadataParcel parcel: metadataParcels) {
- ensureHappyPathAsExpected(parcel);
- }
- }
-
- /* Verifies Happy Path FastPairAccountKeyDeviceMetadataParcel. */
- private static void ensureHappyPathAsExpected(
- FastPairAccountKeyDeviceMetadataParcel metadataParcel) {
- assertThat(metadataParcel).isNotNull();
- assertThat(metadataParcel.deviceAccountKey).isEqualTo(ACCOUNT_KEY);
- assertThat(metadataParcel.sha256DeviceAccountKeyPublicAddress)
- .isEqualTo(SHA256_ACCOUNT_KEY_PUBLIC_ADDRESS);
- ensureHappyPathAsExpected(metadataParcel.metadata);
- ensureHappyPathAsExpected(metadataParcel.discoveryItem);
- }
-
- /* Verifies Happy Path FastPairAccountKeyDeviceMetadata. */
- private static void ensureHappyPathAsExpected(
- FastPairAccountKeyDeviceMetadata metadata) {
- assertThat(metadata.getDeviceAccountKey()).isEqualTo(ACCOUNT_KEY);
- assertThat(metadata.getSha256DeviceAccountKeyPublicAddress())
- .isEqualTo(SHA256_ACCOUNT_KEY_PUBLIC_ADDRESS);
- ensureHappyPathAsExpected(metadata.getFastPairDeviceMetadata());
- ensureHappyPathAsExpected(metadata.getFastPairDiscoveryItem());
- }
-
- /* Verifies Happy Path DeviceMetadataParcel. */
- private static void ensureHappyPathAsExpected(FastPairDeviceMetadataParcel metadataParcel) {
- assertThat(metadataParcel).isNotNull();
- assertThat(metadataParcel.bleTxPower).isEqualTo(BLE_TX_POWER);
-
- assertThat(metadataParcel.connectSuccessCompanionAppInstalled).isEqualTo(
- CONNECT_SUCCESS_COMPANION_APP_INSTALLED);
- assertThat(metadataParcel.connectSuccessCompanionAppNotInstalled).isEqualTo(
- CONNECT_SUCCESS_COMPANION_APP_NOT_INSTALLED);
-
- assertThat(metadataParcel.deviceType).isEqualTo(DEVICE_TYPE);
- assertThat(metadataParcel.downloadCompanionAppDescription).isEqualTo(
- DOWNLOAD_COMPANION_APP_DESCRIPTION);
-
- assertThat(metadataParcel.failConnectGoToSettingsDescription).isEqualTo(
- FAIL_CONNECT_GOTO_SETTINGS_DESCRIPTION);
-
- assertThat(metadataParcel.image).isEqualTo(IMAGE);
- assertThat(metadataParcel.imageUrl).isEqualTo(IMAGE_URL);
- assertThat(metadataParcel.initialNotificationDescription).isEqualTo(
- INITIAL_NOTIFICATION_DESCRIPTION);
- assertThat(metadataParcel.initialNotificationDescriptionNoAccount).isEqualTo(
- INITIAL_NOTIFICATION_DESCRIPTION_NO_ACCOUNT);
- assertThat(metadataParcel.initialPairingDescription).isEqualTo(INITIAL_PAIRING_DESCRIPTION);
- assertThat(metadataParcel.intentUri).isEqualTo(INTENT_URI);
-
- assertThat(metadataParcel.name).isEqualTo(NAME);
-
- assertThat(metadataParcel.openCompanionAppDescription).isEqualTo(
- OPEN_COMPANION_APP_DESCRIPTION);
-
- assertThat(metadataParcel.retroactivePairingDescription).isEqualTo(
- RETRO_ACTIVE_PAIRING_DESCRIPTION);
-
- assertThat(metadataParcel.subsequentPairingDescription).isEqualTo(
- SUBSEQUENT_PAIRING_DESCRIPTION);
-
- assertThat(metadataParcel.triggerDistance).isWithin(DELTA).of(TRIGGER_DISTANCE);
- assertThat(metadataParcel.trueWirelessImageUrlCase).isEqualTo(TRUE_WIRELESS_IMAGE_URL_CASE);
- assertThat(metadataParcel.trueWirelessImageUrlLeftBud).isEqualTo(
- TRUE_WIRELESS_IMAGE_URL_LEFT_BUD);
- assertThat(metadataParcel.trueWirelessImageUrlRightBud).isEqualTo(
- TRUE_WIRELESS_IMAGE_URL_RIGHT_BUD);
-
- assertThat(metadataParcel.unableToConnectDescription).isEqualTo(
- UNABLE_TO_CONNECT_DESCRIPTION);
- assertThat(metadataParcel.unableToConnectTitle).isEqualTo(UNABLE_TO_CONNECT_TITLE);
- assertThat(metadataParcel.updateCompanionAppDescription).isEqualTo(
- UPDATE_COMPANION_APP_DESCRIPTION);
-
- assertThat(metadataParcel.waitLaunchCompanionAppDescription).isEqualTo(
- WAIT_LAUNCH_COMPANION_APP_DESCRIPTION);
- }
-
- /* Verifies Happy Path DeviceMetadata. */
- private static void ensureHappyPathAsExpected(FastPairDeviceMetadata metadata) {
- assertThat(metadata.getBleTxPower()).isEqualTo(BLE_TX_POWER);
- assertThat(metadata.getConnectSuccessCompanionAppInstalled())
- .isEqualTo(CONNECT_SUCCESS_COMPANION_APP_INSTALLED);
- assertThat(metadata.getConnectSuccessCompanionAppNotInstalled())
- .isEqualTo(CONNECT_SUCCESS_COMPANION_APP_NOT_INSTALLED);
- assertThat(metadata.getDeviceType()).isEqualTo(DEVICE_TYPE);
- assertThat(metadata.getDownloadCompanionAppDescription())
- .isEqualTo(DOWNLOAD_COMPANION_APP_DESCRIPTION);
- assertThat(metadata.getFailConnectGoToSettingsDescription())
- .isEqualTo(FAIL_CONNECT_GOTO_SETTINGS_DESCRIPTION);
- assertThat(metadata.getImage()).isEqualTo(IMAGE);
- assertThat(metadata.getImageUrl()).isEqualTo(IMAGE_URL);
- assertThat(metadata.getInitialNotificationDescription())
- .isEqualTo(INITIAL_NOTIFICATION_DESCRIPTION);
- assertThat(metadata.getInitialNotificationDescriptionNoAccount())
- .isEqualTo(INITIAL_NOTIFICATION_DESCRIPTION_NO_ACCOUNT);
- assertThat(metadata.getInitialPairingDescription()).isEqualTo(INITIAL_PAIRING_DESCRIPTION);
- assertThat(metadata.getIntentUri()).isEqualTo(INTENT_URI);
- assertThat(metadata.getName()).isEqualTo(NAME);
- assertThat(metadata.getOpenCompanionAppDescription())
- .isEqualTo(OPEN_COMPANION_APP_DESCRIPTION);
- assertThat(metadata.getRetroactivePairingDescription())
- .isEqualTo(RETRO_ACTIVE_PAIRING_DESCRIPTION);
- assertThat(metadata.getSubsequentPairingDescription())
- .isEqualTo(SUBSEQUENT_PAIRING_DESCRIPTION);
- assertThat(metadata.getTriggerDistance()).isWithin(DELTA).of(TRIGGER_DISTANCE);
- assertThat(metadata.getTrueWirelessImageUrlCase()).isEqualTo(TRUE_WIRELESS_IMAGE_URL_CASE);
- assertThat(metadata.getTrueWirelessImageUrlLeftBud())
- .isEqualTo(TRUE_WIRELESS_IMAGE_URL_LEFT_BUD);
- assertThat(metadata.getTrueWirelessImageUrlRightBud())
- .isEqualTo(TRUE_WIRELESS_IMAGE_URL_RIGHT_BUD);
- assertThat(metadata.getUnableToConnectDescription())
- .isEqualTo(UNABLE_TO_CONNECT_DESCRIPTION);
- assertThat(metadata.getUnableToConnectTitle()).isEqualTo(UNABLE_TO_CONNECT_TITLE);
- assertThat(metadata.getUpdateCompanionAppDescription())
- .isEqualTo(UPDATE_COMPANION_APP_DESCRIPTION);
- assertThat(metadata.getWaitLaunchCompanionAppDescription())
- .isEqualTo(WAIT_LAUNCH_COMPANION_APP_DESCRIPTION);
- }
-
- /* Verifies Happy Path FastPairDiscoveryItemParcel. */
- private static void ensureHappyPathAsExpected(FastPairDiscoveryItemParcel itemParcel) {
- assertThat(itemParcel.actionUrl).isEqualTo(ACTION_URL);
- assertThat(itemParcel.actionUrlType).isEqualTo(ACTION_URL_TYPE);
- assertThat(itemParcel.appName).isEqualTo(APP_NAME);
- assertThat(itemParcel.authenticationPublicKeySecp256r1)
- .isEqualTo(AUTHENTICATION_PUBLIC_KEY_SEC_P256R1);
- assertThat(itemParcel.description).isEqualTo(DESCRIPTION);
- assertThat(itemParcel.deviceName).isEqualTo(DEVICE_NAME);
- assertThat(itemParcel.displayUrl).isEqualTo(DISPLAY_URL);
- assertThat(itemParcel.firstObservationTimestampMillis)
- .isEqualTo(FIRST_OBSERVATION_TIMESTAMP_MILLIS);
- assertThat(itemParcel.iconFifeUrl).isEqualTo(ICON_FIFE_URL);
- assertThat(itemParcel.iconPng).isEqualTo(ICON_PNG);
- assertThat(itemParcel.id).isEqualTo(ID);
- assertThat(itemParcel.lastObservationTimestampMillis)
- .isEqualTo(LAST_OBSERVATION_TIMESTAMP_MILLIS);
- assertThat(itemParcel.macAddress).isEqualTo(MAC_ADDRESS);
- assertThat(itemParcel.packageName).isEqualTo(PACKAGE_NAME);
- assertThat(itemParcel.pendingAppInstallTimestampMillis)
- .isEqualTo(PENDING_APP_INSTALL_TIMESTAMP_MILLIS);
- assertThat(itemParcel.rssi).isEqualTo(RSSI);
- assertThat(itemParcel.state).isEqualTo(STATE);
- assertThat(itemParcel.title).isEqualTo(TITLE);
- assertThat(itemParcel.triggerId).isEqualTo(TRIGGER_ID);
- assertThat(itemParcel.txPower).isEqualTo(TX_POWER);
- }
-
- /* Verifies Happy Path FastPairDiscoveryItem. */
- private static void ensureHappyPathAsExpected(FastPairDiscoveryItem item) {
- assertThat(item.getActionUrl()).isEqualTo(ACTION_URL);
- assertThat(item.getActionUrlType()).isEqualTo(ACTION_URL_TYPE);
- assertThat(item.getAppName()).isEqualTo(APP_NAME);
- assertThat(item.getAuthenticationPublicKeySecp256r1())
- .isEqualTo(AUTHENTICATION_PUBLIC_KEY_SEC_P256R1);
- assertThat(item.getDescription()).isEqualTo(DESCRIPTION);
- assertThat(item.getDeviceName()).isEqualTo(DEVICE_NAME);
- assertThat(item.getDisplayUrl()).isEqualTo(DISPLAY_URL);
- assertThat(item.getFirstObservationTimestampMillis())
- .isEqualTo(FIRST_OBSERVATION_TIMESTAMP_MILLIS);
- assertThat(item.getIconFfeUrl()).isEqualTo(ICON_FIFE_URL);
- assertThat(item.getIconPng()).isEqualTo(ICON_PNG);
- assertThat(item.getId()).isEqualTo(ID);
- assertThat(item.getLastObservationTimestampMillis())
- .isEqualTo(LAST_OBSERVATION_TIMESTAMP_MILLIS);
- assertThat(item.getMacAddress()).isEqualTo(MAC_ADDRESS);
- assertThat(item.getPackageName()).isEqualTo(PACKAGE_NAME);
- assertThat(item.getPendingAppInstallTimestampMillis())
- .isEqualTo(PENDING_APP_INSTALL_TIMESTAMP_MILLIS);
- assertThat(item.getRssi()).isEqualTo(RSSI);
- assertThat(item.getState()).isEqualTo(STATE);
- assertThat(item.getTitle()).isEqualTo(TITLE);
- assertThat(item.getTriggerId()).isEqualTo(TRIGGER_ID);
- assertThat(item.getTxPower()).isEqualTo(TX_POWER);
- }
-
- /* Verifies Happy Path EligibleAccountParcel[]. */
- private static void ensureHappyPathAsExpected(FastPairEligibleAccountParcel[] accountsParcel) {
- assertThat(accountsParcel).hasLength(ELIGIBLE_ACCOUNTS_NUM);
-
- assertThat(accountsParcel[0].account).isEqualTo(ELIGIBLE_ACCOUNT_1);
- assertThat(accountsParcel[0].optIn).isEqualTo(ELIGIBLE_ACCOUNT_1_OPT_IN);
-
- assertThat(accountsParcel[1].account).isEqualTo(ELIGIBLE_ACCOUNT_2);
- assertThat(accountsParcel[1].optIn).isEqualTo(ELIGIBLE_ACCOUNT_2_OPT_IN);
- }
-}
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/FastPairEligibleAccountTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/FastPairEligibleAccountTest.java
deleted file mode 100644
index 0d91d4e..0000000
--- a/nearby/tests/cts/fastpair/src/android/nearby/cts/FastPairEligibleAccountTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.nearby.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.accounts.Account;
-import android.nearby.FastPairEligibleAccount;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SdkSuppress;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class FastPairEligibleAccountTest {
-
- private static final Account ACCOUNT = new Account("abc@google.com", "type1");
- private static final Account ACCOUNT_NULL = null;
-
- private static final boolean OPT_IN_TRUE = true;
-
- @Test
- @SdkSuppress(minSdkVersion = 32, codeName = "T")
- public void testSetGetFastPairEligibleAccountNotNull() {
- FastPairEligibleAccount eligibleAccount =
- genFastPairEligibleAccount(ACCOUNT, OPT_IN_TRUE);
-
- assertThat(eligibleAccount.getAccount()).isEqualTo(ACCOUNT);
- assertThat(eligibleAccount.isOptIn()).isEqualTo(OPT_IN_TRUE);
- }
-
- @Test
- @SdkSuppress(minSdkVersion = 32, codeName = "T")
- public void testSetGetFastPairEligibleAccountNull() {
- FastPairEligibleAccount eligibleAccount =
- genFastPairEligibleAccount(ACCOUNT_NULL, OPT_IN_TRUE);
-
- assertThat(eligibleAccount.getAccount()).isEqualTo(ACCOUNT_NULL);
- assertThat(eligibleAccount.isOptIn()).isEqualTo(OPT_IN_TRUE);
- }
-
- /* Generates FastPairEligibleAccount. */
- private static FastPairEligibleAccount genFastPairEligibleAccount(
- Account account, boolean optIn) {
- FastPairEligibleAccount.Builder builder = new FastPairEligibleAccount.Builder();
- builder.setAccount(account);
- builder.setOptIn(optIn);
-
- return builder.build();
- }
-}
diff --git a/nearby/tests/multidevices/clients/test_service/fastpair_seeker_data_provider/Android.bp b/nearby/tests/multidevices/clients/test_service/fastpair_seeker_data_provider/Android.bp
index a6d51ca..1fcee37 100644
--- a/nearby/tests/multidevices/clients/test_service/fastpair_seeker_data_provider/Android.bp
+++ b/nearby/tests/multidevices/clients/test_service/fastpair_seeker_data_provider/Android.bp
@@ -21,6 +21,8 @@
srcs: ["shared/**/*.kt"],
sdk_version: "test_current",
static_libs: [
+ // TODO(b/227513829): Remove "framework-nearby-static" once Fast Pair system APIs add back.
+ "framework-nearby-static",
"guava",
"gson-prebuilt-jar",
],
diff --git a/nearby/tests/multidevices/clients/test_support/fastpair_provider/Android.bp b/nearby/tests/multidevices/clients/test_support/fastpair_provider/Android.bp
index e01c436..298c9dc 100644
--- a/nearby/tests/multidevices/clients/test_support/fastpair_provider/Android.bp
+++ b/nearby/tests/multidevices/clients/test_support/fastpair_provider/Android.bp
@@ -34,11 +34,13 @@
],
static_libs: [
"NearbyFastPairProviderLiteProtos",
+ "androidx.core_core",
"androidx.test.core",
"error_prone_annotations",
"fast-pair-lite-protos",
"framework-annotations-lib",
+ "guava",
"kotlin-stdlib",
- "service-nearby-pre-jarjar",
+ "nearby-common-lib",
],
}
diff --git a/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/Android.bp b/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/Android.bp
index 87d352f..125c34e 100644
--- a/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/Android.bp
+++ b/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/Android.bp
@@ -25,6 +25,7 @@
// adb remount
// adb push ${ANDROID_PRODUCT_OUT}/system/app/NearbyFastPairProviderSimulatorApp /system/app/
// adb reboot
+// Grant all permissions requested to NearbyFastPairProviderSimulatorApp before launching it.
android_app {
name: "NearbyFastPairProviderSimulatorApp",
sdk_version: "test_current",
diff --git a/nearby/tests/multidevices/host/AndroidTest.xml b/nearby/tests/multidevices/host/AndroidTest.xml
index a5f6839..5926cc1 100644
--- a/nearby/tests/multidevices/host/AndroidTest.xml
+++ b/nearby/tests/multidevices/host/AndroidTest.xml
@@ -21,11 +21,13 @@
<!-- For coverage to work, the APK should not be uninstalled until after coverage is pulled.
So it's a lot easier to install APKs outside the python code.
-->
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="test-file-name" value="NearbyMultiDevicesClientsSnippets.apk" />
- <option name="test-file-name" value="NearbyFastPairSeekerDataProvider.apk" />
- <option name="check-min-sdk" value="true" />
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="remount-system" value="true" />
+ <option name="push" value="NearbyMultiDevicesClientsSnippets.apk->/system/app/NearbyMultiDevicesClientsSnippets/NearbyMultiDevicesClientsSnippets.apk" />
+ <option name="push" value="NearbyFastPairSeekerDataProvider.apk->/system/app/NearbyFastPairSeekerDataProvider/NearbyFastPairSeekerDataProvider.apk" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer" />
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
<option name="run-command" value="wm dismiss-keyguard" />
@@ -39,14 +41,47 @@
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
<option name="force-skip-system-props" value="true" /> <!-- avoid restarting device -->
<option name="screen-always-on" value="on" />
+ <!-- List permissions requested by the APK: aapt d permissions <PATH_TO_YOUR_APK> -->
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.BLUETOOTH" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.BLUETOOTH_ADMIN" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.BLUETOOTH_ADVERTISE" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.BLUETOOTH_CONNECT" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.BLUETOOTH_PRIVILEGED" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.BLUETOOTH_SCAN" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.INTERNET" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.GET_ACCOUNTS" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.WRITE_SECURE_SETTINGS" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.REORDER_TASKS" />
</target_preparer>
</device>
<device name="device2">
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="test-file-name" value="NearbyMultiDevicesClientsSnippets.apk" />
- <option name="test-file-name" value="NearbyFastPairSeekerDataProvider.apk" />
- <option name="check-min-sdk" value="true" />
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="remount-system" value="true" />
+ <option name="push" value="NearbyMultiDevicesClientsSnippets.apk->/system/app/NearbyMultiDevicesClientsSnippets/NearbyMultiDevicesClientsSnippets.apk" />
+ <option name="push" value="NearbyFastPairSeekerDataProvider.apk->/system/app/NearbyFastPairSeekerDataProvider/NearbyFastPairSeekerDataProvider.apk" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer" />
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
<option name="run-command" value="wm dismiss-keyguard" />
@@ -54,6 +89,37 @@
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
<option name="force-skip-system-props" value="true" /> <!-- avoid restarting device -->
<option name="screen-always-on" value="on" />
+ <!-- List permissions requested by the APK: aapt d permissions <PATH_TO_YOUR_APK> -->
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.BLUETOOTH" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.BLUETOOTH_ADMIN" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.BLUETOOTH_ADVERTISE" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.BLUETOOTH_CONNECT" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.BLUETOOTH_PRIVILEGED" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.BLUETOOTH_SCAN" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.INTERNET" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.GET_ACCOUNTS" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.WRITE_SECURE_SETTINGS" />
+ <option
+ name="run-command"
+ value="pm grant android.nearby.multidevices android.permission.REORDER_TASKS" />
</target_preparer>
</device>
diff --git a/service-t/Android.bp b/service-t/Android.bp
index 50dd995..0beb4c8 100644
--- a/service-t/Android.bp
+++ b/service-t/Android.bp
@@ -22,6 +22,17 @@
// Include build rules from Sources.bp
build = ["Sources.bp"]
+filegroup {
+ name: "service-connectivity-tiramisu-sources",
+ srcs: [
+ "src/**/*.java",
+ ],
+ visibility: ["//visibility:private"],
+}
+// The above filegroup can be used to specify different sources depending
+// on the branch, while minimizing merge conflicts in the rest of the
+// build rules.
+
// This builds T+ services depending on framework-connectivity-t
// hidden symbols separately from the S+ services, to ensure that S+
// services cannot accidentally depend on T+ hidden symbols from
@@ -32,9 +43,7 @@
// TODO(b/210962470): Bump this to at least S, and then T.
min_sdk_version: "30",
srcs: [
- "src/**/*.java",
- ":ethernet-service-updatable-sources",
- ":services.connectivity-tiramisu-updatable-sources",
+ ":service-connectivity-tiramisu-sources",
],
libs: [
"framework-annotations-lib",
@@ -63,3 +72,18 @@
"//packages/modules/IPsec/tests/iketests",
],
}
+
+// Ethernet related libraries.
+// TODO: remove when ethernet tests are merged into connectivity tests
+filegroup {
+ name: "ethernet-service-test-sources",
+ srcs: [
+ "src/com/android/server/ethernet/**/*.java",
+ "src/com/android/server/net/DelayedDiskWrite.java",
+ "src/com/android/server/net/IpConfigStore.java",
+ ],
+ path: "src",
+ visibility: [
+ "//packages/modules/Connectivity/tests:__subpackages__",
+ ],
+}
diff --git a/service-t/Sources.bp b/service-t/Sources.bp
index 04866fb..4e669b6 100644
--- a/service-t/Sources.bp
+++ b/service-t/Sources.bp
@@ -59,48 +59,6 @@
],
}
-// Nsd related libraries.
-
-filegroup {
- name: "services.connectivity-nsd-sources",
- srcs: [
- "src/com/android/server/INativeDaemon*.java",
- "src/com/android/server/NativeDaemon*.java",
- "src/com/android/server/Nsd*.java",
- ],
- path: "src",
- visibility: [
- "//visibility:private",
- ],
-}
-
-// IpSec related libraries.
-
-filegroup {
- name: "services.connectivity-ipsec-sources",
- srcs: [
- "src/com/android/server/IpSecService.java",
- ],
- path: "src",
- visibility: [
- "//visibility:private",
- ],
-}
-
-// Ethernet related libraries.
-
-filegroup {
- name: "services.connectivity-ethernet-sources",
- srcs: [
- "src/com/android/server/net/DelayedDiskWrite.java",
- "src/com/android/server/net/IpConfigStore.java",
- ],
- path: "src",
- visibility: [
- "//frameworks/opt/net/ethernet/tests",
- ],
-}
-
// Connectivity-T common libraries.
// TODO: remove this empty filegroup.
@@ -111,20 +69,6 @@
visibility: ["//frameworks/base/services/core"],
}
-filegroup {
- name: "services.connectivity-tiramisu-updatable-sources",
- srcs: [
- ":services.connectivity-ethernet-sources",
- ":services.connectivity-ipsec-sources",
- ":services.connectivity-netstats-sources",
- ":services.connectivity-nsd-sources",
- ],
- path: "src",
- visibility: [
- "//packages/modules/Connectivity:__subpackages__",
- ],
-}
-
cc_library_shared {
name: "libcom_android_net_module_util_jni",
min_sdk_version: "30",
diff --git a/service-t/src/com/android/server/ethernet/EthernetConfigStore.java b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java
new file mode 100644
index 0000000..6b623f4
--- /dev/null
+++ b/service-t/src/com/android/server/ethernet/EthernetConfigStore.java
@@ -0,0 +1,88 @@
+/*
+ * 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.ethernet;
+
+import android.annotation.Nullable;
+import android.net.IpConfiguration;
+import android.os.Environment;
+import android.util.ArrayMap;
+
+import com.android.server.net.IpConfigStore;
+
+
+/**
+ * This class provides an API to store and manage Ethernet network configuration.
+ */
+public class EthernetConfigStore {
+ private static final String ipConfigFile = Environment.getDataDirectory() +
+ "/misc/ethernet/ipconfig.txt";
+
+ private IpConfigStore mStore = new IpConfigStore();
+ private ArrayMap<String, IpConfiguration> mIpConfigurations;
+ private IpConfiguration mIpConfigurationForDefaultInterface;
+ private final Object mSync = new Object();
+
+ public EthernetConfigStore() {
+ mIpConfigurations = new ArrayMap<>(0);
+ }
+
+ public void read() {
+ synchronized (mSync) {
+ ArrayMap<String, IpConfiguration> configs =
+ IpConfigStore.readIpConfigurations(ipConfigFile);
+
+ // This configuration may exist in old file versions when there was only a single active
+ // Ethernet interface.
+ if (configs.containsKey("0")) {
+ mIpConfigurationForDefaultInterface = configs.remove("0");
+ }
+
+ mIpConfigurations = configs;
+ }
+ }
+
+ public void write(String iface, IpConfiguration config) {
+ boolean modified;
+
+ synchronized (mSync) {
+ if (config == null) {
+ modified = mIpConfigurations.remove(iface) != null;
+ } else {
+ IpConfiguration oldConfig = mIpConfigurations.put(iface, config);
+ modified = !config.equals(oldConfig);
+ }
+
+ if (modified) {
+ mStore.writeIpConfigurations(ipConfigFile, mIpConfigurations);
+ }
+ }
+ }
+
+ public ArrayMap<String, IpConfiguration> getIpConfigurations() {
+ synchronized (mSync) {
+ return new ArrayMap<>(mIpConfigurations);
+ }
+ }
+
+ @Nullable
+ public IpConfiguration getIpConfigurationForDefaultInterface() {
+ synchronized (mSync) {
+ return mIpConfigurationForDefaultInterface == null
+ ? null : new IpConfiguration(mIpConfigurationForDefaultInterface);
+ }
+ }
+}
diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkAgent.java b/service-t/src/com/android/server/ethernet/EthernetNetworkAgent.java
new file mode 100644
index 0000000..57fbce7
--- /dev/null
+++ b/service-t/src/com/android/server/ethernet/EthernetNetworkAgent.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.ethernet;
+
+import android.content.Context;
+import android.net.LinkProperties;
+import android.net.NetworkAgent;
+import android.net.NetworkAgentConfig;
+import android.net.NetworkCapabilities;
+import android.net.NetworkProvider;
+import android.net.NetworkScore;
+import android.os.Looper;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+public class EthernetNetworkAgent extends NetworkAgent {
+
+ private static final String TAG = "EthernetNetworkAgent";
+
+ public interface Callbacks {
+ void onNetworkUnwanted();
+ }
+
+ private final Callbacks mCallbacks;
+
+ EthernetNetworkAgent(
+ @NonNull Context context,
+ @NonNull Looper looper,
+ @NonNull NetworkCapabilities nc,
+ @NonNull LinkProperties lp,
+ @NonNull NetworkAgentConfig config,
+ @Nullable NetworkProvider provider,
+ @NonNull Callbacks cb) {
+ super(context, looper, TAG, nc, lp, new NetworkScore.Builder().build(), config, provider);
+ mCallbacks = cb;
+ }
+
+ @Override
+ public void onNetworkUnwanted() {
+ mCallbacks.onNetworkUnwanted();
+ }
+
+ // sendLinkProperties is final in NetworkAgent, so it cannot be mocked.
+ public void sendLinkPropertiesImpl(LinkProperties lp) {
+ sendLinkProperties(lp);
+ }
+
+ public Callbacks getCallbacks() {
+ return mCallbacks;
+ }
+}
diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
new file mode 100644
index 0000000..d910629
--- /dev/null
+++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
@@ -0,0 +1,785 @@
+/*
+ * 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.ethernet;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityResources;
+import android.net.EthernetManager;
+import android.net.EthernetNetworkSpecifier;
+import android.net.EthernetNetworkManagementException;
+import android.net.INetworkInterfaceOutcomeReceiver;
+import android.net.IpConfiguration;
+import android.net.IpConfiguration.IpAssignment;
+import android.net.IpConfiguration.ProxySettings;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkAgentConfig;
+import android.net.NetworkCapabilities;
+import android.net.NetworkFactory;
+import android.net.NetworkProvider;
+import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
+import android.net.ip.IIpClient;
+import android.net.ip.IpClientCallbacks;
+import android.net.ip.IpClientManager;
+import android.net.ip.IpClientUtil;
+import android.net.shared.ProvisioningConfiguration;
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.AndroidRuntimeException;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.connectivity.resources.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.InterfaceParams;
+
+import java.io.FileDescriptor;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * {@link NetworkFactory} that represents Ethernet networks.
+ *
+ * This class reports a static network score of 70 when it is tracking an interface and that
+ * interface's link is up, and a score of 0 otherwise.
+ */
+public class EthernetNetworkFactory extends NetworkFactory {
+ private final static String TAG = EthernetNetworkFactory.class.getSimpleName();
+ final static boolean DBG = true;
+
+ private final static int NETWORK_SCORE = 70;
+ private static final String NETWORK_TYPE = "Ethernet";
+ private static final String LEGACY_TCP_BUFFER_SIZES =
+ "524288,1048576,3145728,524288,1048576,2097152";
+
+ private final ConcurrentHashMap<String, NetworkInterfaceState> mTrackingInterfaces =
+ new ConcurrentHashMap<>();
+ private final Handler mHandler;
+ private final Context mContext;
+ final Dependencies mDeps;
+
+ public static class Dependencies {
+ public void makeIpClient(Context context, String iface, IpClientCallbacks callbacks) {
+ IpClientUtil.makeIpClient(context, iface, callbacks);
+ }
+
+ public IpClientManager makeIpClientManager(@NonNull final IIpClient ipClient) {
+ return new IpClientManager(ipClient, TAG);
+ }
+
+ public EthernetNetworkAgent makeEthernetNetworkAgent(Context context, Looper looper,
+ NetworkCapabilities nc, LinkProperties lp, NetworkAgentConfig config,
+ NetworkProvider provider, EthernetNetworkAgent.Callbacks cb) {
+ return new EthernetNetworkAgent(context, looper, nc, lp, config, provider, cb);
+ }
+
+ public InterfaceParams getNetworkInterfaceByName(String name) {
+ return InterfaceParams.getByName(name);
+ }
+
+ // TODO: remove legacy resource fallback after migrating its overlays.
+ private String getPlatformTcpBufferSizes(Context context) {
+ final Resources r = context.getResources();
+ final int resId = r.getIdentifier("config_ethernet_tcp_buffers", "string",
+ context.getPackageName());
+ return r.getString(resId);
+ }
+
+ public String getTcpBufferSizesFromResource(Context context) {
+ final String tcpBufferSizes;
+ final String platformTcpBufferSizes = getPlatformTcpBufferSizes(context);
+ if (!LEGACY_TCP_BUFFER_SIZES.equals(platformTcpBufferSizes)) {
+ // Platform resource is not the historical default: use the overlay.
+ tcpBufferSizes = platformTcpBufferSizes;
+ } else {
+ final ConnectivityResources resources = new ConnectivityResources(context);
+ tcpBufferSizes = resources.get().getString(R.string.config_ethernet_tcp_buffers);
+ }
+ return tcpBufferSizes;
+ }
+ }
+
+ public static class ConfigurationException extends AndroidRuntimeException {
+ public ConfigurationException(String msg) {
+ super(msg);
+ }
+ }
+
+ public EthernetNetworkFactory(Handler handler, Context context) {
+ this(handler, context, new Dependencies());
+ }
+
+ @VisibleForTesting
+ EthernetNetworkFactory(Handler handler, Context context, Dependencies deps) {
+ super(handler.getLooper(), context, NETWORK_TYPE, createDefaultNetworkCapabilities());
+
+ mHandler = handler;
+ mContext = context;
+ mDeps = deps;
+
+ setScoreFilter(NETWORK_SCORE);
+ }
+
+ @Override
+ public boolean acceptRequest(NetworkRequest request) {
+ if (DBG) {
+ Log.d(TAG, "acceptRequest, request: " + request);
+ }
+
+ return networkForRequest(request) != null;
+ }
+
+ @Override
+ protected void needNetworkFor(NetworkRequest networkRequest) {
+ NetworkInterfaceState network = networkForRequest(networkRequest);
+
+ if (network == null) {
+ Log.e(TAG, "needNetworkFor, failed to get a network for " + networkRequest);
+ return;
+ }
+
+ if (++network.refCount == 1) {
+ network.start();
+ }
+ }
+
+ @Override
+ protected void releaseNetworkFor(NetworkRequest networkRequest) {
+ NetworkInterfaceState network = networkForRequest(networkRequest);
+ if (network == null) {
+ Log.e(TAG, "releaseNetworkFor, failed to get a network for " + networkRequest);
+ return;
+ }
+
+ if (--network.refCount == 0) {
+ network.stop();
+ }
+ }
+
+ /**
+ * Returns an array of available interface names. The array is sorted: unrestricted interfaces
+ * goes first, then sorted by name.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ protected String[] getAvailableInterfaces(boolean includeRestricted) {
+ return mTrackingInterfaces.values()
+ .stream()
+ .filter(iface -> !iface.isRestricted() || includeRestricted)
+ .sorted((iface1, iface2) -> {
+ int r = Boolean.compare(iface1.isRestricted(), iface2.isRestricted());
+ return r == 0 ? iface1.name.compareTo(iface2.name) : r;
+ })
+ .map(iface -> iface.name)
+ .toArray(String[]::new);
+ }
+
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ protected void addInterface(@NonNull final String ifaceName, @NonNull final String hwAddress,
+ @NonNull final IpConfiguration ipConfig,
+ @NonNull final NetworkCapabilities capabilities) {
+ if (mTrackingInterfaces.containsKey(ifaceName)) {
+ Log.e(TAG, "Interface with name " + ifaceName + " already exists.");
+ return;
+ }
+
+ final NetworkCapabilities nc = new NetworkCapabilities.Builder(capabilities)
+ .setNetworkSpecifier(new EthernetNetworkSpecifier(ifaceName))
+ .build();
+
+ if (DBG) {
+ Log.d(TAG, "addInterface, iface: " + ifaceName + ", capabilities: " + nc);
+ }
+
+ final NetworkInterfaceState iface = new NetworkInterfaceState(
+ ifaceName, hwAddress, mHandler, mContext, ipConfig, nc, this, mDeps);
+ mTrackingInterfaces.put(ifaceName, iface);
+ updateCapabilityFilter();
+ }
+
+ @VisibleForTesting
+ protected int getInterfaceState(@NonNull String iface) {
+ final NetworkInterfaceState interfaceState = mTrackingInterfaces.get(iface);
+ if (interfaceState == null) {
+ return EthernetManager.STATE_ABSENT;
+ } else if (!interfaceState.mLinkUp) {
+ return EthernetManager.STATE_LINK_DOWN;
+ } else {
+ return EthernetManager.STATE_LINK_UP;
+ }
+ }
+
+ /**
+ * Update a network's configuration and restart it if necessary.
+ *
+ * @param ifaceName the interface name of the network to be updated.
+ * @param ipConfig the desired {@link IpConfiguration} for the given network or null. If
+ * {@code null} is passed, the existing IpConfiguration is not updated.
+ * @param capabilities the desired {@link NetworkCapabilities} for the given network. If
+ * {@code null} is passed, then the network's current
+ * {@link NetworkCapabilities} will be used in support of existing APIs as
+ * the public API does not allow this.
+ * @param listener an optional {@link INetworkInterfaceOutcomeReceiver} to notify callers of
+ * completion.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ protected void updateInterface(@NonNull final String ifaceName,
+ @Nullable final IpConfiguration ipConfig,
+ @Nullable final NetworkCapabilities capabilities,
+ @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ if (!hasInterface(ifaceName)) {
+ maybeSendNetworkManagementCallbackForUntracked(ifaceName, listener);
+ return;
+ }
+
+ final NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName);
+ iface.updateInterface(ipConfig, capabilities, listener);
+ mTrackingInterfaces.put(ifaceName, iface);
+ updateCapabilityFilter();
+ }
+
+ private static NetworkCapabilities mixInCapabilities(NetworkCapabilities nc,
+ NetworkCapabilities addedNc) {
+ final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder(nc);
+ for (int transport : addedNc.getTransportTypes()) builder.addTransportType(transport);
+ for (int capability : addedNc.getCapabilities()) builder.addCapability(capability);
+ return builder.build();
+ }
+
+ private void updateCapabilityFilter() {
+ NetworkCapabilities capabilitiesFilter = createDefaultNetworkCapabilities();
+ for (NetworkInterfaceState iface: mTrackingInterfaces.values()) {
+ capabilitiesFilter = mixInCapabilities(capabilitiesFilter, iface.mCapabilities);
+ }
+
+ if (DBG) Log.d(TAG, "updateCapabilityFilter: " + capabilitiesFilter);
+ setCapabilityFilter(capabilitiesFilter);
+ }
+
+ private static NetworkCapabilities createDefaultNetworkCapabilities() {
+ return NetworkCapabilities.Builder
+ .withoutDefaultCapabilities()
+ .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET).build();
+ }
+
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ protected void removeInterface(String interfaceName) {
+ NetworkInterfaceState iface = mTrackingInterfaces.remove(interfaceName);
+ if (iface != null) {
+ iface.maybeSendNetworkManagementCallbackForAbort();
+ iface.stop();
+ }
+
+ updateCapabilityFilter();
+ }
+
+ /** Returns true if state has been modified */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ protected boolean updateInterfaceLinkState(@NonNull final String ifaceName, final boolean up,
+ @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ if (!hasInterface(ifaceName)) {
+ maybeSendNetworkManagementCallbackForUntracked(ifaceName, listener);
+ return false;
+ }
+
+ if (DBG) {
+ Log.d(TAG, "updateInterfaceLinkState, iface: " + ifaceName + ", up: " + up);
+ }
+
+ NetworkInterfaceState iface = mTrackingInterfaces.get(ifaceName);
+ return iface.updateLinkState(up, listener);
+ }
+
+ private void maybeSendNetworkManagementCallbackForUntracked(
+ String ifaceName, INetworkInterfaceOutcomeReceiver listener) {
+ maybeSendNetworkManagementCallback(listener, null,
+ new EthernetNetworkManagementException(
+ ifaceName + " can't be updated as it is not available."));
+ }
+
+ @VisibleForTesting
+ protected boolean hasInterface(String ifaceName) {
+ return mTrackingInterfaces.containsKey(ifaceName);
+ }
+
+ private NetworkInterfaceState networkForRequest(NetworkRequest request) {
+ String requestedIface = null;
+
+ NetworkSpecifier specifier = request.getNetworkSpecifier();
+ if (specifier instanceof EthernetNetworkSpecifier) {
+ requestedIface = ((EthernetNetworkSpecifier) specifier)
+ .getInterfaceName();
+ }
+
+ NetworkInterfaceState network = null;
+ if (!TextUtils.isEmpty(requestedIface)) {
+ NetworkInterfaceState n = mTrackingInterfaces.get(requestedIface);
+ if (n != null && request.canBeSatisfiedBy(n.mCapabilities)) {
+ network = n;
+ }
+ } else {
+ for (NetworkInterfaceState n : mTrackingInterfaces.values()) {
+ if (request.canBeSatisfiedBy(n.mCapabilities) && n.mLinkUp) {
+ network = n;
+ break;
+ }
+ }
+ }
+
+ if (DBG) {
+ Log.i(TAG, "networkForRequest, request: " + request + ", network: " + network);
+ }
+
+ return network;
+ }
+
+ private static void maybeSendNetworkManagementCallback(
+ @Nullable final INetworkInterfaceOutcomeReceiver listener,
+ @Nullable final String iface,
+ @Nullable final EthernetNetworkManagementException e) {
+ if (null == listener) {
+ return;
+ }
+
+ try {
+ if (iface != null) {
+ listener.onResult(iface);
+ } else {
+ listener.onError(e);
+ }
+ } catch (RemoteException re) {
+ Log.e(TAG, "Can't send onComplete for network management callback", re);
+ }
+ }
+
+ @VisibleForTesting
+ static class NetworkInterfaceState {
+ final String name;
+
+ private final String mHwAddress;
+ private final Handler mHandler;
+ private final Context mContext;
+ private final NetworkFactory mNetworkFactory;
+ private final Dependencies mDeps;
+
+ private static String sTcpBufferSizes = null; // Lazy initialized.
+
+ private boolean mLinkUp;
+ private int mLegacyType;
+ private LinkProperties mLinkProperties = new LinkProperties();
+
+ private volatile @Nullable IpClientManager mIpClient;
+ private @NonNull NetworkCapabilities mCapabilities;
+ private @Nullable EthernetIpClientCallback mIpClientCallback;
+ private @Nullable EthernetNetworkAgent mNetworkAgent;
+ private @Nullable IpConfiguration mIpConfig;
+
+ /**
+ * A map of TRANSPORT_* types to legacy transport types available for each type an ethernet
+ * interface could propagate.
+ *
+ * There are no legacy type equivalents to LOWPAN or WIFI_AWARE. These types are set to
+ * TYPE_NONE to match the behavior of their own network factories.
+ */
+ private static final SparseArray<Integer> sTransports = new SparseArray();
+ static {
+ sTransports.put(NetworkCapabilities.TRANSPORT_ETHERNET,
+ ConnectivityManager.TYPE_ETHERNET);
+ sTransports.put(NetworkCapabilities.TRANSPORT_BLUETOOTH,
+ ConnectivityManager.TYPE_BLUETOOTH);
+ sTransports.put(NetworkCapabilities.TRANSPORT_WIFI, ConnectivityManager.TYPE_WIFI);
+ sTransports.put(NetworkCapabilities.TRANSPORT_CELLULAR,
+ ConnectivityManager.TYPE_MOBILE);
+ sTransports.put(NetworkCapabilities.TRANSPORT_LOWPAN, ConnectivityManager.TYPE_NONE);
+ sTransports.put(NetworkCapabilities.TRANSPORT_WIFI_AWARE,
+ ConnectivityManager.TYPE_NONE);
+ }
+
+ long refCount = 0;
+
+ private class EthernetIpClientCallback extends IpClientCallbacks {
+ private final ConditionVariable mIpClientStartCv = new ConditionVariable(false);
+ private final ConditionVariable mIpClientShutdownCv = new ConditionVariable(false);
+ @Nullable INetworkInterfaceOutcomeReceiver mNetworkManagementListener;
+
+ EthernetIpClientCallback(@Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ mNetworkManagementListener = listener;
+ }
+
+ @Override
+ public void onIpClientCreated(IIpClient ipClient) {
+ mIpClient = mDeps.makeIpClientManager(ipClient);
+ mIpClientStartCv.open();
+ }
+
+ private void awaitIpClientStart() {
+ mIpClientStartCv.block();
+ }
+
+ private void awaitIpClientShutdown() {
+ mIpClientShutdownCv.block();
+ }
+
+ // At the time IpClient is stopped, an IpClient event may have already been posted on
+ // the back of the handler and is awaiting execution. Once that event is executed, the
+ // associated callback object may not be valid anymore
+ // (NetworkInterfaceState#mIpClientCallback points to a different object / null).
+ private boolean isCurrentCallback() {
+ return this == mIpClientCallback;
+ }
+
+ private void handleIpEvent(final @NonNull Runnable r) {
+ mHandler.post(() -> {
+ if (!isCurrentCallback()) {
+ Log.i(TAG, "Ignoring stale IpClientCallbacks " + this);
+ return;
+ }
+ r.run();
+ });
+ }
+
+ @Override
+ public void onProvisioningSuccess(LinkProperties newLp) {
+ handleIpEvent(() -> onIpLayerStarted(newLp, mNetworkManagementListener));
+ }
+
+ @Override
+ public void onProvisioningFailure(LinkProperties newLp) {
+ // This cannot happen due to provisioning timeout, because our timeout is 0. It can
+ // happen due to errors while provisioning or on provisioning loss.
+ handleIpEvent(() -> onIpLayerStopped(mNetworkManagementListener));
+ }
+
+ @Override
+ public void onLinkPropertiesChange(LinkProperties newLp) {
+ handleIpEvent(() -> updateLinkProperties(newLp));
+ }
+
+ @Override
+ public void onReachabilityLost(String logMsg) {
+ handleIpEvent(() -> updateNeighborLostEvent(logMsg));
+ }
+
+ @Override
+ public void onQuit() {
+ mIpClient = null;
+ mIpClientShutdownCv.open();
+ }
+ }
+
+ NetworkInterfaceState(String ifaceName, String hwAddress, Handler handler, Context context,
+ @NonNull IpConfiguration ipConfig, @NonNull NetworkCapabilities capabilities,
+ NetworkFactory networkFactory, Dependencies deps) {
+ name = ifaceName;
+ mIpConfig = Objects.requireNonNull(ipConfig);
+ mCapabilities = Objects.requireNonNull(capabilities);
+ mLegacyType = getLegacyType(mCapabilities);
+ mHandler = handler;
+ mContext = context;
+ mNetworkFactory = networkFactory;
+ mDeps = deps;
+ mHwAddress = hwAddress;
+ }
+
+ /**
+ * Determines the legacy transport type from a NetworkCapabilities transport type. Defaults
+ * to legacy TYPE_NONE if there is no known conversion
+ */
+ private static int getLegacyType(int transport) {
+ return sTransports.get(transport, ConnectivityManager.TYPE_NONE);
+ }
+
+ private static int getLegacyType(@NonNull final NetworkCapabilities capabilities) {
+ final int[] transportTypes = capabilities.getTransportTypes();
+ if (transportTypes.length > 0) {
+ return getLegacyType(transportTypes[0]);
+ }
+
+ // Should never happen as transport is always one of ETHERNET or a valid override
+ throw new ConfigurationException("Network Capabilities do not have an associated "
+ + "transport type.");
+ }
+
+ private void setCapabilities(@NonNull final NetworkCapabilities capabilities) {
+ mCapabilities = new NetworkCapabilities(capabilities);
+ mLegacyType = getLegacyType(mCapabilities);
+ }
+
+ void updateInterface(@Nullable final IpConfiguration ipConfig,
+ @Nullable final NetworkCapabilities capabilities,
+ @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ if (DBG) {
+ Log.d(TAG, "updateInterface, iface: " + name
+ + ", ipConfig: " + ipConfig + ", old ipConfig: " + mIpConfig
+ + ", capabilities: " + capabilities + ", old capabilities: " + mCapabilities
+ + ", listener: " + listener
+ );
+ }
+
+ if (null != ipConfig){
+ mIpConfig = ipConfig;
+ }
+ if (null != capabilities) {
+ setCapabilities(capabilities);
+ }
+ // Send an abort callback if a request is filed before the previous one has completed.
+ maybeSendNetworkManagementCallbackForAbort();
+ // TODO: Update this logic to only do a restart if required. Although a restart may
+ // be required due to the capabilities or ipConfiguration values, not all
+ // capabilities changes require a restart.
+ restart(listener);
+ }
+
+ boolean isRestricted() {
+ return !mCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+ }
+
+ private void start() {
+ start(null);
+ }
+
+ private void start(@Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ if (mIpClient != null) {
+ if (DBG) Log.d(TAG, "IpClient already started");
+ return;
+ }
+ if (DBG) {
+ Log.d(TAG, String.format("Starting Ethernet IpClient(%s)", name));
+ }
+
+ mIpClientCallback = new EthernetIpClientCallback(listener);
+ mDeps.makeIpClient(mContext, name, mIpClientCallback);
+ mIpClientCallback.awaitIpClientStart();
+
+ if (sTcpBufferSizes == null) {
+ sTcpBufferSizes = mDeps.getTcpBufferSizesFromResource(mContext);
+ }
+ provisionIpClient(mIpClient, mIpConfig, sTcpBufferSizes);
+ }
+
+ void onIpLayerStarted(@NonNull final LinkProperties linkProperties,
+ @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ if (mNetworkAgent != null) {
+ Log.e(TAG, "Already have a NetworkAgent - aborting new request");
+ stop();
+ return;
+ }
+ mLinkProperties = linkProperties;
+
+ // Create our NetworkAgent.
+ final NetworkAgentConfig config = new NetworkAgentConfig.Builder()
+ .setLegacyType(mLegacyType)
+ .setLegacyTypeName(NETWORK_TYPE)
+ .setLegacyExtraInfo(mHwAddress)
+ .build();
+ mNetworkAgent = mDeps.makeEthernetNetworkAgent(mContext, mHandler.getLooper(),
+ mCapabilities, mLinkProperties, config, mNetworkFactory.getProvider(),
+ new EthernetNetworkAgent.Callbacks() {
+ @Override
+ public void onNetworkUnwanted() {
+ // if mNetworkAgent is null, we have already called stop.
+ if (mNetworkAgent == null) return;
+
+ if (this == mNetworkAgent.getCallbacks()) {
+ stop();
+ } else {
+ Log.d(TAG, "Ignoring unwanted as we have a more modern " +
+ "instance");
+ }
+ }
+ });
+ mNetworkAgent.register();
+ mNetworkAgent.markConnected();
+ realizeNetworkManagementCallback(name, null);
+ }
+
+ void onIpLayerStopped(@Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ // There is no point in continuing if the interface is gone as stop() will be triggered
+ // by removeInterface() when processed on the handler thread and start() won't
+ // work for a non-existent interface.
+ if (null == mDeps.getNetworkInterfaceByName(name)) {
+ if (DBG) Log.d(TAG, name + " is no longer available.");
+ // Send a callback in case a provisioning request was in progress.
+ maybeSendNetworkManagementCallbackForAbort();
+ return;
+ }
+ restart(listener);
+ }
+
+ private void maybeSendNetworkManagementCallbackForAbort() {
+ realizeNetworkManagementCallback(null,
+ new EthernetNetworkManagementException(
+ "The IP provisioning request has been aborted."));
+ }
+
+ // Must be called on the handler thread
+ private void realizeNetworkManagementCallback(@Nullable final String iface,
+ @Nullable final EthernetNetworkManagementException e) {
+ ensureRunningOnEthernetHandlerThread();
+ if (null == mIpClientCallback) {
+ return;
+ }
+
+ EthernetNetworkFactory.maybeSendNetworkManagementCallback(
+ mIpClientCallback.mNetworkManagementListener, iface, e);
+ // Only send a single callback per listener.
+ mIpClientCallback.mNetworkManagementListener = null;
+ }
+
+ private void ensureRunningOnEthernetHandlerThread() {
+ if (mHandler.getLooper().getThread() != Thread.currentThread()) {
+ throw new IllegalStateException(
+ "Not running on the Ethernet thread: "
+ + Thread.currentThread().getName());
+ }
+ }
+
+ void updateLinkProperties(LinkProperties linkProperties) {
+ mLinkProperties = linkProperties;
+ if (mNetworkAgent != null) {
+ mNetworkAgent.sendLinkPropertiesImpl(linkProperties);
+ }
+ }
+
+ void updateNeighborLostEvent(String logMsg) {
+ Log.i(TAG, "updateNeighborLostEvent " + logMsg);
+ // Reachability lost will be seen only if the gateway is not reachable.
+ // Since ethernet FW doesn't have the mechanism to scan for new networks
+ // like WiFi, simply restart.
+ // If there is a better network, that will become default and apps
+ // will be able to use internet. If ethernet gets connected again,
+ // and has backhaul connectivity, it will become default.
+ restart();
+ }
+
+ /** Returns true if state has been modified */
+ boolean updateLinkState(final boolean up,
+ @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ if (mLinkUp == up) {
+ EthernetNetworkFactory.maybeSendNetworkManagementCallback(listener, null,
+ new EthernetNetworkManagementException(
+ "No changes with requested link state " + up + " for " + name));
+ return false;
+ }
+ mLinkUp = up;
+
+ if (!up) { // was up, goes down
+ // Send an abort on a provisioning request callback if necessary before stopping.
+ maybeSendNetworkManagementCallbackForAbort();
+ stop();
+ // If only setting the interface down, send a callback to signal completion.
+ EthernetNetworkFactory.maybeSendNetworkManagementCallback(listener, name, null);
+ } else { // was down, goes up
+ stop();
+ start(listener);
+ }
+
+ return true;
+ }
+
+ void stop() {
+ // Invalidate all previous start requests
+ if (mIpClient != null) {
+ mIpClient.shutdown();
+ mIpClientCallback.awaitIpClientShutdown();
+ mIpClient = null;
+ }
+ mIpClientCallback = null;
+
+ if (mNetworkAgent != null) {
+ mNetworkAgent.unregister();
+ mNetworkAgent = null;
+ }
+ mLinkProperties.clear();
+ }
+
+ private static void provisionIpClient(@NonNull final IpClientManager ipClient,
+ @NonNull final IpConfiguration config, @NonNull final String tcpBufferSizes) {
+ if (config.getProxySettings() == ProxySettings.STATIC ||
+ config.getProxySettings() == ProxySettings.PAC) {
+ ipClient.setHttpProxy(config.getHttpProxy());
+ }
+
+ if (!TextUtils.isEmpty(tcpBufferSizes)) {
+ ipClient.setTcpBufferSizes(tcpBufferSizes);
+ }
+
+ ipClient.startProvisioning(createProvisioningConfiguration(config));
+ }
+
+ private static ProvisioningConfiguration createProvisioningConfiguration(
+ @NonNull final IpConfiguration config) {
+ if (config.getIpAssignment() == IpAssignment.STATIC) {
+ return new ProvisioningConfiguration.Builder()
+ .withStaticConfiguration(config.getStaticIpConfiguration())
+ .build();
+ }
+ return new ProvisioningConfiguration.Builder()
+ .withProvisioningTimeoutMs(0)
+ .build();
+ }
+
+ void restart() {
+ restart(null);
+ }
+
+ void restart(@Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ if (DBG) Log.d(TAG, "reconnecting Ethernet");
+ stop();
+ start(listener);
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "{ "
+ + "refCount: " + refCount + ", "
+ + "iface: " + name + ", "
+ + "up: " + mLinkUp + ", "
+ + "hwAddress: " + mHwAddress + ", "
+ + "networkCapabilities: " + mCapabilities + ", "
+ + "networkAgent: " + mNetworkAgent + ", "
+ + "ipClient: " + mIpClient + ","
+ + "linkProperties: " + mLinkProperties
+ + "}";
+ }
+ }
+
+ void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
+ super.dump(fd, pw, args);
+ pw.println(getClass().getSimpleName());
+ pw.println("Tracking interfaces:");
+ pw.increaseIndent();
+ for (String iface: mTrackingInterfaces.keySet()) {
+ NetworkInterfaceState ifaceState = mTrackingInterfaces.get(iface);
+ pw.println(iface + ":" + ifaceState);
+ pw.increaseIndent();
+ if (null == ifaceState.mIpClient) {
+ pw.println("IpClient is null");
+ }
+ pw.decreaseIndent();
+ }
+ pw.decreaseIndent();
+ }
+}
diff --git a/service-t/src/com/android/server/ethernet/EthernetService.java b/service-t/src/com/android/server/ethernet/EthernetService.java
new file mode 100644
index 0000000..d405fd5
--- /dev/null
+++ b/service-t/src/com/android/server/ethernet/EthernetService.java
@@ -0,0 +1,47 @@
+/*
+ * 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.ethernet;
+
+import android.content.Context;
+import android.net.INetd;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+
+import java.util.Objects;
+
+// TODO: consider renaming EthernetServiceImpl to EthernetService and deleting this file.
+public final class EthernetService {
+ private static final String TAG = "EthernetService";
+ private static final String THREAD_NAME = "EthernetServiceThread";
+
+ private static INetd getNetd(Context context) {
+ final INetd netd =
+ INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE));
+ Objects.requireNonNull(netd, "could not get netd instance");
+ return netd;
+ }
+
+ public static EthernetServiceImpl create(Context context) {
+ final HandlerThread handlerThread = new HandlerThread(THREAD_NAME);
+ handlerThread.start();
+ final Handler handler = new Handler(handlerThread.getLooper());
+ final EthernetNetworkFactory factory = new EthernetNetworkFactory(handler, context);
+ return new EthernetServiceImpl(context, handler,
+ new EthernetTracker(context, handler, factory, getNetd(context)));
+ }
+}
diff --git a/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
new file mode 100644
index 0000000..5e830ad
--- /dev/null
+++ b/service-t/src/com/android/server/ethernet/EthernetServiceImpl.java
@@ -0,0 +1,299 @@
+/*
+ * 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.ethernet;
+
+import static android.net.NetworkCapabilities.TRANSPORT_TEST;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.IEthernetManager;
+import android.net.IEthernetServiceListener;
+import android.net.INetworkInterfaceOutcomeReceiver;
+import android.net.ITetheredInterfaceCallback;
+import android.net.EthernetNetworkUpdateRequest;
+import android.net.IpConfiguration;
+import android.net.NetworkCapabilities;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.PrintWriterPrinter;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.PermissionUtils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * EthernetServiceImpl handles remote Ethernet operation requests by implementing
+ * the IEthernetManager interface.
+ */
+public class EthernetServiceImpl extends IEthernetManager.Stub {
+ private static final String TAG = "EthernetServiceImpl";
+
+ @VisibleForTesting
+ final AtomicBoolean mStarted = new AtomicBoolean(false);
+ private final Context mContext;
+ private final Handler mHandler;
+ private final EthernetTracker mTracker;
+
+ EthernetServiceImpl(@NonNull final Context context, @NonNull final Handler handler,
+ @NonNull final EthernetTracker tracker) {
+ mContext = context;
+ mHandler = handler;
+ mTracker = tracker;
+ }
+
+ private void enforceAutomotiveDevice(final @NonNull String methodName) {
+ PermissionUtils.enforceSystemFeature(mContext, PackageManager.FEATURE_AUTOMOTIVE,
+ methodName + " is only available on automotive devices.");
+ }
+
+ private boolean checkUseRestrictedNetworksPermission() {
+ return PermissionUtils.checkAnyPermissionOf(mContext,
+ android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS);
+ }
+
+ public void start() {
+ Log.i(TAG, "Starting Ethernet service");
+ mTracker.start();
+ mStarted.set(true);
+ }
+
+ private void throwIfEthernetNotStarted() {
+ if (!mStarted.get()) {
+ throw new IllegalStateException("System isn't ready to change ethernet configurations");
+ }
+ }
+
+ @Override
+ public String[] getAvailableInterfaces() throws RemoteException {
+ PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG);
+ return mTracker.getInterfaces(checkUseRestrictedNetworksPermission());
+ }
+
+ /**
+ * Get Ethernet configuration
+ * @return the Ethernet Configuration, contained in {@link IpConfiguration}.
+ */
+ @Override
+ public IpConfiguration getConfiguration(String iface) {
+ PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG);
+ if (mTracker.isRestrictedInterface(iface)) {
+ PermissionUtils.enforceRestrictedNetworkPermission(mContext, TAG);
+ }
+
+ return new IpConfiguration(mTracker.getIpConfiguration(iface));
+ }
+
+ /**
+ * Set Ethernet configuration
+ */
+ @Override
+ public void setConfiguration(String iface, IpConfiguration config) {
+ throwIfEthernetNotStarted();
+
+ PermissionUtils.enforceNetworkStackPermission(mContext);
+ if (mTracker.isRestrictedInterface(iface)) {
+ PermissionUtils.enforceRestrictedNetworkPermission(mContext, TAG);
+ }
+
+ // TODO: this does not check proxy settings, gateways, etc.
+ // Fix this by making IpConfiguration a complete representation of static configuration.
+ mTracker.updateIpConfiguration(iface, new IpConfiguration(config));
+ }
+
+ /**
+ * Indicates whether given interface is available.
+ */
+ @Override
+ public boolean isAvailable(String iface) {
+ PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG);
+ if (mTracker.isRestrictedInterface(iface)) {
+ PermissionUtils.enforceRestrictedNetworkPermission(mContext, TAG);
+ }
+
+ return mTracker.isTrackingInterface(iface);
+ }
+
+ /**
+ * Adds a listener.
+ * @param listener A {@link IEthernetServiceListener} to add.
+ */
+ public void addListener(IEthernetServiceListener listener) throws RemoteException {
+ Objects.requireNonNull(listener, "listener must not be null");
+ PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG);
+ mTracker.addListener(listener, checkUseRestrictedNetworksPermission());
+ }
+
+ /**
+ * Removes a listener.
+ * @param listener A {@link IEthernetServiceListener} to remove.
+ */
+ public void removeListener(IEthernetServiceListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("listener must not be null");
+ }
+ PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG);
+ mTracker.removeListener(listener);
+ }
+
+ @Override
+ public void setIncludeTestInterfaces(boolean include) {
+ PermissionUtils.enforceNetworkStackPermissionOr(mContext,
+ android.Manifest.permission.NETWORK_SETTINGS);
+ mTracker.setIncludeTestInterfaces(include);
+ }
+
+ @Override
+ public void requestTetheredInterface(ITetheredInterfaceCallback callback) {
+ Objects.requireNonNull(callback, "callback must not be null");
+ PermissionUtils.enforceNetworkStackPermissionOr(mContext,
+ android.Manifest.permission.NETWORK_SETTINGS);
+ mTracker.requestTetheredInterface(callback);
+ }
+
+ @Override
+ public void releaseTetheredInterface(ITetheredInterfaceCallback callback) {
+ Objects.requireNonNull(callback, "callback must not be null");
+ PermissionUtils.enforceNetworkStackPermissionOr(mContext,
+ android.Manifest.permission.NETWORK_SETTINGS);
+ mTracker.releaseTetheredInterface(callback);
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump EthernetService from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ pw.println("Current Ethernet state: ");
+ pw.increaseIndent();
+ mTracker.dump(fd, pw, args);
+ pw.decreaseIndent();
+
+ pw.println("Handler:");
+ pw.increaseIndent();
+ mHandler.dump(new PrintWriterPrinter(pw), "EthernetServiceImpl");
+ pw.decreaseIndent();
+ }
+
+ private void enforceNetworkManagementPermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_ETHERNET_NETWORKS,
+ "EthernetServiceImpl");
+ }
+
+ private void enforceManageTestNetworksPermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_TEST_NETWORKS,
+ "EthernetServiceImpl");
+ }
+
+ private void maybeValidateTestCapabilities(final String iface,
+ @Nullable final NetworkCapabilities nc) {
+ if (!mTracker.isValidTestInterface(iface)) {
+ return;
+ }
+ // For test interfaces, only null or capabilities that include TRANSPORT_TEST are
+ // allowed.
+ if (nc != null && !nc.hasTransport(TRANSPORT_TEST)) {
+ throw new IllegalArgumentException(
+ "Updates to test interfaces must have NetworkCapabilities.TRANSPORT_TEST.");
+ }
+ }
+
+ private void enforceAdminPermission(final String iface, boolean enforceAutomotive,
+ final String logMessage) {
+ if (mTracker.isValidTestInterface(iface)) {
+ enforceManageTestNetworksPermission();
+ } else {
+ enforceNetworkManagementPermission();
+ if (enforceAutomotive) {
+ enforceAutomotiveDevice(logMessage);
+ }
+ }
+ }
+
+ @Override
+ public void updateConfiguration(@NonNull final String iface,
+ @NonNull final EthernetNetworkUpdateRequest request,
+ @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ Objects.requireNonNull(iface);
+ Objects.requireNonNull(request);
+ throwIfEthernetNotStarted();
+
+ // TODO: validate that iface is listed in overlay config_ethernet_interfaces
+ // only automotive devices are allowed to set the NetworkCapabilities using this API
+ enforceAdminPermission(iface, request.getNetworkCapabilities() != null,
+ "updateConfiguration() with non-null capabilities");
+ maybeValidateTestCapabilities(iface, request.getNetworkCapabilities());
+
+ mTracker.updateConfiguration(
+ iface, request.getIpConfiguration(), request.getNetworkCapabilities(), listener);
+ }
+
+ @Override
+ public void connectNetwork(@NonNull final String iface,
+ @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ Log.i(TAG, "connectNetwork called with: iface=" + iface + ", listener=" + listener);
+ Objects.requireNonNull(iface);
+ throwIfEthernetNotStarted();
+
+ enforceAdminPermission(iface, true, "connectNetwork()");
+
+ mTracker.connectNetwork(iface, listener);
+ }
+
+ @Override
+ public void disconnectNetwork(@NonNull final String iface,
+ @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ Log.i(TAG, "disconnectNetwork called with: iface=" + iface + ", listener=" + listener);
+ Objects.requireNonNull(iface);
+ throwIfEthernetNotStarted();
+
+ enforceAdminPermission(iface, true, "connectNetwork()");
+
+ mTracker.disconnectNetwork(iface, listener);
+ }
+
+ @Override
+ public void setEthernetEnabled(boolean enabled) {
+ PermissionUtils.enforceNetworkStackPermissionOr(mContext,
+ android.Manifest.permission.NETWORK_SETTINGS);
+
+ mTracker.setEthernetEnabled(enabled);
+ }
+
+ @Override
+ public List<String> getInterfaceList() {
+ PermissionUtils.enforceAccessNetworkStatePermission(mContext, TAG);
+ return mTracker.getInterfaceList();
+ }
+}
diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java
new file mode 100644
index 0000000..abb1635
--- /dev/null
+++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java
@@ -0,0 +1,943 @@
+/*
+ * 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.ethernet;
+
+import static android.net.EthernetManager.ETHERNET_STATE_DISABLED;
+import static android.net.EthernetManager.ETHERNET_STATE_ENABLED;
+import static android.net.TestNetworkManager.TEST_TAP_PREFIX;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.ConnectivityResources;
+import android.net.EthernetManager;
+import android.net.IEthernetServiceListener;
+import android.net.INetworkInterfaceOutcomeReceiver;
+import android.net.INetd;
+import android.net.ITetheredInterfaceCallback;
+import android.net.InterfaceConfigurationParcel;
+import android.net.IpConfiguration;
+import android.net.IpConfiguration.IpAssignment;
+import android.net.IpConfiguration.ProxySettings;
+import android.net.LinkAddress;
+import android.net.NetworkCapabilities;
+import android.net.StaticIpConfiguration;
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.BaseNetdUnsolicitedEventListener;
+import com.android.net.module.util.NetdUtils;
+import com.android.net.module.util.PermissionUtils;
+
+import java.io.FileDescriptor;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Tracks Ethernet interfaces and manages interface configurations.
+ *
+ * <p>Interfaces may have different {@link android.net.NetworkCapabilities}. This mapping is defined
+ * in {@code config_ethernet_interfaces}. Notably, some interfaces could be marked as restricted by
+ * not specifying {@link android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED} flag.
+ * Interfaces could have associated {@link android.net.IpConfiguration}.
+ * Ethernet Interfaces may be present at boot time or appear after boot (e.g., for Ethernet adapters
+ * connected over USB). This class supports multiple interfaces. When an interface appears on the
+ * system (or is present at boot time) this class will start tracking it and bring it up. Only
+ * interfaces whose names match the {@code config_ethernet_iface_regex} regular expression are
+ * tracked.
+ *
+ * <p>All public or package private methods must be thread-safe unless stated otherwise.
+ */
+@VisibleForTesting(visibility = PACKAGE)
+public class EthernetTracker {
+ private static final int INTERFACE_MODE_CLIENT = 1;
+ private static final int INTERFACE_MODE_SERVER = 2;
+
+ private static final String TAG = EthernetTracker.class.getSimpleName();
+ private static final boolean DBG = EthernetNetworkFactory.DBG;
+
+ private static final String TEST_IFACE_REGEXP = TEST_TAP_PREFIX + "\\d+";
+ private static final String LEGACY_IFACE_REGEXP = "eth\\d";
+
+ /**
+ * Interface names we track. This is a product-dependent regular expression, plus,
+ * if setIncludeTestInterfaces is true, any test interfaces.
+ */
+ private volatile String mIfaceMatch;
+
+ /**
+ * Track test interfaces if true, don't track otherwise.
+ */
+ private boolean mIncludeTestInterfaces = false;
+
+ /** Mapping between {iface name | mac address} -> {NetworkCapabilities} */
+ private final ConcurrentHashMap<String, NetworkCapabilities> mNetworkCapabilities =
+ new ConcurrentHashMap<>();
+ private final ConcurrentHashMap<String, IpConfiguration> mIpConfigurations =
+ new ConcurrentHashMap<>();
+
+ private final Context mContext;
+ private final INetd mNetd;
+ private final Handler mHandler;
+ private final EthernetNetworkFactory mFactory;
+ private final EthernetConfigStore mConfigStore;
+ private final Dependencies mDeps;
+
+ private final RemoteCallbackList<IEthernetServiceListener> mListeners =
+ new RemoteCallbackList<>();
+ private final TetheredInterfaceRequestList mTetheredInterfaceRequests =
+ new TetheredInterfaceRequestList();
+
+ // Used only on the handler thread
+ private String mDefaultInterface;
+ private int mDefaultInterfaceMode = INTERFACE_MODE_CLIENT;
+ // Tracks whether clients were notified that the tethered interface is available
+ private boolean mTetheredInterfaceWasAvailable = false;
+ private volatile IpConfiguration mIpConfigForDefaultInterface;
+
+ private int mEthernetState = ETHERNET_STATE_ENABLED;
+
+ private class TetheredInterfaceRequestList extends
+ RemoteCallbackList<ITetheredInterfaceCallback> {
+ @Override
+ public void onCallbackDied(ITetheredInterfaceCallback cb, Object cookie) {
+ mHandler.post(EthernetTracker.this::maybeUntetherDefaultInterface);
+ }
+ }
+
+ public static class Dependencies {
+ // TODO: remove legacy resource fallback after migrating its overlays.
+ private String getPlatformRegexResource(Context context) {
+ final Resources r = context.getResources();
+ final int resId =
+ r.getIdentifier("config_ethernet_iface_regex", "string", context.getPackageName());
+ return r.getString(resId);
+ }
+
+ // TODO: remove legacy resource fallback after migrating its overlays.
+ private String[] getPlatformInterfaceConfigs(Context context) {
+ final Resources r = context.getResources();
+ final int resId = r.getIdentifier("config_ethernet_interfaces", "array",
+ context.getPackageName());
+ return r.getStringArray(resId);
+ }
+
+ public String getInterfaceRegexFromResource(Context context) {
+ final String platformRegex = getPlatformRegexResource(context);
+ final String match;
+ if (!LEGACY_IFACE_REGEXP.equals(platformRegex)) {
+ // Platform resource is not the historical default: use the overlay
+ match = platformRegex;
+ } else {
+ final ConnectivityResources resources = new ConnectivityResources(context);
+ match = resources.get().getString(
+ com.android.connectivity.resources.R.string.config_ethernet_iface_regex);
+ }
+ return match;
+ }
+
+ public String[] getInterfaceConfigFromResource(Context context) {
+ final String[] platformInterfaceConfigs = getPlatformInterfaceConfigs(context);
+ final String[] interfaceConfigs;
+ if (platformInterfaceConfigs.length != 0) {
+ // Platform resource is not the historical default: use the overlay
+ interfaceConfigs = platformInterfaceConfigs;
+ } else {
+ final ConnectivityResources resources = new ConnectivityResources(context);
+ interfaceConfigs = resources.get().getStringArray(
+ com.android.connectivity.resources.R.array.config_ethernet_interfaces);
+ }
+ return interfaceConfigs;
+ }
+ }
+
+ EthernetTracker(@NonNull final Context context, @NonNull final Handler handler,
+ @NonNull final EthernetNetworkFactory factory, @NonNull final INetd netd) {
+ this(context, handler, factory, netd, new Dependencies());
+ }
+
+ @VisibleForTesting
+ EthernetTracker(@NonNull final Context context, @NonNull final Handler handler,
+ @NonNull final EthernetNetworkFactory factory, @NonNull final INetd netd,
+ @NonNull final Dependencies deps) {
+ mContext = context;
+ mHandler = handler;
+ mFactory = factory;
+ mNetd = netd;
+ mDeps = deps;
+
+ // Interface match regex.
+ updateIfaceMatchRegexp();
+
+ // Read default Ethernet interface configuration from resources
+ final String[] interfaceConfigs = mDeps.getInterfaceConfigFromResource(context);
+ for (String strConfig : interfaceConfigs) {
+ parseEthernetConfig(strConfig);
+ }
+
+ mConfigStore = new EthernetConfigStore();
+ }
+
+ void start() {
+ mFactory.register();
+ mConfigStore.read();
+
+ // Default interface is just the first one we want to track.
+ mIpConfigForDefaultInterface = mConfigStore.getIpConfigurationForDefaultInterface();
+ final ArrayMap<String, IpConfiguration> configs = mConfigStore.getIpConfigurations();
+ for (int i = 0; i < configs.size(); i++) {
+ mIpConfigurations.put(configs.keyAt(i), configs.valueAt(i));
+ }
+
+ try {
+ PermissionUtils.enforceNetworkStackPermission(mContext);
+ mNetd.registerUnsolicitedEventListener(new InterfaceObserver());
+ } catch (RemoteException | ServiceSpecificException e) {
+ Log.e(TAG, "Could not register InterfaceObserver " + e);
+ }
+
+ mHandler.post(this::trackAvailableInterfaces);
+ }
+
+ void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) {
+ if (DBG) {
+ Log.i(TAG, "updateIpConfiguration, iface: " + iface + ", cfg: " + ipConfiguration);
+ }
+ writeIpConfiguration(iface, ipConfiguration);
+ mHandler.post(() -> {
+ mFactory.updateInterface(iface, ipConfiguration, null, null);
+ broadcastInterfaceStateChange(iface);
+ });
+ }
+
+ private void writeIpConfiguration(@NonNull final String iface,
+ @NonNull final IpConfiguration ipConfig) {
+ mConfigStore.write(iface, ipConfig);
+ mIpConfigurations.put(iface, ipConfig);
+ }
+
+ private IpConfiguration getIpConfigurationForCallback(String iface, int state) {
+ return (state == EthernetManager.STATE_ABSENT) ? null : getOrCreateIpConfiguration(iface);
+ }
+
+ private void ensureRunningOnEthernetServiceThread() {
+ if (mHandler.getLooper().getThread() != Thread.currentThread()) {
+ throw new IllegalStateException(
+ "Not running on EthernetService thread: "
+ + Thread.currentThread().getName());
+ }
+ }
+
+ /**
+ * Broadcast the link state or IpConfiguration change of existing Ethernet interfaces to all
+ * listeners.
+ */
+ protected void broadcastInterfaceStateChange(@NonNull String iface) {
+ ensureRunningOnEthernetServiceThread();
+ final int state = mFactory.getInterfaceState(iface);
+ final int role = getInterfaceRole(iface);
+ final IpConfiguration config = getIpConfigurationForCallback(iface, state);
+ final int n = mListeners.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mListeners.getBroadcastItem(i).onInterfaceStateChanged(iface, state, role, config);
+ } catch (RemoteException e) {
+ // Do nothing here.
+ }
+ }
+ mListeners.finishBroadcast();
+ }
+
+ /**
+ * Unicast the interface state or IpConfiguration change of existing Ethernet interfaces to a
+ * specific listener.
+ */
+ protected void unicastInterfaceStateChange(@NonNull IEthernetServiceListener listener,
+ @NonNull String iface) {
+ ensureRunningOnEthernetServiceThread();
+ final int state = mFactory.getInterfaceState(iface);
+ final int role = getInterfaceRole(iface);
+ final IpConfiguration config = getIpConfigurationForCallback(iface, state);
+ try {
+ listener.onInterfaceStateChanged(iface, state, role, config);
+ } catch (RemoteException e) {
+ // Do nothing here.
+ }
+ }
+
+ @VisibleForTesting(visibility = PACKAGE)
+ protected void updateConfiguration(@NonNull final String iface,
+ @Nullable final IpConfiguration ipConfig,
+ @Nullable final NetworkCapabilities capabilities,
+ @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ if (DBG) {
+ Log.i(TAG, "updateConfiguration, iface: " + iface + ", capabilities: " + capabilities
+ + ", ipConfig: " + ipConfig);
+ }
+
+ final IpConfiguration localIpConfig = ipConfig == null
+ ? null : new IpConfiguration(ipConfig);
+ if (ipConfig != null) {
+ writeIpConfiguration(iface, localIpConfig);
+ }
+
+ if (null != capabilities) {
+ mNetworkCapabilities.put(iface, capabilities);
+ }
+ mHandler.post(() -> {
+ mFactory.updateInterface(iface, localIpConfig, capabilities, listener);
+ broadcastInterfaceStateChange(iface);
+ });
+ }
+
+ @VisibleForTesting(visibility = PACKAGE)
+ protected void connectNetwork(@NonNull final String iface,
+ @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ mHandler.post(() -> updateInterfaceState(iface, true, listener));
+ }
+
+ @VisibleForTesting(visibility = PACKAGE)
+ protected void disconnectNetwork(@NonNull final String iface,
+ @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ mHandler.post(() -> updateInterfaceState(iface, false, listener));
+ }
+
+ IpConfiguration getIpConfiguration(String iface) {
+ return mIpConfigurations.get(iface);
+ }
+
+ @VisibleForTesting(visibility = PACKAGE)
+ protected boolean isTrackingInterface(String iface) {
+ return mFactory.hasInterface(iface);
+ }
+
+ String[] getInterfaces(boolean includeRestricted) {
+ return mFactory.getAvailableInterfaces(includeRestricted);
+ }
+
+ List<String> getInterfaceList() {
+ final List<String> interfaceList = new ArrayList<String>();
+ final String[] ifaces;
+ try {
+ ifaces = mNetd.interfaceGetList();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not get list of interfaces " + e);
+ return interfaceList;
+ }
+ final String ifaceMatch = mIfaceMatch;
+ for (String iface : ifaces) {
+ if (iface.matches(ifaceMatch)) interfaceList.add(iface);
+ }
+ return interfaceList;
+ }
+
+ /**
+ * Returns true if given interface was configured as restricted (doesn't have
+ * NET_CAPABILITY_NOT_RESTRICTED) capability. Otherwise, returns false.
+ */
+ boolean isRestrictedInterface(String iface) {
+ final NetworkCapabilities nc = mNetworkCapabilities.get(iface);
+ return nc != null && !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+ }
+
+ void addListener(IEthernetServiceListener listener, boolean canUseRestrictedNetworks) {
+ mHandler.post(() -> {
+ if (!mListeners.register(listener, new ListenerInfo(canUseRestrictedNetworks))) {
+ // Remote process has already died
+ return;
+ }
+ for (String iface : getInterfaces(canUseRestrictedNetworks)) {
+ unicastInterfaceStateChange(listener, iface);
+ }
+
+ unicastEthernetStateChange(listener, mEthernetState);
+ });
+ }
+
+ void removeListener(IEthernetServiceListener listener) {
+ mHandler.post(() -> mListeners.unregister(listener));
+ }
+
+ public void setIncludeTestInterfaces(boolean include) {
+ mHandler.post(() -> {
+ mIncludeTestInterfaces = include;
+ updateIfaceMatchRegexp();
+ mHandler.post(() -> trackAvailableInterfaces());
+ });
+ }
+
+ public void requestTetheredInterface(ITetheredInterfaceCallback callback) {
+ mHandler.post(() -> {
+ if (!mTetheredInterfaceRequests.register(callback)) {
+ // Remote process has already died
+ return;
+ }
+ if (mDefaultInterfaceMode == INTERFACE_MODE_SERVER) {
+ if (mTetheredInterfaceWasAvailable) {
+ notifyTetheredInterfaceAvailable(callback, mDefaultInterface);
+ }
+ return;
+ }
+
+ setDefaultInterfaceMode(INTERFACE_MODE_SERVER);
+ });
+ }
+
+ public void releaseTetheredInterface(ITetheredInterfaceCallback callback) {
+ mHandler.post(() -> {
+ mTetheredInterfaceRequests.unregister(callback);
+ maybeUntetherDefaultInterface();
+ });
+ }
+
+ private void notifyTetheredInterfaceAvailable(ITetheredInterfaceCallback cb, String iface) {
+ try {
+ cb.onAvailable(iface);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error sending tethered interface available callback", e);
+ }
+ }
+
+ private void notifyTetheredInterfaceUnavailable(ITetheredInterfaceCallback cb) {
+ try {
+ cb.onUnavailable();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error sending tethered interface available callback", e);
+ }
+ }
+
+ private void maybeUntetherDefaultInterface() {
+ if (mTetheredInterfaceRequests.getRegisteredCallbackCount() > 0) return;
+ if (mDefaultInterfaceMode == INTERFACE_MODE_CLIENT) return;
+ setDefaultInterfaceMode(INTERFACE_MODE_CLIENT);
+ }
+
+ private void setDefaultInterfaceMode(int mode) {
+ Log.d(TAG, "Setting default interface mode to " + mode);
+ mDefaultInterfaceMode = mode;
+ if (mDefaultInterface != null) {
+ removeInterface(mDefaultInterface);
+ addInterface(mDefaultInterface);
+ }
+ }
+
+ private int getInterfaceRole(final String iface) {
+ if (!mFactory.hasInterface(iface)) return EthernetManager.ROLE_NONE;
+ final int mode = getInterfaceMode(iface);
+ return (mode == INTERFACE_MODE_CLIENT)
+ ? EthernetManager.ROLE_CLIENT
+ : EthernetManager.ROLE_SERVER;
+ }
+
+ private int getInterfaceMode(final String iface) {
+ if (iface.equals(mDefaultInterface)) {
+ return mDefaultInterfaceMode;
+ }
+ return INTERFACE_MODE_CLIENT;
+ }
+
+ private void removeInterface(String iface) {
+ mFactory.removeInterface(iface);
+ maybeUpdateServerModeInterfaceState(iface, false);
+ }
+
+ private void stopTrackingInterface(String iface) {
+ removeInterface(iface);
+ if (iface.equals(mDefaultInterface)) {
+ mDefaultInterface = null;
+ }
+ broadcastInterfaceStateChange(iface);
+ }
+
+ private void addInterface(String iface) {
+ InterfaceConfigurationParcel config = null;
+ // Bring up the interface so we get link status indications.
+ try {
+ PermissionUtils.enforceNetworkStackPermission(mContext);
+ NetdUtils.setInterfaceUp(mNetd, iface);
+ config = NetdUtils.getInterfaceConfigParcel(mNetd, iface);
+ } catch (IllegalStateException e) {
+ // Either the system is crashing or the interface has disappeared. Just ignore the
+ // error; we haven't modified any state because we only do that if our calls succeed.
+ Log.e(TAG, "Error upping interface " + iface, e);
+ }
+
+ if (config == null) {
+ Log.e(TAG, "Null interface config parcelable for " + iface + ". Bailing out.");
+ return;
+ }
+
+ final String hwAddress = config.hwAddr;
+
+ NetworkCapabilities nc = mNetworkCapabilities.get(iface);
+ if (nc == null) {
+ // Try to resolve using mac address
+ nc = mNetworkCapabilities.get(hwAddress);
+ if (nc == null) {
+ final boolean isTestIface = iface.matches(TEST_IFACE_REGEXP);
+ nc = createDefaultNetworkCapabilities(isTestIface);
+ }
+ }
+
+ final int mode = getInterfaceMode(iface);
+ if (mode == INTERFACE_MODE_CLIENT) {
+ IpConfiguration ipConfiguration = getOrCreateIpConfiguration(iface);
+ Log.d(TAG, "Tracking interface in client mode: " + iface);
+ mFactory.addInterface(iface, hwAddress, ipConfiguration, nc);
+ } else {
+ maybeUpdateServerModeInterfaceState(iface, true);
+ }
+
+ // Note: if the interface already has link (e.g., if we crashed and got
+ // restarted while it was running), we need to fake a link up notification so we
+ // start configuring it.
+ if (NetdUtils.hasFlag(config, "running")) {
+ updateInterfaceState(iface, true);
+ }
+ }
+
+ private void updateInterfaceState(String iface, boolean up) {
+ updateInterfaceState(iface, up, null /* listener */);
+ }
+
+ private void updateInterfaceState(@NonNull final String iface, final boolean up,
+ @Nullable final INetworkInterfaceOutcomeReceiver listener) {
+ final int mode = getInterfaceMode(iface);
+ final boolean factoryLinkStateUpdated = (mode == INTERFACE_MODE_CLIENT)
+ && mFactory.updateInterfaceLinkState(iface, up, listener);
+
+ if (factoryLinkStateUpdated) {
+ broadcastInterfaceStateChange(iface);
+ }
+ }
+
+ private void maybeUpdateServerModeInterfaceState(String iface, boolean available) {
+ if (available == mTetheredInterfaceWasAvailable || !iface.equals(mDefaultInterface)) return;
+
+ Log.d(TAG, (available ? "Tracking" : "No longer tracking")
+ + " interface in server mode: " + iface);
+
+ final int pendingCbs = mTetheredInterfaceRequests.beginBroadcast();
+ for (int i = 0; i < pendingCbs; i++) {
+ ITetheredInterfaceCallback item = mTetheredInterfaceRequests.getBroadcastItem(i);
+ if (available) {
+ notifyTetheredInterfaceAvailable(item, iface);
+ } else {
+ notifyTetheredInterfaceUnavailable(item);
+ }
+ }
+ mTetheredInterfaceRequests.finishBroadcast();
+ mTetheredInterfaceWasAvailable = available;
+ }
+
+ private void maybeTrackInterface(String iface) {
+ if (!iface.matches(mIfaceMatch)) {
+ return;
+ }
+
+ // If we don't already track this interface, and if this interface matches
+ // our regex, start tracking it.
+ if (mFactory.hasInterface(iface) || iface.equals(mDefaultInterface)) {
+ if (DBG) Log.w(TAG, "Ignoring already-tracked interface " + iface);
+ return;
+ }
+ if (DBG) Log.i(TAG, "maybeTrackInterface: " + iface);
+
+ // TODO: avoid making an interface default if it has configured NetworkCapabilities.
+ if (mDefaultInterface == null) {
+ mDefaultInterface = iface;
+ }
+
+ if (mIpConfigForDefaultInterface != null) {
+ updateIpConfiguration(iface, mIpConfigForDefaultInterface);
+ mIpConfigForDefaultInterface = null;
+ }
+
+ addInterface(iface);
+
+ broadcastInterfaceStateChange(iface);
+ }
+
+ private void trackAvailableInterfaces() {
+ try {
+ final String[] ifaces = mNetd.interfaceGetList();
+ for (String iface : ifaces) {
+ maybeTrackInterface(iface);
+ }
+ } catch (RemoteException | ServiceSpecificException e) {
+ Log.e(TAG, "Could not get list of interfaces " + e);
+ }
+ }
+
+ private class InterfaceObserver extends BaseNetdUnsolicitedEventListener {
+
+ @Override
+ public void onInterfaceLinkStateChanged(String iface, boolean up) {
+ if (DBG) {
+ Log.i(TAG, "interfaceLinkStateChanged, iface: " + iface + ", up: " + up);
+ }
+ mHandler.post(() -> updateInterfaceState(iface, up));
+ }
+
+ @Override
+ public void onInterfaceAdded(String iface) {
+ if (DBG) {
+ Log.i(TAG, "onInterfaceAdded, iface: " + iface);
+ }
+ mHandler.post(() -> maybeTrackInterface(iface));
+ }
+
+ @Override
+ public void onInterfaceRemoved(String iface) {
+ if (DBG) {
+ Log.i(TAG, "onInterfaceRemoved, iface: " + iface);
+ }
+ mHandler.post(() -> stopTrackingInterface(iface));
+ }
+ }
+
+ private static class ListenerInfo {
+
+ boolean canUseRestrictedNetworks = false;
+
+ ListenerInfo(boolean canUseRestrictedNetworks) {
+ this.canUseRestrictedNetworks = canUseRestrictedNetworks;
+ }
+ }
+
+ /**
+ * Parses an Ethernet interface configuration
+ *
+ * @param configString represents an Ethernet configuration in the following format: {@code
+ * <interface name|mac address>;[Network Capabilities];[IP config];[Override Transport]}
+ */
+ private void parseEthernetConfig(String configString) {
+ final EthernetTrackerConfig config = createEthernetTrackerConfig(configString);
+ NetworkCapabilities nc = createNetworkCapabilities(
+ !TextUtils.isEmpty(config.mCapabilities) /* clear default capabilities */,
+ config.mCapabilities, config.mTransport).build();
+ mNetworkCapabilities.put(config.mIface, nc);
+
+ if (null != config.mIpConfig) {
+ IpConfiguration ipConfig = parseStaticIpConfiguration(config.mIpConfig);
+ mIpConfigurations.put(config.mIface, ipConfig);
+ }
+ }
+
+ @VisibleForTesting
+ static EthernetTrackerConfig createEthernetTrackerConfig(@NonNull final String configString) {
+ Objects.requireNonNull(configString, "EthernetTrackerConfig requires non-null config");
+ return new EthernetTrackerConfig(configString.split(";", /* limit of tokens */ 4));
+ }
+
+ private static NetworkCapabilities createDefaultNetworkCapabilities(boolean isTestIface) {
+ NetworkCapabilities.Builder builder = createNetworkCapabilities(
+ false /* clear default capabilities */, null, null)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+
+ if (isTestIface) {
+ builder.addTransportType(NetworkCapabilities.TRANSPORT_TEST);
+ } else {
+ builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * Parses a static list of network capabilities
+ *
+ * @param clearDefaultCapabilities Indicates whether or not to clear any default capabilities
+ * @param commaSeparatedCapabilities A comma separated string list of integer encoded
+ * NetworkCapability.NET_CAPABILITY_* values
+ * @param overrideTransport A string representing a single integer encoded override transport
+ * type. Must be one of the NetworkCapability.TRANSPORT_*
+ * values. TRANSPORT_VPN is not supported. Errors with input
+ * will cause the override to be ignored.
+ */
+ @VisibleForTesting
+ static NetworkCapabilities.Builder createNetworkCapabilities(
+ boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities,
+ @Nullable String overrideTransport) {
+
+ final NetworkCapabilities.Builder builder = clearDefaultCapabilities
+ ? NetworkCapabilities.Builder.withoutDefaultCapabilities()
+ : new NetworkCapabilities.Builder();
+
+ // Determine the transport type. If someone has tried to define an override transport then
+ // attempt to add it. Since we can only have one override, all errors with it will
+ // gracefully default back to TRANSPORT_ETHERNET and warn the user. VPN is not allowed as an
+ // override type. Wifi Aware and LoWPAN are currently unsupported as well.
+ int transport = NetworkCapabilities.TRANSPORT_ETHERNET;
+ if (!TextUtils.isEmpty(overrideTransport)) {
+ try {
+ int parsedTransport = Integer.valueOf(overrideTransport);
+ if (parsedTransport == NetworkCapabilities.TRANSPORT_VPN
+ || parsedTransport == NetworkCapabilities.TRANSPORT_WIFI_AWARE
+ || parsedTransport == NetworkCapabilities.TRANSPORT_LOWPAN) {
+ Log.e(TAG, "Override transport '" + parsedTransport + "' is not supported. "
+ + "Defaulting to TRANSPORT_ETHERNET");
+ } else {
+ transport = parsedTransport;
+ }
+ } catch (NumberFormatException nfe) {
+ Log.e(TAG, "Override transport type '" + overrideTransport + "' "
+ + "could not be parsed. Defaulting to TRANSPORT_ETHERNET");
+ }
+ }
+
+ // Apply the transport. If the user supplied a valid number that is not a valid transport
+ // then adding will throw an exception. Default back to TRANSPORT_ETHERNET if that happens
+ try {
+ builder.addTransportType(transport);
+ } catch (IllegalArgumentException iae) {
+ Log.e(TAG, transport + " is not a valid NetworkCapability.TRANSPORT_* value. "
+ + "Defaulting to TRANSPORT_ETHERNET");
+ builder.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET);
+ }
+
+ builder.setLinkUpstreamBandwidthKbps(100 * 1000);
+ builder.setLinkDownstreamBandwidthKbps(100 * 1000);
+
+ if (!TextUtils.isEmpty(commaSeparatedCapabilities)) {
+ for (String strNetworkCapability : commaSeparatedCapabilities.split(",")) {
+ if (!TextUtils.isEmpty(strNetworkCapability)) {
+ try {
+ builder.addCapability(Integer.valueOf(strNetworkCapability));
+ } catch (NumberFormatException nfe) {
+ Log.e(TAG, "Capability '" + strNetworkCapability + "' could not be parsed");
+ } catch (IllegalArgumentException iae) {
+ Log.e(TAG, strNetworkCapability + " is not a valid "
+ + "NetworkCapability.NET_CAPABILITY_* value");
+ }
+ }
+ }
+ }
+ // Ethernet networks have no way to update the following capabilities, so they always
+ // have them.
+ builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
+ builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED);
+ builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
+
+ return builder;
+ }
+
+ /**
+ * Parses static IP configuration.
+ *
+ * @param staticIpConfig represents static IP configuration in the following format: {@code
+ * ip=<ip-address/mask> gateway=<ip-address> dns=<comma-sep-ip-addresses>
+ * domains=<comma-sep-domains>}
+ */
+ @VisibleForTesting
+ static IpConfiguration parseStaticIpConfiguration(String staticIpConfig) {
+ final StaticIpConfiguration.Builder staticIpConfigBuilder =
+ new StaticIpConfiguration.Builder();
+
+ for (String keyValueAsString : staticIpConfig.trim().split(" ")) {
+ if (TextUtils.isEmpty(keyValueAsString)) continue;
+
+ String[] pair = keyValueAsString.split("=");
+ if (pair.length != 2) {
+ throw new IllegalArgumentException("Unexpected token: " + keyValueAsString
+ + " in " + staticIpConfig);
+ }
+
+ String key = pair[0];
+ String value = pair[1];
+
+ switch (key) {
+ case "ip":
+ staticIpConfigBuilder.setIpAddress(new LinkAddress(value));
+ break;
+ case "domains":
+ staticIpConfigBuilder.setDomains(value);
+ break;
+ case "gateway":
+ staticIpConfigBuilder.setGateway(InetAddress.parseNumericAddress(value));
+ break;
+ case "dns": {
+ ArrayList<InetAddress> dnsAddresses = new ArrayList<>();
+ for (String address: value.split(",")) {
+ dnsAddresses.add(InetAddress.parseNumericAddress(address));
+ }
+ staticIpConfigBuilder.setDnsServers(dnsAddresses);
+ break;
+ }
+ default : {
+ throw new IllegalArgumentException("Unexpected key: " + key
+ + " in " + staticIpConfig);
+ }
+ }
+ }
+ return createIpConfiguration(staticIpConfigBuilder.build());
+ }
+
+ private static IpConfiguration createIpConfiguration(
+ @NonNull final StaticIpConfiguration staticIpConfig) {
+ return new IpConfiguration.Builder().setStaticIpConfiguration(staticIpConfig).build();
+ }
+
+ private IpConfiguration getOrCreateIpConfiguration(String iface) {
+ IpConfiguration ret = mIpConfigurations.get(iface);
+ if (ret != null) return ret;
+ ret = new IpConfiguration();
+ ret.setIpAssignment(IpAssignment.DHCP);
+ ret.setProxySettings(ProxySettings.NONE);
+ return ret;
+ }
+
+ private void updateIfaceMatchRegexp() {
+ final String match = mDeps.getInterfaceRegexFromResource(mContext);
+ mIfaceMatch = mIncludeTestInterfaces
+ ? "(" + match + "|" + TEST_IFACE_REGEXP + ")"
+ : match;
+ Log.d(TAG, "Interface match regexp set to '" + mIfaceMatch + "'");
+ }
+
+ /**
+ * Validate if a given interface is valid for testing.
+ *
+ * @param iface the name of the interface to validate.
+ * @return {@code true} if test interfaces are enabled and the given {@code iface} has a test
+ * interface prefix, {@code false} otherwise.
+ */
+ public boolean isValidTestInterface(@NonNull final String iface) {
+ return mIncludeTestInterfaces && iface.matches(TEST_IFACE_REGEXP);
+ }
+
+ private void postAndWaitForRunnable(Runnable r) {
+ final ConditionVariable cv = new ConditionVariable();
+ if (mHandler.post(() -> {
+ r.run();
+ cv.open();
+ })) {
+ cv.block(2000L);
+ }
+ }
+
+ @VisibleForTesting(visibility = PACKAGE)
+ protected void setEthernetEnabled(boolean enabled) {
+ mHandler.post(() -> {
+ int newState = enabled ? ETHERNET_STATE_ENABLED : ETHERNET_STATE_DISABLED;
+ if (mEthernetState == newState) return;
+
+ mEthernetState = newState;
+
+ if (enabled) {
+ trackAvailableInterfaces();
+ } else {
+ // TODO: maybe also disable server mode interface as well.
+ untrackFactoryInterfaces();
+ }
+ broadcastEthernetStateChange(mEthernetState);
+ });
+ }
+
+ private void untrackFactoryInterfaces() {
+ for (String iface : mFactory.getAvailableInterfaces(true /* includeRestricted */)) {
+ stopTrackingInterface(iface);
+ }
+ }
+
+ private void unicastEthernetStateChange(@NonNull IEthernetServiceListener listener,
+ int state) {
+ ensureRunningOnEthernetServiceThread();
+ try {
+ listener.onEthernetStateChanged(state);
+ } catch (RemoteException e) {
+ // Do nothing here.
+ }
+ }
+
+ private void broadcastEthernetStateChange(int state) {
+ ensureRunningOnEthernetServiceThread();
+ final int n = mListeners.beginBroadcast();
+ for (int i = 0; i < n; i++) {
+ try {
+ mListeners.getBroadcastItem(i).onEthernetStateChanged(state);
+ } catch (RemoteException e) {
+ // Do nothing here.
+ }
+ }
+ mListeners.finishBroadcast();
+ }
+
+ void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
+ postAndWaitForRunnable(() -> {
+ pw.println(getClass().getSimpleName());
+ pw.println("Ethernet interface name filter: " + mIfaceMatch);
+ pw.println("Default interface: " + mDefaultInterface);
+ pw.println("Default interface mode: " + mDefaultInterfaceMode);
+ pw.println("Tethered interface requests: "
+ + mTetheredInterfaceRequests.getRegisteredCallbackCount());
+ pw.println("Listeners: " + mListeners.getRegisteredCallbackCount());
+ pw.println("IP Configurations:");
+ pw.increaseIndent();
+ for (String iface : mIpConfigurations.keySet()) {
+ pw.println(iface + ": " + mIpConfigurations.get(iface));
+ }
+ pw.decreaseIndent();
+ pw.println();
+
+ pw.println("Network Capabilities:");
+ pw.increaseIndent();
+ for (String iface : mNetworkCapabilities.keySet()) {
+ pw.println(iface + ": " + mNetworkCapabilities.get(iface));
+ }
+ pw.decreaseIndent();
+ pw.println();
+
+ mFactory.dump(fd, pw, args);
+ });
+ }
+
+ @VisibleForTesting
+ static class EthernetTrackerConfig {
+ final String mIface;
+ final String mCapabilities;
+ final String mIpConfig;
+ final String mTransport;
+
+ EthernetTrackerConfig(@NonNull final String[] tokens) {
+ Objects.requireNonNull(tokens, "EthernetTrackerConfig requires non-null tokens");
+ mIface = tokens[0];
+ mCapabilities = tokens.length > 1 ? tokens[1] : null;
+ mIpConfig = tokens.length > 2 && !TextUtils.isEmpty(tokens[2]) ? tokens[2] : null;
+ mTransport = tokens.length > 3 ? tokens[3] : null;
+ }
+ }
+}
diff --git a/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java b/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java
index b761762..ce955fd 100644
--- a/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java
+++ b/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java
@@ -19,8 +19,6 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static com.android.networkstack.apishim.ConstantsShim.RECEIVER_NOT_EXPORTED;
-
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -160,7 +158,7 @@
private void registerForCarrierChanges() {
final IntentFilter filter = new IntentFilter();
filter.addAction(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED);
- mContext.registerReceiver(this, filter, null, mHandler, RECEIVER_NOT_EXPORTED /* flags */);
+ mContext.registerReceiver(this, filter, null, mHandler);
registerCarrierPrivilegesListeners();
}
diff --git a/tests/ethernet/Android.bp b/tests/ethernet/Android.bp
new file mode 100644
index 0000000..8342490
--- /dev/null
+++ b/tests/ethernet/Android.bp
@@ -0,0 +1,52 @@
+// 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 {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+// TODO: merge the tests into service-connectivity tests after
+// ethernet service migration completes. So far just import the
+// ethernet service source to fix the dependencies.
+android_test {
+ name: "EthernetServiceTests",
+
+ srcs: [
+ ":ethernet-service-test-sources",
+ "java/**/*.java",
+ ],
+
+ certificate: "platform",
+ platform_apis: true,
+
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ "framework-connectivity.impl",
+ "framework-connectivity-t.impl",
+ "ServiceConnectivityResources",
+ ],
+
+ static_libs: [
+ "androidx.test.rules",
+ "frameworks-base-testutils",
+ "mockito-target-minus-junit4",
+ "net-tests-utils",
+ "services.core",
+ "services.net",
+ ],
+ test_suites: ["general-tests"],
+}
diff --git a/tests/ethernet/AndroidManifest.xml b/tests/ethernet/AndroidManifest.xml
new file mode 100644
index 0000000..cd875b0
--- /dev/null
+++ b/tests/ethernet/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.ethernet.tests">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.ethernet.tests"
+ android:label="Ethernet Service Tests" />
+</manifest>
diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java
new file mode 100644
index 0000000..4d3e4d3
--- /dev/null
+++ b/tests/ethernet/java/com/android/server/ethernet/EthernetNetworkFactoryTest.java
@@ -0,0 +1,783 @@
+/*
+ * Copyright (C) 2020 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.ethernet;
+
+import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.app.test.MockAnswerUtil.AnswerWithArguments;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.EthernetNetworkSpecifier;
+import android.net.EthernetNetworkManagementException;
+import android.net.INetworkInterfaceOutcomeReceiver;
+import android.net.IpConfiguration;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkAgentConfig;
+import android.net.NetworkCapabilities;
+import android.net.NetworkProvider;
+import android.net.NetworkRequest;
+import android.net.StaticIpConfiguration;
+import android.net.ip.IpClientCallbacks;
+import android.net.ip.IpClientManager;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.test.TestLooper;
+import android.util.Pair;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.connectivity.resources.R;
+import com.android.net.module.util.InterfaceParams;
+
+import com.android.testutils.DevSdkIgnoreRule;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class EthernetNetworkFactoryTest {
+ private static final int TIMEOUT_MS = 2_000;
+ private static final String TEST_IFACE = "test123";
+ private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null;
+ private static final String IP_ADDR = "192.0.2.2/25";
+ private static final LinkAddress LINK_ADDR = new LinkAddress(IP_ADDR);
+ private static final String HW_ADDR = "01:02:03:04:05:06";
+ private TestLooper mLooper;
+ private Handler mHandler;
+ private EthernetNetworkFactory mNetFactory = null;
+ private IpClientCallbacks mIpClientCallbacks;
+ @Mock private Context mContext;
+ @Mock private Resources mResources;
+ @Mock private EthernetNetworkFactory.Dependencies mDeps;
+ @Mock private IpClientManager mIpClient;
+ @Mock private EthernetNetworkAgent mNetworkAgent;
+ @Mock private InterfaceParams mInterfaceParams;
+ @Mock private Network mMockNetwork;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ setupNetworkAgentMock();
+ setupIpClientMock();
+ setupContext();
+ }
+
+ //TODO: Move away from usage of TestLooper in order to move this logic back into @Before.
+ private void initEthernetNetworkFactory() {
+ mLooper = new TestLooper();
+ mHandler = new Handler(mLooper.getLooper());
+ mNetFactory = new EthernetNetworkFactory(mHandler, mContext, mDeps);
+ }
+
+ private void setupNetworkAgentMock() {
+ when(mDeps.makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any()))
+ .thenAnswer(new AnswerWithArguments() {
+ public EthernetNetworkAgent answer(
+ Context context,
+ Looper looper,
+ NetworkCapabilities nc,
+ LinkProperties lp,
+ NetworkAgentConfig config,
+ NetworkProvider provider,
+ EthernetNetworkAgent.Callbacks cb) {
+ when(mNetworkAgent.getCallbacks()).thenReturn(cb);
+ when(mNetworkAgent.getNetwork())
+ .thenReturn(mMockNetwork);
+ return mNetworkAgent;
+ }
+ }
+ );
+ }
+
+ private void setupIpClientMock() throws Exception {
+ doAnswer(inv -> {
+ // these tests only support one concurrent IpClient, so make sure we do not accidentally
+ // create a mess.
+ assertNull("An IpClient has already been created.", mIpClientCallbacks);
+
+ mIpClientCallbacks = inv.getArgument(2);
+ mIpClientCallbacks.onIpClientCreated(null);
+ mLooper.dispatchAll();
+ return null;
+ }).when(mDeps).makeIpClient(any(Context.class), anyString(), any());
+
+ doAnswer(inv -> {
+ mIpClientCallbacks.onQuit();
+ mLooper.dispatchAll();
+ mIpClientCallbacks = null;
+ return null;
+ }).when(mIpClient).shutdown();
+
+ when(mDeps.makeIpClientManager(any())).thenReturn(mIpClient);
+ }
+
+ private void triggerOnProvisioningSuccess() {
+ mIpClientCallbacks.onProvisioningSuccess(new LinkProperties());
+ mLooper.dispatchAll();
+ }
+
+ private void triggerOnProvisioningFailure() {
+ mIpClientCallbacks.onProvisioningFailure(new LinkProperties());
+ mLooper.dispatchAll();
+ }
+
+ private void triggerOnReachabilityLost() {
+ mIpClientCallbacks.onReachabilityLost("ReachabilityLost");
+ mLooper.dispatchAll();
+ }
+
+ private void setupContext() {
+ when(mDeps.getTcpBufferSizesFromResource(eq(mContext))).thenReturn("");
+ }
+
+ @After
+ public void tearDown() {
+ // looper is shared with the network agents, so there may still be messages to dispatch on
+ // tear down.
+ mLooper.dispatchAll();
+ }
+
+ private NetworkCapabilities createDefaultFilterCaps() {
+ return NetworkCapabilities.Builder.withoutDefaultCapabilities()
+ .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
+ .build();
+ }
+
+ private NetworkCapabilities.Builder createInterfaceCapsBuilder(final int transportType) {
+ return new NetworkCapabilities.Builder()
+ .addTransportType(transportType)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+ }
+
+ private NetworkRequest.Builder createDefaultRequestBuilder() {
+ return new NetworkRequest.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ }
+
+ private NetworkRequest createDefaultRequest() {
+ return createDefaultRequestBuilder().build();
+ }
+
+ private IpConfiguration createDefaultIpConfig() {
+ IpConfiguration ipConfig = new IpConfiguration();
+ ipConfig.setIpAssignment(IpConfiguration.IpAssignment.DHCP);
+ ipConfig.setProxySettings(IpConfiguration.ProxySettings.NONE);
+ return ipConfig;
+ }
+
+ /**
+ * Create an {@link IpConfiguration} with an associated {@link StaticIpConfiguration}.
+ *
+ * @return {@link IpConfiguration} with its {@link StaticIpConfiguration} set.
+ */
+ private IpConfiguration createStaticIpConfig() {
+ final IpConfiguration ipConfig = new IpConfiguration();
+ ipConfig.setIpAssignment(IpConfiguration.IpAssignment.STATIC);
+ ipConfig.setStaticIpConfiguration(
+ new StaticIpConfiguration.Builder().setIpAddress(LINK_ADDR).build());
+ return ipConfig;
+ }
+
+ // creates an interface with provisioning in progress (since updating the interface link state
+ // automatically starts the provisioning process)
+ private void createInterfaceUndergoingProvisioning(String iface) {
+ // Default to the ethernet transport type.
+ createInterfaceUndergoingProvisioning(iface, NetworkCapabilities.TRANSPORT_ETHERNET);
+ }
+
+ private void createInterfaceUndergoingProvisioning(
+ @NonNull final String iface, final int transportType) {
+ final IpConfiguration ipConfig = createDefaultIpConfig();
+ mNetFactory.addInterface(iface, HW_ADDR, ipConfig,
+ createInterfaceCapsBuilder(transportType).build());
+ assertTrue(mNetFactory.updateInterfaceLinkState(iface, true, NULL_LISTENER));
+ verifyStart(ipConfig);
+ clearInvocations(mDeps);
+ clearInvocations(mIpClient);
+ }
+
+ // creates a provisioned interface
+ private void createAndVerifyProvisionedInterface(String iface) throws Exception {
+ // Default to the ethernet transport type.
+ createAndVerifyProvisionedInterface(iface, NetworkCapabilities.TRANSPORT_ETHERNET,
+ ConnectivityManager.TYPE_ETHERNET);
+ }
+
+ private void createVerifyAndRemoveProvisionedInterface(final int transportType,
+ final int expectedLegacyType) throws Exception {
+ createAndVerifyProvisionedInterface(TEST_IFACE, transportType,
+ expectedLegacyType);
+ mNetFactory.removeInterface(TEST_IFACE);
+ }
+
+ private void createAndVerifyProvisionedInterface(
+ @NonNull final String iface, final int transportType, final int expectedLegacyType)
+ throws Exception {
+ createInterfaceUndergoingProvisioning(iface, transportType);
+ triggerOnProvisioningSuccess();
+ // provisioning succeeded, verify that the network agent is created, registered, marked
+ // as connected and legacy type are correctly set.
+ final ArgumentCaptor<NetworkCapabilities> ncCaptor = ArgumentCaptor.forClass(
+ NetworkCapabilities.class);
+ verify(mDeps).makeEthernetNetworkAgent(any(), any(), ncCaptor.capture(), any(),
+ argThat(x -> x.getLegacyType() == expectedLegacyType), any(), any());
+ assertEquals(
+ new EthernetNetworkSpecifier(iface), ncCaptor.getValue().getNetworkSpecifier());
+ verifyNetworkAgentRegistersAndConnects();
+ clearInvocations(mDeps);
+ clearInvocations(mNetworkAgent);
+ }
+
+ // creates an unprovisioned interface
+ private void createUnprovisionedInterface(String iface) throws Exception {
+ // To create an unprovisioned interface, provision and then "stop" it, i.e. stop its
+ // NetworkAgent and IpClient. One way this can be done is by provisioning an interface and
+ // then calling onNetworkUnwanted.
+ createAndVerifyProvisionedInterface(iface);
+
+ mNetworkAgent.getCallbacks().onNetworkUnwanted();
+ mLooper.dispatchAll();
+ verifyStop();
+
+ clearInvocations(mIpClient);
+ clearInvocations(mNetworkAgent);
+ }
+
+ @Test
+ public void testAcceptRequest() throws Exception {
+ initEthernetNetworkFactory();
+ createInterfaceUndergoingProvisioning(TEST_IFACE);
+ assertTrue(mNetFactory.acceptRequest(createDefaultRequest()));
+
+ NetworkRequest wifiRequest = createDefaultRequestBuilder()
+ .removeTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build();
+ assertFalse(mNetFactory.acceptRequest(wifiRequest));
+ }
+
+ @Test
+ public void testUpdateInterfaceLinkStateForActiveProvisioningInterface() throws Exception {
+ initEthernetNetworkFactory();
+ createInterfaceUndergoingProvisioning(TEST_IFACE);
+ final TestNetworkManagementListener listener = new TestNetworkManagementListener();
+
+ // verify that the IpClient gets shut down when interface state changes to down.
+ final boolean ret =
+ mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */, listener);
+
+ assertTrue(ret);
+ verify(mIpClient).shutdown();
+ assertEquals(listener.expectOnResult(), TEST_IFACE);
+ }
+
+ @Test
+ public void testUpdateInterfaceLinkStateForProvisionedInterface() throws Exception {
+ initEthernetNetworkFactory();
+ createAndVerifyProvisionedInterface(TEST_IFACE);
+ final TestNetworkManagementListener listener = new TestNetworkManagementListener();
+
+ final boolean ret =
+ mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */, listener);
+
+ assertTrue(ret);
+ verifyStop();
+ assertEquals(listener.expectOnResult(), TEST_IFACE);
+ }
+
+ @Test
+ public void testUpdateInterfaceLinkStateForUnprovisionedInterface() throws Exception {
+ initEthernetNetworkFactory();
+ createUnprovisionedInterface(TEST_IFACE);
+ final TestNetworkManagementListener listener = new TestNetworkManagementListener();
+
+ final boolean ret =
+ mNetFactory.updateInterfaceLinkState(TEST_IFACE, false /* up */, listener);
+
+ assertTrue(ret);
+ // There should not be an active IPClient or NetworkAgent.
+ verify(mDeps, never()).makeIpClient(any(), any(), any());
+ verify(mDeps, never())
+ .makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any());
+ assertEquals(listener.expectOnResult(), TEST_IFACE);
+ }
+
+ @Test
+ public void testUpdateInterfaceLinkStateForNonExistingInterface() throws Exception {
+ initEthernetNetworkFactory();
+ final TestNetworkManagementListener listener = new TestNetworkManagementListener();
+
+ // if interface was never added, link state cannot be updated.
+ final boolean ret =
+ mNetFactory.updateInterfaceLinkState(TEST_IFACE, true /* up */, listener);
+
+ assertFalse(ret);
+ verifyNoStopOrStart();
+ listener.expectOnErrorWithMessage("can't be updated as it is not available");
+ }
+
+ @Test
+ public void testUpdateInterfaceLinkStateWithNoChanges() throws Exception {
+ initEthernetNetworkFactory();
+ createAndVerifyProvisionedInterface(TEST_IFACE);
+ final TestNetworkManagementListener listener = new TestNetworkManagementListener();
+
+ final boolean ret =
+ mNetFactory.updateInterfaceLinkState(TEST_IFACE, true /* up */, listener);
+
+ assertFalse(ret);
+ verifyNoStopOrStart();
+ listener.expectOnErrorWithMessage("No changes");
+ }
+
+ @Test
+ public void testNeedNetworkForOnProvisionedInterface() throws Exception {
+ initEthernetNetworkFactory();
+ createAndVerifyProvisionedInterface(TEST_IFACE);
+ mNetFactory.needNetworkFor(createDefaultRequest());
+ verify(mIpClient, never()).startProvisioning(any());
+ }
+
+ @Test
+ public void testNeedNetworkForOnUnprovisionedInterface() throws Exception {
+ initEthernetNetworkFactory();
+ createUnprovisionedInterface(TEST_IFACE);
+ mNetFactory.needNetworkFor(createDefaultRequest());
+ verify(mIpClient).startProvisioning(any());
+
+ triggerOnProvisioningSuccess();
+ verifyNetworkAgentRegistersAndConnects();
+ }
+
+ @Test
+ public void testNeedNetworkForOnInterfaceUndergoingProvisioning() throws Exception {
+ initEthernetNetworkFactory();
+ createInterfaceUndergoingProvisioning(TEST_IFACE);
+ mNetFactory.needNetworkFor(createDefaultRequest());
+ verify(mIpClient, never()).startProvisioning(any());
+
+ triggerOnProvisioningSuccess();
+ verifyNetworkAgentRegistersAndConnects();
+ }
+
+ @Test
+ public void testProvisioningLoss() throws Exception {
+ initEthernetNetworkFactory();
+ when(mDeps.getNetworkInterfaceByName(TEST_IFACE)).thenReturn(mInterfaceParams);
+ createAndVerifyProvisionedInterface(TEST_IFACE);
+
+ triggerOnProvisioningFailure();
+ verifyStop();
+ // provisioning loss should trigger a retry, since the interface is still there
+ verify(mIpClient).startProvisioning(any());
+ }
+
+ @Test
+ public void testProvisioningLossForDisappearedInterface() throws Exception {
+ initEthernetNetworkFactory();
+ // mocked method returns null by default, but just to be explicit in the test:
+ when(mDeps.getNetworkInterfaceByName(eq(TEST_IFACE))).thenReturn(null);
+
+ createAndVerifyProvisionedInterface(TEST_IFACE);
+ triggerOnProvisioningFailure();
+
+ // the interface disappeared and getNetworkInterfaceByName returns null, we should not retry
+ verify(mIpClient, never()).startProvisioning(any());
+ verifyNoStopOrStart();
+ }
+
+ private void verifyNoStopOrStart() {
+ verify(mNetworkAgent, never()).register();
+ verify(mIpClient, never()).shutdown();
+ verify(mNetworkAgent, never()).unregister();
+ verify(mIpClient, never()).startProvisioning(any());
+ }
+
+ @Test
+ public void testIpClientIsNotStartedWhenLinkIsDown() throws Exception {
+ initEthernetNetworkFactory();
+ createUnprovisionedInterface(TEST_IFACE);
+ mNetFactory.updateInterfaceLinkState(TEST_IFACE, false, NULL_LISTENER);
+
+ mNetFactory.needNetworkFor(createDefaultRequest());
+
+ verify(mDeps, never()).makeIpClient(any(), any(), any());
+
+ // BUG(b/191854824): requesting a network with a specifier (Android Auto use case) should
+ // not start an IpClient when the link is down, but fixing this may make matters worse by
+ // tiggering b/197548738.
+ NetworkRequest specificNetRequest = new NetworkRequest.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
+ .setNetworkSpecifier(new EthernetNetworkSpecifier(TEST_IFACE))
+ .build();
+ mNetFactory.needNetworkFor(specificNetRequest);
+ mNetFactory.releaseNetworkFor(specificNetRequest);
+
+ mNetFactory.updateInterfaceLinkState(TEST_IFACE, true, NULL_LISTENER);
+ // TODO: change to once when b/191854824 is fixed.
+ verify(mDeps, times(2)).makeIpClient(any(), eq(TEST_IFACE), any());
+ }
+
+ @Test
+ public void testLinkPropertiesChanged() throws Exception {
+ initEthernetNetworkFactory();
+ createAndVerifyProvisionedInterface(TEST_IFACE);
+
+ LinkProperties lp = new LinkProperties();
+ mIpClientCallbacks.onLinkPropertiesChange(lp);
+ mLooper.dispatchAll();
+ verify(mNetworkAgent).sendLinkPropertiesImpl(same(lp));
+ }
+
+ @Test
+ public void testNetworkUnwanted() throws Exception {
+ initEthernetNetworkFactory();
+ createAndVerifyProvisionedInterface(TEST_IFACE);
+
+ mNetworkAgent.getCallbacks().onNetworkUnwanted();
+ mLooper.dispatchAll();
+ verifyStop();
+ }
+
+ @Test
+ public void testNetworkUnwantedWithStaleNetworkAgent() throws Exception {
+ initEthernetNetworkFactory();
+ // ensures provisioning is restarted after provisioning loss
+ when(mDeps.getNetworkInterfaceByName(TEST_IFACE)).thenReturn(mInterfaceParams);
+ createAndVerifyProvisionedInterface(TEST_IFACE);
+
+ EthernetNetworkAgent.Callbacks oldCbs = mNetworkAgent.getCallbacks();
+ // replace network agent in EthernetNetworkFactory
+ // Loss of provisioning will restart the ip client and network agent.
+ triggerOnProvisioningFailure();
+ verify(mDeps).makeIpClient(any(), any(), any());
+
+ triggerOnProvisioningSuccess();
+ verify(mDeps).makeEthernetNetworkAgent(any(), any(), any(), any(), any(), any(), any());
+
+ // verify that unwanted is ignored
+ clearInvocations(mIpClient);
+ clearInvocations(mNetworkAgent);
+ oldCbs.onNetworkUnwanted();
+ verify(mIpClient, never()).shutdown();
+ verify(mNetworkAgent, never()).unregister();
+ }
+
+ @Test
+ public void testTransportOverrideIsCorrectlySet() throws Exception {
+ initEthernetNetworkFactory();
+ // createProvisionedInterface() has verifications in place for transport override
+ // functionality which for EthernetNetworkFactory is network score and legacy type mappings.
+ createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_ETHERNET,
+ ConnectivityManager.TYPE_ETHERNET);
+ createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_BLUETOOTH,
+ ConnectivityManager.TYPE_BLUETOOTH);
+ createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_WIFI,
+ ConnectivityManager.TYPE_WIFI);
+ createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_CELLULAR,
+ ConnectivityManager.TYPE_MOBILE);
+ createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_LOWPAN,
+ ConnectivityManager.TYPE_NONE);
+ createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_WIFI_AWARE,
+ ConnectivityManager.TYPE_NONE);
+ createVerifyAndRemoveProvisionedInterface(NetworkCapabilities.TRANSPORT_TEST,
+ ConnectivityManager.TYPE_NONE);
+ }
+
+ @Test
+ public void testReachabilityLoss() throws Exception {
+ initEthernetNetworkFactory();
+ createAndVerifyProvisionedInterface(TEST_IFACE);
+
+ triggerOnReachabilityLost();
+
+ // Reachability loss should trigger a stop and start, since the interface is still there
+ verifyRestart(createDefaultIpConfig());
+ }
+
+ private IpClientCallbacks getStaleIpClientCallbacks() throws Exception {
+ createAndVerifyProvisionedInterface(TEST_IFACE);
+ final IpClientCallbacks staleIpClientCallbacks = mIpClientCallbacks;
+ mNetFactory.removeInterface(TEST_IFACE);
+ verifyStop();
+ assertNotSame(mIpClientCallbacks, staleIpClientCallbacks);
+ return staleIpClientCallbacks;
+ }
+
+ @Test
+ public void testIgnoreOnIpLayerStartedCallbackForStaleCallback() throws Exception {
+ initEthernetNetworkFactory();
+ final IpClientCallbacks staleIpClientCallbacks = getStaleIpClientCallbacks();
+
+ staleIpClientCallbacks.onProvisioningSuccess(new LinkProperties());
+ mLooper.dispatchAll();
+
+ verify(mIpClient, never()).startProvisioning(any());
+ verify(mNetworkAgent, never()).register();
+ }
+
+ @Test
+ public void testIgnoreOnIpLayerStoppedCallbackForStaleCallback() throws Exception {
+ initEthernetNetworkFactory();
+ when(mDeps.getNetworkInterfaceByName(TEST_IFACE)).thenReturn(mInterfaceParams);
+ final IpClientCallbacks staleIpClientCallbacks = getStaleIpClientCallbacks();
+
+ staleIpClientCallbacks.onProvisioningFailure(new LinkProperties());
+ mLooper.dispatchAll();
+
+ verify(mIpClient, never()).startProvisioning(any());
+ }
+
+ @Test
+ public void testIgnoreLinkPropertiesCallbackForStaleCallback() throws Exception {
+ initEthernetNetworkFactory();
+ final IpClientCallbacks staleIpClientCallbacks = getStaleIpClientCallbacks();
+ final LinkProperties lp = new LinkProperties();
+
+ staleIpClientCallbacks.onLinkPropertiesChange(lp);
+ mLooper.dispatchAll();
+
+ verify(mNetworkAgent, never()).sendLinkPropertiesImpl(eq(lp));
+ }
+
+ @Test
+ public void testIgnoreNeighborLossCallbackForStaleCallback() throws Exception {
+ initEthernetNetworkFactory();
+ final IpClientCallbacks staleIpClientCallbacks = getStaleIpClientCallbacks();
+
+ staleIpClientCallbacks.onReachabilityLost("Neighbor Lost");
+ mLooper.dispatchAll();
+
+ verify(mIpClient, never()).startProvisioning(any());
+ verify(mNetworkAgent, never()).register();
+ }
+
+ private void verifyRestart(@NonNull final IpConfiguration ipConfig) {
+ verifyStop();
+ verifyStart(ipConfig);
+ }
+
+ private void verifyStart(@NonNull final IpConfiguration ipConfig) {
+ verify(mDeps).makeIpClient(any(Context.class), anyString(), any());
+ verify(mIpClient).startProvisioning(
+ argThat(x -> Objects.equals(x.mStaticIpConfig, ipConfig.getStaticIpConfiguration()))
+ );
+ }
+
+ private void verifyStop() {
+ verify(mIpClient).shutdown();
+ verify(mNetworkAgent).unregister();
+ }
+
+ private void verifyNetworkAgentRegistersAndConnects() {
+ verify(mNetworkAgent).register();
+ verify(mNetworkAgent).markConnected();
+ }
+
+ private static final class TestNetworkManagementListener
+ implements INetworkInterfaceOutcomeReceiver {
+ private final CompletableFuture<String> mResult = new CompletableFuture<>();
+ private final CompletableFuture<EthernetNetworkManagementException> mError =
+ new CompletableFuture<>();
+
+ @Override
+ public void onResult(@NonNull String iface) {
+ mResult.complete(iface);
+ }
+
+ @Override
+ public void onError(@NonNull EthernetNetworkManagementException exception) {
+ mError.complete(exception);
+ }
+
+ String expectOnResult() throws Exception {
+ return mResult.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ }
+
+ EthernetNetworkManagementException expectOnError() throws Exception {
+ return mError.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ }
+
+ void expectOnErrorWithMessage(String msg) throws Exception {
+ assertTrue(expectOnError().getMessage().contains(msg));
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return null;
+ }
+ }
+
+ @Test
+ public void testUpdateInterfaceCallsListenerCorrectlyOnSuccess() throws Exception {
+ initEthernetNetworkFactory();
+ createAndVerifyProvisionedInterface(TEST_IFACE);
+ final NetworkCapabilities capabilities = createDefaultFilterCaps();
+ final IpConfiguration ipConfiguration = createStaticIpConfig();
+ final TestNetworkManagementListener listener = new TestNetworkManagementListener();
+
+ mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener);
+ triggerOnProvisioningSuccess();
+
+ assertEquals(listener.expectOnResult(), TEST_IFACE);
+ }
+
+ @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available
+ @Test
+ public void testUpdateInterfaceAbortsOnConcurrentRemoveInterface() throws Exception {
+ initEthernetNetworkFactory();
+ verifyNetworkManagementCallIsAbortedWhenInterrupted(
+ TEST_IFACE,
+ () -> mNetFactory.removeInterface(TEST_IFACE));
+ }
+
+ @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available
+ @Test
+ public void testUpdateInterfaceAbortsOnConcurrentUpdateInterfaceLinkState() throws Exception {
+ initEthernetNetworkFactory();
+ verifyNetworkManagementCallIsAbortedWhenInterrupted(
+ TEST_IFACE,
+ () -> mNetFactory.updateInterfaceLinkState(TEST_IFACE, false, NULL_LISTENER));
+ }
+
+ @DevSdkIgnoreRule.IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available
+ @Test
+ public void testUpdateInterfaceCallsListenerCorrectlyOnConcurrentRequests() throws Exception {
+ initEthernetNetworkFactory();
+ final NetworkCapabilities capabilities = createDefaultFilterCaps();
+ final IpConfiguration ipConfiguration = createStaticIpConfig();
+ final TestNetworkManagementListener successfulListener =
+ new TestNetworkManagementListener();
+
+ // If two calls come in before the first one completes, the first listener will be aborted
+ // and the second one will be successful.
+ verifyNetworkManagementCallIsAbortedWhenInterrupted(
+ TEST_IFACE,
+ () -> {
+ mNetFactory.updateInterface(
+ TEST_IFACE, ipConfiguration, capabilities, successfulListener);
+ triggerOnProvisioningSuccess();
+ });
+
+ assertEquals(successfulListener.expectOnResult(), TEST_IFACE);
+ }
+
+ private void verifyNetworkManagementCallIsAbortedWhenInterrupted(
+ @NonNull final String iface,
+ @NonNull final Runnable interruptingRunnable) throws Exception {
+ createAndVerifyProvisionedInterface(iface);
+ final NetworkCapabilities capabilities = createDefaultFilterCaps();
+ final IpConfiguration ipConfiguration = createStaticIpConfig();
+ final TestNetworkManagementListener failedListener = new TestNetworkManagementListener();
+
+ // An active update request will be aborted on interrupt prior to provisioning completion.
+ mNetFactory.updateInterface(iface, ipConfiguration, capabilities, failedListener);
+ interruptingRunnable.run();
+
+ failedListener.expectOnErrorWithMessage("aborted");
+ }
+
+ @Test
+ public void testUpdateInterfaceRestartsAgentCorrectly() throws Exception {
+ initEthernetNetworkFactory();
+ createAndVerifyProvisionedInterface(TEST_IFACE);
+ final NetworkCapabilities capabilities = createDefaultFilterCaps();
+ final IpConfiguration ipConfiguration = createStaticIpConfig();
+ final TestNetworkManagementListener listener = new TestNetworkManagementListener();
+
+ mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener);
+ triggerOnProvisioningSuccess();
+
+ assertEquals(listener.expectOnResult(), TEST_IFACE);
+ verify(mDeps).makeEthernetNetworkAgent(any(), any(),
+ eq(capabilities), any(), any(), any(), any());
+ verifyRestart(ipConfiguration);
+ }
+
+ @Test
+ public void testUpdateInterfaceForNonExistingInterface() throws Exception {
+ initEthernetNetworkFactory();
+ // No interface exists due to not calling createAndVerifyProvisionedInterface(...).
+ final NetworkCapabilities capabilities = createDefaultFilterCaps();
+ final IpConfiguration ipConfiguration = createStaticIpConfig();
+ final TestNetworkManagementListener listener = new TestNetworkManagementListener();
+
+ mNetFactory.updateInterface(TEST_IFACE, ipConfiguration, capabilities, listener);
+
+ verifyNoStopOrStart();
+ listener.expectOnErrorWithMessage("can't be updated as it is not available");
+ }
+
+ @Test
+ public void testUpdateInterfaceWithNullIpConfiguration() throws Exception {
+ initEthernetNetworkFactory();
+ createAndVerifyProvisionedInterface(TEST_IFACE);
+
+ final IpConfiguration initialIpConfig = createStaticIpConfig();
+ mNetFactory.updateInterface(TEST_IFACE, initialIpConfig, null /*capabilities*/,
+ null /*listener*/);
+ triggerOnProvisioningSuccess();
+ verifyRestart(initialIpConfig);
+
+ // TODO: have verifyXyz functions clear invocations.
+ clearInvocations(mDeps);
+ clearInvocations(mIpClient);
+ clearInvocations(mNetworkAgent);
+
+
+ // verify that sending a null ipConfig does not update the current ipConfig.
+ mNetFactory.updateInterface(TEST_IFACE, null /*ipConfig*/, null /*capabilities*/,
+ null /*listener*/);
+ triggerOnProvisioningSuccess();
+ verifyRestart(initialIpConfig);
+ }
+}
diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java
new file mode 100644
index 0000000..dd1f1ed
--- /dev/null
+++ b/tests/ethernet/java/com/android/server/ethernet/EthernetServiceImplTest.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.ethernet;
+
+import static android.net.NetworkCapabilities.TRANSPORT_TEST;
+
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.fail;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.INetworkInterfaceOutcomeReceiver;
+import android.net.EthernetNetworkUpdateRequest;
+import android.net.IpConfiguration;
+import android.net.NetworkCapabilities;
+import android.os.Handler;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class EthernetServiceImplTest {
+ private static final String TEST_IFACE = "test123";
+ private static final EthernetNetworkUpdateRequest UPDATE_REQUEST =
+ new EthernetNetworkUpdateRequest.Builder()
+ .setIpConfiguration(new IpConfiguration())
+ .setNetworkCapabilities(new NetworkCapabilities.Builder().build())
+ .build();
+ private static final EthernetNetworkUpdateRequest UPDATE_REQUEST_WITHOUT_CAPABILITIES =
+ new EthernetNetworkUpdateRequest.Builder()
+ .setIpConfiguration(new IpConfiguration())
+ .build();
+ private static final EthernetNetworkUpdateRequest UPDATE_REQUEST_WITHOUT_IP_CONFIG =
+ new EthernetNetworkUpdateRequest.Builder()
+ .setNetworkCapabilities(new NetworkCapabilities.Builder().build())
+ .build();
+ private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null;
+ private EthernetServiceImpl mEthernetServiceImpl;
+ @Mock private Context mContext;
+ @Mock private Handler mHandler;
+ @Mock private EthernetTracker mEthernetTracker;
+ @Mock private PackageManager mPackageManager;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ doReturn(mPackageManager).when(mContext).getPackageManager();
+ mEthernetServiceImpl = new EthernetServiceImpl(mContext, mHandler, mEthernetTracker);
+ mEthernetServiceImpl.mStarted.set(true);
+ toggleAutomotiveFeature(true);
+ shouldTrackIface(TEST_IFACE, true);
+ }
+
+ private void toggleAutomotiveFeature(final boolean isEnabled) {
+ doReturn(isEnabled)
+ .when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+ }
+
+ private void shouldTrackIface(@NonNull final String iface, final boolean shouldTrack) {
+ doReturn(shouldTrack).when(mEthernetTracker).isTrackingInterface(iface);
+ }
+
+ @Test
+ public void testSetConfigurationRejectsWhenEthNotStarted() {
+ mEthernetServiceImpl.mStarted.set(false);
+ assertThrows(IllegalStateException.class, () -> {
+ mEthernetServiceImpl.setConfiguration("" /* iface */, new IpConfiguration());
+ });
+ }
+
+ @Test
+ public void testUpdateConfigurationRejectsWhenEthNotStarted() {
+ mEthernetServiceImpl.mStarted.set(false);
+ assertThrows(IllegalStateException.class, () -> {
+ mEthernetServiceImpl.updateConfiguration(
+ "" /* iface */, UPDATE_REQUEST, null /* listener */);
+ });
+ }
+
+ @Test
+ public void testConnectNetworkRejectsWhenEthNotStarted() {
+ mEthernetServiceImpl.mStarted.set(false);
+ assertThrows(IllegalStateException.class, () -> {
+ mEthernetServiceImpl.connectNetwork("" /* iface */, null /* listener */);
+ });
+ }
+
+ @Test
+ public void testDisconnectNetworkRejectsWhenEthNotStarted() {
+ mEthernetServiceImpl.mStarted.set(false);
+ assertThrows(IllegalStateException.class, () -> {
+ mEthernetServiceImpl.disconnectNetwork("" /* iface */, null /* listener */);
+ });
+ }
+
+ @Test
+ public void testUpdateConfigurationRejectsNullIface() {
+ assertThrows(NullPointerException.class, () -> {
+ mEthernetServiceImpl.updateConfiguration(null, UPDATE_REQUEST, NULL_LISTENER);
+ });
+ }
+
+ @Test
+ public void testConnectNetworkRejectsNullIface() {
+ assertThrows(NullPointerException.class, () -> {
+ mEthernetServiceImpl.connectNetwork(null /* iface */, NULL_LISTENER);
+ });
+ }
+
+ @Test
+ public void testDisconnectNetworkRejectsNullIface() {
+ assertThrows(NullPointerException.class, () -> {
+ mEthernetServiceImpl.disconnectNetwork(null /* iface */, NULL_LISTENER);
+ });
+ }
+
+ @Test
+ public void testUpdateConfigurationWithCapabilitiesRejectsWithoutAutomotiveFeature() {
+ toggleAutomotiveFeature(false);
+ assertThrows(UnsupportedOperationException.class, () -> {
+ mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER);
+ });
+ }
+
+ @Test
+ public void testUpdateConfigurationWithCapabilitiesWithAutomotiveFeature() {
+ toggleAutomotiveFeature(false);
+ mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST_WITHOUT_CAPABILITIES,
+ NULL_LISTENER);
+ verify(mEthernetTracker).updateConfiguration(eq(TEST_IFACE),
+ eq(UPDATE_REQUEST_WITHOUT_CAPABILITIES.getIpConfiguration()),
+ eq(UPDATE_REQUEST_WITHOUT_CAPABILITIES.getNetworkCapabilities()), isNull());
+ }
+
+ @Test
+ public void testConnectNetworkRejectsWithoutAutomotiveFeature() {
+ toggleAutomotiveFeature(false);
+ assertThrows(UnsupportedOperationException.class, () -> {
+ mEthernetServiceImpl.connectNetwork("" /* iface */, NULL_LISTENER);
+ });
+ }
+
+ @Test
+ public void testDisconnectNetworkRejectsWithoutAutomotiveFeature() {
+ toggleAutomotiveFeature(false);
+ assertThrows(UnsupportedOperationException.class, () -> {
+ mEthernetServiceImpl.disconnectNetwork("" /* iface */, NULL_LISTENER);
+ });
+ }
+
+ private void denyManageEthPermission() {
+ doThrow(new SecurityException("")).when(mContext)
+ .enforceCallingOrSelfPermission(
+ eq(Manifest.permission.MANAGE_ETHERNET_NETWORKS), anyString());
+ }
+
+ private void denyManageTestNetworksPermission() {
+ doThrow(new SecurityException("")).when(mContext)
+ .enforceCallingOrSelfPermission(
+ eq(Manifest.permission.MANAGE_TEST_NETWORKS), anyString());
+ }
+
+ @Test
+ public void testUpdateConfigurationRejectsWithoutManageEthPermission() {
+ denyManageEthPermission();
+ assertThrows(SecurityException.class, () -> {
+ mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER);
+ });
+ }
+
+ @Test
+ public void testConnectNetworkRejectsWithoutManageEthPermission() {
+ denyManageEthPermission();
+ assertThrows(SecurityException.class, () -> {
+ mEthernetServiceImpl.connectNetwork(TEST_IFACE, NULL_LISTENER);
+ });
+ }
+
+ @Test
+ public void testDisconnectNetworkRejectsWithoutManageEthPermission() {
+ denyManageEthPermission();
+ assertThrows(SecurityException.class, () -> {
+ mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, NULL_LISTENER);
+ });
+ }
+
+ private void enableTestInterface() {
+ when(mEthernetTracker.isValidTestInterface(eq(TEST_IFACE))).thenReturn(true);
+ }
+
+ @Test
+ public void testUpdateConfigurationRejectsTestRequestWithoutTestPermission() {
+ enableTestInterface();
+ denyManageTestNetworksPermission();
+ assertThrows(SecurityException.class, () -> {
+ mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER);
+ });
+ }
+
+ @Test
+ public void testConnectNetworkRejectsTestRequestWithoutTestPermission() {
+ enableTestInterface();
+ denyManageTestNetworksPermission();
+ assertThrows(SecurityException.class, () -> {
+ mEthernetServiceImpl.connectNetwork(TEST_IFACE, NULL_LISTENER);
+ });
+ }
+
+ @Test
+ public void testDisconnectNetworkRejectsTestRequestWithoutTestPermission() {
+ enableTestInterface();
+ denyManageTestNetworksPermission();
+ assertThrows(SecurityException.class, () -> {
+ mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, NULL_LISTENER);
+ });
+ }
+
+ @Test
+ public void testUpdateConfiguration() {
+ mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER);
+ verify(mEthernetTracker).updateConfiguration(
+ eq(TEST_IFACE),
+ eq(UPDATE_REQUEST.getIpConfiguration()),
+ eq(UPDATE_REQUEST.getNetworkCapabilities()), eq(NULL_LISTENER));
+ }
+
+ @Test
+ public void testConnectNetwork() {
+ mEthernetServiceImpl.connectNetwork(TEST_IFACE, NULL_LISTENER);
+ verify(mEthernetTracker).connectNetwork(eq(TEST_IFACE), eq(NULL_LISTENER));
+ }
+
+ @Test
+ public void testDisconnectNetwork() {
+ mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, NULL_LISTENER);
+ verify(mEthernetTracker).disconnectNetwork(eq(TEST_IFACE), eq(NULL_LISTENER));
+ }
+
+ @Test
+ public void testUpdateConfigurationAcceptsTestRequestWithNullCapabilities() {
+ enableTestInterface();
+ final EthernetNetworkUpdateRequest request =
+ new EthernetNetworkUpdateRequest
+ .Builder()
+ .setIpConfiguration(new IpConfiguration()).build();
+ mEthernetServiceImpl.updateConfiguration(TEST_IFACE, request, NULL_LISTENER);
+ verify(mEthernetTracker).updateConfiguration(eq(TEST_IFACE),
+ eq(request.getIpConfiguration()),
+ eq(request.getNetworkCapabilities()), isNull());
+ }
+
+ @Test
+ public void testUpdateConfigurationAcceptsRequestWithNullIpConfiguration() {
+ mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST_WITHOUT_IP_CONFIG,
+ NULL_LISTENER);
+ verify(mEthernetTracker).updateConfiguration(eq(TEST_IFACE),
+ eq(UPDATE_REQUEST_WITHOUT_IP_CONFIG.getIpConfiguration()),
+ eq(UPDATE_REQUEST_WITHOUT_IP_CONFIG.getNetworkCapabilities()), isNull());
+ }
+
+ @Test
+ public void testUpdateConfigurationRejectsInvalidTestRequest() {
+ enableTestInterface();
+ assertThrows(IllegalArgumentException.class, () -> {
+ mEthernetServiceImpl.updateConfiguration(TEST_IFACE, UPDATE_REQUEST, NULL_LISTENER);
+ });
+ }
+
+ private EthernetNetworkUpdateRequest createTestNetworkUpdateRequest() {
+ final NetworkCapabilities nc = new NetworkCapabilities
+ .Builder(UPDATE_REQUEST.getNetworkCapabilities())
+ .addTransportType(TRANSPORT_TEST).build();
+
+ return new EthernetNetworkUpdateRequest
+ .Builder(UPDATE_REQUEST)
+ .setNetworkCapabilities(nc).build();
+ }
+
+ @Test
+ public void testUpdateConfigurationForTestRequestDoesNotRequireAutoOrEthernetPermission() {
+ enableTestInterface();
+ toggleAutomotiveFeature(false);
+ denyManageEthPermission();
+ final EthernetNetworkUpdateRequest request = createTestNetworkUpdateRequest();
+
+ mEthernetServiceImpl.updateConfiguration(TEST_IFACE, request, NULL_LISTENER);
+ verify(mEthernetTracker).updateConfiguration(
+ eq(TEST_IFACE),
+ eq(request.getIpConfiguration()),
+ eq(request.getNetworkCapabilities()), eq(NULL_LISTENER));
+ }
+
+ @Test
+ public void testConnectNetworkForTestRequestDoesNotRequireAutoOrNetPermission() {
+ enableTestInterface();
+ toggleAutomotiveFeature(false);
+ denyManageEthPermission();
+
+ mEthernetServiceImpl.connectNetwork(TEST_IFACE, NULL_LISTENER);
+ verify(mEthernetTracker).connectNetwork(eq(TEST_IFACE), eq(NULL_LISTENER));
+ }
+
+ @Test
+ public void testDisconnectNetworkForTestRequestDoesNotRequireAutoOrNetPermission() {
+ enableTestInterface();
+ toggleAutomotiveFeature(false);
+ denyManageEthPermission();
+
+ mEthernetServiceImpl.disconnectNetwork(TEST_IFACE, NULL_LISTENER);
+ verify(mEthernetTracker).disconnectNetwork(eq(TEST_IFACE), eq(NULL_LISTENER));
+ }
+
+ private void denyPermissions(String... permissions) {
+ for (String permission: permissions) {
+ doReturn(PackageManager.PERMISSION_DENIED).when(mContext)
+ .checkCallingOrSelfPermission(eq(permission));
+ }
+ }
+
+ @Test
+ public void testSetEthernetEnabled() {
+ denyPermissions(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
+ mEthernetServiceImpl.setEthernetEnabled(true);
+ verify(mEthernetTracker).setEthernetEnabled(true);
+ reset(mEthernetTracker);
+
+ denyPermissions(Manifest.permission.NETWORK_STACK);
+ mEthernetServiceImpl.setEthernetEnabled(false);
+ verify(mEthernetTracker).setEthernetEnabled(false);
+ reset(mEthernetTracker);
+
+ denyPermissions(Manifest.permission.NETWORK_SETTINGS);
+ try {
+ mEthernetServiceImpl.setEthernetEnabled(true);
+ fail("Should get SecurityException");
+ } catch (SecurityException e) { }
+ verify(mEthernetTracker, never()).setEthernetEnabled(false);
+ }
+}
diff --git a/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java
new file mode 100644
index 0000000..b1831c4
--- /dev/null
+++ b/tests/ethernet/java/com/android/server/ethernet/EthernetTrackerTest.java
@@ -0,0 +1,456 @@
+/*
+ * 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.ethernet;
+
+import static android.net.TestNetworkManager.TEST_TAP_PREFIX;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.EthernetManager;
+import android.net.InetAddresses;
+import android.net.INetworkInterfaceOutcomeReceiver;
+import android.net.IEthernetServiceListener;
+import android.net.INetd;
+import android.net.IpConfiguration;
+import android.net.IpConfiguration.IpAssignment;
+import android.net.IpConfiguration.ProxySettings;
+import android.net.InterfaceConfigurationParcel;
+import android.net.LinkAddress;
+import android.net.NetworkCapabilities;
+import android.net.StaticIpConfiguration;
+import android.os.HandlerThread;
+import android.os.RemoteException;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.connectivity.resources.R;
+import com.android.testutils.HandlerUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EthernetTrackerTest {
+ private static final String TEST_IFACE = "test123";
+ private static final int TIMEOUT_MS = 1_000;
+ private static final String THREAD_NAME = "EthernetServiceThread";
+ private static final INetworkInterfaceOutcomeReceiver NULL_LISTENER = null;
+ private EthernetTracker tracker;
+ private HandlerThread mHandlerThread;
+ @Mock private Context mContext;
+ @Mock private EthernetNetworkFactory mFactory;
+ @Mock private INetd mNetd;
+ @Mock private EthernetTracker.Dependencies mDeps;
+
+ @Before
+ public void setUp() throws RemoteException {
+ MockitoAnnotations.initMocks(this);
+ initMockResources();
+ when(mFactory.updateInterfaceLinkState(anyString(), anyBoolean(), any())).thenReturn(false);
+ when(mNetd.interfaceGetList()).thenReturn(new String[0]);
+ mHandlerThread = new HandlerThread(THREAD_NAME);
+ mHandlerThread.start();
+ tracker = new EthernetTracker(mContext, mHandlerThread.getThreadHandler(), mFactory, mNetd,
+ mDeps);
+ }
+
+ @After
+ public void cleanUp() {
+ mHandlerThread.quitSafely();
+ }
+
+ private void initMockResources() {
+ when(mDeps.getInterfaceRegexFromResource(eq(mContext))).thenReturn("");
+ when(mDeps.getInterfaceConfigFromResource(eq(mContext))).thenReturn(new String[0]);
+ }
+
+ private void waitForIdle() {
+ HandlerUtils.waitForIdle(mHandlerThread, TIMEOUT_MS);
+ }
+
+ /**
+ * Test: Creation of various valid static IP configurations
+ */
+ @Test
+ public void createStaticIpConfiguration() {
+ // Empty gives default StaticIPConfiguration object
+ assertStaticConfiguration(new StaticIpConfiguration(), "");
+
+ // Setting only the IP address properly cascades and assumes defaults
+ assertStaticConfiguration(new StaticIpConfiguration.Builder()
+ .setIpAddress(new LinkAddress("192.0.2.10/24")).build(), "ip=192.0.2.10/24");
+
+ final ArrayList<InetAddress> dnsAddresses = new ArrayList<>();
+ dnsAddresses.add(InetAddresses.parseNumericAddress("4.4.4.4"));
+ dnsAddresses.add(InetAddresses.parseNumericAddress("8.8.8.8"));
+ // Setting other fields properly cascades them
+ assertStaticConfiguration(new StaticIpConfiguration.Builder()
+ .setIpAddress(new LinkAddress("192.0.2.10/24"))
+ .setDnsServers(dnsAddresses)
+ .setGateway(InetAddresses.parseNumericAddress("192.0.2.1"))
+ .setDomains("android").build(),
+ "ip=192.0.2.10/24 dns=4.4.4.4,8.8.8.8 gateway=192.0.2.1 domains=android");
+
+ // Verify order doesn't matter
+ assertStaticConfiguration(new StaticIpConfiguration.Builder()
+ .setIpAddress(new LinkAddress("192.0.2.10/24"))
+ .setDnsServers(dnsAddresses)
+ .setGateway(InetAddresses.parseNumericAddress("192.0.2.1"))
+ .setDomains("android").build(),
+ "domains=android ip=192.0.2.10/24 gateway=192.0.2.1 dns=4.4.4.4,8.8.8.8 ");
+ }
+
+ /**
+ * Test: Attempt creation of various bad static IP configurations
+ */
+ @Test
+ public void createStaticIpConfiguration_Bad() {
+ assertStaticConfigurationFails("ip=192.0.2.1/24 gateway= blah=20.20.20.20"); // Unknown key
+ assertStaticConfigurationFails("ip=192.0.2.1"); // mask is missing
+ assertStaticConfigurationFails("ip=a.b.c"); // not a valid ip address
+ assertStaticConfigurationFails("dns=4.4.4.4,1.2.3.A"); // not valid ip address in dns
+ assertStaticConfigurationFails("="); // Key and value is empty
+ assertStaticConfigurationFails("ip="); // Value is empty
+ assertStaticConfigurationFails("ip=192.0.2.1/24 gateway="); // Gateway is empty
+ }
+
+ private void assertStaticConfigurationFails(String config) {
+ try {
+ EthernetTracker.parseStaticIpConfiguration(config);
+ fail("Expected to fail: " + config);
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ private void assertStaticConfiguration(StaticIpConfiguration expectedStaticIpConfig,
+ String configAsString) {
+ final IpConfiguration expectedIpConfiguration = new IpConfiguration();
+ expectedIpConfiguration.setIpAssignment(IpAssignment.STATIC);
+ expectedIpConfiguration.setProxySettings(ProxySettings.NONE);
+ expectedIpConfiguration.setStaticIpConfiguration(expectedStaticIpConfig);
+
+ assertEquals(expectedIpConfiguration,
+ EthernetTracker.parseStaticIpConfiguration(configAsString));
+ }
+
+ private NetworkCapabilities.Builder makeEthernetCapabilitiesBuilder(boolean clearAll) {
+ final NetworkCapabilities.Builder builder =
+ clearAll ? NetworkCapabilities.Builder.withoutDefaultCapabilities()
+ : new NetworkCapabilities.Builder();
+ return builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
+ }
+
+ /**
+ * Test: Attempt to create a capabilties with various valid sets of capabilities/transports
+ */
+ @Test
+ public void createNetworkCapabilities() {
+
+ // Particularly common expected results
+ NetworkCapabilities defaultEthernetCleared =
+ makeEthernetCapabilitiesBuilder(true /* clearAll */)
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
+ .build();
+
+ NetworkCapabilities ethernetClearedWithCommonCaps =
+ makeEthernetCapabilitiesBuilder(true /* clearAll */)
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
+ .addCapability(12)
+ .addCapability(13)
+ .addCapability(14)
+ .addCapability(15)
+ .build();
+
+ // Empty capabilities and transports lists with a "please clear defaults" should
+ // yield an empty capabilities set with TRANPORT_ETHERNET
+ assertParsedNetworkCapabilities(defaultEthernetCleared, true, "", "");
+
+ // Empty capabilities and transports without the clear defaults flag should return the
+ // default capabilities set with TRANSPORT_ETHERNET
+ assertParsedNetworkCapabilities(
+ makeEthernetCapabilitiesBuilder(false /* clearAll */)
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
+ .build(),
+ false, "", "");
+
+ // A list of capabilities without the clear defaults flag should return the default
+ // capabilities, mixed with the desired capabilities, and TRANSPORT_ETHERNET
+ assertParsedNetworkCapabilities(
+ makeEthernetCapabilitiesBuilder(false /* clearAll */)
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET)
+ .addCapability(11)
+ .addCapability(12)
+ .build(),
+ false, "11,12", "");
+
+ // Adding a list of capabilities with a clear defaults will leave exactly those capabilities
+ // with a default TRANSPORT_ETHERNET since no overrides are specified
+ assertParsedNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15", "");
+
+ // Adding any invalid capabilities to the list will cause them to be ignored
+ assertParsedNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15,65,73", "");
+ assertParsedNetworkCapabilities(ethernetClearedWithCommonCaps, true, "12,13,14,15,abcdefg", "");
+
+ // Adding a valid override transport will remove the default TRANSPORT_ETHERNET transport
+ // and apply only the override to the capabiltities object
+ assertParsedNetworkCapabilities(
+ makeEthernetCapabilitiesBuilder(true /* clearAll */)
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addTransportType(0)
+ .build(),
+ true, "", "0");
+ assertParsedNetworkCapabilities(
+ makeEthernetCapabilitiesBuilder(true /* clearAll */)
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addTransportType(1)
+ .build(),
+ true, "", "1");
+ assertParsedNetworkCapabilities(
+ makeEthernetCapabilitiesBuilder(true /* clearAll */)
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addTransportType(2)
+ .build(),
+ true, "", "2");
+ assertParsedNetworkCapabilities(
+ makeEthernetCapabilitiesBuilder(true /* clearAll */)
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addTransportType(3)
+ .build(),
+ true, "", "3");
+
+ // "4" is TRANSPORT_VPN, which is unsupported. Should default back to TRANPORT_ETHERNET
+ assertParsedNetworkCapabilities(defaultEthernetCleared, true, "", "4");
+
+ // "5" is TRANSPORT_WIFI_AWARE, which is currently supported due to no legacy TYPE_NONE
+ // conversion. When that becomes available, this test must be updated
+ assertParsedNetworkCapabilities(defaultEthernetCleared, true, "", "5");
+
+ // "6" is TRANSPORT_LOWPAN, which is currently supported due to no legacy TYPE_NONE
+ // conversion. When that becomes available, this test must be updated
+ assertParsedNetworkCapabilities(defaultEthernetCleared, true, "", "6");
+
+ // Adding an invalid override transport will leave the transport as TRANSPORT_ETHERNET
+ assertParsedNetworkCapabilities(defaultEthernetCleared,true, "", "100");
+ assertParsedNetworkCapabilities(defaultEthernetCleared, true, "", "abcdefg");
+
+ // Ensure the adding of both capabilities and transports work
+ assertParsedNetworkCapabilities(
+ makeEthernetCapabilitiesBuilder(true /* clearAll */)
+ .setLinkUpstreamBandwidthKbps(100000)
+ .setLinkDownstreamBandwidthKbps(100000)
+ .addCapability(12)
+ .addCapability(13)
+ .addCapability(14)
+ .addCapability(15)
+ .addTransportType(3)
+ .build(),
+ true, "12,13,14,15", "3");
+
+ // Ensure order does not matter for capability list
+ assertParsedNetworkCapabilities(ethernetClearedWithCommonCaps, true, "13,12,15,14", "");
+ }
+
+ private void assertParsedNetworkCapabilities(NetworkCapabilities expectedNetworkCapabilities,
+ boolean clearCapabilties, String configCapabiltiies,String configTransports) {
+ assertEquals(expectedNetworkCapabilities,
+ EthernetTracker.createNetworkCapabilities(clearCapabilties, configCapabiltiies,
+ configTransports).build());
+ }
+
+ @Test
+ public void testCreateEthernetTrackerConfigReturnsCorrectValue() {
+ final String capabilities = "2";
+ final String ipConfig = "3";
+ final String transport = "4";
+ final String configString = String.join(";", TEST_IFACE, capabilities, ipConfig, transport);
+
+ final EthernetTracker.EthernetTrackerConfig config =
+ EthernetTracker.createEthernetTrackerConfig(configString);
+
+ assertEquals(TEST_IFACE, config.mIface);
+ assertEquals(capabilities, config.mCapabilities);
+ assertEquals(ipConfig, config.mIpConfig);
+ assertEquals(transport, config.mTransport);
+ }
+
+ @Test
+ public void testCreateEthernetTrackerConfigThrowsNpeWithNullInput() {
+ assertThrows(NullPointerException.class,
+ () -> EthernetTracker.createEthernetTrackerConfig(null));
+ }
+
+ @Test
+ public void testUpdateConfiguration() {
+ final NetworkCapabilities capabilities = new NetworkCapabilities.Builder().build();
+ final LinkAddress linkAddr = new LinkAddress("192.0.2.2/25");
+ final StaticIpConfiguration staticIpConfig =
+ new StaticIpConfiguration.Builder().setIpAddress(linkAddr).build();
+ final IpConfiguration ipConfig =
+ new IpConfiguration.Builder().setStaticIpConfiguration(staticIpConfig).build();
+ final INetworkInterfaceOutcomeReceiver listener = null;
+
+ tracker.updateConfiguration(TEST_IFACE, ipConfig, capabilities, listener);
+ waitForIdle();
+
+ verify(mFactory).updateInterface(
+ eq(TEST_IFACE), eq(ipConfig), eq(capabilities), eq(listener));
+ }
+
+ @Test
+ public void testConnectNetworkCorrectlyCallsFactory() {
+ tracker.connectNetwork(TEST_IFACE, NULL_LISTENER);
+ waitForIdle();
+
+ verify(mFactory).updateInterfaceLinkState(eq(TEST_IFACE), eq(true /* up */),
+ eq(NULL_LISTENER));
+ }
+
+ @Test
+ public void testDisconnectNetworkCorrectlyCallsFactory() {
+ tracker.disconnectNetwork(TEST_IFACE, NULL_LISTENER);
+ waitForIdle();
+
+ verify(mFactory).updateInterfaceLinkState(eq(TEST_IFACE), eq(false /* up */),
+ eq(NULL_LISTENER));
+ }
+
+ @Test
+ public void testIsValidTestInterfaceIsFalseWhenTestInterfacesAreNotIncluded() {
+ final String validIfaceName = TEST_TAP_PREFIX + "123";
+ tracker.setIncludeTestInterfaces(false);
+ waitForIdle();
+
+ final boolean isValidTestInterface = tracker.isValidTestInterface(validIfaceName);
+
+ assertFalse(isValidTestInterface);
+ }
+
+ @Test
+ public void testIsValidTestInterfaceIsFalseWhenTestInterfaceNameIsInvalid() {
+ final String invalidIfaceName = "123" + TEST_TAP_PREFIX;
+ tracker.setIncludeTestInterfaces(true);
+ waitForIdle();
+
+ final boolean isValidTestInterface = tracker.isValidTestInterface(invalidIfaceName);
+
+ assertFalse(isValidTestInterface);
+ }
+
+ @Test
+ public void testIsValidTestInterfaceIsTrueWhenTestInterfacesIncludedAndValidName() {
+ final String validIfaceName = TEST_TAP_PREFIX + "123";
+ tracker.setIncludeTestInterfaces(true);
+ waitForIdle();
+
+ final boolean isValidTestInterface = tracker.isValidTestInterface(validIfaceName);
+
+ assertTrue(isValidTestInterface);
+ }
+
+ public static class EthernetStateListener extends IEthernetServiceListener.Stub {
+ @Override
+ public void onEthernetStateChanged(int state) { }
+
+ @Override
+ public void onInterfaceStateChanged(String iface, int state, int role,
+ IpConfiguration configuration) { }
+ }
+
+ @Test
+ public void testListenEthernetStateChange() throws Exception {
+ final String testIface = "testtap123";
+ final String testHwAddr = "11:22:33:44:55:66";
+ final InterfaceConfigurationParcel ifaceParcel = new InterfaceConfigurationParcel();
+ ifaceParcel.ifName = testIface;
+ ifaceParcel.hwAddr = testHwAddr;
+ ifaceParcel.flags = new String[] {INetd.IF_STATE_UP};
+
+ tracker.setIncludeTestInterfaces(true);
+ waitForIdle();
+
+ when(mNetd.interfaceGetList()).thenReturn(new String[] {testIface});
+ when(mNetd.interfaceGetCfg(eq(testIface))).thenReturn(ifaceParcel);
+ doReturn(new String[] {testIface}).when(mFactory).getAvailableInterfaces(anyBoolean());
+ doReturn(EthernetManager.STATE_LINK_UP).when(mFactory).getInterfaceState(eq(testIface));
+
+ final EthernetStateListener listener = spy(new EthernetStateListener());
+ tracker.addListener(listener, true /* canUseRestrictedNetworks */);
+ // Check default state.
+ waitForIdle();
+ verify(listener).onInterfaceStateChanged(eq(testIface), eq(EthernetManager.STATE_LINK_UP),
+ anyInt(), any());
+ verify(listener).onEthernetStateChanged(eq(EthernetManager.ETHERNET_STATE_ENABLED));
+ reset(listener);
+
+ doReturn(EthernetManager.STATE_ABSENT).when(mFactory).getInterfaceState(eq(testIface));
+ tracker.setEthernetEnabled(false);
+ waitForIdle();
+ verify(mFactory).removeInterface(eq(testIface));
+ verify(listener).onEthernetStateChanged(eq(EthernetManager.ETHERNET_STATE_DISABLED));
+ verify(listener).onInterfaceStateChanged(eq(testIface), eq(EthernetManager.STATE_ABSENT),
+ anyInt(), any());
+ reset(listener);
+
+ doReturn(EthernetManager.STATE_LINK_UP).when(mFactory).getInterfaceState(eq(testIface));
+ tracker.setEthernetEnabled(true);
+ waitForIdle();
+ verify(mFactory).addInterface(eq(testIface), eq(testHwAddr), any(), any());
+ verify(listener).onEthernetStateChanged(eq(EthernetManager.ETHERNET_STATE_ENABLED));
+ verify(listener).onInterfaceStateChanged(eq(testIface), eq(EthernetManager.STATE_LINK_UP),
+ anyInt(), any());
+ }
+}
diff --git a/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java b/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java
index 553cb83..157507b 100644
--- a/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java
@@ -69,8 +69,6 @@
@RunWith(DevSdkIgnoreRunner.class)
@IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available
public class CarrierPrivilegeAuthenticatorTest {
- // TODO : use ConstantsShim.RECEIVER_NOT_EXPORTED when it's available in tests.
- private static final int RECEIVER_NOT_EXPORTED = 4;
private static final int SUBSCRIPTION_COUNT = 2;
private static final int TEST_SUBSCRIPTION_ID = 1;
@@ -117,7 +115,7 @@
private IntentFilter getIntentFilter() {
final ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class);
- verify(mContext).registerReceiver(any(), captor.capture(), any(), any(), anyInt());
+ verify(mContext).registerReceiver(any(), captor.capture(), any(), any());
return captor.getValue();
}
@@ -140,11 +138,10 @@
@Test
public void testConstructor() throws Exception {
verify(mContext).registerReceiver(
- eq(mCarrierPrivilegeAuthenticator),
- any(IntentFilter.class),
- any(),
- any(),
- eq(RECEIVER_NOT_EXPORTED));
+ eq(mCarrierPrivilegeAuthenticator),
+ any(IntentFilter.class),
+ any(),
+ any());
final IntentFilter filter = getIntentFilter();
assertEquals(1, filter.countActions());
assertTrue(filter.hasAction(ACTION_MULTI_SIM_CONFIG_CHANGED));