Merge "Use separate catch for getTcpKeepalivePacket"
diff --git a/Tethering/apex/hiddenapi/hiddenapi-max-target-o-low-priority-tiramisu.txt b/Tethering/apex/hiddenapi/hiddenapi-max-target-o-low-priority-tiramisu.txt
index 3a02682..ce0d69c 100644
--- a/Tethering/apex/hiddenapi/hiddenapi-max-target-o-low-priority-tiramisu.txt
+++ b/Tethering/apex/hiddenapi/hiddenapi-max-target-o-low-priority-tiramisu.txt
@@ -77,6 +77,47 @@
Landroid/net/DataUsageRequest;->REQUEST_ID_UNSET:I
Landroid/net/DataUsageRequest;->template:Landroid/net/NetworkTemplate;
Landroid/net/DataUsageRequest;->thresholdInBytes:J
+Landroid/net/EthernetManager;-><init>(Landroid/content/Context;Landroid/net/IEthernetManager;)V
+Landroid/net/EthernetManager;->mContext:Landroid/content/Context;
+Landroid/net/EthernetManager;->mHandler:Landroid/os/Handler;
+Landroid/net/EthernetManager;->mListeners:Ljava/util/ArrayList;
+Landroid/net/EthernetManager;->mService:Landroid/net/IEthernetManager;
+Landroid/net/EthernetManager;->mServiceListener:Landroid/net/IEthernetServiceListener$Stub;
+Landroid/net/EthernetManager;->MSG_AVAILABILITY_CHANGED:I
+Landroid/net/EthernetManager;->TAG:Ljava/lang/String;
+Landroid/net/IEthernetManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/net/IEthernetManager$Stub$Proxy;->addListener(Landroid/net/IEthernetServiceListener;)V
+Landroid/net/IEthernetManager$Stub$Proxy;->getAvailableInterfaces()[Ljava/lang/String;
+Landroid/net/IEthernetManager$Stub$Proxy;->getConfiguration(Ljava/lang/String;)Landroid/net/IpConfiguration;
+Landroid/net/IEthernetManager$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
+Landroid/net/IEthernetManager$Stub$Proxy;->isAvailable(Ljava/lang/String;)Z
+Landroid/net/IEthernetManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
+Landroid/net/IEthernetManager$Stub$Proxy;->removeListener(Landroid/net/IEthernetServiceListener;)V
+Landroid/net/IEthernetManager$Stub$Proxy;->setConfiguration(Ljava/lang/String;Landroid/net/IpConfiguration;)V
+Landroid/net/IEthernetManager$Stub;-><init>()V
+Landroid/net/IEthernetManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/IEthernetManager;
+Landroid/net/IEthernetManager$Stub;->DESCRIPTOR:Ljava/lang/String;
+Landroid/net/IEthernetManager$Stub;->TRANSACTION_addListener:I
+Landroid/net/IEthernetManager$Stub;->TRANSACTION_getAvailableInterfaces:I
+Landroid/net/IEthernetManager$Stub;->TRANSACTION_getConfiguration:I
+Landroid/net/IEthernetManager$Stub;->TRANSACTION_isAvailable:I
+Landroid/net/IEthernetManager$Stub;->TRANSACTION_removeListener:I
+Landroid/net/IEthernetManager$Stub;->TRANSACTION_setConfiguration:I
+Landroid/net/IEthernetManager;->addListener(Landroid/net/IEthernetServiceListener;)V
+Landroid/net/IEthernetManager;->getAvailableInterfaces()[Ljava/lang/String;
+Landroid/net/IEthernetManager;->getConfiguration(Ljava/lang/String;)Landroid/net/IpConfiguration;
+Landroid/net/IEthernetManager;->isAvailable(Ljava/lang/String;)Z
+Landroid/net/IEthernetManager;->removeListener(Landroid/net/IEthernetServiceListener;)V
+Landroid/net/IEthernetManager;->setConfiguration(Ljava/lang/String;Landroid/net/IpConfiguration;)V
+Landroid/net/IEthernetServiceListener$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/net/IEthernetServiceListener$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
+Landroid/net/IEthernetServiceListener$Stub$Proxy;->mRemote:Landroid/os/IBinder;
+Landroid/net/IEthernetServiceListener$Stub$Proxy;->onAvailabilityChanged(Ljava/lang/String;Z)V
+Landroid/net/IEthernetServiceListener$Stub;-><init>()V
+Landroid/net/IEthernetServiceListener$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/IEthernetServiceListener;
+Landroid/net/IEthernetServiceListener$Stub;->DESCRIPTOR:Ljava/lang/String;
+Landroid/net/IEthernetServiceListener$Stub;->TRANSACTION_onAvailabilityChanged:I
+Landroid/net/IEthernetServiceListener;->onAvailabilityChanged(Ljava/lang/String;Z)V
Landroid/net/IIpSecService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/net/IIpSecService$Stub$Proxy;->addAddressToTunnelInterface(ILandroid/net/LinkAddress;Ljava/lang/String;)V
Landroid/net/IIpSecService$Stub$Proxy;->allocateSecurityParameterIndex(Ljava/lang/String;ILandroid/os/IBinder;)Landroid/net/IpSecSpiResponse;
diff --git a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
index 4ca36df..844efde 100644
--- a/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
+++ b/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
@@ -16,6 +16,7 @@
package com.android.networkstack.tethering;
+import static android.content.pm.PackageManager.GET_ACTIVITIES;
import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE;
import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK;
import static android.net.TetheringConstants.EXTRA_RUN_PROVISION;
@@ -32,6 +33,9 @@
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED;
+import static com.android.networkstack.apishim.ConstantsShim.ACTION_TETHER_UNSUPPORTED_CARRIER_UI;
+import static com.android.networkstack.apishim.ConstantsShim.KEY_CARRIER_SUPPORTS_TETHERING_BOOL;
+
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -39,6 +43,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.net.util.SharedLog;
import android.os.Bundle;
import android.os.Handler;
@@ -52,6 +57,7 @@
import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.modules.utils.build.SdkLevel;
import java.io.PrintWriter;
import java.util.BitSet;
@@ -74,6 +80,13 @@
protected static final String ACTION_PROVISIONING_ALARM =
"com.android.networkstack.tethering.PROVISIONING_RECHECK_ALARM";
+ // Indicate tether provisioning is not required by carrier.
+ private static final int TETHERING_PROVISIONING_REQUIRED = 1000;
+ // Indicate tether provisioning is required by carrier.
+ private static final int TETHERING_PROVISIONING_NOT_REQUIRED = 1001;
+ // Indicate tethering is not supported by carrier.
+ private static final int TETHERING_PROVISIONING_CARRIER_UNSUPPORT = 1002;
+
private final ComponentName mSilentProvisioningService;
private static final int MS_PER_HOUR = 60 * 60 * 1000;
private static final int DUMP_TIMEOUT = 10_000;
@@ -96,7 +109,7 @@
private boolean mLastCellularUpstreamPermitted = true;
private boolean mUsingCellularAsUpstream = false;
private boolean mNeedReRunProvisioningUi = false;
- private OnUiEntitlementFailedListener mListener;
+ private OnTetherProvisioningFailedListener mListener;
private TetheringConfigurationFetcher mFetcher;
public EntitlementManager(Context ctx, Handler h, SharedLog log,
@@ -115,18 +128,20 @@
mContext.getResources().getString(R.string.config_wifi_tether_enable));
}
- public void setOnUiEntitlementFailedListener(final OnUiEntitlementFailedListener listener) {
+ public void setOnTetherProvisioningFailedListener(
+ final OnTetherProvisioningFailedListener listener) {
mListener = listener;
}
/** Callback fired when UI entitlement failed. */
- public interface OnUiEntitlementFailedListener {
+ public interface OnTetherProvisioningFailedListener {
/**
* Ui entitlement check fails in |downstream|.
*
* @param downstream tethering type from TetheringManager.TETHERING_{@code *}.
+ * @param reason Failed reason.
*/
- void onUiEntitlementFailed(int downstream);
+ void onTetherProvisioningFailed(int downstream, String reason);
}
public void setTetheringConfigurationFetcher(final TetheringConfigurationFetcher fetcher) {
@@ -153,6 +168,9 @@
}
private boolean isCellularUpstreamPermitted(final TetheringConfiguration config) {
+ // If #getTetherProvisioningCondition return TETHERING_PROVISIONING_CARRIER_UNSUPPORT,
+ // that means cellular upstream is not supported and entitlement check result is empty
+ // because entitlement check should not be run.
if (!isTetherProvisioningRequired(config)) return true;
// If provisioning is required and EntitlementManager doesn't know any downstreams, cellular
@@ -199,11 +217,7 @@
// If upstream is not cellular, provisioning app would not be launched
// till upstream change to cellular.
if (mUsingCellularAsUpstream) {
- if (showProvisioningUi) {
- runUiTetherProvisioning(downstreamType, config);
- } else {
- runSilentTetherProvisioning(downstreamType, config);
- }
+ runTetheringProvisioning(showProvisioningUi, downstreamType, config);
mNeedReRunProvisioningUi = false;
} else {
mNeedReRunProvisioningUi |= showProvisioningUi;
@@ -262,18 +276,51 @@
// the change and get the new correct value.
for (int downstream = mCurrentDownstreams.nextSetBit(0); downstream >= 0;
downstream = mCurrentDownstreams.nextSetBit(downstream + 1)) {
+ // If tethering provisioning is required but entitlement check result is empty,
+ // this means tethering may need to run entitlement check or carrier network
+ // is not supported.
if (mCurrentEntitlementResults.indexOfKey(downstream) < 0) {
- if (mNeedReRunProvisioningUi) {
- mNeedReRunProvisioningUi = false;
- runUiTetherProvisioning(downstream, config);
- } else {
- runSilentTetherProvisioning(downstream, config);
- }
+ runTetheringProvisioning(mNeedReRunProvisioningUi, downstream, config);
+ mNeedReRunProvisioningUi = false;
}
}
}
/**
+ * Tether provisioning has these conditions to control provisioning behavior.
+ * 1st priority : Uses system property to disable any provisioning behavior.
+ * 2nd priority : Uses {@code CarrierConfigManager#KEY_CARRIER_SUPPORTS_TETHERING_BOOL} to
+ * decide current carrier support cellular upstream tethering or not.
+ * If value is true, it means check follow up condition to know whether
+ * provisioning is required.
+ * If value is false, it means tethering could not use cellular as upstream.
+ * 3rd priority : Uses {@code CarrierConfigManager#KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL} to
+ * decide current carrier require the provisioning.
+ * 4th priority : Checks whether provisioning is required from RRO configuration.
+ *
+ * @param config
+ * @return integer {@see #TETHERING_PROVISIONING_NOT_REQUIRED,
+ * #TETHERING_PROVISIONING_REQUIRED,
+ * #TETHERING_PROVISIONING_CARRIER_UNSUPPORT}
+ */
+ private int getTetherProvisioningCondition(final TetheringConfiguration config) {
+ if (SystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)) {
+ return TETHERING_PROVISIONING_NOT_REQUIRED;
+ }
+ // TODO: Find a way to avoid get carrier config twice.
+ if (carrierConfigAffirmsCarrierNotSupport(config)) {
+ // To block tethering, behave as if running provisioning check and failed.
+ return TETHERING_PROVISIONING_CARRIER_UNSUPPORT;
+ }
+
+ if (carrierConfigAffirmsEntitlementCheckNotRequired(config)) {
+ return TETHERING_PROVISIONING_NOT_REQUIRED;
+ }
+ return (config.provisioningApp.length == 2)
+ ? TETHERING_PROVISIONING_REQUIRED : TETHERING_PROVISIONING_NOT_REQUIRED;
+ }
+
+ /**
* Check if the device requires a provisioning check in order to enable tethering.
*
* @param config an object that encapsulates the various tethering configuration elements.
@@ -281,14 +328,26 @@
*/
@VisibleForTesting
protected boolean isTetherProvisioningRequired(final TetheringConfiguration config) {
- if (SystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)
- || config.provisioningApp.length == 0) {
+ return getTetherProvisioningCondition(config) != TETHERING_PROVISIONING_NOT_REQUIRED;
+ }
+
+ /**
+ * Confirms the need of tethering provisioning but no entitlement package exists.
+ */
+ public boolean isProvisioningNeededButUnavailable() {
+ final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
+ return getTetherProvisioningCondition(config) == TETHERING_PROVISIONING_REQUIRED
+ && !doesEntitlementPackageExist(config);
+ }
+
+ private boolean doesEntitlementPackageExist(final TetheringConfiguration config) {
+ final PackageManager pm = mContext.getPackageManager();
+ try {
+ pm.getPackageInfo(config.provisioningApp[0], GET_ACTIVITIES);
+ } catch (PackageManager.NameNotFoundException e) {
return false;
}
- if (carrierConfigAffirmsEntitlementCheckNotRequired(config)) {
- return false;
- }
- return (config.provisioningApp.length == 2);
+ return true;
}
/**
@@ -310,9 +369,7 @@
mEntitlementCacheValue.clear();
mCurrentEntitlementResults.clear();
- // TODO: refine provisioning check to isTetherProvisioningRequired() ??
- if (!config.hasMobileHotspotProvisionApp()
- || carrierConfigAffirmsEntitlementCheckNotRequired(config)) {
+ if (!isTetherProvisioningRequired(config)) {
evaluateCellularPermission(config);
return;
}
@@ -327,8 +384,8 @@
* @param config an object that encapsulates the various tethering configuration elements.
* */
public PersistableBundle getCarrierConfig(final TetheringConfiguration config) {
- final CarrierConfigManager configManager = (CarrierConfigManager) mContext
- .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ final CarrierConfigManager configManager = mContext
+ .getSystemService(CarrierConfigManager.class);
if (configManager == null) return null;
final PersistableBundle carrierConfig = configManager.getConfigForSubId(
@@ -346,6 +403,7 @@
//
// TODO: find a better way to express this, or alter the checking process
// entirely so that this is more intuitive.
+ // TODO: Find a way to avoid using getCarrierConfig everytime.
private boolean carrierConfigAffirmsEntitlementCheckNotRequired(
final TetheringConfiguration config) {
// Check carrier config for entitlement checks
@@ -358,16 +416,29 @@
return !isEntitlementCheckRequired;
}
+ private boolean carrierConfigAffirmsCarrierNotSupport(final TetheringConfiguration config) {
+ if (!SdkLevel.isAtLeastT()) {
+ return false;
+ }
+ // Check carrier config for entitlement checks
+ final PersistableBundle carrierConfig = getCarrierConfig(config);
+ if (carrierConfig == null) return false;
+
+ // A CarrierConfigManager was found and it has a config.
+ final boolean mIsCarrierSupport = carrierConfig.getBoolean(
+ KEY_CARRIER_SUPPORTS_TETHERING_BOOL, true);
+ return !mIsCarrierSupport;
+ }
+
/**
* Run no UI tethering provisioning check.
* @param type tethering type from TetheringManager.TETHERING_{@code *}
* @param subId default data subscription ID.
*/
@VisibleForTesting
- protected Intent runSilentTetherProvisioning(int type, final TetheringConfiguration config) {
+ protected Intent runSilentTetherProvisioning(
+ int type, final TetheringConfiguration config, ResultReceiver receiver) {
if (DBG) mLog.i("runSilentTetherProvisioning: " + type);
- // For silent provisioning, settings would stop tethering when entitlement fail.
- ResultReceiver receiver = buildProxyReceiver(type, false/* notifyFail */, null);
Intent intent = new Intent();
intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
@@ -383,11 +454,6 @@
return intent;
}
- private void runUiTetherProvisioning(int type, final TetheringConfiguration config) {
- ResultReceiver receiver = buildProxyReceiver(type, true/* notifyFail */, null);
- runUiTetherProvisioning(type, config, receiver);
- }
-
/**
* Run the UI-enabled tethering provisioning check.
* @param type tethering type from TetheringManager.TETHERING_{@code *}
@@ -411,6 +477,35 @@
return intent;
}
+ private void runTetheringProvisioning(
+ boolean showProvisioningUi, int downstreamType, final TetheringConfiguration config) {
+ if (carrierConfigAffirmsCarrierNotSupport(config)) {
+ mListener.onTetherProvisioningFailed(downstreamType, "Carrier does not support.");
+ if (showProvisioningUi) {
+ showCarrierUnsupportedDialog();
+ }
+ return;
+ }
+
+ ResultReceiver receiver =
+ buildProxyReceiver(downstreamType, showProvisioningUi/* notifyFail */, null);
+ if (showProvisioningUi) {
+ runUiTetherProvisioning(downstreamType, config, receiver);
+ } else {
+ runSilentTetherProvisioning(downstreamType, config, receiver);
+ }
+ }
+
+ private void showCarrierUnsupportedDialog() {
+ // This is only used when carrierConfigAffirmsCarrierNotSupport() is true.
+ if (!SdkLevel.isAtLeastT()) {
+ return;
+ }
+ Intent intent = new Intent(ACTION_TETHER_UNSUPPORTED_CARRIER_UI);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(intent);
+ }
+
@VisibleForTesting
PendingIntent createRecheckAlarmIntent() {
final Intent intent = new Intent(ACTION_PROVISIONING_ALARM);
@@ -576,7 +671,8 @@
int updatedCacheValue = updateEntitlementCacheValue(type, resultCode);
addDownstreamMapping(type, updatedCacheValue);
if (updatedCacheValue == TETHER_ERROR_PROVISIONING_FAILED && notifyFail) {
- mListener.onUiEntitlementFailed(type);
+ mListener.onTetherProvisioningFailed(
+ type, "Tethering provisioning failed.");
}
if (receiver != null) receiver.send(updatedCacheValue, null);
}
@@ -632,9 +728,14 @@
}
final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
- if (!isTetherProvisioningRequired(config)) {
- receiver.send(TETHER_ERROR_NO_ERROR, null);
- return;
+
+ switch (getTetherProvisioningCondition(config)) {
+ case TETHERING_PROVISIONING_NOT_REQUIRED:
+ receiver.send(TETHER_ERROR_NO_ERROR, null);
+ return;
+ case TETHERING_PROVISIONING_CARRIER_UNSUPPORT:
+ receiver.send(TETHER_ERROR_PROVISIONING_FAILED, null);
+ return;
}
final int cacheValue = mEntitlementCacheValue.get(
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index bb9b6fb..0b607bd 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -18,7 +18,6 @@
import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.Manifest.permission.NETWORK_STACK;
-import static android.content.pm.PackageManager.GET_ACTIVITIES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
@@ -319,8 +318,8 @@
mEntitlementMgr = mDeps.getEntitlementManager(mContext, mHandler, mLog,
() -> mTetherMainSM.sendMessage(
TetherMainSM.EVENT_UPSTREAM_PERMISSION_CHANGED));
- mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> {
- mLog.log("OBSERVED UiEnitlementFailed");
+ mEntitlementMgr.setOnTetherProvisioningFailedListener((downstream, reason) -> {
+ mLog.log("OBSERVED OnTetherProvisioningFailed : " + reason);
stopTethering(downstream);
});
mEntitlementMgr.setTetheringConfigurationFetcher(() -> {
@@ -995,30 +994,11 @@
return tetherState.lastError;
}
- private boolean isProvisioningNeededButUnavailable() {
- return isTetherProvisioningRequired() && !doesEntitlementPackageExist();
- }
-
boolean isTetherProvisioningRequired() {
final TetheringConfiguration cfg = mConfig;
return mEntitlementMgr.isTetherProvisioningRequired(cfg);
}
- private boolean doesEntitlementPackageExist() {
- // provisioningApp must contain package and class name.
- if (mConfig.provisioningApp.length != 2) {
- return false;
- }
-
- final PackageManager pm = mContext.getPackageManager();
- try {
- pm.getPackageInfo(mConfig.provisioningApp[0], GET_ACTIVITIES);
- } catch (PackageManager.NameNotFoundException e) {
- return false;
- }
- return true;
- }
-
private int getRequestedState(int type) {
final TetheringRequestParcel request = mActiveTetheringRequests.get(type);
@@ -2476,7 +2456,7 @@
&& !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
return tetherEnabledInSettings && hasAnySupportedDownstream()
- && !isProvisioningNeededButUnavailable();
+ && !mEntitlementMgr.isProvisioningNeededButUnavailable();
}
private void dumpBpf(IndentingPrintWriter pw) {
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
index 46ce82c..690ff71 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
@@ -37,6 +37,9 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.networkstack.apishim.ConstantsShim.KEY_CARRIER_SUPPORTS_TETHERING_BOOL;
+import static com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -47,6 +50,7 @@
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -77,9 +81,12 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.test.BroadcastInterceptingContext;
+import com.android.modules.utils.build.SdkLevel;
+import com.android.testutils.DevSdkIgnoreRule;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
@@ -96,6 +103,7 @@
private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app";
private static final String PROVISIONING_APP_RESPONSE = "app_response";
private static final String TEST_PACKAGE_NAME = "com.android.tethering.test";
+ private static final String FAILED_TETHERING_REASON = "Tethering provisioning failed.";
private static final int RECHECK_TIMER_HOURS = 24;
@Mock private CarrierConfigManager mCarrierConfigManager;
@@ -103,10 +111,14 @@
@Mock private Resources mResources;
@Mock private SharedLog mLog;
@Mock private PackageManager mPm;
- @Mock private EntitlementManager.OnUiEntitlementFailedListener mEntitlementFailedListener;
+ @Mock private EntitlementManager
+ .OnTetherProvisioningFailedListener mTetherProvisioningFailedListener;
@Mock private AlarmManager mAlarmManager;
@Mock private PendingIntent mAlarmIntent;
+ @Rule
+ public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
+
// Like so many Android system APIs, these cannot be mocked because it is marked final.
// We have to use the real versions.
private final PersistableBundle mCarrierConfig = new PersistableBundle();
@@ -179,8 +191,8 @@
@Override
protected Intent runSilentTetherProvisioning(int type,
- final TetheringConfiguration config) {
- Intent intent = super.runSilentTetherProvisioning(type, config);
+ final TetheringConfiguration config, final ResultReceiver receiver) {
+ Intent intent = super.runSilentTetherProvisioning(type, config, receiver);
assertSilentTetherProvisioning(type, config, intent);
silentProvisionCount++;
addDownstreamMapping(type, fakeEntitlementResult);
@@ -245,7 +257,7 @@
mPermissionChangeCallback = spy(() -> { });
mEnMgr = new WrappedEntitlementManager(mMockContext, new Handler(mLooper.getLooper()), mLog,
mPermissionChangeCallback);
- mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener);
+ mEnMgr.setOnTetherProvisioningFailedListener(mTetherProvisioningFailedListener);
mConfig = new FakeTetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
mEnMgr.setTetheringConfigurationFetcher(() -> {
return mConfig;
@@ -268,14 +280,23 @@
when(mResources.getInteger(R.integer.config_mobile_hotspot_provision_check_period))
.thenReturn(RECHECK_TIMER_HOURS);
// Act like the CarrierConfigManager is present and ready unless told otherwise.
- when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
- .thenReturn(mCarrierConfigManager);
+ mockService(Context.CARRIER_CONFIG_SERVICE,
+ CarrierConfigManager.class, mCarrierConfigManager);
when(mCarrierConfigManager.getConfigForSubId(anyInt())).thenReturn(mCarrierConfig);
mCarrierConfig.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
mCarrierConfig.putBoolean(CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL, true);
mConfig = new FakeTetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
}
+ private void setupCarrierConfig(boolean carrierSupported) {
+ mCarrierConfig.putBoolean(KEY_CARRIER_SUPPORTS_TETHERING_BOOL, carrierSupported);
+ }
+
+ private <T> void mockService(String serviceName, Class<T> serviceClass, T service) {
+ when(mMockContext.getSystemServiceName(serviceClass)).thenReturn(serviceName);
+ when(mMockContext.getSystemService(serviceName)).thenReturn(service);
+ }
+
@Test
public void canRequireProvisioning() {
setupForRequiredProvisioning();
@@ -285,8 +306,7 @@
@Test
public void toleratesCarrierConfigManagerMissing() {
setupForRequiredProvisioning();
- when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
- .thenReturn(null);
+ mockService(Context.CARRIER_CONFIG_SERVICE, CarrierConfigManager.class, null);
mConfig = new FakeTetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
// Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
// Therefore provisioning still be required.
@@ -613,14 +633,16 @@
@Test
public void testCallStopTetheringWhenUiProvisioningFail() {
setupForRequiredProvisioning();
- verify(mEntitlementFailedListener, times(0)).onUiEntitlementFailed(TETHERING_WIFI);
+ verify(mTetherProvisioningFailedListener, times(0))
+ .onTetherProvisioningFailed(TETHERING_WIFI, FAILED_TETHERING_REASON);
mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISIONING_FAILED;
mEnMgr.notifyUpstream(true);
mLooper.dispatchAll();
mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
mLooper.dispatchAll();
assertEquals(1, mEnMgr.uiProvisionCount);
- verify(mEntitlementFailedListener, times(1)).onUiEntitlementFailed(TETHERING_WIFI);
+ verify(mTetherProvisioningFailedListener, times(1))
+ .onTetherProvisioningFailed(TETHERING_WIFI, FAILED_TETHERING_REASON);
}
@Test
@@ -644,7 +666,8 @@
// When second downstream is down, exempted downstream can use cellular upstream.
assertEquals(1, mEnMgr.uiProvisionCount);
- verify(mEntitlementFailedListener).onUiEntitlementFailed(TETHERING_USB);
+ verify(mTetherProvisioningFailedListener).onTetherProvisioningFailed(TETHERING_USB,
+ FAILED_TETHERING_REASON);
mEnMgr.stopProvisioningIfNeeded(TETHERING_USB);
assertTrue(mEnMgr.isCellularUpstreamPermitted());
@@ -678,4 +701,85 @@
verify(mAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), anyLong(),
eq(mAlarmIntent));
}
+
+ @Test
+ @IgnoreUpTo(SC_V2)
+ public void requestLatestTetheringEntitlementResult_carrierDoesNotSupport_noProvisionCount()
+ throws Exception {
+ setupForRequiredProvisioning();
+ setupCarrierConfig(false);
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
+ ResultReceiver receiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ assertEquals(TETHER_ERROR_PROVISIONING_FAILED, resultCode);
+ }
+ };
+ mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
+ mLooper.dispatchAll();
+ assertEquals(0, mEnMgr.uiProvisionCount);
+ mEnMgr.reset();
+ }
+
+ @Test
+ @IgnoreUpTo(SC_V2)
+ public void reevaluateSimCardProvisioning_carrierUnsupportAndSimswitch() {
+ setupForRequiredProvisioning();
+
+ // Start a tethering with cellular data without provisioning.
+ mEnMgr.notifyUpstream(true);
+ mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, false);
+ mLooper.dispatchAll();
+
+ // Tear down mobile, then switch SIM.
+ mEnMgr.notifyUpstream(false);
+ mLooper.dispatchAll();
+ setupCarrierConfig(false);
+ mEnMgr.reevaluateSimCardProvisioning(mConfig);
+
+ // Turn on upstream.
+ mEnMgr.notifyUpstream(true);
+ mLooper.dispatchAll();
+
+ verify(mTetherProvisioningFailedListener)
+ .onTetherProvisioningFailed(TETHERING_WIFI, "Carrier does not support.");
+ }
+
+ @Test
+ @IgnoreUpTo(SC_V2)
+ public void startProvisioningIfNeeded_carrierUnsupport()
+ throws Exception {
+ setupForRequiredProvisioning();
+ setupCarrierConfig(false);
+ mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
+ verify(mTetherProvisioningFailedListener, never())
+ .onTetherProvisioningFailed(TETHERING_WIFI, "Carrier does not support.");
+
+ mEnMgr.notifyUpstream(true);
+ mLooper.dispatchAll();
+ verify(mTetherProvisioningFailedListener)
+ .onTetherProvisioningFailed(TETHERING_WIFI, "Carrier does not support.");
+ mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
+ reset(mTetherProvisioningFailedListener);
+
+ mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
+ mLooper.dispatchAll();
+ verify(mTetherProvisioningFailedListener)
+ .onTetherProvisioningFailed(TETHERING_WIFI, "Carrier does not support.");
+ }
+
+ @Test
+ public void isTetherProvisioningRequired_carrierUnSupport() {
+ setupForRequiredProvisioning();
+ setupCarrierConfig(false);
+ when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
+ .thenReturn(new String[0]);
+ mConfig = new FakeTetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+
+ if (SdkLevel.isAtLeastT()) {
+ assertTrue(mEnMgr.isTetherProvisioningRequired(mConfig));
+ } else {
+ assertFalse(mEnMgr.isTetherProvisioningRequired(mConfig));
+ }
+ }
}
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java
index fc34585..e9716b3 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadControllerTest.java
@@ -26,7 +26,7 @@
import static android.net.RouteInfo.RTN_UNICAST;
import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
-import static com.android.modules.utils.build.SdkLevel.isAtLeastS;
+import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_IFACE;
import static com.android.networkstack.tethering.OffloadController.StatsType.STATS_PER_UID;
import static com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats;
@@ -666,10 +666,12 @@
callback.onStoppedLimitReached();
mTetherStatsProviderCb.expectNotifyStatsUpdated();
- if (isAtLeastS()) {
+ if (isAtLeastT()) {
+ mTetherStatsProviderCb.expectNotifyLimitReached();
+ } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.S) {
mTetherStatsProviderCb.expectNotifyWarningOrLimitReached();
} else {
- mTetherStatsProviderCb.expectLegacyNotifyLimitReached();
+ mTetherStatsProviderCb.expectNotifyLimitReached();
}
}
@@ -680,7 +682,12 @@
final OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue();
callback.onWarningReached();
mTetherStatsProviderCb.expectNotifyStatsUpdated();
- mTetherStatsProviderCb.expectNotifyWarningOrLimitReached();
+
+ if (isAtLeastT()) {
+ mTetherStatsProviderCb.expectNotifyWarningReached();
+ } else {
+ mTetherStatsProviderCb.expectNotifyWarningOrLimitReached();
+ }
}
@Test
diff --git a/framework-t/Android.bp b/framework-t/Android.bp
index 2ab69b8..f46d887 100644
--- a/framework-t/Android.bp
+++ b/framework-t/Android.bp
@@ -127,6 +127,7 @@
"//frameworks/base/tests/vcn",
"//frameworks/libs/net/common/testutils",
"//frameworks/libs/net/common/tests:__subpackages__",
+ "//frameworks/opt/net/ethernet/tests:__subpackages__",
"//frameworks/opt/telephony/tests/telephonytests",
"//packages/modules/CaptivePortalLogin/tests",
"//packages/modules/Connectivity/Tethering/tests:__subpackages__",
diff --git a/framework-t/api/current.txt b/framework-t/api/current.txt
index 3d6fb3e..1b47481 100644
--- a/framework-t/api/current.txt
+++ b/framework-t/api/current.txt
@@ -61,6 +61,14 @@
package android.net {
+ public final class EthernetNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
+ ctor public EthernetNetworkSpecifier(@NonNull String);
+ method public int describeContents();
+ method @Nullable public String getInterfaceName();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkSpecifier> CREATOR;
+ }
+
public final class IpSecAlgorithm implements android.os.Parcelable {
ctor public IpSecAlgorithm(@NonNull String, @NonNull byte[]);
ctor public IpSecAlgorithm(@NonNull String, @NonNull byte[], int);
@@ -180,10 +188,12 @@
public final class NsdManager {
method public void discoverServices(String, int, android.net.nsd.NsdManager.DiscoveryListener);
- method public void discoverServices(@NonNull String, int, @Nullable android.net.Network, @NonNull android.net.nsd.NsdManager.DiscoveryListener);
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void discoverServices(@NonNull String, int, @NonNull android.net.NetworkRequest, @NonNull android.net.nsd.NsdManager.DiscoveryListener);
+ method public void discoverServices(@NonNull String, int, @Nullable android.net.Network, @NonNull java.util.concurrent.Executor, @NonNull android.net.nsd.NsdManager.DiscoveryListener);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void discoverServices(@NonNull String, int, @NonNull android.net.NetworkRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.nsd.NsdManager.DiscoveryListener);
method public void registerService(android.net.nsd.NsdServiceInfo, int, android.net.nsd.NsdManager.RegistrationListener);
+ method public void registerService(@NonNull android.net.nsd.NsdServiceInfo, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.nsd.NsdManager.RegistrationListener);
method public void resolveService(android.net.nsd.NsdServiceInfo, android.net.nsd.NsdManager.ResolveListener);
+ method public void resolveService(@NonNull android.net.nsd.NsdServiceInfo, @NonNull java.util.concurrent.Executor, @NonNull android.net.nsd.NsdManager.ResolveListener);
method public void stopServiceDiscovery(android.net.nsd.NsdManager.DiscoveryListener);
method public void unregisterService(android.net.nsd.NsdManager.RegistrationListener);
field public static final String ACTION_NSD_STATE_CHANGED = "android.net.nsd.STATE_CHANGED";
diff --git a/framework-t/api/module-lib-current.txt b/framework-t/api/module-lib-current.txt
index aaaa628..1bdd388 100644
--- a/framework-t/api/module-lib-current.txt
+++ b/framework-t/api/module-lib-current.txt
@@ -4,6 +4,7 @@
public class NetworkStatsManager {
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void forceUpdate();
method public static int getCollapsedRatType(int);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void noteUidForeground(int, boolean);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyNetworkStatus(@NonNull java.util.List<android.net.Network>, @NonNull java.util.List<android.net.NetworkStateSnapshot>, @Nullable String, @NonNull java.util.List<android.net.UnderlyingNetworkInfo>);
method @NonNull @WorkerThread public android.app.usage.NetworkStats queryDetailsForDevice(@NonNull android.net.NetworkTemplate, long, long);
method @NonNull @WorkerThread public android.app.usage.NetworkStats queryDetailsForUidTagState(@NonNull android.net.NetworkTemplate, long, long, int, int, int) throws java.lang.SecurityException;
@@ -15,7 +16,6 @@
method public void setPollForce(boolean);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setPollOnOpen(boolean);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setStatsProviderWarningAndLimitAsync(@NonNull String, long, long);
- method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void setUidForeground(int, boolean);
field public static final int NETWORK_TYPE_5G_NSA = -2; // 0xfffffffe
}
@@ -31,6 +31,22 @@
method public static void registerServiceWrappers();
}
+ public class EthernetManager {
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void addInterfaceStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.EthernetManager.InterfaceStateListener);
+ method public void removeInterfaceStateListener(@NonNull android.net.EthernetManager.InterfaceStateListener);
+ method public void setIncludeTestInterfaces(boolean);
+ field public static final int ROLE_CLIENT = 1; // 0x1
+ field public static final int ROLE_NONE = 0; // 0x0
+ field public static final int ROLE_SERVER = 2; // 0x2
+ field public static final int STATE_ABSENT = 0; // 0x0
+ field public static final int STATE_LINK_DOWN = 1; // 0x1
+ field public static final int STATE_LINK_UP = 2; // 0x2
+ }
+
+ public static interface EthernetManager.InterfaceStateListener {
+ method public void onInterfaceStateChanged(@NonNull String, int, int, @Nullable android.net.IpConfiguration);
+ }
+
public class IpSecManager {
field public static final int DIRECTION_FWD = 2; // 0x2
}
diff --git a/framework-t/api/system-current.txt b/framework-t/api/system-current.txt
index 4035e9b..e110155 100644
--- a/framework-t/api/system-current.txt
+++ b/framework-t/api/system-current.txt
@@ -12,6 +12,45 @@
package android.net {
+ public class EthernetManager {
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void connectNetwork(@NonNull String, @Nullable java.util.concurrent.Executor, @Nullable android.os.OutcomeReceiver<java.lang.String,android.net.EthernetNetworkManagementException>);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void disconnectNetwork(@NonNull String, @Nullable java.util.concurrent.Executor, @Nullable android.os.OutcomeReceiver<java.lang.String,android.net.EthernetNetworkManagementException>);
+ method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public android.net.EthernetManager.TetheredInterfaceRequest requestTetheredInterface(@NonNull java.util.concurrent.Executor, @NonNull android.net.EthernetManager.TetheredInterfaceCallback);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) public void updateConfiguration(@NonNull String, @NonNull android.net.EthernetNetworkUpdateRequest, @Nullable java.util.concurrent.Executor, @Nullable android.os.OutcomeReceiver<java.lang.String,android.net.EthernetNetworkManagementException>);
+ }
+
+ public static interface EthernetManager.TetheredInterfaceCallback {
+ method public void onAvailable(@NonNull String);
+ method public void onUnavailable();
+ }
+
+ public static class EthernetManager.TetheredInterfaceRequest {
+ method public void release();
+ }
+
+ public final class EthernetNetworkManagementException extends java.lang.RuntimeException implements android.os.Parcelable {
+ ctor public EthernetNetworkManagementException(@NonNull String);
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkManagementException> CREATOR;
+ }
+
+ public final class EthernetNetworkUpdateRequest implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.net.IpConfiguration getIpConfiguration();
+ method @Nullable public android.net.NetworkCapabilities getNetworkCapabilities();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkUpdateRequest> CREATOR;
+ }
+
+ public static final class EthernetNetworkUpdateRequest.Builder {
+ ctor public EthernetNetworkUpdateRequest.Builder();
+ ctor public EthernetNetworkUpdateRequest.Builder(@NonNull android.net.EthernetNetworkUpdateRequest);
+ method @NonNull public android.net.EthernetNetworkUpdateRequest build();
+ method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setIpConfiguration(@Nullable android.net.IpConfiguration);
+ method @NonNull public android.net.EthernetNetworkUpdateRequest.Builder setNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
+ }
+
public class IpSecManager {
method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
diff --git a/framework/Android.bp b/framework/Android.bp
index 66b662b..f31a7d5 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -64,6 +64,7 @@
":framework-connectivity-sources",
":net-utils-framework-common-srcs",
":framework-connectivity-api-shared-srcs",
+ ":framework-connectivity-javastream-protos",
],
aidl: {
generate_get_transaction_name: true,
@@ -85,7 +86,7 @@
"net-utils-device-common",
],
static_libs: [
- "framework-connectivity-protos",
+ "modules-utils-backgroundthread",
"modules-utils-build",
"modules-utils-preconditions",
],
@@ -139,6 +140,7 @@
"//frameworks/base/tests/vcn",
"//frameworks/libs/net/common/testutils",
"//frameworks/libs/net/common/tests:__subpackages__",
+ "//frameworks/opt/net/ethernet/tests:__subpackages__",
"//frameworks/opt/telephony/tests/telephonytests",
"//packages/modules/CaptivePortalLogin/tests",
"//packages/modules/Connectivity/Tethering/tests:__subpackages__",
@@ -180,22 +182,36 @@
],
}
-// TODO: reduce size of this library; consider using
-// proto nano for example
-java_library {
+filegroup {
name: "framework-connectivity-protos",
- sdk_version: "module_current",
- min_sdk_version: "30",
- proto: {
- type: "lite",
- },
srcs: [
- "proto/**/*.*",
+ "proto/**/*.proto",
],
- static_libs: ["libprotobuf-java-lite"],
- apex_available: [
- "com.android.tethering",
+ visibility: ["//frameworks/base"],
+}
+
+gensrcs {
+ name: "framework-connectivity-javastream-protos",
+ depfile: true,
+
+ tools: [
+ "aprotoc",
+ "protoc-gen-javastream",
+ "soong_zip",
],
- lint: { strict_updatability_linting: true },
- visibility: ["//visibility:private"],
+
+ cmd: "mkdir -p $(genDir)/$(in) " +
+ "&& $(location aprotoc) " +
+ " --plugin=$(location protoc-gen-javastream) " +
+ " --dependency_out=$(depfile) " +
+ " --javastream_out=$(genDir)/$(in) " +
+ " -Iexternal/protobuf/src " +
+ " -I . " +
+ " $(in) " +
+ "&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
+
+ srcs: [
+ ":framework-connectivity-protos",
+ ],
+ output_extension: "srcjar",
}
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index 9fe6505..e4e2151 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -12,8 +12,8 @@
method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshots();
method @Nullable public android.net.ProxyInfo getGlobalProxy();
method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange();
- method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.LinkProperties redactLinkPropertiesForPackage(@NonNull android.net.LinkProperties, int, @NonNull String);
- method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.NetworkCapabilities redactNetworkCapabilitiesForPackage(@NonNull android.net.NetworkCapabilities, int, @NonNull String);
+ method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.LinkProperties getRedactedLinkPropertiesForPackage(@NonNull android.net.LinkProperties, int, @NonNull String);
+ method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.NetworkCapabilities getRedactedNetworkCapabilitiesForPackage(@NonNull android.net.NetworkCapabilities, int, @NonNull String);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackForUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void removeUidFromMeteredNetworkAllowList(int);
@@ -141,7 +141,7 @@
}
public final class NetworkCapabilities implements android.os.Parcelable {
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public java.util.Set<java.lang.Integer> getAccessUids();
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public java.util.Set<java.lang.Integer> getAllowedUids();
method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids();
method public boolean hasForbiddenCapability(int);
field public static final long REDACT_ALL = -1L; // 0xffffffffffffffffL
@@ -153,7 +153,7 @@
}
public static final class NetworkCapabilities.Builder {
- method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAccessUids(@NonNull java.util.Set<java.lang.Integer>);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAllowedUids(@NonNull java.util.Set<java.lang.Integer>);
method @NonNull public android.net.NetworkCapabilities.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
}
@@ -172,8 +172,8 @@
public final class ProfileNetworkPreference implements android.os.Parcelable {
method public int describeContents();
- method @NonNull public java.util.List<java.lang.Integer> getExcludedUids();
- method @NonNull public java.util.List<java.lang.Integer> getIncludedUids();
+ method @NonNull public int[] getExcludedUids();
+ method @NonNull public int[] getIncludedUids();
method public int getPreference();
method public int getPreferenceEnterpriseId();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -183,8 +183,8 @@
public static final class ProfileNetworkPreference.Builder {
ctor public ProfileNetworkPreference.Builder();
method @NonNull public android.net.ProfileNetworkPreference build();
- method @NonNull public android.net.ProfileNetworkPreference.Builder setExcludedUids(@Nullable java.util.List<java.lang.Integer>);
- method @NonNull public android.net.ProfileNetworkPreference.Builder setIncludedUids(@Nullable java.util.List<java.lang.Integer>);
+ method @NonNull public android.net.ProfileNetworkPreference.Builder setExcludedUids(@NonNull int[]);
+ method @NonNull public android.net.ProfileNetworkPreference.Builder setIncludedUids(@NonNull int[]);
method @NonNull public android.net.ProfileNetworkPreference.Builder setPreference(int);
method @NonNull public android.net.ProfileNetworkPreference.Builder setPreferenceEnterpriseId(int);
}
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 764cffa..53d485d 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -236,6 +236,7 @@
public abstract class NetworkAgent {
ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkScore, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
+ method public void destroyAndAwaitReplacement(@IntRange(from=0, to=0x1388) int);
method @Nullable public android.net.Network getNetwork();
method public void markConnected();
method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
@@ -360,6 +361,7 @@
}
public class NetworkReleasedException extends java.lang.Exception {
+ ctor public NetworkReleasedException();
}
public class NetworkRequest implements android.os.Parcelable {
@@ -424,6 +426,8 @@
}
public final class QosCallbackException extends java.lang.Exception {
+ ctor public QosCallbackException(@NonNull String);
+ ctor public QosCallbackException(@NonNull Throwable);
}
public abstract class QosFilter {
@@ -469,9 +473,11 @@
}
public class SocketLocalAddressChangedException extends java.lang.Exception {
+ ctor public SocketLocalAddressChangedException();
}
public class SocketNotBoundException extends java.lang.Exception {
+ ctor public SocketNotBoundException();
}
public final class StaticIpConfiguration implements android.os.Parcelable {
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index 68ca46d..a798f6e 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -1643,10 +1643,10 @@
android.Manifest.permission.NETWORK_SETTINGS})
@SystemApi(client = MODULE_LIBRARIES)
@Nullable
- public LinkProperties redactLinkPropertiesForPackage(@NonNull LinkProperties lp, int uid,
+ public LinkProperties getRedactedLinkPropertiesForPackage(@NonNull LinkProperties lp, int uid,
@NonNull String packageName) {
try {
- return mService.redactLinkPropertiesForPackage(
+ return mService.getRedactedLinkPropertiesForPackage(
lp, uid, packageName, getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1683,9 +1683,11 @@
* Redact {@link NetworkCapabilities} for a given package.
*
* Returns an instance of {@link NetworkCapabilities} that is appropriately redacted to send
- * to the given package, considering its permissions. Calling this method will blame the UID for
- * retrieving the device location if the passed capabilities contain location-sensitive
- * information.
+ * to the given package, considering its permissions. If the passed capabilities contain
+ * location-sensitive information, they will be redacted to the correct degree for the location
+ * permissions of the app (COARSE or FINE), and will blame the UID accordingly for retrieving
+ * that level of location. If the UID holds no location permission, the returned object will
+ * contain no location-sensitive information and the UID is not blamed.
*
* @param nc A {@link NetworkCapabilities} instance which will be redacted.
* @param uid The target uid.
@@ -1700,11 +1702,11 @@
android.Manifest.permission.NETWORK_SETTINGS})
@SystemApi(client = MODULE_LIBRARIES)
@Nullable
- public NetworkCapabilities redactNetworkCapabilitiesForPackage(
+ public NetworkCapabilities getRedactedNetworkCapabilitiesForPackage(
@NonNull NetworkCapabilities nc,
int uid, @NonNull String packageName) {
try {
- return mService.redactNetworkCapabilitiesForPackage(nc, uid, packageName,
+ return mService.getRedactedNetworkCapabilitiesForPackage(nc, uid, packageName,
getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl
index 1e1f653..0988bf3 100644
--- a/framework/src/android/net/IConnectivityManager.aidl
+++ b/framework/src/android/net/IConnectivityManager.aidl
@@ -76,13 +76,13 @@
LinkProperties getActiveLinkProperties();
LinkProperties getLinkPropertiesForType(int networkType);
LinkProperties getLinkProperties(in Network network);
- LinkProperties redactLinkPropertiesForPackage(in LinkProperties lp, int uid, String packageName,
- String callingAttributionTag);
+ LinkProperties getRedactedLinkPropertiesForPackage(in LinkProperties lp, int uid,
+ String packageName, String callingAttributionTag);
NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName,
String callingAttributionTag);
- NetworkCapabilities redactNetworkCapabilitiesForPackage(in NetworkCapabilities nc, int uid,
+ NetworkCapabilities getRedactedNetworkCapabilitiesForPackage(in NetworkCapabilities nc, int uid,
String callingPackageName, String callingAttributionTag);
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
diff --git a/framework/src/android/net/INetworkAgentRegistry.aidl b/framework/src/android/net/INetworkAgentRegistry.aidl
index 08536ca..2b22a5c 100644
--- a/framework/src/android/net/INetworkAgentRegistry.aidl
+++ b/framework/src/android/net/INetworkAgentRegistry.aidl
@@ -47,4 +47,5 @@
void sendAddDscpPolicy(in DscpPolicy policy);
void sendRemoveDscpPolicy(int policyId);
void sendRemoveAllDscpPolicies();
+ void sendDestroyAndAwaitReplacement(int timeoutMillis);
}
diff --git a/framework/src/android/net/ITestNetworkManager.aidl b/framework/src/android/net/ITestNetworkManager.aidl
index 2a863ad..847f14e 100644
--- a/framework/src/android/net/ITestNetworkManager.aidl
+++ b/framework/src/android/net/ITestNetworkManager.aidl
@@ -29,8 +29,7 @@
*/
interface ITestNetworkManager
{
- TestNetworkInterface createTunInterface(in LinkAddress[] linkAddrs);
- TestNetworkInterface createTapInterface();
+ TestNetworkInterface createInterface(boolean isTun, boolean bringUp, in LinkAddress[] addrs);
void setupTestNetwork(in String iface, in LinkProperties lp, in boolean isMetered,
in int[] administratorUids, in IBinder binder);
diff --git a/framework/src/android/net/NetworkAgent.java b/framework/src/android/net/NetworkAgent.java
index 945e670..fdc9081 100644
--- a/framework/src/android/net/NetworkAgent.java
+++ b/framework/src/android/net/NetworkAgent.java
@@ -434,6 +434,14 @@
*/
public static final int CMD_DSCP_POLICY_STATUS = BASE + 28;
+ /**
+ * Sent by the NetworkAgent to ConnectivityService to notify that this network is expected to be
+ * replaced within the specified time by a similar network.
+ * arg1 = timeout in milliseconds
+ * @hide
+ */
+ public static final int EVENT_DESTROY_AND_AWAIT_REPLACEMENT = BASE + 29;
+
private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacySubType,
config.legacyTypeName, config.legacySubTypeName);
@@ -943,6 +951,45 @@
}
/**
+ * Indicates that this agent will likely soon be replaced by another agent for a very similar
+ * network (e.g., same Wi-Fi SSID).
+ *
+ * If the network is not currently satisfying any {@link NetworkRequest}s, it will be torn down.
+ * If it is satisfying requests, then the native network corresponding to the agent will be
+ * destroyed immediately, but the agent will remain registered and will continue to satisfy
+ * requests until {@link #unregister} is called, the network is replaced by an equivalent or
+ * better network, or the specified timeout expires. During this time:
+ *
+ * <ul>
+ * <li>The agent may not send any further updates, for example by calling methods
+ * such as {@link #sendNetworkCapabilities}, {@link #sendLinkProperties},
+ * {@link #sendNetworkScore(NetworkScore)} and so on. Any such updates will be ignored.
+ * <li>The network will remain connected and continue to satisfy any requests that it would
+ * otherwise satisfy (including, possibly, the default request).
+ * <li>The validation state of the network will not change, and calls to
+ * {@link ConnectivityManager#reportNetworkConnectivity(Network, boolean)} will be ignored.
+ * </ul>
+ *
+ * Once this method is called, it is not possible to restore the agent to a functioning state.
+ * If a replacement network becomes available, then a new agent must be registered. When that
+ * replacement network is fully capable of replacing this network (including, possibly, being
+ * validated), this agent will no longer be needed and will be torn down. Otherwise, this agent
+ * can be disconnected by calling {@link #unregister}. If {@link #unregister} is not called,
+ * this agent will automatically be unregistered when the specified timeout expires. Any
+ * teardown delay previously set using{@link #setTeardownDelayMillis} is ignored.
+ *
+ * <p>This method has no effect if {@link #markConnected} has not yet been called.
+ * <p>This method may only be called once.
+ *
+ * @param timeoutMillis the timeout after which this network will be unregistered even if
+ * {@link #unregister} was not called.
+ */
+ public void destroyAndAwaitReplacement(
+ @IntRange(from = 0, to = MAX_TEARDOWN_DELAY_MS) int timeoutMillis) {
+ queueOrSendMessage(reg -> reg.sendDestroyAndAwaitReplacement(timeoutMillis));
+ }
+
+ /**
* Change the legacy subtype of this network agent.
*
* This is only for backward compatibility and should not be used by non-legacy network agents,
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index 41be732..f7f2f57 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -147,27 +147,32 @@
private String mRequestorPackageName;
/**
- * Enterprise capability identifier 1.
+ * Enterprise capability identifier 1. It will be used to uniquely identify specific
+ * enterprise network.
*/
public static final int NET_ENTERPRISE_ID_1 = 1;
/**
- * Enterprise capability identifier 2.
+ * Enterprise capability identifier 2. It will be used to uniquely identify specific
+ * enterprise network.
*/
public static final int NET_ENTERPRISE_ID_2 = 2;
/**
- * Enterprise capability identifier 3.
+ * Enterprise capability identifier 3. It will be used to uniquely identify specific
+ * enterprise network.
*/
public static final int NET_ENTERPRISE_ID_3 = 3;
/**
- * Enterprise capability identifier 4.
+ * Enterprise capability identifier 4. It will be used to uniquely identify specific
+ * enterprise network.
*/
public static final int NET_ENTERPRISE_ID_4 = 4;
/**
- * Enterprise capability identifier 5.
+ * Enterprise capability identifier 5. It will be used to uniquely identify specific
+ * enterprise network.
*/
public static final int NET_ENTERPRISE_ID_5 = 5;
@@ -264,7 +269,7 @@
mTransportInfo = null;
mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
mUids = null;
- mAccessUids.clear();
+ mAllowedUids.clear();
mAdministratorUids = new int[0];
mOwnerUid = Process.INVALID_UID;
mSSID = null;
@@ -295,7 +300,7 @@
}
mSignalStrength = nc.mSignalStrength;
mUids = (nc.mUids == null) ? null : new ArraySet<>(nc.mUids);
- setAccessUids(nc.mAccessUids);
+ setAllowedUids(nc.mAllowedUids);
setAdministratorUids(nc.getAdministratorUids());
mOwnerUid = nc.mOwnerUid;
mForbiddenNetworkCapabilities = nc.mForbiddenNetworkCapabilities;
@@ -1029,7 +1034,7 @@
final int[] originalAdministratorUids = getAdministratorUids();
final TransportInfo originalTransportInfo = getTransportInfo();
final Set<Integer> originalSubIds = getSubscriptionIds();
- final Set<Integer> originalAccessUids = new ArraySet<>(mAccessUids);
+ final Set<Integer> originalAllowedUids = new ArraySet<>(mAllowedUids);
clearAll();
if (0 != (originalCapabilities & (1 << NET_CAPABILITY_NOT_RESTRICTED))) {
// If the test network is not restricted, then it is only allowed to declare some
@@ -1049,7 +1054,7 @@
mNetworkSpecifier = originalSpecifier;
mSignalStrength = originalSignalStrength;
mTransportInfo = originalTransportInfo;
- mAccessUids.addAll(originalAccessUids);
+ mAllowedUids.addAll(originalAllowedUids);
// Only retain the owner and administrator UIDs if they match the app registering the remote
// caller that registered the network.
@@ -1836,20 +1841,20 @@
* @hide
*/
@NonNull
- private final ArraySet<Integer> mAccessUids = new ArraySet<>();
+ private final ArraySet<Integer> mAllowedUids = new ArraySet<>();
/**
* Set the list of UIDs that can always access this network.
* @param uids
* @hide
*/
- public void setAccessUids(@NonNull final Set<Integer> uids) {
+ public void setAllowedUids(@NonNull final Set<Integer> uids) {
// could happen with nc.set(nc), cheaper than always making a defensive copy
- if (uids == mAccessUids) return;
+ if (uids == mAllowedUids) return;
Objects.requireNonNull(uids);
- mAccessUids.clear();
- mAccessUids.addAll(uids);
+ mAllowedUids.clear();
+ mAllowedUids.addAll(uids);
}
/**
@@ -1867,35 +1872,36 @@
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
- public @NonNull Set<Integer> getAccessUids() {
- return new ArraySet<>(mAccessUids);
+ public @NonNull Set<Integer> getAllowedUids() {
+ return new ArraySet<>(mAllowedUids);
}
/** @hide */
// For internal clients that know what they are doing and need to avoid the performance hit
// of the defensive copy.
- public @NonNull ArraySet<Integer> getAccessUidsNoCopy() {
- return mAccessUids;
+ public @NonNull ArraySet<Integer> getAllowedUidsNoCopy() {
+ return mAllowedUids;
}
/**
- * Test whether this UID has special permission to access this network, as per mAccessUids.
+ * Test whether this UID has special permission to access this network, as per mAllowedUids.
* @hide
*/
- public boolean isAccessUid(int uid) {
- return mAccessUids.contains(uid);
+ // TODO : should this be "doesUidHaveAccess" and check the USE_RESTRICTED_NETWORKS permission ?
+ public boolean isUidWithAccess(int uid) {
+ return mAllowedUids.contains(uid);
}
/**
* @return whether any UID is in the list of access UIDs
* @hide
*/
- public boolean hasAccessUids() {
- return !mAccessUids.isEmpty();
+ public boolean hasAllowedUids() {
+ return !mAllowedUids.isEmpty();
}
- private boolean equalsAccessUids(@NonNull NetworkCapabilities other) {
- return mAccessUids.equals(other.mAccessUids);
+ private boolean equalsAllowedUids(@NonNull NetworkCapabilities other) {
+ return mAllowedUids.equals(other.mAllowedUids);
}
/**
@@ -2052,7 +2058,7 @@
&& equalsSpecifier(that)
&& equalsTransportInfo(that)
&& equalsUids(that)
- && equalsAccessUids(that)
+ && equalsAllowedUids(that)
&& equalsSSID(that)
&& equalsOwnerUid(that)
&& equalsPrivateDnsBroken(that)
@@ -2077,7 +2083,7 @@
+ mSignalStrength * 29
+ mOwnerUid * 31
+ Objects.hashCode(mUids) * 37
- + Objects.hashCode(mAccessUids) * 41
+ + Objects.hashCode(mAllowedUids) * 41
+ Objects.hashCode(mSSID) * 43
+ Objects.hashCode(mTransportInfo) * 47
+ Objects.hashCode(mPrivateDnsBroken) * 53
@@ -2114,7 +2120,7 @@
dest.writeParcelable((Parcelable) mTransportInfo, flags);
dest.writeInt(mSignalStrength);
writeParcelableArraySet(dest, mUids, flags);
- dest.writeIntArray(CollectionUtils.toIntArray(mAccessUids));
+ dest.writeIntArray(CollectionUtils.toIntArray(mAllowedUids));
dest.writeString(mSSID);
dest.writeBoolean(mPrivateDnsBroken);
dest.writeIntArray(getAdministratorUids());
@@ -2141,10 +2147,10 @@
netCap.mTransportInfo = in.readParcelable(null);
netCap.mSignalStrength = in.readInt();
netCap.mUids = readParcelableArraySet(in, null /* ClassLoader, null for default */);
- final int[] accessUids = in.createIntArray();
- netCap.mAccessUids.ensureCapacity(accessUids.length);
- for (int uid : accessUids) {
- netCap.mAccessUids.add(uid);
+ final int[] allowedUids = in.createIntArray();
+ netCap.mAllowedUids.ensureCapacity(allowedUids.length);
+ for (int uid : allowedUids) {
+ netCap.mAllowedUids.add(uid);
}
netCap.mSSID = in.readString();
netCap.mPrivateDnsBroken = in.readBoolean();
@@ -2223,8 +2229,8 @@
}
}
- if (hasAccessUids()) {
- sb.append(" AccessUids: <").append(mAccessUids).append(">");
+ if (hasAllowedUids()) {
+ sb.append(" AllowedUids: <").append(mAllowedUids).append(">");
}
if (mOwnerUid != Process.INVALID_UID) {
@@ -3043,9 +3049,9 @@
@NonNull
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
- public Builder setAccessUids(@NonNull Set<Integer> uids) {
+ public Builder setAllowedUids(@NonNull Set<Integer> uids) {
Objects.requireNonNull(uids);
- mCaps.setAccessUids(uids);
+ mCaps.setAllowedUids(uids);
return this;
}
diff --git a/framework/src/android/net/NetworkReleasedException.java b/framework/src/android/net/NetworkReleasedException.java
index 0629b75..cdfb6a1 100644
--- a/framework/src/android/net/NetworkReleasedException.java
+++ b/framework/src/android/net/NetworkReleasedException.java
@@ -18,6 +18,8 @@
import android.annotation.SystemApi;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
* Indicates that the {@link Network} was released and is no longer available.
*
@@ -25,7 +27,7 @@
*/
@SystemApi
public class NetworkReleasedException extends Exception {
- /** @hide */
+ @VisibleForTesting
public NetworkReleasedException() {
super("The network was released and is no longer available");
}
diff --git a/framework/src/android/net/ProfileNetworkPreference.java b/framework/src/android/net/ProfileNetworkPreference.java
index f43acce..fb271e3 100644
--- a/framework/src/android/net/ProfileNetworkPreference.java
+++ b/framework/src/android/net/ProfileNetworkPreference.java
@@ -22,14 +22,12 @@
import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_5;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.ConnectivityManager.ProfileNetworkPreferencePolicy;
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Arrays;
import java.util.Objects;
/**
@@ -41,31 +39,31 @@
public final class ProfileNetworkPreference implements Parcelable {
private final @ProfileNetworkPreferencePolicy int mPreference;
private final @NetworkCapabilities.EnterpriseId int mPreferenceEnterpriseId;
- private final List<Integer> mIncludedUids;
- private final List<Integer> mExcludedUids;
+ private int[] mIncludedUids = new int[0];
+ private int[] mExcludedUids = new int[0];
- private ProfileNetworkPreference(int preference, List<Integer> includedUids,
- List<Integer> excludedUids,
+ private ProfileNetworkPreference(int preference, int[] includedUids,
+ int[] excludedUids,
@NetworkCapabilities.EnterpriseId int preferenceEnterpriseId) {
mPreference = preference;
mPreferenceEnterpriseId = preferenceEnterpriseId;
if (includedUids != null) {
- mIncludedUids = new ArrayList<>(includedUids);
+ mIncludedUids = includedUids.clone();
} else {
- mIncludedUids = new ArrayList<>();
+ mIncludedUids = new int[0];
}
if (excludedUids != null) {
- mExcludedUids = new ArrayList<>(excludedUids);
+ mExcludedUids = excludedUids.clone();
} else {
- mExcludedUids = new ArrayList<>();
+ mExcludedUids = new int[0];
}
}
private ProfileNetworkPreference(Parcel in) {
mPreference = in.readInt();
- mIncludedUids = in.readArrayList(Integer.class.getClassLoader());
- mExcludedUids = in.readArrayList(Integer.class.getClassLoader());
+ in.readIntArray(mIncludedUids);
+ in.readIntArray(mExcludedUids);
mPreferenceEnterpriseId = in.readInt();
}
@@ -74,31 +72,31 @@
}
/**
- * Get the list of UIDs subject to this preference.
+ * Get the array of UIDs subject to this preference.
*
* Included UIDs and Excluded UIDs can't both be non-empty.
* if both are empty, it means this request applies to all uids in the user profile.
* if included is not empty, then only included UIDs are applied.
* if excluded is not empty, then it is all uids in the user profile except these UIDs.
- * @return List of uids included for the profile preference.
+ * @return Array of uids included for the profile preference.
* {@see #getExcludedUids()}
*/
- public @NonNull List<Integer> getIncludedUids() {
- return new ArrayList<>(mIncludedUids);
+ public @NonNull int[] getIncludedUids() {
+ return mIncludedUids.clone();
}
/**
- * Get the list of UIDS excluded from this preference.
+ * Get the array of UIDS excluded from this preference.
*
* <ul>Included UIDs and Excluded UIDs can't both be non-empty.</ul>
* <ul>If both are empty, it means this request applies to all uids in the user profile.</ul>
* <ul>If included is not empty, then only included UIDs are applied.</ul>
* <ul>If excluded is not empty, then it is all uids in the user profile except these UIDs.</ul>
- * @return List of uids not included for the profile preference.
+ * @return Array of uids not included for the profile preference.
* {@see #getIncludedUids()}
*/
- public @NonNull List<Integer> getExcludedUids() {
- return new ArrayList<>(mExcludedUids);
+ public @NonNull int[] getExcludedUids() {
+ return mExcludedUids.clone();
}
/**
@@ -134,8 +132,8 @@
if (o == null || getClass() != o.getClass()) return false;
final ProfileNetworkPreference that = (ProfileNetworkPreference) o;
return mPreference == that.mPreference
- && (Objects.equals(mIncludedUids, that.mIncludedUids))
- && (Objects.equals(mExcludedUids, that.mExcludedUids))
+ && (Arrays.equals(mIncludedUids, that.mIncludedUids))
+ && (Arrays.equals(mExcludedUids, that.mExcludedUids))
&& mPreferenceEnterpriseId == that.mPreferenceEnterpriseId;
}
@@ -143,8 +141,8 @@
public int hashCode() {
return mPreference
+ mPreferenceEnterpriseId * 2
- + (Objects.hashCode(mIncludedUids) * 11)
- + (Objects.hashCode(mExcludedUids) * 13);
+ + (Arrays.hashCode(mIncludedUids) * 11)
+ + (Arrays.hashCode(mExcludedUids) * 13);
}
/**
@@ -154,8 +152,8 @@
public static final class Builder {
private @ProfileNetworkPreferencePolicy int mPreference =
PROFILE_NETWORK_PREFERENCE_DEFAULT;
- private @NonNull List<Integer> mIncludedUids = new ArrayList<>();
- private @NonNull List<Integer> mExcludedUids = new ArrayList<>();
+ private int[] mIncludedUids = new int[0];
+ private int[] mExcludedUids = new int[0];
private int mPreferenceEnterpriseId;
/**
@@ -177,44 +175,38 @@
}
/**
- * This is a list of uids for which profile perefence is set.
- * Null would mean that this preference applies to all uids in the profile.
- * {@see #setExcludedUids(List<Integer>)}
+ * This is a array of uids for which profile perefence is set.
+ * Empty would mean that this preference applies to all uids in the profile.
+ * {@see #setExcludedUids(int[])}
* Included UIDs and Excluded UIDs can't both be non-empty.
* if both are empty, it means this request applies to all uids in the user profile.
* if included is not empty, then only included UIDs are applied.
* if excluded is not empty, then it is all uids in the user profile except these UIDs.
- * @param uids list of uids that are included
+ * @param uids Array of uids that are included
* @return The builder to facilitate chaining.
*/
@NonNull
- public Builder setIncludedUids(@Nullable List<Integer> uids) {
- if (uids != null) {
- mIncludedUids = new ArrayList<Integer>(uids);
- } else {
- mIncludedUids = new ArrayList<Integer>();
- }
+ public Builder setIncludedUids(@NonNull int[] uids) {
+ Objects.requireNonNull(uids);
+ mIncludedUids = uids.clone();
return this;
}
/**
- * This is a list of uids that are excluded for the profile perefence.
- * {@see #setIncludedUids(List<Integer>)}
+ * This is a array of uids that are excluded for the profile perefence.
+ * {@see #setIncludedUids(int[])}
* Included UIDs and Excluded UIDs can't both be non-empty.
* if both are empty, it means this request applies to all uids in the user profile.
* if included is not empty, then only included UIDs are applied.
* if excluded is not empty, then it is all uids in the user profile except these UIDs.
- * @param uids list of uids that are not included
+ * @param uids Array of uids that are not included
* @return The builder to facilitate chaining.
*/
@NonNull
- public Builder setExcludedUids(@Nullable List<Integer> uids) {
- if (uids != null) {
- mExcludedUids = new ArrayList<Integer>(uids);
- } else {
- mExcludedUids = new ArrayList<Integer>();
- }
+ public Builder setExcludedUids(@NonNull int[] uids) {
+ Objects.requireNonNull(uids);
+ mExcludedUids = uids.clone();
return this;
}
@@ -241,7 +233,7 @@
*/
@NonNull
public ProfileNetworkPreference build() {
- if (mIncludedUids.size() > 0 && mExcludedUids.size() > 0) {
+ if (mIncludedUids.length > 0 && mExcludedUids.length > 0) {
throw new IllegalArgumentException("Both includedUids and excludedUids "
+ "cannot be nonempty");
}
@@ -280,8 +272,8 @@
@Override
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
dest.writeInt(mPreference);
- dest.writeList(mIncludedUids);
- dest.writeList(mExcludedUids);
+ dest.writeIntArray(mIncludedUids);
+ dest.writeIntArray(mExcludedUids);
dest.writeInt(mPreferenceEnterpriseId);
}
diff --git a/framework/src/android/net/QosCallbackException.java b/framework/src/android/net/QosCallbackException.java
index 7fd9a52..ed6eb15 100644
--- a/framework/src/android/net/QosCallbackException.java
+++ b/framework/src/android/net/QosCallbackException.java
@@ -21,6 +21,8 @@
import android.annotation.SystemApi;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -94,16 +96,12 @@
}
}
- /**
- * @hide
- */
+ @VisibleForTesting
public QosCallbackException(@NonNull final String message) {
super(message);
}
- /**
- * @hide
- */
+ @VisibleForTesting
public QosCallbackException(@NonNull final Throwable cause) {
super(cause);
}
diff --git a/framework/src/android/net/QosSession.java b/framework/src/android/net/QosSession.java
index 93f2ff2..25f3965 100644
--- a/framework/src/android/net/QosSession.java
+++ b/framework/src/android/net/QosSession.java
@@ -58,12 +58,12 @@
}
/**
- * Gets the session id that is unique within that type.
+ * Gets the {@link QosSession} identifier which is set by the actor providing the QoS.
* <p/>
- * Note: The session id is set by the actor providing the qos. It can be either manufactured by
- * the actor, but also may have a particular meaning within that type. For example, using the
- * bearer id as the session id for {@link android.telephony.data.EpsBearerQosSessionAttributes}
- * is a straight forward way to keep the sessions unique from one another within that type.
+ * Note: It can be either manufactured by the actor, but also may have a particular meaning
+ * within that type. For example, using the bearer id as the session id for
+ * {@link android.telephony.data.EpsBearerQosSessionAttributes} is a straight forward way to
+ * keep the sessions unique from one another within that type.
*
* @return the id of the session
*/
diff --git a/framework/src/android/net/SocketLocalAddressChangedException.java b/framework/src/android/net/SocketLocalAddressChangedException.java
index 9daad83..7be3793 100644
--- a/framework/src/android/net/SocketLocalAddressChangedException.java
+++ b/framework/src/android/net/SocketLocalAddressChangedException.java
@@ -18,6 +18,8 @@
import android.annotation.SystemApi;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
* Thrown when the local address of the socket has changed.
*
@@ -25,7 +27,7 @@
*/
@SystemApi
public class SocketLocalAddressChangedException extends Exception {
- /** @hide */
+ @VisibleForTesting
public SocketLocalAddressChangedException() {
super("The local address of the socket changed");
}
diff --git a/framework/src/android/net/SocketNotBoundException.java b/framework/src/android/net/SocketNotBoundException.java
index b1d7026..59f34a3 100644
--- a/framework/src/android/net/SocketNotBoundException.java
+++ b/framework/src/android/net/SocketNotBoundException.java
@@ -18,6 +18,8 @@
import android.annotation.SystemApi;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
* Thrown when a previously bound socket becomes unbound.
*
@@ -25,7 +27,7 @@
*/
@SystemApi
public class SocketNotBoundException extends Exception {
- /** @hide */
+ @VisibleForTesting
public SocketNotBoundException() {
super("The socket is unbound");
}
diff --git a/framework/src/android/net/TestNetworkManager.java b/framework/src/android/net/TestNetworkManager.java
index 9ddd2f5..280e497 100644
--- a/framework/src/android/net/TestNetworkManager.java
+++ b/framework/src/android/net/TestNetworkManager.java
@@ -49,6 +49,11 @@
@NonNull private final ITestNetworkManager mService;
+ private static final boolean TAP = false;
+ private static final boolean TUN = true;
+ private static final boolean BRING_UP = true;
+ private static final LinkAddress[] NO_ADDRS = new LinkAddress[0];
+
/** @hide */
public TestNetworkManager(@NonNull ITestNetworkManager service) {
mService = Objects.requireNonNull(service, "missing ITestNetworkManager");
@@ -155,7 +160,7 @@
public TestNetworkInterface createTunInterface(@NonNull Collection<LinkAddress> linkAddrs) {
try {
final LinkAddress[] arr = new LinkAddress[linkAddrs.size()];
- return mService.createTunInterface(linkAddrs.toArray(arr));
+ return mService.createInterface(TUN, BRING_UP, linkAddrs.toArray(arr));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -173,10 +178,28 @@
@NonNull
public TestNetworkInterface createTapInterface() {
try {
- return mService.createTapInterface();
+ return mService.createInterface(TAP, BRING_UP, NO_ADDRS);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
+ /**
+ * Create a tap interface for testing purposes
+ *
+ * @param bringUp whether to bring up the interface before returning it.
+ *
+ * @return A ParcelFileDescriptor of the underlying TAP interface. Close this to tear down the
+ * TAP interface.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_TEST_NETWORKS)
+ @NonNull
+ public TestNetworkInterface createTapInterface(boolean bringUp) {
+ try {
+ return mService.createInterface(TAP, bringUp, NO_ADDRS);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/nearby/Android.bp b/nearby/Android.bp
index b968f5d..fb4e3cd 100644
--- a/nearby/Android.bp
+++ b/nearby/Android.bp
@@ -30,7 +30,7 @@
java_library {
- name: "service-nearby",
+ name: "service-nearby-pre-jarjar",
srcs: ["service-src/**/*.java"],
sdk_version: "module_current",
min_sdk_version: "30",
diff --git a/service-t/Android.bp b/service-t/Android.bp
index 3d9820d..8851554 100644
--- a/service-t/Android.bp
+++ b/service-t/Android.bp
@@ -30,6 +30,7 @@
min_sdk_version: "30",
srcs: [
"src/**/*.java",
+ ":ethernet-service-updatable-sources",
":services.connectivity-tiramisu-updatable-sources",
],
libs: [
@@ -38,7 +39,8 @@
"framework-connectivity-t-pre-jarjar",
"framework-tethering.stubs.module_lib",
"service-connectivity-pre-jarjar",
- "service-nearby",
+ "service-nearby-pre-jarjar",
+ "ServiceConnectivityResources",
"unsupportedappusage",
],
static_libs: [
diff --git a/service-t/src/com/android/server/ConnectivityServiceInitializer.java b/service-t/src/com/android/server/ConnectivityServiceInitializer.java
index 25fe5e9..fa86f39 100644
--- a/service-t/src/com/android/server/ConnectivityServiceInitializer.java
+++ b/service-t/src/com/android/server/ConnectivityServiceInitializer.java
@@ -21,6 +21,8 @@
import com.android.modules.utils.build.SdkLevel;
import com.android.networkstack.apishim.ConstantsShim;
+import com.android.server.ethernet.EthernetService;
+import com.android.server.ethernet.EthernetServiceImpl;
import com.android.server.nearby.NearbyService;
/**
@@ -33,11 +35,13 @@
private final IpSecService mIpSecService;
private final NsdService mNsdService;
private final NearbyService mNearbyService;
+ private final EthernetServiceImpl mEthernetServiceImpl;
public ConnectivityServiceInitializer(Context context) {
super(context);
// Load JNI libraries used by ConnectivityService and its dependencies
System.loadLibrary("service-connectivity");
+ mEthernetServiceImpl = createEthernetService(context);
mConnectivity = new ConnectivityService(context);
mIpSecService = createIpSecService(context);
mNsdService = createNsdService(context);
@@ -46,6 +50,12 @@
@Override
public void onStart() {
+ if (mEthernetServiceImpl != null) {
+ Log.i(TAG, "Registering " + Context.ETHERNET_SERVICE);
+ publishBinderService(Context.ETHERNET_SERVICE, mEthernetServiceImpl,
+ /* allowIsolated= */ false);
+ }
+
Log.i(TAG, "Registering " + Context.CONNECTIVITY_SERVICE);
publishBinderService(Context.CONNECTIVITY_SERVICE, mConnectivity,
/* allowIsolated= */ false);
@@ -65,6 +75,7 @@
publishBinderService(ConstantsShim.NEARBY_SERVICE, mNearbyService,
/* allowIsolated= */ false);
}
+
}
@Override
@@ -72,6 +83,10 @@
if (mNearbyService != null) {
mNearbyService.onBootPhase(phase);
}
+
+ if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && mEthernetServiceImpl != null) {
+ mEthernetServiceImpl.start();
+ }
}
/**
@@ -106,4 +121,15 @@
return null;
}
}
+
+ /**
+ * Return EthernetServiceImpl instance or null if current SDK is lower than T or Ethernet
+ * service isn't necessary.
+ */
+ private EthernetServiceImpl createEthernetService(final Context context) {
+ if (!SdkLevel.isAtLeastT() || !mConnectivity.deviceSupportsEthernet(context)) {
+ return null;
+ }
+ return EthernetService.create(context);
+ }
}
diff --git a/service/Android.bp b/service/Android.bp
index a4d8d64..0e6fe92 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -114,6 +114,7 @@
"net-utils-device-common",
"net-utils-device-common-bpf",
"net-utils-device-common-netlink",
+ "net-utils-services-common",
"netd-client",
"networkstack-client",
"PlatformProperties",
@@ -159,7 +160,7 @@
static_libs: [
"service-connectivity-pre-jarjar",
"service-connectivity-tiramisu-pre-jarjar",
- "service-nearby",
+ "service-nearby-pre-jarjar",
],
jarjar_rules: ":connectivity-jarjar-rules",
apex_available: [
diff --git a/service/ServiceConnectivityResources/res/values/config.xml b/service/ServiceConnectivityResources/res/values/config.xml
index f8f86a2..1af00c7 100644
--- a/service/ServiceConnectivityResources/res/values/config.xml
+++ b/service/ServiceConnectivityResources/res/values/config.xml
@@ -136,4 +136,47 @@
extreme adverse effects on performance of the new network.
-->
<bool translatable="false" name="config_cellular_radio_timesharing_capable">true</bool>
+
+ <!-- Configure ethernet tcp buffersizes in the form:
+ rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max -->
+ <string translatable="false" name="config_ethernet_tcp_buffers">524288,1048576,3145728,524288,1048576,2097152</string>
+
+ <!-- Configuration of Ethernet interfaces in the following format:
+ <interface name|mac address>;[Network Capabilities];[IP config];[Override Transport]
+ Where
+ [Network Capabilities] Optional. A comma separated list of network capabilities.
+ Values must be from NetworkCapabilities#NET_CAPABILITY_* constants.
+ The NOT_ROAMING, NOT_CONGESTED and NOT_SUSPENDED capabilities are always
+ added automatically because this configuration provides no way to update
+ them dynamically.
+ [IP config] Optional. If empty or not specified - DHCP will be used, otherwise
+ use the following format to specify static IP configuration:
+ ip=<ip-address/mask> gateway=<ip-address> dns=<comma-sep-ip-addresses>
+ domains=<comma-sep-domains>
+ [Override Transport] Optional. An override network transport type to allow
+ the propagation of an interface type on the other end of a local Ethernet
+ interface. Value must be from NetworkCapabilities#TRANSPORT_* constants. If
+ left out, this will default to TRANSPORT_ETHERNET.
+ -->
+ <string-array translatable="false" name="config_ethernet_interfaces">
+ <!--
+ <item>eth1;12,13,14,15;ip=192.168.0.10/24 gateway=192.168.0.1 dns=4.4.4.4,8.8.8.8</item>
+ <item>eth2;;ip=192.168.0.11/24</item>
+ <item>eth3;12,13,14,15;ip=192.168.0.12/24;1</item>
+ -->
+ </string-array>
+
+ <!-- Regex of wired ethernet ifaces -->
+ <string translatable="false" name="config_ethernet_iface_regex">eth\\d</string>
+
+ <!-- Ignores Wi-Fi validation failures after roam.
+ If validation fails on a Wi-Fi network after a roam to a new BSSID,
+ assume that the roam temporarily disrupted network connectivity, and
+ ignore all failures until this time has passed.
+ NetworkMonitor will continue to attempt validation, and if it fails after this time has passed,
+ the network will be marked unvalidated.
+
+ Only supported up to S. On T+, the Wi-Fi code should use destroyAndAwaitReplacement in order
+ to ensure that apps see the network disconnect and reconnect. -->
+ <integer translatable="false" name="config_validationFailureAfterRoamIgnoreTimeMillis">-1</integer>
</resources>
diff --git a/service/ServiceConnectivityResources/res/values/overlayable.xml b/service/ServiceConnectivityResources/res/values/overlayable.xml
index e5010d7..b92dd08 100644
--- a/service/ServiceConnectivityResources/res/values/overlayable.xml
+++ b/service/ServiceConnectivityResources/res/values/overlayable.xml
@@ -37,6 +37,10 @@
<item type="drawable" name="stat_notify_wifi_in_range"/>
<item type="drawable" name="stat_notify_rssi_in_range"/>
<item type="bool" name="config_cellular_radio_timesharing_capable" />
+ <item type="string" name="config_ethernet_tcp_buffers"/>
+ <item type="array" name="config_ethernet_interfaces"/>
+ <item type="string" name="config_ethernet_iface_regex"/>
+ <item type="integer" name="config_validationFailureAfterRoamIgnoreTimeMillis" />
</policy>
</overlayable>
</resources>
diff --git a/service/jarjar-rules.txt b/service/jarjar-rules.txt
index 06a4cef..e90b29b 100644
--- a/service/jarjar-rules.txt
+++ b/service/jarjar-rules.txt
@@ -105,5 +105,8 @@
# From the API shims
rule com.android.networkstack.apishim.** com.android.connectivity.@0
+# From filegroup framework-connectivity-protos
+rule android.service.*Proto com.android.connectivity.@0
+
# Remaining are connectivity sources in com.android.server and com.android.server.connectivity:
# TODO: move to a subpackage of com.android.connectivity (such as com.android.connectivity.server)
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index dd92a18..e58160a 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -199,6 +199,7 @@
import android.net.resolv.aidl.PrivateDnsValidationEventParcel;
import android.net.shared.PrivateDnsConfig;
import android.net.util.MultinetworkPolicyTracker;
+import android.net.wifi.WifiInfo;
import android.os.BatteryStatsManager;
import android.os.Binder;
import android.os.Build;
@@ -348,6 +349,9 @@
private static final int DEFAULT_LINGER_DELAY_MS = 30_000;
private static final int DEFAULT_NASCENT_DELAY_MS = 5_000;
+ // The maximum value for the blocking validation result, in milliseconds.
+ public static final int MAX_VALIDATION_FAILURE_BLOCKING_TIME_MS = 10000;
+
// The maximum number of network request allowed per uid before an exception is thrown.
@VisibleForTesting
static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
@@ -936,7 +940,7 @@
}
// Ethernet is often not specified in the configs, although many devices can use it via
// USB host adapters. Add it as long as the ethernet service is here.
- if (ctx.getSystemService(Context.ETHERNET_SERVICE) != null) {
+ if (deviceSupportsEthernet(ctx)) {
addSupportedType(TYPE_ETHERNET);
}
@@ -1621,6 +1625,15 @@
mContext);
}
+ /**
+ * Check whether or not the device supports Ethernet transport.
+ */
+ public static boolean deviceSupportsEthernet(final Context context) {
+ final PackageManager pm = context.getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_ETHERNET)
+ || pm.hasSystemFeature(PackageManager.FEATURE_USB_HOST);
+ }
+
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
return createDefaultNetworkCapabilitiesForUidRangeSet(Collections.singleton(
new UidRange(uid, uid)));
@@ -2172,7 +2185,7 @@
@Override
@Nullable
- public LinkProperties redactLinkPropertiesForPackage(@NonNull LinkProperties lp, int uid,
+ public LinkProperties getRedactedLinkPropertiesForPackage(@NonNull LinkProperties lp, int uid,
@NonNull String packageName, @Nullable String callingAttributionTag) {
Objects.requireNonNull(packageName);
Objects.requireNonNull(lp);
@@ -2207,8 +2220,9 @@
}
@Override
- public NetworkCapabilities redactNetworkCapabilitiesForPackage(@NonNull NetworkCapabilities nc,
- int uid, @NonNull String packageName, @Nullable String callingAttributionTag) {
+ public NetworkCapabilities getRedactedNetworkCapabilitiesForPackage(
+ @NonNull NetworkCapabilities nc, int uid, @NonNull String packageName,
+ @Nullable String callingAttributionTag) {
Objects.requireNonNull(nc);
Objects.requireNonNull(packageName);
enforceNetworkStackOrSettingsPermission();
@@ -2239,10 +2253,13 @@
if (newNc.getNetworkSpecifier() != null) {
newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact());
}
- newNc.setAdministratorUids(new int[0]);
+ if (!checkAnyPermissionOf(callerPid, callerUid, android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)) {
+ newNc.setAdministratorUids(new int[0]);
+ }
if (!checkAnyPermissionOf(
callerPid, callerUid, android.Manifest.permission.NETWORK_FACTORY)) {
- newNc.setAccessUids(new ArraySet<>());
+ newNc.setAllowedUids(new ArraySet<>());
newNc.setSubscriptionIds(Collections.emptySet());
}
@@ -3502,6 +3519,12 @@
return false;
}
+ private boolean isDisconnectRequest(Message msg) {
+ if (msg.what != NetworkAgent.EVENT_NETWORK_INFO_CHANGED) return false;
+ final NetworkInfo info = (NetworkInfo) ((Pair) msg.obj).second;
+ return info.getState() == NetworkInfo.State.DISCONNECTED;
+ }
+
// must be stateless - things change under us.
private class NetworkStateTrackerHandler extends Handler {
public NetworkStateTrackerHandler(Looper looper) {
@@ -3518,10 +3541,16 @@
return;
}
+ // If the network has been destroyed, the only thing that it can do is disconnect.
+ if (nai.destroyed && !isDisconnectRequest(msg)) {
+ return;
+ }
+
switch (msg.what) {
case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
final NetworkCapabilities networkCapabilities = new NetworkCapabilities(
(NetworkCapabilities) arg.second);
+ maybeUpdateWifiRoamTimestamp(nai, networkCapabilities);
processCapabilitiesFromAgent(nai, networkCapabilities);
updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
break;
@@ -3619,12 +3648,60 @@
}
break;
}
+ case NetworkAgent.EVENT_DESTROY_AND_AWAIT_REPLACEMENT: {
+ // If nai is not yet created, or is already destroyed, ignore.
+ if (!shouldDestroyNativeNetwork(nai)) break;
+
+ final int timeoutMs = (int) arg.second;
+ if (timeoutMs < 0 || timeoutMs > NetworkAgent.MAX_TEARDOWN_DELAY_MS) {
+ Log.e(TAG, "Invalid network replacement timer " + timeoutMs
+ + ", must be between 0 and " + NetworkAgent.MAX_TEARDOWN_DELAY_MS);
+ }
+
+ // Marking a network awaiting replacement is used to ensure that any requests
+ // satisfied by the network do not switch to another network until a
+ // replacement is available or the wait for a replacement times out.
+ // If the network is inactive (i.e., nascent or lingering), then there are no
+ // such requests, and there is no point keeping it. Just tear it down.
+ // Note that setLingerDuration(0) cannot be used to do this because the network
+ // could be nascent.
+ nai.clearInactivityState();
+ if (unneeded(nai, UnneededFor.TEARDOWN)) {
+ Log.d(TAG, nai.toShortString()
+ + " marked awaiting replacement is unneeded, tearing down instead");
+ teardownUnneededNetwork(nai);
+ break;
+ }
+
+ Log.d(TAG, "Marking " + nai.toShortString()
+ + " destroyed, awaiting replacement within " + timeoutMs + "ms");
+ destroyNativeNetwork(nai);
+
+ // TODO: deduplicate this call with the one in disconnectAndDestroyNetwork.
+ // This is not trivial because KeepaliveTracker#handleStartKeepalive does not
+ // consider the fact that the network could already have disconnected or been
+ // destroyed. Fix the code to send ERROR_INVALID_NETWORK when this happens
+ // (taking care to ensure no dup'd FD leaks), then remove the code duplication
+ // and move this code to a sensible location (destroyNativeNetwork perhaps?).
+ mKeepaliveTracker.handleStopAllKeepalives(nai,
+ SocketKeepalive.ERROR_INVALID_NETWORK);
+
+ nai.updateScoreForNetworkAgentUpdate();
+ // This rematch is almost certainly not going to result in any changes, because
+ // the destroyed flag is only just above the "current satisfier wins"
+ // tie-breaker. But technically anything that affects scoring should rematch.
+ rematchAllNetworksAndRequests();
+ mHandler.postDelayed(() -> nai.disconnect(), timeoutMs);
+ break;
+ }
}
}
private boolean maybeHandleNetworkMonitorMessage(Message msg) {
final int netId = msg.arg2;
final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
+ // If a network has already been destroyed, all NetworkMonitor updates are ignored.
+ if (nai != null && nai.destroyed) return true;
switch (msg.what) {
default:
return false;
@@ -3721,15 +3798,22 @@
private void handleNetworkTested(
@NonNull NetworkAgentInfo nai, int testResult, @NonNull String redirectUrl) {
+ final boolean valid = ((testResult & NETWORK_VALIDATION_RESULT_VALID) != 0);
+ if (!valid && shouldIgnoreValidationFailureAfterRoam(nai)) {
+ // Assume the validation failure is due to a temporary failure after roaming
+ // and ignore it. NetworkMonitor will continue to retry validation. If it
+ // continues to fail after the block timeout expires, the network will be
+ // marked unvalidated. If it succeeds, then validation state will not change.
+ return;
+ }
+
+ final boolean wasValidated = nai.lastValidated;
+ final boolean wasDefault = isDefaultNetwork(nai);
final boolean wasPartial = nai.partialConnectivity;
nai.partialConnectivity = ((testResult & NETWORK_VALIDATION_RESULT_PARTIAL) != 0);
final boolean partialConnectivityChanged =
(wasPartial != nai.partialConnectivity);
- final boolean valid = ((testResult & NETWORK_VALIDATION_RESULT_VALID) != 0);
- final boolean wasValidated = nai.lastValidated;
- final boolean wasDefault = isDefaultNetwork(nai);
-
if (DBG) {
final String logMsg = !TextUtils.isEmpty(redirectUrl)
? " with redirect to " + redirectUrl
@@ -4124,6 +4208,27 @@
}
}
+ private static boolean shouldDestroyNativeNetwork(@NonNull NetworkAgentInfo nai) {
+ return nai.created && !nai.destroyed;
+ }
+
+ private boolean shouldIgnoreValidationFailureAfterRoam(NetworkAgentInfo nai) {
+ // T+ devices should use destroyAndAwaitReplacement.
+ if (SdkLevel.isAtLeastT()) return false;
+ final long blockTimeOut = Long.valueOf(mResources.get().getInteger(
+ R.integer.config_validationFailureAfterRoamIgnoreTimeMillis));
+ if (blockTimeOut <= MAX_VALIDATION_FAILURE_BLOCKING_TIME_MS
+ && blockTimeOut >= 0) {
+ final long currentTimeMs = SystemClock.elapsedRealtime();
+ long timeSinceLastRoam = currentTimeMs - nai.lastRoamTimestamp;
+ if (timeSinceLastRoam <= blockTimeOut) {
+ log ("blocked because only " + timeSinceLastRoam + "ms after roam");
+ return true;
+ }
+ }
+ return false;
+ }
+
private void handleNetworkAgentDisconnected(Message msg) {
NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj;
disconnectAndDestroyNetwork(nai);
@@ -4230,7 +4335,7 @@
}
private void destroyNetwork(NetworkAgentInfo nai) {
- if (nai.created) {
+ if (shouldDestroyNativeNetwork(nai)) {
// Tell netd to clean up the configuration for this network
// (routing rules, DNS, etc).
// This may be slow as it requires a lot of netd shelling out to ip and
@@ -4239,15 +4344,15 @@
// network or service a new request from an app), so network traffic isn't interrupted
// for an unnecessarily long time.
destroyNativeNetwork(nai);
- mDnsManager.removeNetwork(nai.network);
-
- // clean up tc police filters on interface.
- if (nai.everConnected && canNetworkBeRateLimited(nai) && mIngressRateLimit >= 0) {
- mDeps.disableIngressRateLimit(nai.linkProperties.getInterfaceName());
- }
+ }
+ if (!nai.created && !SdkLevel.isAtLeastT()) {
+ // Backwards compatibility: send onNetworkDestroyed even if network was never created.
+ // This can never run if the code above runs because shouldDestroyNativeNetwork is
+ // false if the network was never created.
+ // TODO: delete when S is no longer supported.
+ nai.onNetworkDestroyed();
}
mNetIdManager.releaseNetId(nai.network.getNetId());
- nai.onNetworkDestroyed();
}
private boolean createNativeNetwork(@NonNull NetworkAgentInfo nai) {
@@ -4290,6 +4395,18 @@
} catch (RemoteException | ServiceSpecificException e) {
loge("Exception destroying network: " + e);
}
+ // TODO: defer calling this until the network is removed from mNetworkAgentInfos.
+ // Otherwise, a private DNS configuration update for a destroyed network, or one that never
+ // gets created, could add data to DnsManager data structures that will never get deleted.
+ mDnsManager.removeNetwork(nai.network);
+
+ // clean up tc police filters on interface.
+ if (nai.everConnected && canNetworkBeRateLimited(nai) && mIngressRateLimit >= 0) {
+ mDeps.disableIngressRateLimit(nai.linkProperties.getInterfaceName());
+ }
+
+ nai.destroyed = true;
+ nai.onNetworkDestroyed();
}
// If this method proves to be too slow then we can maintain a separate
@@ -6381,7 +6498,7 @@
if (nc.isPrivateDnsBroken()) {
throw new IllegalArgumentException("Can't request broken private DNS");
}
- if (nc.hasAccessUids()) {
+ if (nc.hasAllowedUids()) {
throw new IllegalArgumentException("Can't request access UIDs");
}
}
@@ -7838,7 +7955,7 @@
final NetworkCapabilities prevNc = nai.getAndSetNetworkCapabilities(newNc);
updateVpnUids(nai, prevNc, newNc);
- updateAccessUids(nai, prevNc, newNc);
+ updateAllowedUids(nai, prevNc, newNc);
nai.updateScoreForNetworkAgentUpdate();
if (nai.getCurrentScore() == oldScore && newNc.equalRequestableCapabilities(prevNc)) {
@@ -8068,17 +8185,17 @@
}
}
- private void updateAccessUids(@NonNull NetworkAgentInfo nai,
+ private void updateAllowedUids(@NonNull NetworkAgentInfo nai,
@Nullable NetworkCapabilities prevNc, @Nullable NetworkCapabilities newNc) {
// In almost all cases both NC code for empty access UIDs. return as fast as possible.
- final boolean prevEmpty = null == prevNc || prevNc.getAccessUidsNoCopy().isEmpty();
- final boolean newEmpty = null == newNc || newNc.getAccessUidsNoCopy().isEmpty();
+ final boolean prevEmpty = null == prevNc || prevNc.getAllowedUidsNoCopy().isEmpty();
+ final boolean newEmpty = null == newNc || newNc.getAllowedUidsNoCopy().isEmpty();
if (prevEmpty && newEmpty) return;
final ArraySet<Integer> prevUids =
- null == prevNc ? new ArraySet<>() : prevNc.getAccessUidsNoCopy();
+ null == prevNc ? new ArraySet<>() : prevNc.getAllowedUidsNoCopy();
final ArraySet<Integer> newUids =
- null == newNc ? new ArraySet<>() : newNc.getAccessUidsNoCopy();
+ null == newNc ? new ArraySet<>() : newNc.getAllowedUidsNoCopy();
if (prevUids.equals(newUids)) return;
@@ -8542,11 +8659,19 @@
log(" accepting network in place of " + previousSatisfier.toShortString());
}
previousSatisfier.removeRequest(previousRequest.requestId);
- if (canSupportGracefulNetworkSwitch(previousSatisfier, newSatisfier)) {
+ if (canSupportGracefulNetworkSwitch(previousSatisfier, newSatisfier)
+ && !previousSatisfier.destroyed) {
// If this network switch can't be supported gracefully, the request is not
// lingered. This allows letting go of the network sooner to reclaim some
// performance on the new network, since the radio can't do both at the same
// time while preserving good performance.
+ //
+ // Also don't linger the request if the old network has been destroyed.
+ // A destroyed network does not provide actual network connectivity, so
+ // lingering it is not useful. In particular this ensures that a destroyed
+ // network is outscored by its replacement,
+ // then it is torn down immediately instead of being lingered, and any apps that
+ // were using it immediately get onLost and can connect using the new network.
previousSatisfier.lingerRequest(previousRequest.requestId, now);
}
} else {
@@ -9020,7 +9145,7 @@
}
networkAgent.created = true;
networkAgent.onNetworkCreated();
- updateAccessUids(networkAgent, null, networkAgent.networkCapabilities);
+ updateAllowedUids(networkAgent, null, networkAgent.networkCapabilities);
}
if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) {
@@ -9520,6 +9645,18 @@
return ((VpnTransportInfo) ti).getType();
}
+ private void maybeUpdateWifiRoamTimestamp(NetworkAgentInfo nai, NetworkCapabilities nc) {
+ if (nai == null) return;
+ final TransportInfo prevInfo = nai.networkCapabilities.getTransportInfo();
+ final TransportInfo newInfo = nc.getTransportInfo();
+ if (!(prevInfo instanceof WifiInfo) || !(newInfo instanceof WifiInfo)) {
+ return;
+ }
+ if (!TextUtils.equals(((WifiInfo)prevInfo).getBSSID(), ((WifiInfo)newInfo).getBSSID())) {
+ nai.lastRoamTimestamp = SystemClock.elapsedRealtime();
+ }
+ }
+
/**
* @param connectionInfo the connection to resolve.
* @return {@code uid} if the connection is found and the app has permission to observe it
@@ -10532,15 +10669,16 @@
@NonNull final UserHandle profile,
@NonNull final ProfileNetworkPreference profileNetworkPreference) {
final UidRange profileUids = UidRange.createForUser(profile);
- Set<UidRange> uidRangeSet = UidRangeUtils.convertListToUidRange(
- profileNetworkPreference.getIncludedUids());
+ Set<UidRange> uidRangeSet = UidRangeUtils.convertArrayToUidRange(
+ profileNetworkPreference.getIncludedUids());
+
if (uidRangeSet.size() > 0) {
if (!UidRangeUtils.isRangeSetInUidRange(profileUids, uidRangeSet)) {
throw new IllegalArgumentException(
"Allow uid range is outside the uid range of profile.");
}
} else {
- ArraySet<UidRange> disallowUidRangeSet = UidRangeUtils.convertListToUidRange(
+ ArraySet<UidRange> disallowUidRangeSet = UidRangeUtils.convertArrayToUidRange(
profileNetworkPreference.getExcludedUids());
if (disallowUidRangeSet.size() > 0) {
if (!UidRangeUtils.isRangeSetInUidRange(profileUids, disallowUidRangeSet)) {
diff --git a/service/src/com/android/server/TestNetworkService.java b/service/src/com/android/server/TestNetworkService.java
index fffd2be..a0bfb4a 100644
--- a/service/src/com/android/server/TestNetworkService.java
+++ b/service/src/com/android/server/TestNetworkService.java
@@ -99,12 +99,14 @@
}
/**
- * Create a TUN or TAP interface with the given interface name and link addresses
+ * Create a TUN or TAP interface with the specified parameters.
*
* <p>This method will return the FileDescriptor to the interface. Close it to tear down the
* interface.
*/
- private TestNetworkInterface createInterface(boolean isTun, LinkAddress[] linkAddrs) {
+ @Override
+ public TestNetworkInterface createInterface(boolean isTun, boolean bringUp,
+ LinkAddress[] linkAddrs) {
enforceTestNetworkPermissions(mContext);
Objects.requireNonNull(linkAddrs, "missing linkAddrs");
@@ -122,7 +124,9 @@
addr.getPrefixLength());
}
- NetdUtils.setInterfaceUp(mNetd, iface);
+ if (bringUp) {
+ NetdUtils.setInterfaceUp(mNetd, iface);
+ }
return new TestNetworkInterface(tunIntf, iface);
} catch (RemoteException e) {
@@ -132,28 +136,6 @@
}
}
- /**
- * Create a TUN interface with the given interface name and link addresses
- *
- * <p>This method will return the FileDescriptor to the TUN interface. Close it to tear down the
- * TUN interface.
- */
- @Override
- public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
- return createInterface(true, linkAddrs);
- }
-
- /**
- * Create a TAP interface with the given interface name
- *
- * <p>This method will return the FileDescriptor to the TAP interface. Close it to tear down the
- * TAP interface.
- */
- @Override
- public TestNetworkInterface createTapInterface() {
- return createInterface(false, new LinkAddress[0]);
- }
-
// Tracker for TestNetworkAgents
@GuardedBy("mTestNetworkTracker")
@NonNull
diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java
index c1a8195..2e26ae4 100644
--- a/service/src/com/android/server/connectivity/ClatCoordinator.java
+++ b/service/src/com/android/server/connectivity/ClatCoordinator.java
@@ -24,6 +24,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.INetd;
+import android.net.InetAddresses;
import android.net.InterfaceConfigurationParcel;
import android.net.IpPrefix;
import android.os.ParcelFileDescriptor;
@@ -36,8 +37,11 @@
import java.io.FileDescriptor;
import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.nio.ByteBuffer;
+import java.util.Objects;
/**
* This coordinator is responsible for providing clat relevant functionality.
@@ -66,23 +70,13 @@
private static final InetAddress GOOGLE_DNS_4 = InetAddress.parseNumericAddress("8.8.8.8");
private static final int INVALID_IFINDEX = 0;
- private static final int INVALID_PID = 0;
- private static final long INVALID_COOKIE = 0;
@NonNull
private final INetd mNetd;
@NonNull
private final Dependencies mDeps;
@Nullable
- private String mIface = null;
- @Nullable
- private String mNat64Prefix = null;
- @Nullable
- private String mXlatLocalAddress4 = null;
- @Nullable
- private String mXlatLocalAddress6 = null;
- private int mPid = INVALID_PID;
- private long mCookie = INVALID_COOKIE;
+ private ClatdTracker mClatdTracker = null;
@VisibleForTesting
abstract static class Dependencies {
@@ -204,6 +198,53 @@
}
@VisibleForTesting
+ static class ClatdTracker {
+ @NonNull
+ public final String iface;
+ public final int ifIndex;
+ @NonNull
+ public final String v4iface;
+ public final int v4ifIndex;
+ @NonNull
+ public final Inet4Address v4;
+ @NonNull
+ public final Inet6Address v6;
+ @NonNull
+ public final Inet6Address pfx96;
+ public final int pid;
+ public final long cookie;
+
+ ClatdTracker(@NonNull String iface, int ifIndex, @NonNull String v4iface,
+ int v4ifIndex, @NonNull Inet4Address v4, @NonNull Inet6Address v6,
+ @NonNull Inet6Address pfx96, int pid, long cookie) {
+ this.iface = iface;
+ this.ifIndex = ifIndex;
+ this.v4iface = v4iface;
+ this.v4ifIndex = v4ifIndex;
+ this.v4 = v4;
+ this.v6 = v6;
+ this.pfx96 = pfx96;
+ this.pid = pid;
+ this.cookie = cookie;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof ClatdTracker)) return false;
+ ClatdTracker that = (ClatdTracker) o;
+ return Objects.equals(this.iface, that.iface)
+ && this.ifIndex == that.ifIndex
+ && Objects.equals(this.v4iface, that.v4iface)
+ && this.v4ifIndex == that.v4ifIndex
+ && Objects.equals(this.v4, that.v4)
+ && Objects.equals(this.v6, that.v6)
+ && Objects.equals(this.pfx96, that.pfx96)
+ && this.pid == that.pid
+ && this.cookie == that.cookie;
+ }
+ };
+
+ @VisibleForTesting
static int getFwmark(int netId) {
// See union Fwmark in system/netd/include/Fwmark.h
return (netId & 0xffff)
@@ -235,30 +276,46 @@
public String clatStart(final String iface, final int netId,
@NonNull final IpPrefix nat64Prefix)
throws IOException {
- if (mIface != null || mPid != INVALID_PID) {
- throw new IOException("Clatd is already running on " + mIface + " (pid " + mPid + ")");
+ if (mClatdTracker != null) {
+ throw new IOException("Clatd is already running on " + mClatdTracker.iface
+ + " (pid " + mClatdTracker.pid + ")");
}
if (nat64Prefix.getPrefixLength() != 96) {
throw new IOException("Prefix must be 96 bits long: " + nat64Prefix);
}
// [1] Pick an IPv4 address from 192.0.0.4, 192.0.0.5, 192.0.0.6 ..
- final String v4;
+ final String v4Str;
try {
- v4 = mDeps.selectIpv4Address(INIT_V4ADDR_STRING, INIT_V4ADDR_PREFIX_LEN);
+ v4Str = mDeps.selectIpv4Address(INIT_V4ADDR_STRING, INIT_V4ADDR_PREFIX_LEN);
} catch (IOException e) {
throw new IOException("no IPv4 addresses were available for clat: " + e);
}
- // [2] Generate a checksum-neutral IID.
- final String pfx96 = nat64Prefix.getAddress().getHostAddress();
- final String v6;
+ final Inet4Address v4;
try {
- v6 = mDeps.generateIpv6Address(iface, v4, pfx96);
+ v4 = (Inet4Address) InetAddresses.parseNumericAddress(v4Str);
+ } catch (ClassCastException | IllegalArgumentException | NullPointerException e) {
+ throw new IOException("Invalid IPv4 address " + v4Str);
+ }
+
+ // [2] Generate a checksum-neutral IID.
+ final String pfx96Str = nat64Prefix.getAddress().getHostAddress();
+ final String v6Str;
+ try {
+ v6Str = mDeps.generateIpv6Address(iface, v4Str, pfx96Str);
} catch (IOException e) {
throw new IOException("no IPv6 addresses were available for clat: " + e);
}
+ final Inet6Address pfx96 = (Inet6Address) nat64Prefix.getAddress();
+ final Inet6Address v6;
+ try {
+ v6 = (Inet6Address) InetAddresses.parseNumericAddress(v6Str);
+ } catch (ClassCastException | IllegalArgumentException | NullPointerException e) {
+ throw new IOException("Invalid IPv6 address " + v6Str);
+ }
+
// [3] Open, configure and bring up the tun interface.
// Create the v4-... tun interface.
final String tunIface = CLAT_PREFIX + iface;
@@ -269,6 +326,12 @@
throw new IOException("Create tun interface " + tunIface + " failed: " + e);
}
+ final int tunIfIndex = mDeps.getInterfaceIndex(tunIface);
+ if (tunIfIndex == INVALID_IFINDEX) {
+ tunFd.close();
+ throw new IOException("Fail to get interface index for interface " + tunIface);
+ }
+
// disable IPv6 on it - failing to do so is not a critical error
try {
mNetd.interfaceSetEnableIPv6(tunIface, false /* enabled */);
@@ -279,7 +342,7 @@
// Detect ipv4 mtu.
final Integer fwmark = getFwmark(netId);
- final int detectedMtu = mDeps.detectMtu(pfx96,
+ final int detectedMtu = mDeps.detectMtu(pfx96Str,
ByteBuffer.wrap(GOOGLE_DNS_4.getAddress()).getInt(), fwmark);
final int mtu = adjustMtu(detectedMtu);
Log.i(TAG, "ipv4 mtu is " + mtu);
@@ -295,7 +358,7 @@
}
final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel();
ifConfig.ifName = tunIface;
- ifConfig.ipv4Addr = v4;
+ ifConfig.ipv4Addr = v4Str;
ifConfig.prefixLength = 32;
ifConfig.hwAddr = "";
ifConfig.flags = new String[] {IF_STATE_UP};
@@ -333,8 +396,8 @@
throw new IOException("Open raw socket failed: " + e);
}
- final int ifaceIndex = mDeps.getInterfaceIndex(iface);
- if (ifaceIndex == INVALID_IFINDEX) {
+ final int ifIndex = mDeps.getInterfaceIndex(iface);
+ if (ifIndex == INVALID_IFINDEX) {
tunFd.close();
readSock6.close();
writeSock6.close();
@@ -343,7 +406,7 @@
// Start translating packets to the new prefix.
try {
- mDeps.addAnycastSetsockopt(writeSock6.getFileDescriptor(), v6, ifaceIndex);
+ mDeps.addAnycastSetsockopt(writeSock6.getFileDescriptor(), v6Str, ifIndex);
} catch (IOException e) {
tunFd.close();
readSock6.close();
@@ -352,7 +415,7 @@
}
// Tag socket as AID_CLAT to avoid duplicated CLAT data usage accounting.
- long cookie;
+ final long cookie;
try {
cookie = mDeps.tagSocketAsClat(writeSock6.getFileDescriptor());
} catch (IOException e) {
@@ -364,7 +427,7 @@
// Update our packet socket filter to reflect the new 464xlat IP address.
try {
- mDeps.configurePacketSocket(readSock6.getFileDescriptor(), v6, ifaceIndex);
+ mDeps.configurePacketSocket(readSock6.getFileDescriptor(), v6Str, ifIndex);
} catch (IOException e) {
tunFd.close();
readSock6.close();
@@ -373,15 +436,12 @@
}
// [5] Start clatd.
+ final int pid;
try {
- mPid = mDeps.startClatd(tunFd.getFileDescriptor(), readSock6.getFileDescriptor(),
- writeSock6.getFileDescriptor(), iface, pfx96, v4, v6);
- mIface = iface;
- mNat64Prefix = pfx96;
- mXlatLocalAddress4 = v4;
- mXlatLocalAddress6 = v6;
- mCookie = cookie;
+ pid = mDeps.startClatd(tunFd.getFileDescriptor(), readSock6.getFileDescriptor(),
+ writeSock6.getFileDescriptor(), iface, pfx96Str, v4Str, v6Str);
} catch (IOException e) {
+ // TODO: probably refactor to handle the exception of #untagSocket if any.
mDeps.untagSocket(cookie);
throw new IOException("Error start clatd on " + iface + ": " + e);
} finally {
@@ -390,29 +450,38 @@
writeSock6.close();
}
- return v6;
+ // [6] Initialize and store clatd tracker object.
+ mClatdTracker = new ClatdTracker(iface, ifIndex, tunIface, tunIfIndex, v4, v6, pfx96,
+ pid, cookie);
+
+ return v6Str;
}
/**
* Stop clatd
*/
public void clatStop() throws IOException {
- if (mPid == INVALID_PID) {
+ if (mClatdTracker == null) {
throw new IOException("Clatd has not started");
}
- Log.i(TAG, "Stopping clatd pid=" + mPid + " on " + mIface);
+ Log.i(TAG, "Stopping clatd pid=" + mClatdTracker.pid + " on " + mClatdTracker.iface);
- mDeps.stopClatd(mIface, mNat64Prefix, mXlatLocalAddress4, mXlatLocalAddress6, mPid);
- mDeps.untagSocket(mCookie);
+ mDeps.stopClatd(mClatdTracker.iface, mClatdTracker.pfx96.getHostAddress(),
+ mClatdTracker.v4.getHostAddress(), mClatdTracker.v6.getHostAddress(),
+ mClatdTracker.pid);
+ mDeps.untagSocket(mClatdTracker.cookie);
- Log.i(TAG, "clatd on " + mIface + " stopped");
+ Log.i(TAG, "clatd on " + mClatdTracker.iface + " stopped");
+ mClatdTracker = null;
+ }
- mIface = null;
- mNat64Prefix = null;
- mXlatLocalAddress4 = null;
- mXlatLocalAddress6 = null;
- mPid = INVALID_PID;
- mCookie = INVALID_COOKIE;
+ /**
+ * Get clatd tracker. For test only.
+ */
+ @VisibleForTesting
+ @Nullable
+ ClatdTracker getClatdTrackerForTesting() {
+ return mClatdTracker;
}
private static native String native_selectIpv4Address(String v4addr, int prefixlen)
diff --git a/service/src/com/android/server/connectivity/Nat464Xlat.java b/service/src/com/android/server/connectivity/Nat464Xlat.java
index c66a280..7b06682 100644
--- a/service/src/com/android/server/connectivity/Nat464Xlat.java
+++ b/service/src/com/android/server/connectivity/Nat464Xlat.java
@@ -132,8 +132,8 @@
final boolean skip464xlat = (nai.netAgentConfig() != null)
&& nai.netAgentConfig().skip464xlat;
- return supported && connected && isIpv6OnlyNetwork && !skip464xlat
- && (nai.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)
+ return supported && connected && isIpv6OnlyNetwork && !skip464xlat && !nai.destroyed
+ && (nai.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)
? isCellular464XlatEnabled() : true);
}
diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
index e29d616..b73e2cc 100644
--- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
@@ -192,6 +192,8 @@
public boolean everConnected;
// Whether this network has been destroyed and is being kept temporarily until it is replaced.
public boolean destroyed;
+ // To check how long it has been since last roam.
+ public long lastRoamTimestamp;
// Set to true if this Network successfully passed validation or if it did not satisfy the
// default NetworkRequest in which case validation will not be attempted.
@@ -732,6 +734,12 @@
mHandler.obtainMessage(NetworkAgent.EVENT_REMOVE_ALL_DSCP_POLICIES,
new Pair<>(NetworkAgentInfo.this, null)).sendToTarget();
}
+
+ @Override
+ public void sendDestroyAndAwaitReplacement(final int timeoutMillis) {
+ mHandler.obtainMessage(NetworkAgent.EVENT_DESTROY_AND_AWAIT_REPLACEMENT,
+ new Pair<>(NetworkAgentInfo.this, timeoutMillis)).sendToTarget();
+ }
}
/**
@@ -976,7 +984,7 @@
/**
* Update the ConnectivityService-managed bits in the score.
*
- * Call this after updating the network agent config.
+ * Call this after changing any data that might affect the score (e.g., agent config).
*/
public void updateScoreForNetworkAgentUpdate() {
mScore = mScore.mixInScore(networkCapabilities, networkAgentConfig,
@@ -1213,16 +1221,16 @@
if (nc.hasTransport(TRANSPORT_TEST)) {
nc.restrictCapabilitiesForTestNetwork(creatorUid);
}
- if (!areAccessUidsAcceptableFromNetworkAgent(nc, authenticator)) {
- nc.setAccessUids(new ArraySet<>());
+ if (!areAllowedUidsAcceptableFromNetworkAgent(nc, authenticator)) {
+ nc.setAllowedUids(new ArraySet<>());
}
}
- private static boolean areAccessUidsAcceptableFromNetworkAgent(
+ private static boolean areAllowedUidsAcceptableFromNetworkAgent(
@NonNull final NetworkCapabilities nc,
@Nullable final CarrierPrivilegeAuthenticator carrierPrivilegeAuthenticator) {
// NCs without access UIDs are fine.
- if (!nc.hasAccessUids()) return true;
+ if (!nc.hasAllowedUids()) return true;
// S and below must never accept access UIDs, even if an agent sends them, because netd
// didn't support the required feature in S.
if (!SdkLevel.isAtLeastT()) return false;
@@ -1238,9 +1246,9 @@
// This can only work in T where there is support for CarrierPrivilegeAuthenticator
if (null != carrierPrivilegeAuthenticator
&& nc.hasSingleTransport(TRANSPORT_CELLULAR)
- && (1 == nc.getAccessUidsNoCopy().size())
+ && (1 == nc.getAllowedUidsNoCopy().size())
&& (carrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities(
- nc.getAccessUidsNoCopy().valueAt(0), nc))) {
+ nc.getAllowedUidsNoCopy().valueAt(0), nc))) {
return true;
}
@@ -1256,6 +1264,8 @@
+ "network{" + network + "} handle{" + network.getNetworkHandle() + "} ni{"
+ networkInfo.toShortString() + "} "
+ mScore + " "
+ + (created ? " created" : "")
+ + (destroyed ? " destroyed" : "")
+ (isNascent() ? " nascent" : (isLingering() ? " lingering" : ""))
+ (everValidated ? " everValidated" : "")
+ (lastValidated ? " lastValidated" : "")
diff --git a/service/src/com/android/server/connectivity/NetworkDiagnostics.java b/service/src/com/android/server/connectivity/NetworkDiagnostics.java
index 2e51be3..509110d 100644
--- a/service/src/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/service/src/com/android/server/connectivity/NetworkDiagnostics.java
@@ -206,7 +206,7 @@
}
for (RouteInfo route : mLinkProperties.getRoutes()) {
- if (route.hasGateway()) {
+ if (route.getType() == RouteInfo.RTN_UNICAST && route.hasGateway()) {
InetAddress gateway = route.getGateway();
prepareIcmpMeasurement(gateway);
if (route.isIPv6Default()) {
diff --git a/service/src/com/android/server/connectivity/PermissionMonitor.java b/service/src/com/android/server/connectivity/PermissionMonitor.java
index ac46054..2885ba7 100755
--- a/service/src/com/android/server/connectivity/PermissionMonitor.java
+++ b/service/src/com/android/server/connectivity/PermissionMonitor.java
@@ -52,6 +52,7 @@
import android.net.Uri;
import android.net.util.SharedLog;
import android.os.Build;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.SystemConfigManager;
@@ -66,7 +67,10 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.modules.utils.build.SdkLevel;
import com.android.net.module.util.CollectionUtils;
+import com.android.networkstack.apishim.ProcessShimImpl;
+import com.android.networkstack.apishim.common.ProcessShim;
import com.android.server.BpfNetMaps;
import java.util.ArrayList;
@@ -95,6 +99,8 @@
private final Context mContext;
private final BpfNetMaps mBpfNetMaps;
+ private static final ProcessShim sProcessShim = ProcessShimImpl.newInstance();
+
@GuardedBy("this")
private final Set<UserHandle> mUsers = new HashSet<>();
@@ -235,6 +241,10 @@
}
}
+ private static boolean hasSdkSandbox(final int uid) {
+ return SdkLevel.isAtLeastT() && Process.isApplicationUid(uid);
+ }
+
// Return the network permission for the passed list of apps. Note that this depends on the
// current settings of the device (See isUidAllowedOnRestrictedNetworks).
private SparseIntArray makeUidsNetworkPerm(final List<PackageInfo> apps) {
@@ -247,6 +257,10 @@
final int permission = getPackageNetdNetworkPermission(app);
if (isHigherNetworkPermission(permission, uidsPerm.get(uid, PERMISSION_NONE))) {
uidsPerm.put(uid, permission);
+ if (hasSdkSandbox(uid)) {
+ int sdkSandboxUid = sProcessShim.toSdkSandboxUid(uid);
+ uidsPerm.put(sdkSandboxUid, permission);
+ }
}
}
return uidsPerm;
@@ -262,7 +276,11 @@
}
final int otherNetdPerms = getNetdPermissionMask(app.requestedPermissions,
app.requestedPermissionsFlags);
- appIdsPerm.put(appId, appIdsPerm.get(appId) | otherNetdPerms);
+ final int permission = appIdsPerm.get(appId) | otherNetdPerms;
+ appIdsPerm.put(appId, permission);
+ if (hasSdkSandbox(appId)) {
+ appIdsPerm.put(sProcessShim.toSdkSandboxUid(appId), permission);
+ }
}
return appIdsPerm;
}
@@ -288,11 +306,19 @@
final SparseIntArray appIdsPerm = new SparseIntArray();
for (final int uid : mSystemConfigManager.getSystemPermissionUids(INTERNET)) {
final int appId = UserHandle.getAppId(uid);
- appIdsPerm.put(appId, appIdsPerm.get(appId) | PERMISSION_INTERNET);
+ final int permission = appIdsPerm.get(appId) | PERMISSION_INTERNET;
+ appIdsPerm.put(appId, permission);
+ if (hasSdkSandbox(appId)) {
+ appIdsPerm.put(sProcessShim.toSdkSandboxUid(appId), permission);
+ }
}
for (final int uid : mSystemConfigManager.getSystemPermissionUids(UPDATE_DEVICE_STATS)) {
final int appId = UserHandle.getAppId(uid);
- appIdsPerm.put(appId, appIdsPerm.get(appId) | PERMISSION_UPDATE_DEVICE_STATS);
+ final int permission = appIdsPerm.get(appId) | PERMISSION_UPDATE_DEVICE_STATS;
+ appIdsPerm.put(appId, permission);
+ if (hasSdkSandbox(appId)) {
+ appIdsPerm.put(sProcessShim.toSdkSandboxUid(appId), permission);
+ }
}
return appIdsPerm;
}
@@ -592,6 +618,12 @@
SparseIntArray apps = new SparseIntArray();
apps.put(uid, permission);
+
+ if (hasSdkSandbox(uid)) {
+ int sdkSandboxUid = sProcessShim.toSdkSandboxUid(uid);
+ mUidToNetworkPerm.put(sdkSandboxUid, permission);
+ apps.put(sdkSandboxUid, permission);
+ }
sendUidsNetworkPermission(apps, true /* add */);
}
@@ -654,13 +686,25 @@
+ ", tPerm=" + permissionToString(trafficPerm));
if (permission != currentPermission) {
final SparseIntArray apps = new SparseIntArray();
+ int sdkSandboxUid = -1;
+ if (hasSdkSandbox(uid)) {
+ sdkSandboxUid = sProcessShim.toSdkSandboxUid(uid);
+ }
if (permission == PERMISSION_NONE) {
mUidToNetworkPerm.delete(uid);
apps.put(uid, PERMISSION_NETWORK); // doesn't matter which permission we pick here
+ if (sdkSandboxUid != -1) {
+ mUidToNetworkPerm.delete(sdkSandboxUid);
+ apps.put(sdkSandboxUid, PERMISSION_NETWORK);
+ }
sendUidsNetworkPermission(apps, false);
} else {
mUidToNetworkPerm.put(uid, permission);
apps.put(uid, permission);
+ if (sdkSandboxUid != -1) {
+ mUidToNetworkPerm.put(sdkSandboxUid, permission);
+ apps.put(sdkSandboxUid, permission);
+ }
sendUidsNetworkPermission(apps, true);
}
}
@@ -828,6 +872,10 @@
void sendPackagePermissionsForAppId(int appId, int permissions) {
SparseIntArray netdPermissionsAppIds = new SparseIntArray();
netdPermissionsAppIds.put(appId, permissions);
+ if (hasSdkSandbox(appId)) {
+ int sdkSandboxAppId = sProcessShim.toSdkSandboxUid(appId);
+ netdPermissionsAppIds.put(sdkSandboxAppId, permissions);
+ }
sendAppIdsTrafficPermission(netdPermissionsAppIds);
}
@@ -925,9 +973,19 @@
// Doesn't matter which permission is set here.
removedUids.put(uid, PERMISSION_NETWORK);
mUidToNetworkPerm.delete(uid);
+ if (hasSdkSandbox(uid)) {
+ int sdkSandboxUid = sProcessShim.toSdkSandboxUid(uid);
+ removedUids.put(sdkSandboxUid, PERMISSION_NETWORK);
+ mUidToNetworkPerm.delete(sdkSandboxUid);
+ }
} else {
updatedUids.put(uid, permission);
mUidToNetworkPerm.put(uid, permission);
+ if (hasSdkSandbox(uid)) {
+ int sdkSandboxUid = sProcessShim.toSdkSandboxUid(uid);
+ updatedUids.put(sdkSandboxUid, permission);
+ mUidToNetworkPerm.put(sdkSandboxUid, permission);
+ }
}
}
diff --git a/service/src/com/android/server/connectivity/UidRangeUtils.java b/service/src/com/android/server/connectivity/UidRangeUtils.java
index 7318296..541340b 100644
--- a/service/src/com/android/server/connectivity/UidRangeUtils.java
+++ b/service/src/com/android/server/connectivity/UidRangeUtils.java
@@ -21,6 +21,7 @@
import android.util.ArraySet;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -125,7 +126,7 @@
}
/**
- * Convert a list of uid to set of UidRanges.
+ * Convert a list of uids to set of UidRanges.
* @param uids list of uids
* @return set of UidRanges
* @hide
@@ -153,4 +154,34 @@
uidRangeSet.add(new UidRange(start, stop));
return uidRangeSet;
}
+
+ /**
+ * Convert an array of uids to set of UidRanges.
+ * @param uids array of uids
+ * @return set of UidRanges
+ * @hide
+ */
+ public static ArraySet<UidRange> convertArrayToUidRange(@NonNull int[] uids) {
+ Objects.requireNonNull(uids);
+ final ArraySet<UidRange> uidRangeSet = new ArraySet<UidRange>();
+ if (uids.length == 0) {
+ return uidRangeSet;
+ }
+ int[] uidsNew = uids.clone();
+ Arrays.sort(uidsNew);
+ int start = uidsNew[0];
+ int stop = start;
+
+ for (int i : uidsNew) {
+ if (i <= stop + 1) {
+ stop = i;
+ } else {
+ uidRangeSet.add(new UidRange(start, stop));
+ start = i;
+ stop = i;
+ }
+ }
+ uidRangeSet.add(new UidRange(start, stop));
+ return uidRangeSet;
+ }
}
diff --git a/tests/common/java/android/net/NetworkCapabilitiesTest.java b/tests/common/java/android/net/NetworkCapabilitiesTest.java
index b6926a8..9ae5fab 100644
--- a/tests/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/common/java/android/net/NetworkCapabilitiesTest.java
@@ -310,38 +310,38 @@
}
@Test @IgnoreUpTo(SC_V2)
- public void testSetAccessUids() {
+ public void testSetAllowedUids() {
final NetworkCapabilities nc = new NetworkCapabilities();
- assertThrows(NullPointerException.class, () -> nc.setAccessUids(null));
- assertFalse(nc.hasAccessUids());
- assertFalse(nc.isAccessUid(0));
- assertFalse(nc.isAccessUid(1000));
- assertEquals(0, nc.getAccessUids().size());
- nc.setAccessUids(new ArraySet<>());
- assertFalse(nc.hasAccessUids());
- assertFalse(nc.isAccessUid(0));
- assertFalse(nc.isAccessUid(1000));
- assertEquals(0, nc.getAccessUids().size());
+ assertThrows(NullPointerException.class, () -> nc.setAllowedUids(null));
+ assertFalse(nc.hasAllowedUids());
+ assertFalse(nc.isUidWithAccess(0));
+ assertFalse(nc.isUidWithAccess(1000));
+ assertEquals(0, nc.getAllowedUids().size());
+ nc.setAllowedUids(new ArraySet<>());
+ assertFalse(nc.hasAllowedUids());
+ assertFalse(nc.isUidWithAccess(0));
+ assertFalse(nc.isUidWithAccess(1000));
+ assertEquals(0, nc.getAllowedUids().size());
final ArraySet<Integer> uids = new ArraySet<>();
uids.add(200);
uids.add(250);
uids.add(-1);
uids.add(Integer.MAX_VALUE);
- nc.setAccessUids(uids);
+ nc.setAllowedUids(uids);
assertNotEquals(nc, new NetworkCapabilities());
- assertTrue(nc.hasAccessUids());
+ assertTrue(nc.hasAllowedUids());
final List<Integer> includedList = List.of(-2, 0, 199, 700, 901, 1000, Integer.MIN_VALUE);
final List<Integer> excludedList = List.of(-1, 200, 250, Integer.MAX_VALUE);
for (final int uid : includedList) {
- assertFalse(nc.isAccessUid(uid));
+ assertFalse(nc.isUidWithAccess(uid));
}
for (final int uid : excludedList) {
- assertTrue(nc.isAccessUid(uid));
+ assertTrue(nc.isUidWithAccess(uid));
}
- final Set<Integer> outUids = nc.getAccessUids();
+ final Set<Integer> outUids = nc.getAllowedUids();
assertEquals(4, outUids.size());
for (final int uid : includedList) {
assertFalse(outUids.contains(uid));
@@ -361,10 +361,10 @@
.addCapability(NET_CAPABILITY_EIMS)
.addCapability(NET_CAPABILITY_NOT_METERED);
if (isAtLeastS()) {
- final ArraySet<Integer> accessUids = new ArraySet<>();
- accessUids.add(4);
- accessUids.add(9);
- netCap.setAccessUids(accessUids);
+ final ArraySet<Integer> allowedUids = new ArraySet<>();
+ allowedUids.add(4);
+ allowedUids.add(9);
+ netCap.setAllowedUids(allowedUids);
netCap.setSubscriptionIds(Set.of(TEST_SUBID1, TEST_SUBID2));
netCap.setUids(uids);
}
diff --git a/tests/cts/OWNERS b/tests/cts/OWNERS
index 8dfa455..d782008 100644
--- a/tests/cts/OWNERS
+++ b/tests/cts/OWNERS
@@ -1,3 +1,4 @@
-# Bug component: 31808
+# Bug template url: http://b/new?component=31808
+# Bug component: 685852 = per-file **IpSec*
set noparent
file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking_xts
diff --git a/tests/cts/net/OWNERS b/tests/cts/net/OWNERS
deleted file mode 100644
index df5569e..0000000
--- a/tests/cts/net/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 31808
-# Inherits parent owners
-per-file src/android/net/cts/NetworkWatchlistTest.java=alanstokes@google.com
-
-# Bug component: 685852 = per-file *IpSec*
\ No newline at end of file
diff --git a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
index a378aa7..0344604 100644
--- a/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
+++ b/tests/cts/net/src/android/net/cts/CaptivePortalTest.kt
@@ -77,7 +77,7 @@
// Re-connecting to the AP, obtaining an IP address, revalidating can take a long time
private const val WIFI_CONNECT_TIMEOUT_MS = 40_000L
-private const val TEST_TIMEOUT_MS = 10_000L
+private const val TEST_TIMEOUT_MS = 20_000L
private const val TAG = "CaptivePortalTest"
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 5e8bffa..d40bc9f 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -591,7 +591,7 @@
@DevSdkIgnoreRule.IgnoreUpTo(SC_V2)
@Test
- public void testRedactLinkPropertiesForPackage() throws Exception {
+ public void testGetRedactedLinkPropertiesForPackage() throws Exception {
final String groundedPkg = findPackageByPermissions(
List.of(), /* requiredPermissions */
List.of(ACCESS_NETWORK_STATE) /* forbiddenPermissions */);
@@ -628,54 +628,55 @@
// No matter what the given uid is, a SecurityException will be thrown if the caller
// doesn't hold the NETWORK_SETTINGS permission.
assertThrows(SecurityException.class,
- () -> mCm.redactLinkPropertiesForPackage(lp, groundedUid, groundedPkg));
+ () -> mCm.getRedactedLinkPropertiesForPackage(lp, groundedUid, groundedPkg));
assertThrows(SecurityException.class,
- () -> mCm.redactLinkPropertiesForPackage(lp, normalUid, normalPkg));
+ () -> mCm.getRedactedLinkPropertiesForPackage(lp, normalUid, normalPkg));
assertThrows(SecurityException.class,
- () -> mCm.redactLinkPropertiesForPackage(lp, privilegedUid, privilegedPkg));
+ () -> mCm.getRedactedLinkPropertiesForPackage(lp, privilegedUid, privilegedPkg));
runAsShell(NETWORK_SETTINGS, () -> {
// No matter what the given uid is, if the given LinkProperties is null, then
// NullPointerException will be thrown.
assertThrows(NullPointerException.class,
- () -> mCm.redactLinkPropertiesForPackage(null, groundedUid, groundedPkg));
+ () -> mCm.getRedactedLinkPropertiesForPackage(null, groundedUid, groundedPkg));
assertThrows(NullPointerException.class,
- () -> mCm.redactLinkPropertiesForPackage(null, normalUid, normalPkg));
+ () -> mCm.getRedactedLinkPropertiesForPackage(null, normalUid, normalPkg));
assertThrows(NullPointerException.class,
- () -> mCm.redactLinkPropertiesForPackage(null, privilegedUid, privilegedPkg));
+ () -> mCm.getRedactedLinkPropertiesForPackage(
+ null, privilegedUid, privilegedPkg));
// Make sure null is returned for a UID without ACCESS_NETWORK_STATE.
- assertNull(mCm.redactLinkPropertiesForPackage(lp, groundedUid, groundedPkg));
+ assertNull(mCm.getRedactedLinkPropertiesForPackage(lp, groundedUid, groundedPkg));
// CaptivePortalApiUrl & CaptivePortalData will be set to null if given uid doesn't hold
// the NETWORK_SETTINGS permission.
- assertNull(mCm.redactLinkPropertiesForPackage(lp, normalUid, normalPkg)
+ assertNull(mCm.getRedactedLinkPropertiesForPackage(lp, normalUid, normalPkg)
.getCaptivePortalApiUrl());
- assertNull(mCm.redactLinkPropertiesForPackage(lp, normalUid, normalPkg)
+ assertNull(mCm.getRedactedLinkPropertiesForPackage(lp, normalUid, normalPkg)
.getCaptivePortalData());
// MTU is not sensitive and is not redacted.
- assertEquals(mtu, mCm.redactLinkPropertiesForPackage(lp, normalUid, normalPkg)
+ assertEquals(mtu, mCm.getRedactedLinkPropertiesForPackage(lp, normalUid, normalPkg)
.getMtu());
// CaptivePortalApiUrl & CaptivePortalData will be preserved if the given uid holds the
// NETWORK_SETTINGS permission.
assertEquals(capportUrl,
- mCm.redactLinkPropertiesForPackage(lp, privilegedUid, privilegedPkg)
+ mCm.getRedactedLinkPropertiesForPackage(lp, privilegedUid, privilegedPkg)
.getCaptivePortalApiUrl());
assertEquals(capportData,
- mCm.redactLinkPropertiesForPackage(lp, privilegedUid, privilegedPkg)
+ mCm.getRedactedLinkPropertiesForPackage(lp, privilegedUid, privilegedPkg)
.getCaptivePortalData());
});
}
private NetworkCapabilities redactNc(@NonNull final NetworkCapabilities nc, int uid,
@NonNull String packageName) {
- return mCm.redactNetworkCapabilitiesForPackage(nc, uid, packageName);
+ return mCm.getRedactedNetworkCapabilitiesForPackage(nc, uid, packageName);
}
@DevSdkIgnoreRule.IgnoreUpTo(SC_V2)
@Test
- public void testRedactNetworkCapabilitiesForPackage() throws Exception {
+ public void testGetRedactedNetworkCapabilitiesForPackage() throws Exception {
final String groundedPkg = findPackageByPermissions(
List.of(), /* requiredPermissions */
List.of(ACCESS_NETWORK_STATE) /* forbiddenPermissions */);
diff --git a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
new file mode 100644
index 0000000..0a32f09
--- /dev/null
+++ b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net.cts
+
+import android.Manifest.permission.MANAGE_TEST_NETWORKS
+import android.Manifest.permission.NETWORK_SETTINGS
+import android.net.IpConfiguration
+import android.net.TestNetworkInterface
+import android.net.TestNetworkManager
+import android.platform.test.annotations.AppModeFull
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.runner.AndroidJUnit4
+import com.android.net.module.util.ArrayTrackRecord
+import com.android.net.module.util.TrackRecord
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.SC_V2
+import com.android.testutils.runAsShell
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import kotlin.test.assertNull
+import kotlin.test.fail
+import android.net.cts.EthernetManagerTest.EthernetStateListener.CallbackEntry.InterfaceStateChanged
+import android.os.Handler
+import android.os.HandlerExecutor
+import android.os.Looper
+import com.android.networkstack.apishim.common.EthernetManagerShim.InterfaceStateListener
+import com.android.networkstack.apishim.common.EthernetManagerShim.STATE_ABSENT
+import com.android.networkstack.apishim.common.EthernetManagerShim.STATE_LINK_DOWN
+import com.android.networkstack.apishim.common.EthernetManagerShim.STATE_LINK_UP
+import com.android.networkstack.apishim.common.EthernetManagerShim.ROLE_CLIENT
+import com.android.networkstack.apishim.common.EthernetManagerShim.ROLE_NONE
+import com.android.networkstack.apishim.EthernetManagerShimImpl
+import java.util.concurrent.Executor
+import kotlin.test.assertEquals
+
+private const val TIMEOUT_MS = 1000L
+private const val NO_CALLBACK_TIMEOUT_MS = 200L
+private val DEFAULT_IP_CONFIGURATION = IpConfiguration(IpConfiguration.IpAssignment.DHCP,
+ IpConfiguration.ProxySettings.NONE, null, null)
+
+@AppModeFull(reason = "Instant apps can't access EthernetManager")
+@RunWith(AndroidJUnit4::class)
+class EthernetManagerTest {
+ // EthernetManager is not updatable before T, so tests do not need to be backwards compatible
+ @get:Rule
+ val ignoreRule = DevSdkIgnoreRule(ignoreClassUpTo = SC_V2)
+
+ private val context by lazy { InstrumentationRegistry.getInstrumentation().context }
+ private val em by lazy { EthernetManagerShimImpl.newInstance(context) }
+
+ private val createdIfaces = ArrayList<TestNetworkInterface>()
+ private val addedListeners = ArrayList<InterfaceStateListener>()
+
+ private open class EthernetStateListener private constructor(
+ private val history: ArrayTrackRecord<CallbackEntry>
+ ) : InterfaceStateListener,
+ TrackRecord<EthernetStateListener.CallbackEntry> by history {
+ constructor() : this(ArrayTrackRecord())
+
+ val events = history.newReadHead()
+
+ sealed class CallbackEntry {
+ data class InterfaceStateChanged(
+ val iface: String,
+ val state: Int,
+ val role: Int,
+ val configuration: IpConfiguration?
+ ) : CallbackEntry()
+ }
+
+ override fun onInterfaceStateChanged(
+ iface: String,
+ state: Int,
+ role: Int,
+ cfg: IpConfiguration?
+ ) {
+ add(InterfaceStateChanged(iface, state, role, cfg))
+ }
+
+ fun <T : CallbackEntry> expectCallback(expected: T): T {
+ val event = pollForNextCallback()
+ assertEquals(expected, event)
+ return event as T
+ }
+
+ fun expectCallback(iface: TestNetworkInterface, state: Int, role: Int) {
+ expectCallback(InterfaceStateChanged(iface.interfaceName, state, role,
+ if (state != STATE_ABSENT) DEFAULT_IP_CONFIGURATION else null))
+ }
+
+ fun pollForNextCallback(): CallbackEntry {
+ return events.poll(TIMEOUT_MS) ?: fail("Did not receive callback after ${TIMEOUT_MS}ms")
+ }
+
+ fun assertNoCallback() {
+ val cb = events.poll(NO_CALLBACK_TIMEOUT_MS)
+ assertNull(cb, "Expected no callback but got $cb")
+ }
+ }
+
+ @Test
+ public fun testCallbacks() {
+ val executor = HandlerExecutor(Handler(Looper.getMainLooper()))
+
+ // If an interface exists when the callback is registered, it is reported on registration.
+ val iface = runAsShell(MANAGE_TEST_NETWORKS) {
+ createInterface()
+ }
+ val listener = EthernetStateListener()
+ addInterfaceStateListener(executor, listener)
+ listener.expectCallback(iface, STATE_LINK_UP, ROLE_CLIENT)
+
+ // If an interface appears, existing callbacks see it.
+ // TODO: fix the up/up/down/up callbacks and only send down/up.
+ val iface2 = runAsShell(MANAGE_TEST_NETWORKS) {
+ createInterface()
+ }
+ listener.expectCallback(iface2, STATE_LINK_UP, ROLE_CLIENT)
+ listener.expectCallback(iface2, STATE_LINK_UP, ROLE_CLIENT)
+ listener.expectCallback(iface2, STATE_LINK_DOWN, ROLE_CLIENT)
+ listener.expectCallback(iface2, STATE_LINK_UP, ROLE_CLIENT)
+
+ // Removing interfaces first sends link down, then STATE_ABSENT/ROLE_NONE.
+ removeInterface(iface)
+ listener.expectCallback(iface, STATE_LINK_DOWN, ROLE_CLIENT)
+ listener.expectCallback(iface, STATE_ABSENT, ROLE_NONE)
+
+ removeInterface(iface2)
+ listener.expectCallback(iface2, STATE_LINK_DOWN, ROLE_CLIENT)
+ listener.expectCallback(iface2, STATE_ABSENT, ROLE_NONE)
+ listener.assertNoCallback()
+ }
+
+ @Before
+ fun setUp() {
+ runAsShell(MANAGE_TEST_NETWORKS, NETWORK_SETTINGS) {
+ em.setIncludeTestInterfaces(true)
+ }
+ }
+
+ @After
+ fun tearDown() {
+ runAsShell(MANAGE_TEST_NETWORKS, NETWORK_SETTINGS) {
+ em.setIncludeTestInterfaces(false)
+ for (iface in createdIfaces) {
+ if (iface.fileDescriptor.fileDescriptor.valid()) iface.fileDescriptor.close()
+ }
+ for (listener in addedListeners) {
+ em.removeInterfaceStateListener(listener)
+ }
+ }
+ }
+
+ private fun addInterfaceStateListener(executor: Executor, listener: InterfaceStateListener) {
+ em.addInterfaceStateListener(executor, listener)
+ addedListeners.add(listener)
+ }
+
+ private fun createInterface(): TestNetworkInterface {
+ val tnm = context.getSystemService(TestNetworkManager::class.java)
+ return tnm.createTapInterface(false /* bringUp */).also { createdIfaces.add(it) }
+ }
+
+ private fun removeInterface(iface: TestNetworkInterface) {
+ iface.fileDescriptor.close()
+ createdIfaces.remove(iface)
+ }
+}
\ No newline at end of file
diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
index 7bce3d2..8234ec1 100644
--- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java
@@ -52,6 +52,7 @@
import static com.android.compatibility.common.util.PropertyUtil.getFirstApiLevel;
import static com.android.compatibility.common.util.PropertyUtil.getVendorApiLevel;
+import static com.android.testutils.MiscAsserts.assertThrows;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -129,12 +130,11 @@
assertTrue("Failed to allocate specified SPI, " + DROID_SPI,
droidSpi.getSpi() == DROID_SPI);
- try {
- mISM.allocateSecurityParameterIndex(addr, DROID_SPI);
- fail("Duplicate SPI was allowed to be created");
- } catch (IpSecManager.SpiUnavailableException expected) {
- // This is a success case because we expect a dupe SPI to throw
- }
+ IpSecManager.SpiUnavailableException expectedException =
+ assertThrows("Duplicate SPI was allowed to be created",
+ IpSecManager.SpiUnavailableException.class,
+ () -> mISM.allocateSecurityParameterIndex(addr, DROID_SPI));
+ assertEquals(expectedException.getSpi(), droidSpi.getSpi());
randomSpi.close();
droidSpi.close();
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index 225602f..53b00db 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -19,6 +19,7 @@
import android.app.Instrumentation
import android.content.Context
import android.net.ConnectivityManager
+import android.net.EthernetNetworkSpecifier
import android.net.INetworkAgent
import android.net.INetworkAgentRegistry
import android.net.InetAddresses
@@ -35,6 +36,7 @@
import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED
import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED
+import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED
import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING
import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED
import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED
@@ -42,7 +44,9 @@
import android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED
import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
+import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
import android.net.NetworkCapabilities.TRANSPORT_TEST
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
import android.net.NetworkCapabilities.TRANSPORT_VPN
import android.net.NetworkInfo
import android.net.NetworkProvider
@@ -100,6 +104,7 @@
import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnUnregisterQosCallback
import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnValidationStatus
import com.android.testutils.TestableNetworkCallback
+import com.android.testutils.assertThrows
import org.junit.After
import org.junit.Assume.assumeFalse
import org.junit.Before
@@ -112,6 +117,8 @@
import org.mockito.Mockito.mock
import org.mockito.Mockito.timeout
import org.mockito.Mockito.verify
+import java.io.IOException
+import java.net.DatagramSocket
import java.net.InetAddress
import java.net.InetSocketAddress
import java.net.Socket
@@ -249,6 +256,28 @@
.build()
}
+ private fun makeTestNetworkCapabilities(
+ specifier: String? = null,
+ transports: IntArray = intArrayOf()
+ ) = NetworkCapabilities().apply {
+ addTransportType(TRANSPORT_TEST)
+ removeCapability(NET_CAPABILITY_TRUSTED)
+ removeCapability(NET_CAPABILITY_INTERNET)
+ addCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ addCapability(NET_CAPABILITY_NOT_ROAMING)
+ addCapability(NET_CAPABILITY_NOT_VPN)
+ if (SdkLevel.isAtLeastS()) {
+ addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ }
+ if (null != specifier) {
+ setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(specifier))
+ }
+ for (t in transports) { addTransportType(t) }
+ // Most transports are not allowed on test networks unless the network is marked restricted.
+ // This test does not need
+ if (transports.size > 0) removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ }
+
private fun createNetworkAgent(
context: Context = realContext,
specifier: String? = null,
@@ -256,20 +285,7 @@
initialLp: LinkProperties? = null,
initialConfig: NetworkAgentConfig? = null
): TestableNetworkAgent {
- val nc = initialNc ?: NetworkCapabilities().apply {
- addTransportType(TRANSPORT_TEST)
- removeCapability(NET_CAPABILITY_TRUSTED)
- removeCapability(NET_CAPABILITY_INTERNET)
- addCapability(NET_CAPABILITY_NOT_SUSPENDED)
- addCapability(NET_CAPABILITY_NOT_ROAMING)
- addCapability(NET_CAPABILITY_NOT_VPN)
- if (SdkLevel.isAtLeastS()) {
- addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
- }
- if (null != specifier) {
- setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(specifier))
- }
- }
+ val nc = initialNc ?: makeTestNetworkCapabilities(specifier)
val lp = initialLp ?: LinkProperties().apply {
addLinkAddress(LinkAddress(LOCAL_IPV4_ADDRESS, 32))
addRoute(RouteInfo(IpPrefix("0.0.0.0/0"), null, null))
@@ -284,12 +300,14 @@
context: Context = realContext,
specifier: String? = UUID.randomUUID().toString(),
initialConfig: NetworkAgentConfig? = null,
- expectedInitSignalStrengthThresholds: IntArray? = intArrayOf()
+ expectedInitSignalStrengthThresholds: IntArray? = intArrayOf(),
+ transports: IntArray = intArrayOf()
): Pair<TestableNetworkAgent, TestableNetworkCallback> {
val callback = TestableNetworkCallback()
// Ensure this NetworkAgent is never unneeded by filing a request with its specifier.
requestNetwork(makeTestNetworkRequest(specifier = specifier), callback)
- val agent = createNetworkAgent(context, specifier, initialConfig = initialConfig)
+ val nc = makeTestNetworkCapabilities(specifier, transports)
+ val agent = createNetworkAgent(context, initialConfig = initialConfig, initialNc = nc)
agent.setTeardownDelayMillis(0)
// Connect the agent and verify initial status callbacks.
agent.register()
@@ -301,6 +319,15 @@
return agent to callback
}
+ private fun connectNetwork(vararg transports: Int): Pair<TestableNetworkAgent, Network> {
+ val (agent, callback) = createConnectedNetworkAgent(transports = transports)
+ val network = agent.network!!
+ // createConnectedNetworkAgent internally files a request; release it so that the network
+ // will be torn down if unneeded.
+ mCM.unregisterNetworkCallback(callback)
+ return agent to network
+ }
+
private fun createNetworkAgentWithFakeCS() = createNetworkAgent().also {
mFakeConnectivityService.connect(it.registerForTest(Network(FAKE_NET_ID)))
}
@@ -466,33 +493,33 @@
}
}
- private fun ncWithAccessUids(vararg uids: Int) = NetworkCapabilities.Builder()
+ private fun ncWithAllowedUids(vararg uids: Int) = NetworkCapabilities.Builder()
.addTransportType(TRANSPORT_TEST)
- .setAccessUids(uids.toSet()).build()
+ .setAllowedUids(uids.toSet()).build()
@Test
fun testRejectedUpdates() {
val callback = TestableNetworkCallback(DEFAULT_TIMEOUT_MS)
// will be cleaned up in tearDown
registerNetworkCallback(makeTestNetworkRequest(), callback)
- val agent = createNetworkAgent(initialNc = ncWithAccessUids(200))
+ val agent = createNetworkAgent(initialNc = ncWithAllowedUids(200))
agent.register()
agent.markConnected()
// Make sure the UIDs have been ignored.
callback.expectCallback<Available>(agent.network!!)
callback.expectCapabilitiesThat(agent.network!!) {
- it.accessUids.isEmpty() && !it.hasCapability(NET_CAPABILITY_VALIDATED)
+ it.allowedUids.isEmpty() && !it.hasCapability(NET_CAPABILITY_VALIDATED)
}
callback.expectCallback<LinkPropertiesChanged>(agent.network!!)
callback.expectCallback<BlockedStatus>(agent.network!!)
callback.expectCapabilitiesThat(agent.network!!) {
- it.accessUids.isEmpty() && it.hasCapability(NET_CAPABILITY_VALIDATED)
+ it.allowedUids.isEmpty() && it.hasCapability(NET_CAPABILITY_VALIDATED)
}
callback.assertNoCallback(NO_CALLBACK_TIMEOUT)
// Make sure that the UIDs are also ignored upon update
- agent.sendNetworkCapabilities(ncWithAccessUids(200, 300))
+ agent.sendNetworkCapabilities(ncWithAllowedUids(200, 300))
callback.assertNoCallback(NO_CALLBACK_TIMEOUT)
}
@@ -1123,4 +1150,138 @@
remoteAddresses
)
}
+
+ @Test
+ fun testDestroyAndAwaitReplacement() {
+ // Keeps an eye on all test networks.
+ val matchAllCallback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
+ registerNetworkCallback(makeTestNetworkRequest(), matchAllCallback)
+
+ // File a request that matches and keeps up the best-scoring test network.
+ val testCallback = TestableNetworkCallback(timeoutMs = DEFAULT_TIMEOUT_MS)
+ requestNetwork(makeTestNetworkRequest(), testCallback)
+
+ // Connect the first network. This should satisfy the request.
+ val (agent1, network1) = connectNetwork()
+ matchAllCallback.expectAvailableThenValidatedCallbacks(network1)
+ testCallback.expectAvailableThenValidatedCallbacks(network1)
+ // Check that network1 exists by binding a socket to it and getting no exceptions.
+ network1.bindSocket(DatagramSocket())
+
+ // Connect a second agent. network1 is preferred because it was already registered, so
+ // testCallback will not see any events. agent2 is be torn down because it has no requests.
+ val (agent2, network2) = connectNetwork()
+ matchAllCallback.expectAvailableThenValidatedCallbacks(network2)
+ matchAllCallback.expectCallback<Lost>(network2)
+ agent2.expectCallback<OnNetworkUnwanted>()
+ agent2.expectCallback<OnNetworkDestroyed>()
+ assertNull(mCM.getLinkProperties(network2))
+
+ // Mark the first network as awaiting replacement. This should destroy the underlying
+ // native network and send onNetworkDestroyed, but will not send any NetworkCallbacks,
+ // because for callback and scoring purposes network1 is still connected.
+ agent1.destroyAndAwaitReplacement(5_000 /* timeoutMillis */)
+ agent1.expectCallback<OnNetworkDestroyed>()
+ assertThrows(IOException::class.java) { network1.bindSocket(DatagramSocket()) }
+ assertNotNull(mCM.getLinkProperties(network1))
+
+ // Calling destroyAndAwaitReplacement more than once has no effect.
+ // If it did, this test would fail because the 1ms timeout means that the network would be
+ // torn down before the replacement arrives.
+ agent1.destroyAndAwaitReplacement(1 /* timeoutMillis */)
+
+ // Connect a third network. Because network1 is awaiting replacement, network3 is preferred
+ // as soon as it validates (until then, it is outscored by network1).
+ // The fact that the first events seen by matchAllCallback is the connection of network3
+ // implicitly ensures that no callbacks are sent since network1 was lost.
+ val (agent3, network3) = connectNetwork()
+ matchAllCallback.expectAvailableThenValidatedCallbacks(network3)
+ testCallback.expectAvailableDoubleValidatedCallbacks(network3)
+
+ // As soon as the replacement arrives, network1 is disconnected.
+ // Check that this happens before the replacement timeout (5 seconds) fires.
+ matchAllCallback.expectCallback<Lost>(network1, 2_000 /* timeoutMs */)
+ agent1.expectCallback<OnNetworkUnwanted>()
+
+ // Test lingering:
+ // - Connect a higher-scoring network and check that network3 starts lingering.
+ // - Mark network3 awaiting replacement.
+ // - Check that network3 is torn down immediately without waiting for the linger timer or
+ // the replacement timer to fire. This is a regular teardown, so it results in
+ // onNetworkUnwanted before onNetworkDestroyed.
+ val (agent4, agent4callback) = createConnectedNetworkAgent()
+ val network4 = agent4.network!!
+ matchAllCallback.expectAvailableThenValidatedCallbacks(network4)
+ agent4.sendNetworkScore(NetworkScore.Builder().setTransportPrimary(true).build())
+ matchAllCallback.expectCallback<Losing>(network3)
+ testCallback.expectAvailableCallbacks(network4, validated = true)
+ mCM.unregisterNetworkCallback(agent4callback)
+ agent3.destroyAndAwaitReplacement(5_000)
+ agent3.expectCallback<OnNetworkUnwanted>()
+ matchAllCallback.expectCallback<Lost>(network3, 1000L)
+ agent3.expectCallback<OnNetworkDestroyed>()
+
+ // Now mark network4 awaiting replacement with a low timeout, and check that if no
+ // replacement arrives, it is torn down.
+ agent4.destroyAndAwaitReplacement(100 /* timeoutMillis */)
+ matchAllCallback.expectCallback<Lost>(network4, 1000L /* timeoutMs */)
+ testCallback.expectCallback<Lost>(network4, 1000L /* timeoutMs */)
+ agent4.expectCallback<OnNetworkDestroyed>()
+ agent4.expectCallback<OnNetworkUnwanted>()
+
+ // If a network that is awaiting replacement is unregistered, it disconnects immediately,
+ // before the replacement timeout fires.
+ val (agent5, network5) = connectNetwork()
+ matchAllCallback.expectAvailableThenValidatedCallbacks(network5)
+ testCallback.expectAvailableThenValidatedCallbacks(network5)
+ agent5.destroyAndAwaitReplacement(5_000 /* timeoutMillis */)
+ agent5.unregister()
+ matchAllCallback.expectCallback<Lost>(network5, 1000L /* timeoutMs */)
+ testCallback.expectCallback<Lost>(network5, 1000L /* timeoutMs */)
+ agent5.expectCallback<OnNetworkDestroyed>()
+ agent5.expectCallback<OnNetworkUnwanted>()
+
+ // If wifi is replaced within the timeout, the device does not switch to cellular.
+ val (cellAgent, cellNetwork) = connectNetwork(TRANSPORT_CELLULAR)
+ testCallback.expectAvailableThenValidatedCallbacks(cellNetwork)
+ matchAllCallback.expectAvailableThenValidatedCallbacks(cellNetwork)
+
+ val (wifiAgent, wifiNetwork) = connectNetwork(TRANSPORT_WIFI)
+ testCallback.expectAvailableCallbacks(wifiNetwork, validated = true)
+ testCallback.expectCapabilitiesThat(wifiNetwork) {
+ it.hasCapability(NET_CAPABILITY_VALIDATED)
+ }
+ matchAllCallback.expectAvailableCallbacks(wifiNetwork, validated = false)
+ matchAllCallback.expectCallback<Losing>(cellNetwork)
+ matchAllCallback.expectCapabilitiesThat(wifiNetwork) {
+ it.hasCapability(NET_CAPABILITY_VALIDATED)
+ }
+
+ wifiAgent.destroyAndAwaitReplacement(5_000 /* timeoutMillis */)
+ wifiAgent.expectCallback<OnNetworkDestroyed>()
+
+ // Once the network is awaiting replacement, changing LinkProperties, NetworkCapabilities or
+ // score, or calling reportNetworkConnectivity, have no effect.
+ val wifiSpecifier = mCM.getNetworkCapabilities(wifiNetwork)!!.networkSpecifier
+ assertNotNull(wifiSpecifier)
+ assertTrue(wifiSpecifier is EthernetNetworkSpecifier)
+
+ val wifiNc = makeTestNetworkCapabilities(wifiSpecifier.interfaceName,
+ intArrayOf(TRANSPORT_WIFI))
+ wifiAgent.sendNetworkCapabilities(wifiNc)
+ val wifiLp = mCM.getLinkProperties(wifiNetwork)!!
+ val newRoute = RouteInfo(IpPrefix("192.0.2.42/24"))
+ assertFalse(wifiLp.getRoutes().contains(newRoute))
+ wifiLp.addRoute(newRoute)
+ wifiAgent.sendLinkProperties(wifiLp)
+ mCM.reportNetworkConnectivity(wifiNetwork, false)
+ // The test implicitly checks that no callbacks are sent here, because the next events seen
+ // by the callbacks are for the new network connecting.
+
+ val (newWifiAgent, newWifiNetwork) = connectNetwork(TRANSPORT_WIFI)
+ testCallback.expectAvailableCallbacks(newWifiNetwork, validated = true)
+ matchAllCallback.expectAvailableThenValidatedCallbacks(newWifiNetwork)
+ matchAllCallback.expectCallback<Lost>(wifiNetwork)
+ wifiAgent.expectCallback<OnNetworkUnwanted>()
+ }
}
diff --git a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
index 9506081..b139a9b 100644
--- a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
@@ -71,6 +71,7 @@
import java.net.ServerSocket
import java.nio.charset.StandardCharsets
import java.util.Random
+import java.util.concurrent.Executor
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertNotNull
@@ -342,9 +343,12 @@
if (DBG) Log.d(TAG, "Port = $localPort")
val registrationRecord = NsdRegistrationRecord()
- val registeredInfo = registerService(registrationRecord, si)
+ // Test registering without an Executor
+ nsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, registrationRecord)
+ val registeredInfo = registrationRecord.expectCallback<ServiceRegistered>().serviceInfo
val discoveryRecord = NsdDiscoveryRecord()
+ // Test discovering without an Executor
nsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, discoveryRecord)
// Expect discovery started
@@ -353,7 +357,10 @@
// Expect a service record to be discovered
val foundInfo = discoveryRecord.waitForServiceDiscovered(registeredInfo.serviceName)
- val resolvedService = resolveService(foundInfo)
+ // Test resolving without an Executor
+ val resolveRecord = NsdResolveRecord()
+ nsdManager.resolveService(foundInfo, resolveRecord)
+ val resolvedService = resolveRecord.expectCallback<ServiceResolved>().serviceInfo
// Check Txt attributes
assertEquals(8, resolvedService.attributes.size)
@@ -408,7 +415,7 @@
@Test
fun testNsdManager_DiscoverOnNetwork() {
- // This tests requires shims supporting T+ APIs (discovering on specific network)
+ // This test requires shims supporting T+ APIs (discovering on specific network)
assumeTrue(ConstantsShim.VERSION > SC_V2)
val si = NsdServiceInfo()
@@ -422,7 +429,7 @@
tryTest {
val discoveryRecord = NsdDiscoveryRecord()
nsdShim.discoverServices(nsdManager, SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD,
- testNetwork1.network, discoveryRecord)
+ testNetwork1.network, Executor { it.run() }, discoveryRecord)
val foundInfo = discoveryRecord.waitForServiceDiscovered(
serviceName, testNetwork1.network)
@@ -442,7 +449,7 @@
@Test
fun testNsdManager_DiscoverWithNetworkRequest() {
- // This tests requires shims supporting T+ APIs (discovering on network request)
+ // This test requires shims supporting T+ APIs (discovering on network request)
assumeTrue(ConstantsShim.VERSION > SC_V2)
val si = NsdServiceInfo()
@@ -462,7 +469,7 @@
.addTransportType(TRANSPORT_TEST)
.setNetworkSpecifier(specifier)
.build(),
- discoveryRecord)
+ Executor { it.run() }, discoveryRecord)
val discoveryStarted = discoveryRecord.expectCallback<DiscoveryStarted>()
assertEquals(SERVICE_TYPE, discoveryStarted.serviceType)
@@ -507,7 +514,7 @@
@Test
fun testNsdManager_ResolveOnNetwork() {
- // This tests requires shims supporting T+ APIs (NsdServiceInfo.network)
+ // This test requires shims supporting T+ APIs (NsdServiceInfo.network)
assumeTrue(ConstantsShim.VERSION > SC_V2)
val si = NsdServiceInfo()
@@ -532,7 +539,7 @@
serviceName, testNetwork2.network)
assertEquals(testNetwork2.network, nsdShim.getNetwork(foundInfo2))
- nsdManager.resolveService(foundInfo1, resolveRecord)
+ nsdShim.resolveService(nsdManager, foundInfo1, Executor { it.run() }, resolveRecord)
val cb = resolveRecord.expectCallback<ServiceResolved>()
cb.serviceInfo.let {
// Resolved service type has leading dot
@@ -553,7 +560,8 @@
* Register a service and return its registration record.
*/
private fun registerService(record: NsdRegistrationRecord, si: NsdServiceInfo): NsdServiceInfo {
- nsdManager.registerService(si, NsdManager.PROTOCOL_DNS_SD, record)
+ nsdShim.registerService(nsdManager, si, NsdManager.PROTOCOL_DNS_SD, Executor { it.run() },
+ record)
// We may not always get the name that we tried to register;
// This events tells us the name that was registered.
val cb = record.expectCallback<ServiceRegistered>()
@@ -562,7 +570,7 @@
private fun resolveService(discoveredInfo: NsdServiceInfo): NsdServiceInfo {
val record = NsdResolveRecord()
- nsdManager.resolveService(discoveredInfo, record)
+ nsdShim.resolveService(nsdManager, discoveredInfo, Executor { it.run() }, record)
val resolvedCb = record.expectCallback<ServiceResolved>()
assertEquals(discoveredInfo.serviceName, resolvedCb.serviceInfo.serviceName)
diff --git a/tests/cts/net/src/android/net/cts/QosCallbackExceptionTest.java b/tests/cts/net/src/android/net/cts/QosCallbackExceptionTest.java
new file mode 100644
index 0000000..cd43a34
--- /dev/null
+++ b/tests/cts/net/src/android/net/cts/QosCallbackExceptionTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.net.NetworkReleasedException;
+import android.net.QosCallbackException;
+import android.net.SocketLocalAddressChangedException;
+import android.net.SocketNotBoundException;
+import android.os.Build;
+
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import com.android.testutils.DevSdkIgnoreRunner;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DevSdkIgnoreRunner.class)
+@IgnoreUpTo(Build.VERSION_CODES.R)
+public class QosCallbackExceptionTest {
+ private static final String ERROR_MESSAGE = "Test Error Message";
+ private static final String ERROR_MSG_SOCK_NOT_BOUND = "The socket is unbound";
+ private static final String ERROR_MSG_NET_RELEASED =
+ "The network was released and is no longer available";
+ private static final String ERROR_MSG_SOCK_ADDR_CHANGED =
+ "The local address of the socket changed";
+
+
+ @Test
+ public void testQosCallbackException() throws Exception {
+ final Throwable testcause = new Throwable(ERROR_MESSAGE);
+ final QosCallbackException exception = new QosCallbackException(testcause);
+ assertEquals(testcause, exception.getCause());
+
+ final QosCallbackException exceptionMsg = new QosCallbackException(ERROR_MESSAGE);
+ assertEquals(ERROR_MESSAGE, exceptionMsg.getMessage());
+ }
+
+ @Test
+ public void testNetworkReleasedExceptions() throws Exception {
+ final Throwable netReleasedException = new NetworkReleasedException();
+ final QosCallbackException exception = new QosCallbackException(netReleasedException);
+
+ assertTrue(exception.getCause() instanceof NetworkReleasedException);
+ assertEquals(netReleasedException, exception.getCause());
+ assertTrue(exception.getMessage().contains(ERROR_MSG_NET_RELEASED));
+ assertThrowableMessageContains(exception, ERROR_MSG_NET_RELEASED);
+ }
+
+ @Test
+ public void testSocketNotBoundExceptions() throws Exception {
+ final Throwable sockNotBoundException = new SocketNotBoundException();
+ final QosCallbackException exception = new QosCallbackException(sockNotBoundException);
+
+ assertTrue(exception.getCause() instanceof SocketNotBoundException);
+ assertEquals(sockNotBoundException, exception.getCause());
+ assertTrue(exception.getMessage().contains(ERROR_MSG_SOCK_NOT_BOUND));
+ assertThrowableMessageContains(exception, ERROR_MSG_SOCK_NOT_BOUND);
+ }
+
+ @Test
+ public void testSocketLocalAddressChangedExceptions() throws Exception {
+ final Throwable localAddrChangedException = new SocketLocalAddressChangedException();
+ final QosCallbackException exception = new QosCallbackException(localAddrChangedException);
+
+ assertTrue(exception.getCause() instanceof SocketLocalAddressChangedException);
+ assertEquals(localAddrChangedException, exception.getCause());
+ assertTrue(exception.getMessage().contains(ERROR_MSG_SOCK_ADDR_CHANGED));
+ assertThrowableMessageContains(exception, ERROR_MSG_SOCK_ADDR_CHANGED);
+ }
+
+ private void assertThrowableMessageContains(QosCallbackException exception, String errorMsg)
+ throws Exception {
+ try {
+ triggerException(exception);
+ fail("Expect exception");
+ } catch (QosCallbackException e) {
+ assertTrue(e.getMessage().contains(errorMsg));
+ }
+ }
+
+ private void triggerException(QosCallbackException exception) throws Exception {
+ throw new QosCallbackException(exception.getCause());
+ }
+}
diff --git a/tests/unit/java/android/net/EthernetNetworkUpdateRequestTest.java b/tests/unit/java/android/net/EthernetNetworkUpdateRequestTest.java
index 314fbcf..ca9558b 100644
--- a/tests/unit/java/android/net/EthernetNetworkUpdateRequestTest.java
+++ b/tests/unit/java/android/net/EthernetNetworkUpdateRequestTest.java
@@ -17,7 +17,9 @@
package android.net;
import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2;
-import static com.android.testutils.ParcelUtils.assertParcelSane;
+import static com.android.testutils.ParcelUtils.assertParcelingIsLossless;
+
+import static org.junit.Assert.assertThrows;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
@@ -47,8 +49,19 @@
EthernetNetworkUpdateRequest reqWithNullCaps =
new EthernetNetworkUpdateRequest.Builder().setIpConfiguration(
buildIpConfiguration()).build();
+ EthernetNetworkUpdateRequest reqWithNullConfig =
+ new EthernetNetworkUpdateRequest.Builder().setNetworkCapabilities(
+ buildNetworkCapabilities()).build();
- assertParcelSane(reqWithNonNull, 2);
- assertParcelSane(reqWithNullCaps, 2);
+ assertParcelingIsLossless(reqWithNonNull);
+ assertParcelingIsLossless(reqWithNullCaps);
+ assertParcelingIsLossless(reqWithNullConfig);
+ }
+
+ @Test
+ public void testEmptyUpdateRequestThrows() {
+ EthernetNetworkUpdateRequest.Builder emptyBuilder =
+ new EthernetNetworkUpdateRequest.Builder();
+ assertThrows(IllegalStateException.class, () -> emptyBuilder.build());
}
}
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index c8dc107..025b28c 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -36,6 +36,7 @@
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.ACTION_USER_UNLOCKED;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
+import static android.content.pm.PackageManager.FEATURE_ETHERNET;
import static android.content.pm.PackageManager.FEATURE_WIFI;
import static android.content.pm.PackageManager.FEATURE_WIFI_DIRECT;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
@@ -159,6 +160,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
+import static org.junit.Assume.assumeFalse;
import static org.mockito.AdditionalMatchers.aryEq;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -282,6 +284,7 @@
import android.net.shared.NetworkMonitorUtils;
import android.net.shared.PrivateDnsConfig;
import android.net.util.MultinetworkPolicyTracker;
+import android.net.wifi.WifiInfo;
import android.os.BadParcelableException;
import android.os.BatteryStatsManager;
import android.os.Binder;
@@ -1739,6 +1742,7 @@
mockDefaultPackages();
mockHasSystemFeature(FEATURE_WIFI, true);
mockHasSystemFeature(FEATURE_WIFI_DIRECT, true);
+ mockHasSystemFeature(FEATURE_ETHERNET, true);
doReturn(true).when(mTelephonyManager).isDataCapable();
FakeSettingsProvider.clearSettingsProvider();
@@ -3904,14 +3908,14 @@
}
@Test
- public void testNoAccessUidsInNetworkRequests() throws Exception {
+ public void testNoAllowedUidsInNetworkRequests() throws Exception {
final PendingIntent pendingIntent = PendingIntent.getBroadcast(
mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
final NetworkRequest r = new NetworkRequest.Builder().build();
- final ArraySet<Integer> accessUids = new ArraySet<>();
- accessUids.add(6);
- accessUids.add(9);
- r.networkCapabilities.setAccessUids(accessUids);
+ final ArraySet<Integer> allowedUids = new ArraySet<>();
+ allowedUids.add(6);
+ allowedUids.add(9);
+ r.networkCapabilities.setAllowedUids(allowedUids);
final Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
final NetworkCallback cb = new NetworkCallback();
@@ -3926,7 +3930,7 @@
// Make sure that resetting the access UIDs to the empty set will allow calling
// requestNetwork and registerNetworkCallback.
- r.networkCapabilities.setAccessUids(Collections.emptySet());
+ r.networkCapabilities.setAllowedUids(Collections.emptySet());
mCm.requestNetwork(r, cb);
mCm.unregisterNetworkCallback(cb);
mCm.registerNetworkCallback(r, cb);
@@ -7078,6 +7082,36 @@
}
@Test
+ public void testAdminUidsRedacted() throws Exception {
+ final int[] adminUids = new int[] {Process.myUid() + 1};
+ final NetworkCapabilities ncTemplate = new NetworkCapabilities();
+ ncTemplate.setAdministratorUids(adminUids);
+ mCellNetworkAgent =
+ new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, new LinkProperties(), ncTemplate);
+ mCellNetworkAgent.connect(false /* validated */);
+
+ // Verify case where caller has permission
+ mServiceContext.setPermission(
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, PERMISSION_GRANTED);
+ TestNetworkCallback callback = new TestNetworkCallback();
+ mCm.registerDefaultNetworkCallback(callback);
+ callback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
+ callback.expectCapabilitiesThat(
+ mCellNetworkAgent, nc -> Arrays.equals(adminUids, nc.getAdministratorUids()));
+ mCm.unregisterNetworkCallback(callback);
+
+ // Verify case where caller does NOT have permission
+ mServiceContext.setPermission(
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, PERMISSION_DENIED);
+ mServiceContext.setPermission(NETWORK_STACK, PERMISSION_DENIED);
+ callback = new TestNetworkCallback();
+ mCm.registerDefaultNetworkCallback(callback);
+ callback.expectCallback(CallbackEntry.AVAILABLE, mCellNetworkAgent);
+ callback.expectCapabilitiesThat(
+ mCellNetworkAgent, nc -> nc.getAdministratorUids().length == 0);
+ }
+
+ @Test
public void testNonVpnUnderlyingNetworks() throws Exception {
// Ensure wifi and cellular are not torn down.
for (int transport : new int[]{TRANSPORT_CELLULAR, TRANSPORT_WIFI}) {
@@ -13868,12 +13902,13 @@
ProfileNetworkPreference profileNetworkPreference) {
final Set<UidRange> uidRangeSet;
UidRange range = UidRange.createForUser(handle);
- if (profileNetworkPreference.getIncludedUids().size() != 0) {
- uidRangeSet = UidRangeUtils.convertListToUidRange(
+ if (profileNetworkPreference.getIncludedUids().length != 0) {
+ uidRangeSet = UidRangeUtils.convertArrayToUidRange(
profileNetworkPreference.getIncludedUids());
- } else if (profileNetworkPreference.getExcludedUids().size() != 0) {
+
+ } else if (profileNetworkPreference.getExcludedUids().length != 0) {
uidRangeSet = UidRangeUtils.removeRangeSetFromUidRange(
- range, UidRangeUtils.convertListToUidRange(
+ range, UidRangeUtils.convertArrayToUidRange(
profileNetworkPreference.getExcludedUids()));
} else {
uidRangeSet = new ArraySet<>();
@@ -14245,7 +14280,7 @@
profileNetworkPreferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
profileNetworkPreferenceBuilder.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1);
profileNetworkPreferenceBuilder.setIncludedUids(
- List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID)));
+ new int[]{testHandle.getUid(TEST_WORK_PROFILE_APP_UID)});
registerDefaultNetworkCallbacks();
testPreferenceForUserNetworkUpDownForGivenPreference(
profileNetworkPreferenceBuilder.build(), false, testHandle,
@@ -14264,7 +14299,7 @@
profileNetworkPreferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
profileNetworkPreferenceBuilder.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1);
profileNetworkPreferenceBuilder.setIncludedUids(
- List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+ new int[]{testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)});
registerDefaultNetworkCallbacks();
testPreferenceForUserNetworkUpDownForGivenPreference(
profileNetworkPreferenceBuilder.build(), false,
@@ -14283,7 +14318,7 @@
profileNetworkPreferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
profileNetworkPreferenceBuilder.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1);
profileNetworkPreferenceBuilder.setExcludedUids(
- List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+ new int[]{testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)});
registerDefaultNetworkCallbacks();
testPreferenceForUserNetworkUpDownForGivenPreference(
profileNetworkPreferenceBuilder.build(), false,
@@ -14303,7 +14338,7 @@
profileNetworkPreferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
profileNetworkPreferenceBuilder.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1);
profileNetworkPreferenceBuilder.setExcludedUids(
- List.of(testHandle.getUid(0) - 1));
+ new int[]{testHandle.getUid(0) - 1});
final TestOnCompleteListener listener = new TestOnCompleteListener();
Assert.assertThrows(IllegalArgumentException.class, () -> mCm.setProfileNetworkPreferences(
testHandle, List.of(profileNetworkPreferenceBuilder.build()),
@@ -14311,7 +14346,7 @@
profileNetworkPreferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
profileNetworkPreferenceBuilder.setIncludedUids(
- List.of(testHandle.getUid(0) - 1));
+ new int[]{testHandle.getUid(0) - 1});
Assert.assertThrows(IllegalArgumentException.class,
() -> mCm.setProfileNetworkPreferences(
testHandle, List.of(profileNetworkPreferenceBuilder.build()),
@@ -14320,9 +14355,9 @@
profileNetworkPreferenceBuilder.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
profileNetworkPreferenceBuilder.setIncludedUids(
- List.of(testHandle.getUid(0) - 1));
+ new int[]{testHandle.getUid(0) - 1});
profileNetworkPreferenceBuilder.setExcludedUids(
- List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+ new int[]{testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)});
Assert.assertThrows(IllegalArgumentException.class,
() -> mCm.setProfileNetworkPreferences(
testHandle, List.of(profileNetworkPreferenceBuilder.build()),
@@ -14333,9 +14368,9 @@
profileNetworkPreferenceBuilder2.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
profileNetworkPreferenceBuilder2.setPreferenceEnterpriseId(NET_ENTERPRISE_ID_1);
profileNetworkPreferenceBuilder2.setIncludedUids(
- List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+ new int[]{testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)});
profileNetworkPreferenceBuilder.setIncludedUids(
- List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+ new int[]{testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)});
Assert.assertThrows(IllegalArgumentException.class,
() -> mCm.setProfileNetworkPreferences(
testHandle, List.of(profileNetworkPreferenceBuilder.build(),
@@ -14344,9 +14379,9 @@
profileNetworkPreferenceBuilder2.setPreference(PROFILE_NETWORK_PREFERENCE_ENTERPRISE);
profileNetworkPreferenceBuilder2.setExcludedUids(
- List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+ new int[]{testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)});
profileNetworkPreferenceBuilder.setExcludedUids(
- List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+ new int[]{testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)});
Assert.assertThrows(IllegalArgumentException.class,
() -> mCm.setProfileNetworkPreferences(
testHandle, List.of(profileNetworkPreferenceBuilder.build(),
@@ -14356,9 +14391,9 @@
profileNetworkPreferenceBuilder2.setPreference(
PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK);
profileNetworkPreferenceBuilder2.setExcludedUids(
- List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+ new int[]{testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)});
profileNetworkPreferenceBuilder.setExcludedUids(
- List.of(testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)));
+ new int[]{testHandle.getUid(TEST_WORK_PROFILE_APP_UID_2)});
Assert.assertThrows(IllegalArgumentException.class,
() -> mCm.setProfileNetworkPreferences(
testHandle, List.of(profileNetworkPreferenceBuilder.build(),
@@ -14685,7 +14720,7 @@
}
@Test
- public void testAccessUids() throws Exception {
+ public void testAllowedUids() throws Exception {
final int preferenceOrder =
ConnectivityService.PREFERENCE_ORDER_IRRELEVANT_BECAUSE_NOT_DEFAULT;
mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
@@ -14702,7 +14737,7 @@
final NetworkCapabilities nc = new NetworkCapabilities.Builder()
.addTransportType(TRANSPORT_TEST)
.removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
- .setAccessUids(uids)
+ .setAllowedUids(uids)
.build();
final TestNetworkAgentWrapper agent = new TestNetworkAgentWrapper(TRANSPORT_TEST,
new LinkProperties(), nc);
@@ -14720,10 +14755,10 @@
uids.add(300);
uids.add(400);
- nc.setAccessUids(uids);
+ nc.setAllowedUids(uids);
agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */);
if (SdkLevel.isAtLeastT()) {
- cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids));
+ cb.expectCapabilitiesThat(agent, caps -> caps.getAllowedUids().equals(uids));
} else {
cb.assertNoCallback();
}
@@ -14737,10 +14772,10 @@
inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids300400Parcel);
}
- nc.setAccessUids(uids);
+ nc.setAllowedUids(uids);
agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */);
if (SdkLevel.isAtLeastT()) {
- cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids));
+ cb.expectCapabilitiesThat(agent, caps -> caps.getAllowedUids().equals(uids));
inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids200Parcel);
} else {
cb.assertNoCallback();
@@ -14748,10 +14783,10 @@
uids.clear();
uids.add(600);
- nc.setAccessUids(uids);
+ nc.setAllowedUids(uids);
agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */);
if (SdkLevel.isAtLeastT()) {
- cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids));
+ cb.expectCapabilitiesThat(agent, caps -> caps.getAllowedUids().equals(uids));
} else {
cb.assertNoCallback();
}
@@ -14765,10 +14800,10 @@
}
uids.clear();
- nc.setAccessUids(uids);
+ nc.setAllowedUids(uids);
agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */);
if (SdkLevel.isAtLeastT()) {
- cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().isEmpty());
+ cb.expectCapabilitiesThat(agent, caps -> caps.getAllowedUids().isEmpty());
inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids600Parcel);
} else {
cb.assertNoCallback();
@@ -14779,7 +14814,7 @@
}
@Test
- public void testCbsAccessUids() throws Exception {
+ public void testCbsAllowedUids() throws Exception {
mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
mServiceContext.setPermission(MANAGE_TEST_NETWORKS, PERMISSION_GRANTED);
@@ -14816,29 +14851,29 @@
new LinkProperties(), ncb.build());
mCellNetworkAgent.connect(true);
cb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- ncb.setAccessUids(serviceUidSet);
+ ncb.setAllowedUids(serviceUidSet);
mCellNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */);
if (SdkLevel.isAtLeastT()) {
cb.expectCapabilitiesThat(mCellNetworkAgent,
- caps -> caps.getAccessUids().equals(serviceUidSet));
+ caps -> caps.getAllowedUids().equals(serviceUidSet));
} else {
// S must ignore access UIDs.
cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS);
}
// ...but not to some other UID. Rejection sets UIDs to the empty set
- ncb.setAccessUids(nonServiceUidSet);
+ ncb.setAllowedUids(nonServiceUidSet);
mCellNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */);
if (SdkLevel.isAtLeastT()) {
cb.expectCapabilitiesThat(mCellNetworkAgent,
- caps -> caps.getAccessUids().isEmpty());
+ caps -> caps.getAllowedUids().isEmpty());
} else {
// S must ignore access UIDs.
cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS);
}
// ...and also not to multiple UIDs even including the service UID
- ncb.setAccessUids(serviceUidSetPlus);
+ ncb.setAllowedUids(serviceUidSetPlus);
mCellNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */);
cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS);
@@ -14861,7 +14896,7 @@
new LinkProperties(), ncb.build());
mWiFiNetworkAgent.connect(true);
cb.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- ncb.setAccessUids(serviceUidSet);
+ ncb.setAllowedUids(serviceUidSet);
mWiFiNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */);
cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS);
mCm.unregisterNetworkCallback(cb);
@@ -15569,4 +15604,91 @@
assertNull(readHead.poll(TEST_CALLBACK_TIMEOUT_MS, it -> true));
}
+
+ @Test
+ public void testIgnoreValidationAfterRoamDisabled() throws Exception {
+ assumeFalse(SdkLevel.isAtLeastT());
+ // testIgnoreValidationAfterRoam off
+ doReturn(-1).when(mResources)
+ .getInteger(R.integer.config_validationFailureAfterRoamIgnoreTimeMillis);
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ NetworkCapabilities wifiNc1 = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .setTransportInfo(new WifiInfo.Builder().setBssid("AA:AA:AA:AA:AA:AA").build());
+ NetworkCapabilities wifiNc2 = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .setTransportInfo(new WifiInfo.Builder().setBssid("BB:BB:BB:BB:BB:BB").build());
+ final LinkProperties wifiLp = new LinkProperties();
+ wifiLp.setInterfaceName(WIFI_IFNAME);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp, wifiNc1);
+ mWiFiNetworkAgent.connect(true);
+
+ // The default network will be switching to Wi-Fi Network.
+ final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
+ final NetworkRequest wifiRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build();
+ mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
+ wifiNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
+ registerDefaultNetworkCallbacks();
+ mDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
+
+ // Wi-Fi roaming from wifiNc1 to wifiNc2.
+ mWiFiNetworkAgent.setNetworkCapabilities(wifiNc2, true);
+ mWiFiNetworkAgent.setNetworkInvalid(false);
+ mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
+ mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ }
+
+ @Test
+ public void testIgnoreValidationAfterRoamEnabled() throws Exception {
+ assumeFalse(SdkLevel.isAtLeastT());
+ // testIgnoreValidationAfterRoam on
+ doReturn(5000).when(mResources)
+ .getInteger(R.integer.config_validationFailureAfterRoamIgnoreTimeMillis);
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ NetworkCapabilities wifiNc1 = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .setTransportInfo(new WifiInfo.Builder().setBssid("AA:AA:AA:AA:AA:AA").build());
+ NetworkCapabilities wifiNc2 = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .setTransportInfo(new WifiInfo.Builder().setBssid("BB:BB:BB:BB:BB:BB").build());
+ final LinkProperties wifiLp = new LinkProperties();
+ wifiLp.setInterfaceName(WIFI_IFNAME);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp, wifiNc1);
+ mWiFiNetworkAgent.connect(true);
+
+ // The default network will be switching to Wi-Fi Network.
+ final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
+ final NetworkRequest wifiRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build();
+ mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
+ wifiNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
+ registerDefaultNetworkCallbacks();
+ mDefaultNetworkCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
+
+ // Wi-Fi roaming from wifiNc1 to wifiNc2.
+ mWiFiNetworkAgent.setNetworkCapabilities(wifiNc2, true);
+ mWiFiNetworkAgent.setNetworkInvalid(false);
+ mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
+
+ // Network validation failed, but the result will be ignored.
+ assertTrue(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).hasCapability(
+ NET_CAPABILITY_VALIDATED));
+ mWiFiNetworkAgent.setNetworkValid(false);
+
+ // Behavior of after config_validationFailureAfterRoamIgnoreTimeMillis
+ ConditionVariable waitForValidationBlock = new ConditionVariable();
+ doReturn(50).when(mResources)
+ .getInteger(R.integer.config_validationFailureAfterRoamIgnoreTimeMillis);
+ // Wi-Fi roaming from wifiNc2 to wifiNc1.
+ mWiFiNetworkAgent.setNetworkCapabilities(wifiNc1, true);
+ mWiFiNetworkAgent.setNetworkInvalid(false);
+ waitForValidationBlock.block(150);
+ mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
+ mDefaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ }
}
diff --git a/tests/unit/java/com/android/server/LegacyTypeTrackerTest.kt b/tests/unit/java/com/android/server/LegacyTypeTrackerTest.kt
index 64736f2..7ed55e5 100644
--- a/tests/unit/java/com/android/server/LegacyTypeTrackerTest.kt
+++ b/tests/unit/java/com/android/server/LegacyTypeTrackerTest.kt
@@ -23,6 +23,8 @@
import android.content.Context
import android.content.pm.PackageManager
+import android.content.pm.PackageManager.FEATURE_ETHERNET
+import android.content.pm.PackageManager.FEATURE_USB_HOST
import android.content.pm.PackageManager.FEATURE_WIFI
import android.content.pm.PackageManager.FEATURE_WIFI_DIRECT
import android.net.ConnectivityManager.TYPE_ETHERNET
@@ -40,7 +42,6 @@
import android.net.ConnectivityManager.TYPE_WIFI
import android.net.ConnectivityManager.TYPE_WIFI_P2P
import android.net.ConnectivityManager.TYPE_WIMAX
-import android.net.EthernetManager
import android.net.NetworkInfo.DetailedState.CONNECTED
import android.net.NetworkInfo.DetailedState.DISCONNECTED
import android.os.Build
@@ -82,9 +83,8 @@
private val mContext = mock(Context::class.java).apply {
doReturn(true).`when`(mPm).hasSystemFeature(FEATURE_WIFI)
doReturn(true).`when`(mPm).hasSystemFeature(FEATURE_WIFI_DIRECT)
+ doReturn(true).`when`(mPm).hasSystemFeature(FEATURE_ETHERNET)
doReturn(mPm).`when`(this).packageManager
- doReturn(mock(EthernetManager::class.java)).`when`(this).getSystemService(
- Context.ETHERNET_SERVICE)
}
private val mTm = mock(TelephonyManager::class.java).apply {
doReturn(true).`when`(this).isDataCapable
@@ -105,7 +105,8 @@
@Test
fun testSupportedTypes_NoEthernet() {
- doReturn(null).`when`(mContext).getSystemService(Context.ETHERNET_SERVICE)
+ doReturn(false).`when`(mPm).hasSystemFeature(FEATURE_ETHERNET)
+ doReturn(false).`when`(mPm).hasSystemFeature(FEATURE_USB_HOST)
assertFalse(makeTracker().isTypeSupported(TYPE_ETHERNET))
}
diff --git a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
index 8a2cfc2..6c8b545 100644
--- a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
@@ -25,6 +25,7 @@
import static com.android.testutils.MiscAsserts.assertThrows;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.clearInvocations;
@@ -33,6 +34,7 @@
import android.annotation.NonNull;
import android.net.INetd;
+import android.net.InetAddresses;
import android.net.IpPrefix;
import android.os.Build;
import android.os.ParcelFileDescriptor;
@@ -52,6 +54,8 @@
import java.io.FileDescriptor;
import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.util.Objects;
@RunWith(DevSdkIgnoreRunner.class)
@@ -61,9 +65,12 @@
private static final String BASE_IFACE = "test0";
private static final String STACKED_IFACE = "v4-test0";
private static final int BASE_IFINDEX = 1000;
+ private static final int STACKED_IFINDEX = 1001;
private static final IpPrefix NAT64_IP_PREFIX = new IpPrefix("64:ff9b::/96");
private static final String NAT64_PREFIX_STRING = "64:ff9b::";
+ private static final Inet6Address INET6_PFX96 = (Inet6Address)
+ InetAddresses.parseNumericAddress(NAT64_PREFIX_STRING);
private static final int GOOGLE_DNS_4 = 0x08080808; // 8.8.8.8
private static final int NETID = 42;
@@ -74,6 +81,10 @@
private static final String XLAT_LOCAL_IPV4ADDR_STRING = "192.0.0.46";
private static final String XLAT_LOCAL_IPV6ADDR_STRING = "2001:db8:0:b11::464";
+ private static final Inet4Address INET4_LOCAL4 = (Inet4Address)
+ InetAddresses.parseNumericAddress(XLAT_LOCAL_IPV4ADDR_STRING);
+ private static final Inet6Address INET6_LOCAL6 = (Inet6Address)
+ InetAddresses.parseNumericAddress(XLAT_LOCAL_IPV6ADDR_STRING);
private static final int CLATD_PID = 10483;
private static final int TUN_FD = 534;
@@ -129,6 +140,8 @@
public int getInterfaceIndex(String ifName) {
if (BASE_IFACE.equals(ifName)) {
return BASE_IFINDEX;
+ } else if (STACKED_IFACE.equals(ifName)) {
+ return STACKED_IFINDEX;
}
fail("unsupported arg: " + ifName);
return -1;
@@ -315,6 +328,11 @@
// [1] Start clatd.
final String addr6For464xlat = coordinator.clatStart(BASE_IFACE, NETID, NAT64_IP_PREFIX);
assertEquals(XLAT_LOCAL_IPV6ADDR_STRING, addr6For464xlat);
+ final ClatCoordinator.ClatdTracker expected = new ClatCoordinator.ClatdTracker(
+ BASE_IFACE, BASE_IFINDEX, STACKED_IFACE, STACKED_IFINDEX,
+ INET4_LOCAL4, INET6_LOCAL6, INET6_PFX96, CLATD_PID, RAW_SOCK_COOKIE);
+ final ClatCoordinator.ClatdTracker actual = coordinator.getClatdTrackerForTesting();
+ assertEquals(expected, actual);
// Pick an IPv4 address.
inOrder.verify(mDeps).selectIpv4Address(eq(INIT_V4ADDR_STRING),
@@ -327,6 +345,7 @@
// Open, configure and bring up the tun interface.
inOrder.verify(mDeps).createTunInterface(eq(STACKED_IFACE));
inOrder.verify(mDeps).adoptFd(eq(TUN_FD));
+ inOrder.verify(mDeps).getInterfaceIndex(eq(STACKED_IFACE));
inOrder.verify(mNetd).interfaceSetEnableIPv6(eq(STACKED_IFACE), eq(false /* enable */));
inOrder.verify(mDeps).detectMtu(eq(NAT64_PREFIX_STRING), eq(GOOGLE_DNS_4), eq(MARK));
inOrder.verify(mNetd).interfaceSetMtu(eq(STACKED_IFACE),
@@ -372,6 +391,7 @@
inOrder.verify(mDeps).stopClatd(eq(BASE_IFACE), eq(NAT64_PREFIX_STRING),
eq(XLAT_LOCAL_IPV4ADDR_STRING), eq(XLAT_LOCAL_IPV6ADDR_STRING), eq(CLATD_PID));
inOrder.verify(mDeps).untagSocket(eq(RAW_SOCK_COOKIE));
+ assertNull(coordinator.getClatdTrackerForTesting());
inOrder.verifyNoMoreInteractions();
// [4] Expect an IO exception while stopping a clatd that doesn't exist.
diff --git a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
index 6590543..6b379e8 100644
--- a/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -77,6 +77,7 @@
import android.net.UidRange;
import android.net.Uri;
import android.os.Build;
+import android.os.Process;
import android.os.SystemConfigManager;
import android.os.UserHandle;
import android.os.UserManager;
@@ -88,7 +89,10 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
+import com.android.modules.utils.build.SdkLevel;
import com.android.net.module.util.CollectionUtils;
+import com.android.networkstack.apishim.ProcessShimImpl;
+import com.android.networkstack.apishim.common.ProcessShim;
import com.android.server.BpfNetMaps;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
@@ -153,6 +157,8 @@
private NetdMonitor mNetdMonitor;
private BpfMapMonitor mBpfMapMonitor;
+ private ProcessShim mProcessShim = ProcessShimImpl.newInstance();
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -197,6 +203,10 @@
return mPermissionMonitor.hasRestrictedNetworkPermission(packageInfo);
}
+ private boolean hasSdkSandbox(final int uid) {
+ return SdkLevel.isAtLeastT() && Process.isApplicationUid(uid);
+ }
+
private static PackageInfo systemPackageInfoWithPermissions(String... permissions) {
return packageInfoWithPermissions(
REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM);
@@ -493,6 +503,11 @@
String... permissions) throws Exception {
addPackage(name, uid, permissions);
assertEquals(hasPermission, mPermissionMonitor.hasUseBackgroundNetworksPermission(uid));
+ if (hasSdkSandbox(uid)) {
+ final int sdkSandboxUid = mProcessShim.toSdkSandboxUid(uid);
+ assertEquals(hasPermission,
+ mPermissionMonitor.hasUseBackgroundNetworksPermission(sdkSandboxUid));
+ }
}
@Test
@@ -531,7 +546,7 @@
}).when(mockBpfmap).setNetPermForUids(anyInt(), any(int[].class));
}
- public void expectTrafficPerm(int permission, int... appIds) {
+ public void expectTrafficPerm(int permission, Integer... appIds) {
for (final int appId : appIds) {
if (mAppIdsTrafficPermission.get(appId, DOES_NOT_EXIST) == DOES_NOT_EXIST) {
fail("appId " + appId + " does not exist.");
@@ -540,6 +555,17 @@
fail("appId " + appId + " has wrong permission: "
+ mAppIdsTrafficPermission.get(appId));
}
+ if (hasSdkSandbox(appId)) {
+ int sdkSandboxAppId = mProcessShim.toSdkSandboxUid(appId);
+ if (mAppIdsTrafficPermission.get(sdkSandboxAppId, DOES_NOT_EXIST)
+ == DOES_NOT_EXIST) {
+ fail("SDK sandbox appId " + sdkSandboxAppId + " does not exist.");
+ }
+ if (mAppIdsTrafficPermission.get(sdkSandboxAppId) != permission) {
+ fail("SDK sandbox appId " + sdkSandboxAppId + " has wrong permission: "
+ + mAppIdsTrafficPermission.get(sdkSandboxAppId));
+ }
+ }
}
}
}
@@ -589,6 +615,17 @@
if (mUidsNetworkPermission.get(uid) != permission) {
fail("uid " + uid + " has wrong permission: " + permission);
}
+ if (hasSdkSandbox(uid)) {
+ int sdkSandboxUid = mProcessShim.toSdkSandboxUid(uid);
+ if (mUidsNetworkPermission.get(sdkSandboxUid, DOES_NOT_EXIST)
+ == DOES_NOT_EXIST) {
+ fail("SDK sandbox uid " + uid + " does not exist.");
+ }
+ if (mUidsNetworkPermission.get(sdkSandboxUid) != permission) {
+ fail("SDK sandbox uid " + uid + " has wrong permission: "
+ + permission);
+ }
+ }
}
}
}
@@ -600,6 +637,14 @@
if (mUidsNetworkPermission.get(uid, DOES_NOT_EXIST) != DOES_NOT_EXIST) {
fail("uid " + uid + " has listed permissions, expected none.");
}
+ if (hasSdkSandbox(uid)) {
+ int sdkSandboxUid = mProcessShim.toSdkSandboxUid(uid);
+ if (mUidsNetworkPermission.get(sdkSandboxUid, DOES_NOT_EXIST)
+ != DOES_NOT_EXIST) {
+ fail("SDK sandbox uid " + sdkSandboxUid
+ + " has listed permissions, expected none.");
+ }
+ }
}
}
}
@@ -785,9 +830,18 @@
// MOCK_APPID2: MOCK_PACKAGE2 does not have any permission.
// SYSTEM_APPID1: SYSTEM_PACKAGE1 has internet permission and update device stats permission
// SYSTEM_APPID2: SYSTEM_PACKAGE2 has only update device stats permission.
+ // The SDK sandbox APPIDs must have permissions mirroring the app
SparseIntArray netdPermissionsAppIds = new SparseIntArray();
netdPermissionsAppIds.put(MOCK_APPID1, PERMISSION_INTERNET);
+ if (hasSdkSandbox(MOCK_APPID1)) {
+ netdPermissionsAppIds.put(mProcessShim.toSdkSandboxUid(MOCK_APPID1),
+ PERMISSION_INTERNET);
+ }
netdPermissionsAppIds.put(MOCK_APPID2, PERMISSION_NONE);
+ if (hasSdkSandbox(MOCK_APPID2)) {
+ netdPermissionsAppIds.put(mProcessShim.toSdkSandboxUid(MOCK_APPID2),
+ PERMISSION_NONE);
+ }
netdPermissionsAppIds.put(SYSTEM_APPID1, PERMISSION_TRAFFIC_ALL);
netdPermissionsAppIds.put(SYSTEM_APPID2, PERMISSION_UPDATE_DEVICE_STATS);
diff --git a/tests/unit/java/com/android/server/connectivity/UidRangeUtilsTest.java b/tests/unit/java/com/android/server/connectivity/UidRangeUtilsTest.java
index b8c2673..b8c552e 100644
--- a/tests/unit/java/com/android/server/connectivity/UidRangeUtilsTest.java
+++ b/tests/unit/java/com/android/server/connectivity/UidRangeUtilsTest.java
@@ -351,4 +351,55 @@
expected.add(uids6);
assertEquals(expected, UidRangeUtils.convertListToUidRange(input));
}
+
+ @Test @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testConvertArrayToUidRange() {
+ final UidRange uids1_1 = new UidRange(1, 1);
+ final UidRange uids1_2 = new UidRange(1, 2);
+ final UidRange uids100_100 = new UidRange(100, 100);
+ final UidRange uids10_10 = new UidRange(10, 10);
+
+ final UidRange uids10_14 = new UidRange(10, 14);
+ final UidRange uids20_24 = new UidRange(20, 24);
+
+ final Set<UidRange> expected = new ArraySet<>();
+ int[] input = new int[0];
+
+ assertThrows(NullPointerException.class, () -> UidRangeUtils.convertArrayToUidRange(null));
+ assertEquals(expected, UidRangeUtils.convertArrayToUidRange(input));
+
+ input = new int[] {1};
+ expected.add(uids1_1);
+ assertEquals(expected, UidRangeUtils.convertArrayToUidRange(input));
+
+ input = new int[]{1, 2};
+ expected.clear();
+ expected.add(uids1_2);
+ assertEquals(expected, UidRangeUtils.convertArrayToUidRange(input));
+
+ input = new int[]{1, 100};
+ expected.clear();
+ expected.add(uids1_1);
+ expected.add(uids100_100);
+ assertEquals(expected, UidRangeUtils.convertArrayToUidRange(input));
+
+ input = new int[]{100, 1};
+ expected.clear();
+ expected.add(uids1_1);
+ expected.add(uids100_100);
+ assertEquals(expected, UidRangeUtils.convertArrayToUidRange(input));
+
+ input = new int[]{100, 1, 2, 1, 10};
+ expected.clear();
+ expected.add(uids1_2);
+ expected.add(uids10_10);
+ expected.add(uids100_100);
+ assertEquals(expected, UidRangeUtils.convertArrayToUidRange(input));
+
+ input = new int[]{10, 11, 12, 13, 14, 20, 21, 22, 23, 24};
+ expected.clear();
+ expected.add(uids10_14);
+ expected.add(uids20_24);
+ assertEquals(expected, UidRangeUtils.convertArrayToUidRange(input));
+ }
}
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index aa4e4bb..ceeb997 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -517,10 +517,10 @@
.insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L)
.insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L));
- mService.setUidForeground(UID_RED, false);
+ mService.noteUidForeground(UID_RED, false);
verify(mUidCounterSetMap, never()).deleteEntry(any());
mService.incrementOperationCount(UID_RED, 0xFAAD, 4);
- mService.setUidForeground(UID_RED, true);
+ mService.noteUidForeground(UID_RED, true);
verify(mUidCounterSetMap).updateEntry(
eq(new U32(UID_RED)), eq(new U8((short) SET_FOREGROUND)));
mService.incrementOperationCount(UID_RED, 0xFAAD, 6);
@@ -1118,7 +1118,7 @@
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L)
.insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L));
- mService.setUidForeground(UID_RED, true);
+ mService.noteUidForeground(UID_RED, true);
verify(mUidCounterSetMap).updateEntry(
eq(new U32(UID_RED)), eq(new U8((short) SET_FOREGROUND)));
mService.incrementOperationCount(UID_RED, 0xFAAD, 1);