summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/test-current.txt1
-rw-r--r--config/OWNERS4
-rw-r--r--core/java/android/annotation/OWNERS2
-rw-r--r--core/java/android/net/ConnectivityManager.java25
-rw-r--r--core/java/android/net/IConnectivityManager.aidl5
-rw-r--r--core/java/android/net/Ikev2VpnProfile.java45
-rw-r--r--core/java/android/net/NetworkCapabilities.java13
-rw-r--r--core/java/android/provider/Settings.java11
-rw-r--r--core/java/android/view/Surface.java4
-rw-r--r--core/java/android/view/SurfaceControl.java2
-rw-r--r--core/java/com/android/internal/compat/OWNERS1
-rw-r--r--core/java/com/android/internal/net/VpnProfile.java32
-rw-r--r--core/proto/android/providers/settings/global.proto9
-rw-r--r--core/res/res/values/config.xml4
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/res/res/xml/sms_short_codes.xml2
-rw-r--r--core/tests/PlatformCompatFramework/OWNERS1
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java1
-rw-r--r--data/etc/privapp-permissions-platform.xml1
-rw-r--r--data/fonts/Android.bp36
-rw-r--r--data/fonts/Android.mk57
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java3
-rw-r--r--packages/Shell/AndroidManifest.xml6
-rw-r--r--packages/Tethering/Android.bp1
-rw-r--r--packages/Tethering/common/TetheringLib/Android.bp40
-rw-r--r--packages/Tethering/res/values/config.xml6
-rw-r--r--packages/Tethering/res/values/overlayable.xml5
-rw-r--r--packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java12
-rw-r--r--packages/Tethering/src/android/net/ip/IpServer.java264
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java124
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/Tethering.java38
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java49
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java185
-rw-r--r--packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java149
-rw-r--r--packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java5
-rw-r--r--packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java215
-rw-r--r--packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java71
-rw-r--r--packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java19
-rw-r--r--packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java60
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java57
-rw-r--r--services/core/java/com/android/server/TestNetworkService.java61
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java8
-rw-r--r--services/core/java/com/android/server/compat/OWNERS1
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java7
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java31
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java49
-rw-r--r--telecomm/java/android/telecom/Conference.java20
-rwxr-xr-xtelecomm/java/android/telecom/ConnectionService.java5
-rw-r--r--telecomm/java/android/telecom/GatewayInfo.java4
-rw-r--r--telecomm/java/android/telecom/ParcelableCall.java4
-rw-r--r--telephony/common/com/android/internal/telephony/CellBroadcastUtils.java65
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java8
-rw-r--r--telephony/java/android/telephony/CellSignalStrengthNr.java4
-rw-r--r--telephony/java/android/telephony/ServiceState.java5
-rw-r--r--test-base/api/lint-baseline.txt3
-rw-r--r--test-mock/api/lint-baseline.txt143
-rw-r--r--test-mock/api/system-lint-baseline.txt15
-rw-r--r--test-runner/api/lint-baseline.txt173
-rw-r--r--tests/net/java/com/android/internal/net/VpnProfileTest.java47
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java13
-rw-r--r--tests/net/java/com/android/server/connectivity/LingerMonitorTest.java3
-rw-r--r--tools/aapt2/cmd/Link.cpp10
62 files changed, 1670 insertions, 575 deletions
diff --git a/api/test-current.txt b/api/test-current.txt
index d3e1e8c4c2bc..9747647845ed 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1440,6 +1440,7 @@ package android.net {
}
public class ConnectivityManager {
+ method @RequiresPermission(anyOf={"android.permission.MANAGE_TEST_NETWORKS", android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
diff --git a/config/OWNERS b/config/OWNERS
index 53f80e698d83..3d4924df3462 100644
--- a/config/OWNERS
+++ b/config/OWNERS
@@ -1,5 +1,5 @@
# compat-team@ for changes to hiddenapi files
-per-file hiddenapi-* = andreionea@google.com, atrost@google.com, mathewi@google.com, satayev@google.com
+per-file hiddenapi-* = andreionea@google.com, mathewi@google.com, satayev@google.com
# Escalations:
-per-file hiddenapi-* = bdc@google.com, narayan@google.com \ No newline at end of file
+per-file hiddenapi-* = bdc@google.com, narayan@google.com
diff --git a/core/java/android/annotation/OWNERS b/core/java/android/annotation/OWNERS
index 8aceb565315c..e1ef54460b56 100644
--- a/core/java/android/annotation/OWNERS
+++ b/core/java/android/annotation/OWNERS
@@ -1,3 +1,3 @@
tnorbye@google.com
aurimas@google.com
-per-file UnsupportedAppUsage.java = mathewi@google.com, dbrazdil@google.com, atrost@google.com, andreionea@google.com
+per-file UnsupportedAppUsage.java = mathewi@google.com, satayev@google.com, andreionea@google.com
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ad07e7cf4d5f..6b713602215a 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -48,6 +48,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -4735,4 +4736,28 @@ public class ConnectivityManager {
Log.d(TAG, "StackLog:" + sb.toString());
}
}
+
+ /**
+ * Simulates a Data Stall for the specified Network.
+ *
+ * <p>The caller must be the owner of the specified Network.
+ *
+ * @param detectionMethod The detection method used to identify the Data Stall.
+ * @param timestampMillis The timestamp at which the stall 'occurred', in milliseconds.
+ * @param network The Network for which a Data Stall is being simluated.
+ * @param extras The PersistableBundle of extras included in the Data Stall notification.
+ * @throws SecurityException if the caller is not the owner of the given network.
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_TEST_NETWORKS,
+ android.Manifest.permission.NETWORK_STACK})
+ public void simulateDataStall(int detectionMethod, long timestampMillis,
+ @NonNull Network network, @NonNull PersistableBundle extras) {
+ try {
+ mService.simulateDataStall(detectionMethod, timestampMillis, network, extras);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index b0f79bcc0b23..d7f178cd0a9b 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -18,6 +18,7 @@ package android.net;
import android.app.PendingIntent;
import android.net.ConnectionInfo;
+import android.net.ConnectivityDiagnosticsManager;
import android.net.IConnectivityDiagnosticsCallback;
import android.net.LinkProperties;
import android.net.Network;
@@ -33,6 +34,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.Messenger;
import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
import android.os.ResultReceiver;
import com.android.internal.net.LegacyVpnInfo;
@@ -228,4 +230,7 @@ interface IConnectivityManager
void unregisterConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback);
IBinder startOrGetTestNetworkService();
+
+ void simulateDataStall(int detectionMethod, long timestampMillis, in Network network,
+ in PersistableBundle extras);
}
diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java
index 836624beb3b2..407ff04dc4a3 100644
--- a/core/java/android/net/Ikev2VpnProfile.java
+++ b/core/java/android/net/Ikev2VpnProfile.java
@@ -101,6 +101,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
private final boolean mIsBypassable; // Defaults in builder
private final boolean mIsMetered; // Defaults in builder
private final int mMaxMtu; // Defaults in builder
+ private final boolean mIsRestrictedToTestNetworks;
private Ikev2VpnProfile(
int type,
@@ -116,7 +117,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
@NonNull List<String> allowedAlgorithms,
boolean isBypassable,
boolean isMetered,
- int maxMtu) {
+ int maxMtu,
+ boolean restrictToTestNetworks) {
super(type);
checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "Server address");
@@ -140,6 +142,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
mIsBypassable = isBypassable;
mIsMetered = isMetered;
mMaxMtu = maxMtu;
+ mIsRestrictedToTestNetworks = restrictToTestNetworks;
validate();
}
@@ -329,6 +332,15 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
return mMaxMtu;
}
+ /**
+ * Returns whether or not this VPN profile is restricted to test networks.
+ *
+ * @hide
+ */
+ public boolean isRestrictedToTestNetworks() {
+ return mIsRestrictedToTestNetworks;
+ }
+
@Override
public int hashCode() {
return Objects.hash(
@@ -345,7 +357,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
mAllowedAlgorithms,
mIsBypassable,
mIsMetered,
- mMaxMtu);
+ mMaxMtu,
+ mIsRestrictedToTestNetworks);
}
@Override
@@ -368,7 +381,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
&& Objects.equals(mAllowedAlgorithms, other.mAllowedAlgorithms)
&& mIsBypassable == other.mIsBypassable
&& mIsMetered == other.mIsMetered
- && mMaxMtu == other.mMaxMtu;
+ && mMaxMtu == other.mMaxMtu
+ && mIsRestrictedToTestNetworks == other.mIsRestrictedToTestNetworks;
}
/**
@@ -381,7 +395,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
*/
@NonNull
public VpnProfile toVpnProfile() throws IOException, GeneralSecurityException {
- final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */);
+ final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */,
+ mIsRestrictedToTestNetworks);
profile.type = mType;
profile.server = mServerAddr;
profile.ipsecIdentifier = mUserIdentity;
@@ -449,6 +464,9 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
builder.setBypassable(profile.isBypassable);
builder.setMetered(profile.isMetered);
builder.setMaxMtu(profile.maxMtu);
+ if (profile.isRestrictedToTestNetworks) {
+ builder.restrictToTestNetworks();
+ }
switch (profile.type) {
case TYPE_IKEV2_IPSEC_USER_PASS:
@@ -621,6 +639,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
private boolean mIsBypassable = false;
private boolean mIsMetered = true;
private int mMaxMtu = PlatformVpnProfile.MAX_MTU_DEFAULT;
+ private boolean mIsRestrictedToTestNetworks = false;
/**
* Creates a new builder with the basic parameters of an IKEv2/IPsec VPN.
@@ -842,6 +861,21 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
}
/**
+ * Restricts this profile to use test networks (only).
+ *
+ * <p>This method is for testing only, and must not be used by apps. Calling
+ * provisionVpnProfile() with a profile where test-network usage is enabled will require the
+ * MANAGE_TEST_NETWORKS permission.
+ *
+ * @hide
+ */
+ @NonNull
+ public Builder restrictToTestNetworks() {
+ mIsRestrictedToTestNetworks = true;
+ return this;
+ }
+
+ /**
* Validates, builds and provisions the VpnProfile.
*
* @throws IllegalArgumentException if any of the required keys or values were invalid
@@ -862,7 +896,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile {
mAllowedAlgorithms,
mIsBypassable,
mIsMetered,
- mMaxMtu);
+ mMaxMtu,
+ mIsRestrictedToTestNetworks);
}
}
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 74eced796b04..57d5d03a6cf2 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -677,16 +677,27 @@ public final class NetworkCapabilities implements Parcelable {
* restrictions.
* @hide
*/
- public void restrictCapabilitesForTestNetwork() {
+ public void restrictCapabilitesForTestNetwork(int creatorUid) {
final long originalCapabilities = mNetworkCapabilities;
final NetworkSpecifier originalSpecifier = mNetworkSpecifier;
final int originalSignalStrength = mSignalStrength;
+ final int originalOwnerUid = getOwnerUid();
+ final int[] originalAdministratorUids = getAdministratorUids();
clearAll();
// Reset the transports to only contain TRANSPORT_TEST.
mTransportTypes = (1 << TRANSPORT_TEST);
mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES;
mNetworkSpecifier = originalSpecifier;
mSignalStrength = originalSignalStrength;
+
+ // Only retain the owner and administrator UIDs if they match the app registering the remote
+ // caller that registered the network.
+ if (originalOwnerUid == creatorUid) {
+ setOwnerUid(creatorUid);
+ }
+ if (ArrayUtils.contains(originalAdministratorUids, creatorUid)) {
+ setAdministratorUids(new int[] {creatorUid});
+ }
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 7923b586ada5..cadae5cecc6d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12061,17 +12061,6 @@ public final class Settings {
public static final String ALWAYS_ON_DISPLAY_CONSTANTS = "always_on_display_constants";
/**
- * System VDSO global setting. This links to the "sys.vdso" system property.
- * The following values are supported:
- * false -> both 32 and 64 bit vdso disabled
- * 32 -> 32 bit vdso enabled
- * 64 -> 64 bit vdso enabled
- * Any other value defaults to both 32 bit and 64 bit true.
- * @hide
- */
- public static final String SYS_VDSO = "sys_vdso";
-
- /**
* UidCpuPower global setting. This links the sys.uidcpupower system property.
* The following values are supported:
* 0 -> /proc/uid_cpupower/* are disabled
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 3a6c8dd3720f..489307beb878 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -189,12 +189,12 @@ public class Surface implements Parcelable {
}
/**
- * Create a Surface assosciated with a given {@link SurfaceControl}. Buffers submitted to this
+ * Create a Surface associated with a given {@link SurfaceControl}. Buffers submitted to this
* surface will be displayed by the system compositor according to the parameters
* specified by the control. Multiple surfaces may be constructed from one SurfaceControl,
* but only one can be connected (e.g. have an active EGL context) at a time.
*
- * @param from The SurfaceControl to assosciate this Surface with
+ * @param from The SurfaceControl to associate this Surface with
*/
public Surface(@NonNull SurfaceControl from) {
copyFrom(from);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index fcd8127bbaa4..4f7bedaf1117 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -2259,7 +2259,7 @@ public final class SurfaceControl implements Parcelable {
}
/**
- * Specify how the buffer assosciated with this Surface is mapped in to the
+ * Specify how the buffer associated with this Surface is mapped in to the
* parent coordinate space. The source frame will be scaled to fit the destination
* frame, after being rotated according to the orientation parameter.
*
diff --git a/core/java/com/android/internal/compat/OWNERS b/core/java/com/android/internal/compat/OWNERS
index 2b7cdb0cbce9..cfd0a4b079ad 100644
--- a/core/java/com/android/internal/compat/OWNERS
+++ b/core/java/com/android/internal/compat/OWNERS
@@ -2,6 +2,5 @@
platform-compat-eng+reviews@google.com
andreionea@google.com
-atrost@google.com
mathewi@google.com
satayev@google.com
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index 829bd8a5a2a7..8ea5aa815a1c 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -136,13 +136,19 @@ public final class VpnProfile implements Cloneable, Parcelable {
public boolean isMetered = false; // 21
public int maxMtu = PlatformVpnProfile.MAX_MTU_DEFAULT; // 22
public boolean areAuthParamsInline = false; // 23
+ public final boolean isRestrictedToTestNetworks; // 24
// Helper fields.
@UnsupportedAppUsage
public transient boolean saveLogin = false;
public VpnProfile(String key) {
+ this(key, false);
+ }
+
+ public VpnProfile(String key, boolean isRestrictedToTestNetworks) {
this.key = key;
+ this.isRestrictedToTestNetworks = isRestrictedToTestNetworks;
}
@UnsupportedAppUsage
@@ -171,6 +177,7 @@ public final class VpnProfile implements Cloneable, Parcelable {
isMetered = in.readBoolean();
maxMtu = in.readInt();
areAuthParamsInline = in.readBoolean();
+ isRestrictedToTestNetworks = in.readBoolean();
}
/**
@@ -220,6 +227,7 @@ public final class VpnProfile implements Cloneable, Parcelable {
out.writeBoolean(isMetered);
out.writeInt(maxMtu);
out.writeBoolean(areAuthParamsInline);
+ out.writeBoolean(isRestrictedToTestNetworks);
}
/**
@@ -237,12 +245,21 @@ public final class VpnProfile implements Cloneable, Parcelable {
String[] values = new String(value, StandardCharsets.UTF_8).split(VALUE_DELIMITER, -1);
// Acceptable numbers of values are:
// 14-19: Standard profile, with option for serverCert, proxy
- // 24: Standard profile with serverCert, proxy and platform-VPN parameters.
- if ((values.length < 14 || values.length > 19) && values.length != 24) {
+ // 24: Standard profile with serverCert, proxy and platform-VPN parameters
+ // 25: Standard profile with platform-VPN parameters and isRestrictedToTestNetworks
+ if ((values.length < 14 || values.length > 19)
+ && values.length != 24 && values.length != 25) {
return null;
}
- VpnProfile profile = new VpnProfile(key);
+ final boolean isRestrictedToTestNetworks;
+ if (values.length >= 25) {
+ isRestrictedToTestNetworks = Boolean.parseBoolean(values[24]);
+ } else {
+ isRestrictedToTestNetworks = false;
+ }
+
+ VpnProfile profile = new VpnProfile(key, isRestrictedToTestNetworks);
profile.name = values[0];
profile.type = Integer.parseInt(values[1]);
if (profile.type < 0 || profile.type > TYPE_MAX) {
@@ -283,6 +300,8 @@ public final class VpnProfile implements Cloneable, Parcelable {
profile.areAuthParamsInline = Boolean.parseBoolean(values[23]);
}
+ // isRestrictedToTestNetworks (values[24]) assigned as part of the constructor
+
profile.saveLogin = !profile.username.isEmpty() || !profile.password.isEmpty();
return profile;
} catch (Exception e) {
@@ -330,6 +349,7 @@ public final class VpnProfile implements Cloneable, Parcelable {
builder.append(VALUE_DELIMITER).append(isMetered);
builder.append(VALUE_DELIMITER).append(maxMtu);
builder.append(VALUE_DELIMITER).append(areAuthParamsInline);
+ builder.append(VALUE_DELIMITER).append(isRestrictedToTestNetworks);
return builder.toString().getBytes(StandardCharsets.UTF_8);
}
@@ -421,7 +441,8 @@ public final class VpnProfile implements Cloneable, Parcelable {
return Objects.hash(
key, type, server, username, password, dnsServers, searchDomains, routes, mppe,
l2tpSecret, ipsecIdentifier, ipsecSecret, ipsecUserCert, ipsecCaCert, ipsecServerCert,
- proxy, mAllowedAlgorithms, isBypassable, isMetered, maxMtu, areAuthParamsInline);
+ proxy, mAllowedAlgorithms, isBypassable, isMetered, maxMtu, areAuthParamsInline,
+ isRestrictedToTestNetworks);
}
/** Checks VPN profiles for interior equality. */
@@ -453,7 +474,8 @@ public final class VpnProfile implements Cloneable, Parcelable {
&& isBypassable == other.isBypassable
&& isMetered == other.isMetered
&& maxMtu == other.maxMtu
- && areAuthParamsInline == other.areAuthParamsInline;
+ && areAuthParamsInline == other.areAuthParamsInline
+ && isRestrictedToTestNetworks == other.isRestrictedToTestNetworks;
}
@NonNull
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 3d99b726e6fe..829e1f7d0d96 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -905,13 +905,8 @@ message GlobalSettingsProto {
optional SettingProto storage_full_threshold_bytes = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto storage_cache_percentage = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto storage_cache_max_bytes = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
- // System VDSO global setting. This links to the "sys.vdso" system property.
- // The following values are supported:
- // false -> both 32 and 64 bit vdso disabled
- // 32 -> 32 bit vdso enabled
- // 64 -> 64 bit vdso enabled
- // Any other value defaults to both 32 bit and 64 bit true.
- optional SettingProto vdso = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ // Used to be sys_vdso
+ reserved 7;
// UidCpuPower global setting. This links the sys.uidcpupower system property.
// The following values are supported:
// 0 -> /proc/uid_cpupower/* are disabled
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2ab44447fde2..6551b28bd5a3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -452,10 +452,6 @@
-->
</string-array>
- <!-- Package name for the default CellBroadcastService module [DO NOT TRANSLATE] -->
- <string name="cellbroadcast_default_package" translatable="false">com.android.cellbroadcastservice
- </string>
-
<!-- If the mobile hotspot feature requires provisioning, a package name and class name
can be provided to launch a supported application that provisions the devices.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a844d8ae5a61..3cee3407296c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -745,7 +745,6 @@
<java-symbol type="string" name="config_ethernet_iface_regex" />
<java-symbol type="array" name="config_ethernet_interfaces" />
<java-symbol type="array" name="config_wakeonlan_supported_interfaces" />
- <java-symbol type="string" name="cellbroadcast_default_package" />
<java-symbol type="string" name="config_forceVoiceInteractionServicePackage" />
<java-symbol type="string" name="config_mms_user_agent" />
<java-symbol type="string" name="config_mms_user_agent_profile_url" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 70917e76f8b4..9cc04d341bdf 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -70,7 +70,7 @@
<shortcode country="by" pattern="\\d{4}" premium="3336|4161|444[4689]|501[34]|7781" />
<!-- Canada: 5-6 digits -->
- <shortcode country="ca" pattern="\\d{5,6}" premium="60999|88188|43030" standard="244444" />
+ <shortcode country="ca" pattern="\\d{5,6}" premium="60999|88188|43030" standard="244444" free="455677" />
<!-- Switzerland: 3-5 digits: http://www.swisscom.ch/fxres/kmu/thirdpartybusiness_code_of_conduct_en.pdf -->
<shortcode country="ch" pattern="[2-9]\\d{2,4}" premium="543|83111|30118" free="98765|30075|30047" />
diff --git a/core/tests/PlatformCompatFramework/OWNERS b/core/tests/PlatformCompatFramework/OWNERS
index 2b7cdb0cbce9..cfd0a4b079ad 100644
--- a/core/tests/PlatformCompatFramework/OWNERS
+++ b/core/tests/PlatformCompatFramework/OWNERS
@@ -2,6 +2,5 @@
platform-compat-eng+reviews@google.com
andreionea@google.com
-atrost@google.com
mathewi@google.com
satayev@google.com
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 802b106a107c..cb91db1934a4 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -454,7 +454,6 @@ public class SettingsBackupTest {
Settings.Global.SYS_STORAGE_FULL_THRESHOLD_BYTES,
Settings.Global.SYS_STORAGE_THRESHOLD_MAX_BYTES,
Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE,
- Settings.Global.SYS_VDSO,
Settings.Global.SYS_UIDCPUPOWER,
Settings.Global.SYS_TRACED,
Settings.Global.FPS_DEVISOR,
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index a1c8e1366803..5b0ef8ef2130 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -291,6 +291,7 @@ applications that come with the platform
<permission name="android.permission.MANAGE_DEVICE_ADMINS"/>
<permission name="android.permission.MANAGE_USB"/>
<permission name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>
+ <permission name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
<permission name="android.permission.MOUNT_FORMAT_FILESYSTEMS"/>
<permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
diff --git a/data/fonts/Android.bp b/data/fonts/Android.bp
new file mode 100644
index 000000000000..94e6a8096849
--- /dev/null
+++ b/data/fonts/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2011 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.
+
+prebuilt_font {
+ name: "DroidSansMono.ttf",
+ src: "DroidSansMono.ttf",
+ required: [
+ "DroidSans.ttf",
+ "DroidSans-Bold.ttf",
+ ],
+}
+
+prebuilt_font {
+ name: "AndroidClock.ttf",
+ src: "AndroidClock.ttf",
+}
+
+/////////////////////////////////
+// Copies the font configuration file into system/etc for the product as fonts.xml.
+// Additional fonts should be installed to /product/fonts/ alongside a corresponding
+// fonts_customiztion.xml in /product/etc/
+prebuilt_etc {
+ name: "fonts.xml",
+ src: "fonts.xml",
+}
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 4226e0882538..e22b72346249 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -12,9 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# We have to use BUILD_PREBUILT instead of PRODUCT_COPY_FIES,
-# because MINIMAL_FONT_FOOTPRINT is only available in Android.mks.
-
LOCAL_PATH := $(call my-dir)
##########################################
@@ -37,61 +34,7 @@ endef
##########################################
$(eval $(call create-font-symlink,DroidSans.ttf,Roboto-Regular.ttf))
$(eval $(call create-font-symlink,DroidSans-Bold.ttf,Roboto-Bold.ttf))
-$(eval $(call create-font-symlink,DroidSerif-Regular.ttf,NotoSerif-Regular.ttf))
-$(eval $(call create-font-symlink,DroidSerif-Bold.ttf,NotoSerif-Bold.ttf))
-$(eval $(call create-font-symlink,DroidSerif-Italic.ttf,NotoSerif-Italic.ttf))
-$(eval $(call create-font-symlink,DroidSerif-BoldItalic.ttf,NotoSerif-BoldItalic.ttf))
-
-extra_font_files := \
- DroidSans.ttf \
- DroidSans-Bold.ttf
-
-################################
-# Use DroidSansMono to hang extra_font_files on
-include $(CLEAR_VARS)
-LOCAL_MODULE := DroidSansMono.ttf
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
-LOCAL_REQUIRED_MODULES := $(extra_font_files)
-include $(BUILD_PREBUILT)
-extra_font_files :=
-
-################################
-# Build the rest of font files as prebuilt.
-
-# $(1): The source file name in LOCAL_PATH.
-# It also serves as the module name and the dest file name.
-define build-one-font-module
-$(eval include $(CLEAR_VARS))\
-$(eval LOCAL_MODULE := $(1))\
-$(eval LOCAL_SRC_FILES := $(1))\
-$(eval LOCAL_MODULE_CLASS := ETC)\
-$(eval LOCAL_MODULE_TAGS := optional)\
-$(eval LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts)\
-$(eval include $(BUILD_PREBUILT))
-endef
-
-font_src_files := \
- AndroidClock.ttf
-
-$(foreach f, $(font_src_files), $(call build-one-font-module, $(f)))
-
-build-one-font-module :=
-font_src_files :=
-
-################################
-# Copies the font configuration file into system/etc for the product as fonts.xml.
-# Additional fonts should be installed to /product/fonts/ alongside a corresponding
-# fonts_customiztion.xml in /product/etc/
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := fonts.xml
-LOCAL_MODULE_CLASS := ETC
-LOCAL_PREBUILT_MODULE_FILE := frameworks/base/data/fonts/fonts.xml
-include $(BUILD_PREBUILT)
# Run sanity tests on fonts on checkbuild
checkbuild: fontchain_lint
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 21129f927873..65f68cc5c5b5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1352,9 +1352,6 @@ class SettingsProtoDumpUtil {
Settings.Global.SYS_STORAGE_CACHE_MAX_BYTES,
GlobalSettingsProto.Sys.STORAGE_CACHE_MAX_BYTES);
dumpSetting(s, p,
- Settings.Global.SYS_VDSO,
- GlobalSettingsProto.Sys.VDSO);
- dumpSetting(s, p,
Settings.Global.SYS_UIDCPUPOWER,
GlobalSettingsProto.Sys.UIDCPUPOWER);
p.end(sysToken);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index ff91c797e9b1..24d089677eac 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -219,6 +219,9 @@
<uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
<uses-permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"/>
+ <!-- Permission required for CTS test - BatterySaverTest -->
+ <uses-permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
+
<!-- Permission required for CTS test - UiModeManagerTest -->
<uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/>
@@ -247,6 +250,9 @@
<!-- Permission required for testing system audio effect APIs. -->
<uses-permission android:name="android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS"/>
+ <!-- Permissions needed to test shared libraries -->
+ <uses-permission android:name="android.permission.ACCESS_SHARED_LIBRARIES" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index 29660a9c4dce..eb72b81fb766 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -114,6 +114,7 @@ android_app {
// InProcessTethering is a replacement for Tethering
overrides: ["Tethering"],
apex_available: ["com.android.tethering"],
+ min_sdk_version: "current",
}
// Updatable tethering packaged as an application
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index 7ac9d251e1bb..79a178297aa5 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -13,49 +13,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-// AIDL interfaces between the core system and the tethering mainline module.
-aidl_interface {
- name: "tethering-aidl-interfaces",
- unstable: true,
- local_include_dir: "src",
- include_dirs: ["frameworks/base/core/java"], // For framework parcelables.
- srcs: [
- // @JavaOnlyStableParcelable aidl declarations must not be listed here, as this would cause
- // compilation to fail (b/148001843).
- "src/android/net/IIntResultListener.aidl",
- "src/android/net/ITetheringConnector.aidl",
- "src/android/net/ITetheringEventCallback.aidl",
- "src/android/net/TetheringCallbackStartedParcel.aidl",
- "src/android/net/TetheringConfigurationParcel.aidl",
- "src/android/net/TetheringRequestParcel.aidl",
- "src/android/net/TetherStatesParcel.aidl",
- ],
- backend: {
- ndk: {
- enabled: false,
- },
- cpp: {
- enabled: false,
- },
- java: {
- apex_available: [
- "//apex_available:platform",
- "com.android.tethering",
- ],
- },
- },
-}
-
java_library {
name: "framework-tethering",
sdk_version: "module_current",
srcs: [
- "src/android/net/TetheredClient.java",
- "src/android/net/TetheringManager.java",
- "src/android/net/TetheringConstants.java",
- ],
- static_libs: [
- "tethering-aidl-interfaces-java",
+ ":framework-tethering-srcs",
],
jarjar_rules: "jarjar-rules.txt",
installable: true,
diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml
index c99922196346..3f5bc901d07b 100644
--- a/packages/Tethering/res/values/config.xml
+++ b/packages/Tethering/res/values/config.xml
@@ -55,6 +55,12 @@
<item>"bt-pan"</item>
</string-array>
+ <!-- Use the BPF offload for tethering when the kernel has support. True by default.
+ If the device doesn't want to support tether BPF offload, this should be false.
+ Note that this setting could be overridden by device config.
+ -->
+ <bool translatable="false" name="config_tether_enable_bpf_offload">true</bool>
+
<!-- Use the old dnsmasq DHCP server for tethering instead of the framework implementation. -->
<bool translatable="false" name="config_tether_enable_legacy_dhcp_server">false</bool>
diff --git a/packages/Tethering/res/values/overlayable.xml b/packages/Tethering/res/values/overlayable.xml
index 4c78a74d5358..4e2bb1e31b2a 100644
--- a/packages/Tethering/res/values/overlayable.xml
+++ b/packages/Tethering/res/values/overlayable.xml
@@ -23,6 +23,11 @@
<item type="array" name="config_tether_wifi_p2p_regexs"/>
<item type="array" name="config_tether_bluetooth_regexs"/>
<item type="array" name="config_tether_dhcp_range"/>
+ <!-- Use the BPF offload for tethering when the kernel has support. True by default.
+ If the device doesn't want to support tether BPF offload, this should be false.
+ Note that this setting could be overridden by device config.
+ -->
+ <item type="bool" name="config_tether_enable_bpf_offload"/>
<item type="bool" name="config_tether_enable_legacy_dhcp_server"/>
<item type="integer" name="config_tether_offload_poll_interval"/>
<item type="array" name="config_tether_upstream_types"/>
diff --git a/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java b/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java
index 4f8ad8a221ef..4710a30b2998 100644
--- a/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java
+++ b/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java
@@ -173,6 +173,18 @@ public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel {
return this;
}
+ /**
+ * Set whether the DHCP server should request a new prefix from IpServer when receiving
+ * DHCPDECLINE message in certain particular link (e.g. there is only one downstream USB
+ * tethering client). If it's false, process DHCPDECLINE message as RFC2131#4.3.3 suggests.
+ *
+ * <p>If not set, the default value is false.
+ */
+ public DhcpServingParamsParcelExt setChangePrefixOnDecline(boolean changePrefixOnDecline) {
+ this.changePrefixOnDecline = changePrefixOnDecline;
+ return this;
+ }
+
private static int[] toIntArray(@NonNull Collection<Inet4Address> addrs) {
int[] res = new int[addrs.size()];
int i = 0;
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index 83727bcdc67e..de537871a776 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -50,6 +50,7 @@ import android.net.shared.NetdUtils;
import android.net.shared.RouteUtils;
import android.net.util.InterfaceParams;
import android.net.util.InterfaceSet;
+import android.net.util.PrefixUtils;
import android.net.util.SharedLog;
import android.os.Handler;
import android.os.Looper;
@@ -60,6 +61,7 @@ import android.util.Log;
import android.util.SparseArray;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.internal.util.MessageUtils;
import com.android.internal.util.State;
@@ -115,6 +117,15 @@ public class IpServer extends StateMachine {
private static final String ETHERNET_IFACE_ADDR = "192.168.50.1";
private static final int ETHERNET_IFACE_PREFIX_LENGTH = 24;
+ // TODO: remove this constant after introducing PrivateAddressCoordinator.
+ private static final List<IpPrefix> NCM_PREFIXES = Collections.unmodifiableList(
+ Arrays.asList(
+ new IpPrefix("192.168.42.0/24"),
+ new IpPrefix("192.168.51.0/24"),
+ new IpPrefix("192.168.52.0/24"),
+ new IpPrefix("192.168.53.0/24")
+ ));
+
// TODO: have PanService use some visible version of this constant
private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1";
private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24;
@@ -212,6 +223,8 @@ public class IpServer extends StateMachine {
public static final int CMD_IPV6_TETHER_UPDATE = BASE_IPSERVER + 10;
// new neighbor cache entry on our interface
public static final int CMD_NEIGHBOR_EVENT = BASE_IPSERVER + 11;
+ // request from DHCP server that it wants to have a new prefix
+ public static final int CMD_NEW_PREFIX_REQUEST = BASE_IPSERVER + 12;
private final State mInitialState;
private final State mLocalHotspotState;
@@ -227,6 +240,7 @@ public class IpServer extends StateMachine {
private final int mInterfaceType;
private final LinkProperties mLinkProperties;
private final boolean mUsingLegacyDhcp;
+ private final boolean mUsingBpfOffload;
private final Dependencies mDeps;
@@ -302,9 +316,12 @@ public class IpServer extends StateMachine {
private final IpNeighborMonitor mIpNeighborMonitor;
+ // TODO: Add a dependency object to pass the data members or variables from the tethering
+ // object. It helps to reduce the arguments of the constructor.
public IpServer(
String ifaceName, Looper looper, int interfaceType, SharedLog log,
- INetd netd, Callback callback, boolean usingLegacyDhcp, Dependencies deps) {
+ INetd netd, Callback callback, boolean usingLegacyDhcp, boolean usingBpfOffload,
+ Dependencies deps) {
super(ifaceName, looper);
mLog = log.forSubComponent(ifaceName);
mNetd = netd;
@@ -314,6 +331,7 @@ public class IpServer extends StateMachine {
mInterfaceType = interfaceType;
mLinkProperties = new LinkProperties();
mUsingLegacyDhcp = usingLegacyDhcp;
+ mUsingBpfOffload = usingBpfOffload;
mDeps = deps;
resetLinkProperties();
mLastError = TetheringManager.TETHER_ERROR_NO_ERROR;
@@ -321,7 +339,12 @@ public class IpServer extends StateMachine {
mIpNeighborMonitor = mDeps.getIpNeighborMonitor(getHandler(), mLog,
new MyNeighborEventConsumer());
- if (!mIpNeighborMonitor.start()) {
+
+ // IP neighbor monitor monitors the neighbor events for adding/removing offload
+ // forwarding rules per client. If BPF offload is not supported, don't start listening
+ // for neighbor events. See updateIpv6ForwardingRules, addIpv6ForwardingRule,
+ // removeIpv6ForwardingRule.
+ if (mUsingBpfOffload && !mIpNeighborMonitor.start()) {
mLog.e("Failed to create IpNeighborMonitor on " + mIfaceName);
}
@@ -452,7 +475,7 @@ public class IpServer extends StateMachine {
handleError();
}
}
- }, new DhcpLeaseCallback());
+ }, new DhcpEventCallback());
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
@@ -465,7 +488,7 @@ public class IpServer extends StateMachine {
}
}
- private class DhcpLeaseCallback extends IDhcpEventCallbacks.Stub {
+ private class DhcpEventCallback extends IDhcpEventCallbacks.Stub {
@Override
public void onLeasesChanged(List<DhcpLeaseParcelable> leaseParcelables) {
final ArrayList<TetheredClient> leases = new ArrayList<>();
@@ -499,8 +522,9 @@ public class IpServer extends StateMachine {
}
@Override
- public void onNewPrefixRequest(IpPrefix currentPrefix) {
- //TODO: add specific implementation.
+ public void onNewPrefixRequest(@NonNull final IpPrefix currentPrefix) {
+ Objects.requireNonNull(currentPrefix);
+ sendMessage(CMD_NEW_PREFIX_REQUEST, currentPrefix);
}
@Override
@@ -514,26 +538,38 @@ public class IpServer extends StateMachine {
}
}
+ private RouteInfo getDirectConnectedRoute(@NonNull final LinkAddress ipv4Address) {
+ Objects.requireNonNull(ipv4Address);
+ return new RouteInfo(PrefixUtils.asIpPrefix(ipv4Address), null, mIfaceName, RTN_UNICAST);
+ }
+
+ private DhcpServingParamsParcel makeServingParams(@NonNull final Inet4Address defaultRouter,
+ @NonNull final Inet4Address dnsServer, @NonNull LinkAddress serverAddr,
+ @Nullable Inet4Address clientAddr) {
+ final boolean changePrefixOnDecline =
+ (mInterfaceType == TetheringManager.TETHERING_NCM && clientAddr == null);
+ return new DhcpServingParamsParcelExt()
+ .setDefaultRouters(defaultRouter)
+ .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS)
+ .setDnsServers(dnsServer)
+ .setServerAddr(serverAddr)
+ .setMetered(true)
+ .setSingleClientAddr(clientAddr)
+ .setChangePrefixOnDecline(changePrefixOnDecline);
+ // TODO: also advertise link MTU
+ }
+
private boolean startDhcp(final LinkAddress serverLinkAddr, final LinkAddress clientLinkAddr) {
if (mUsingLegacyDhcp) {
return true;
}
final Inet4Address addr = (Inet4Address) serverLinkAddr.getAddress();
- final int prefixLen = serverLinkAddr.getPrefixLength();
final Inet4Address clientAddr = clientLinkAddr == null ? null :
(Inet4Address) clientLinkAddr.getAddress();
- final DhcpServingParamsParcel params;
- params = new DhcpServingParamsParcelExt()
- .setDefaultRouters(addr)
- .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS)
- .setDnsServers(addr)
- .setServerAddr(serverLinkAddr)
- .setMetered(true)
- .setSingleClientAddr(clientAddr);
- // TODO: also advertise link MTU
-
+ final DhcpServingParamsParcel params = makeServingParams(addr /* defaultRouter */,
+ addr /* dnsServer */, serverLinkAddr, clientAddr);
mDhcpServerStartIndex++;
mDeps.makeDhcpServer(
mIfaceName, params, new DhcpServerCallbacksImpl(mDhcpServerStartIndex));
@@ -560,7 +596,7 @@ public class IpServer extends StateMachine {
});
mDhcpServer = null;
} catch (RemoteException e) {
- mLog.e("Error stopping DHCP", e);
+ mLog.e("Error stopping DHCP server", e);
// Not much more we can do here
}
}
@@ -642,31 +678,33 @@ public class IpServer extends StateMachine {
return false;
}
- // Directly-connected route.
- final IpPrefix ipv4Prefix = new IpPrefix(mIpv4Address.getAddress(),
- mIpv4Address.getPrefixLength());
- final RouteInfo route = new RouteInfo(ipv4Prefix, null, null, RTN_UNICAST);
if (enabled) {
mLinkProperties.addLinkAddress(mIpv4Address);
- mLinkProperties.addRoute(route);
+ mLinkProperties.addRoute(getDirectConnectedRoute(mIpv4Address));
} else {
mLinkProperties.removeLinkAddress(mIpv4Address);
- mLinkProperties.removeRoute(route);
+ mLinkProperties.removeRoute(getDirectConnectedRoute(mIpv4Address));
}
-
return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr);
}
- private String getRandomWifiIPv4Address() {
+ private Inet4Address getRandomIPv4Address(@NonNull final byte[] rawAddr) {
+ final byte[] ipv4Addr = rawAddr;
+ ipv4Addr[3] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1), FF);
try {
- byte[] bytes = parseNumericAddress(WIFI_HOST_IFACE_ADDR).getAddress();
- bytes[3] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1), FF);
- return InetAddress.getByAddress(bytes).getHostAddress();
- } catch (Exception e) {
- return WIFI_HOST_IFACE_ADDR;
+ return (Inet4Address) InetAddress.getByAddress(ipv4Addr);
+ } catch (UnknownHostException e) {
+ mLog.e("Failed to construct Inet4Address from raw IPv4 addr");
+ return null;
}
}
+ private String getRandomWifiIPv4Address() {
+ final Inet4Address ipv4Addr =
+ getRandomIPv4Address(parseNumericAddress(WIFI_HOST_IFACE_ADDR).getAddress());
+ return ipv4Addr != null ? ipv4Addr.getHostAddress() : WIFI_HOST_IFACE_ADDR;
+ }
+
private boolean startIPv6() {
mInterfaceParams = mDeps.getInterfaceParams(mIfaceName);
if (mInterfaceParams == null) {
@@ -715,12 +753,12 @@ public class IpServer extends StateMachine {
final String upstreamIface = v6only.getInterfaceName();
params = new RaParams();
- // We advertise an mtu lower by 16, which is the closest multiple of 8 >= 14,
- // the ethernet header size. This makes kernel ebpf tethering offload happy.
- // This hack should be reverted once we have the kernel fixed up.
+ // When BPF offload is enabled, we advertise an mtu lower by 16, which is the closest
+ // multiple of 8 >= 14, the ethernet header size. This makes kernel ebpf tethering
+ // offload happy. This hack should be reverted once we have the kernel fixed up.
// Note: this will automatically clamp to at least 1280 (ipv6 minimum mtu)
// see RouterAdvertisementDaemon.java putMtu()
- params.mtu = v6only.getMtu() - 16;
+ params.mtu = mUsingBpfOffload ? v6only.getMtu() - 16 : v6only.getMtu();
params.hasDefaultRoute = v6only.hasIpv6DefaultRoute();
if (params.hasDefaultRoute) params.hopLimit = getHopLimit(upstreamIface);
@@ -751,21 +789,43 @@ public class IpServer extends StateMachine {
mLastIPv6UpstreamIfindex = upstreamIfindex;
}
+ private void removeRoutesFromLocalNetwork(@NonNull final List<RouteInfo> toBeRemoved) {
+ final int removalFailures = RouteUtils.removeRoutesFromLocalNetwork(
+ mNetd, toBeRemoved);
+ if (removalFailures > 0) {
+ mLog.e(String.format("Failed to remove %d IPv6 routes from local table.",
+ removalFailures));
+ }
+
+ for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route);
+ }
+
+ private void addRoutesToLocalNetwork(@NonNull final List<RouteInfo> toBeAdded) {
+ try {
+ // It's safe to call networkAddInterface() even if
+ // the interface is already in the local_network.
+ mNetd.networkAddInterface(INetd.LOCAL_NET_ID, mIfaceName);
+ try {
+ // Add routes from local network. Note that adding routes that
+ // already exist does not cause an error (EEXIST is silently ignored).
+ RouteUtils.addRoutesToLocalNetwork(mNetd, mIfaceName, toBeAdded);
+ } catch (IllegalStateException e) {
+ mLog.e("Failed to add IPv4/v6 routes to local table: " + e);
+ return;
+ }
+ } catch (ServiceSpecificException | RemoteException e) {
+ mLog.e("Failed to add " + mIfaceName + " to local table: ", e);
+ return;
+ }
+
+ for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route);
+ }
+
private void configureLocalIPv6Routes(
HashSet<IpPrefix> deprecatedPrefixes, HashSet<IpPrefix> newPrefixes) {
// [1] Remove the routes that are deprecated.
if (!deprecatedPrefixes.isEmpty()) {
- final ArrayList<RouteInfo> toBeRemoved =
- getLocalRoutesFor(mIfaceName, deprecatedPrefixes);
- // Remove routes from local network.
- final int removalFailures = RouteUtils.removeRoutesFromLocalNetwork(
- mNetd, toBeRemoved);
- if (removalFailures > 0) {
- mLog.e(String.format("Failed to remove %d IPv6 routes from local table.",
- removalFailures));
- }
-
- for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route);
+ removeRoutesFromLocalNetwork(getLocalRoutesFor(mIfaceName, deprecatedPrefixes));
}
// [2] Add only the routes that have not previously been added.
@@ -776,24 +836,7 @@ public class IpServer extends StateMachine {
}
if (!addedPrefixes.isEmpty()) {
- final ArrayList<RouteInfo> toBeAdded =
- getLocalRoutesFor(mIfaceName, addedPrefixes);
- try {
- // It's safe to call networkAddInterface() even if
- // the interface is already in the local_network.
- mNetd.networkAddInterface(INetd.LOCAL_NET_ID, mIfaceName);
- try {
- // Add routes from local network. Note that adding routes that
- // already exist does not cause an error (EEXIST is silently ignored).
- RouteUtils.addRoutesToLocalNetwork(mNetd, mIfaceName, toBeAdded);
- } catch (IllegalStateException e) {
- mLog.e("Failed to add IPv6 routes to local table: " + e);
- }
- } catch (ServiceSpecificException | RemoteException e) {
- mLog.e("Failed to add " + mIfaceName + " to local table: ", e);
- }
-
- for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route);
+ addRoutesToLocalNetwork(getLocalRoutesFor(mIfaceName, addedPrefixes));
}
}
}
@@ -844,6 +887,11 @@ public class IpServer extends StateMachine {
}
private void addIpv6ForwardingRule(Ipv6ForwardingRule rule) {
+ // Theoretically, we don't need this check because IP neighbor monitor doesn't start if BPF
+ // offload is disabled. Add this check just in case.
+ // TODO: Perhaps remove this protection check.
+ if (!mUsingBpfOffload) return;
+
try {
mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel());
mIpv6ForwardingRules.put(rule.address, rule);
@@ -853,6 +901,11 @@ public class IpServer extends StateMachine {
}
private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule, boolean removeFromMap) {
+ // Theoretically, we don't need this check because IP neighbor monitor doesn't start if BPF
+ // offload is disabled. Add this check just in case.
+ // TODO: Perhaps remove this protection check.
+ if (!mUsingBpfOffload) return;
+
try {
mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel());
if (removeFromMap) {
@@ -925,6 +978,80 @@ public class IpServer extends StateMachine {
}
}
+ // TODO: call PrivateAddressCoordinator.requestDownstreamAddress instead of this temporary
+ // logic.
+ private Inet4Address requestDownstreamAddress(@NonNull final IpPrefix currentPrefix) {
+ final int oldIndex = NCM_PREFIXES.indexOf(currentPrefix);
+ if (oldIndex == -1) {
+ mLog.e("current prefix isn't supported for NCM link: " + currentPrefix);
+ return null;
+ }
+
+ final IpPrefix newPrefix = NCM_PREFIXES.get((oldIndex + 1) % NCM_PREFIXES.size());
+ return getRandomIPv4Address(newPrefix.getRawAddress());
+ }
+
+ private void handleNewPrefixRequest(@NonNull final IpPrefix currentPrefix) {
+ if (!currentPrefix.contains(mIpv4Address.getAddress())
+ || currentPrefix.getPrefixLength() != mIpv4Address.getPrefixLength()) {
+ Log.e(TAG, "Invalid prefix: " + currentPrefix);
+ return;
+ }
+
+ final LinkAddress deprecatedLinkAddress = mIpv4Address;
+ final Inet4Address srvAddr = requestDownstreamAddress(currentPrefix);
+ if (srvAddr == null) {
+ mLog.e("Fail to request a new downstream prefix");
+ return;
+ }
+ mIpv4Address = new LinkAddress(srvAddr, currentPrefix.getPrefixLength());
+
+ // Add new IPv4 address on the interface.
+ if (!mInterfaceCtrl.addAddress(srvAddr, currentPrefix.getPrefixLength())) {
+ mLog.e("Failed to add new IP " + srvAddr);
+ return;
+ }
+
+ // Remove deprecated routes from local network.
+ removeRoutesFromLocalNetwork(
+ Collections.singletonList(getDirectConnectedRoute(deprecatedLinkAddress)));
+ mLinkProperties.removeLinkAddress(deprecatedLinkAddress);
+
+ // Add new routes to local network.
+ addRoutesToLocalNetwork(
+ Collections.singletonList(getDirectConnectedRoute(mIpv4Address)));
+ mLinkProperties.addLinkAddress(mIpv4Address);
+
+ // Update local DNS caching server with new IPv4 address, otherwise, dnsmasq doesn't
+ // listen on the interface configured with new IPv4 address, that results DNS validation
+ // failure of downstream client even if appropriate routes have been configured.
+ try {
+ mNetd.tetherApplyDnsInterfaces();
+ } catch (ServiceSpecificException | RemoteException e) {
+ mLog.e("Failed to update local DNS caching server");
+ return;
+ }
+ sendLinkProperties();
+
+ // Notify DHCP server that new prefix/route has been applied on IpServer.
+ final Inet4Address clientAddr = mStaticIpv4ClientAddr == null ? null :
+ (Inet4Address) mStaticIpv4ClientAddr.getAddress();
+ final DhcpServingParamsParcel params = makeServingParams(srvAddr /* defaultRouter */,
+ srvAddr /* dnsServer */, mIpv4Address /* serverLinkAddress */, clientAddr);
+ try {
+ mDhcpServer.updateParams(params, new OnHandlerStatusCallback() {
+ @Override
+ public void callback(int statusCode) {
+ if (statusCode != STATUS_SUCCESS) {
+ mLog.e("Error updating DHCP serving params: " + statusCode);
+ }
+ }
+ });
+ } catch (RemoteException e) {
+ mLog.e("Error updating DHCP serving params", e);
+ }
+ }
+
private byte getHopLimit(String upstreamIface) {
try {
int upstreamHopLimit = Integer.parseUnsignedInt(
@@ -1036,11 +1163,9 @@ public class IpServer extends StateMachine {
}
try {
- final IpPrefix ipv4Prefix = new IpPrefix(mIpv4Address.getAddress(),
- mIpv4Address.getPrefixLength());
- NetdUtils.tetherInterface(mNetd, mIfaceName, ipv4Prefix);
+ NetdUtils.tetherInterface(mNetd, mIfaceName, PrefixUtils.asIpPrefix(mIpv4Address));
} catch (RemoteException | ServiceSpecificException | IllegalStateException e) {
- mLog.e("Error Tethering: " + e);
+ mLog.e("Error Tethering", e);
mLastError = TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR;
return;
}
@@ -1095,6 +1220,9 @@ public class IpServer extends StateMachine {
mLastError = TetheringManager.TETHER_ERROR_INTERNAL_ERROR;
transitionTo(mInitialState);
break;
+ case CMD_NEW_PREFIX_REQUEST:
+ handleNewPrefixRequest((IpPrefix) message.obj);
+ break;
default:
return false;
}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
index 293f8eae32d5..fe92204c25c8 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
@@ -66,6 +66,7 @@ public class OffloadHardwareInterface {
private final Handler mHandler;
private final SharedLog mLog;
+ private final Dependencies mDeps;
private IOffloadControl mOffloadControl;
private TetheringOffloadCallback mTetheringOffloadCallback;
private ControlCallback mControlCallback;
@@ -126,8 +127,76 @@ public class OffloadHardwareInterface {
}
public OffloadHardwareInterface(Handler h, SharedLog log) {
+ this(h, log, new Dependencies(log));
+ }
+
+ OffloadHardwareInterface(Handler h, SharedLog log, Dependencies deps) {
mHandler = h;
mLog = log.forSubComponent(TAG);
+ mDeps = deps;
+ }
+
+ /** Capture OffloadHardwareInterface dependencies, for injection. */
+ static class Dependencies {
+ private final SharedLog mLog;
+
+ Dependencies(SharedLog log) {
+ mLog = log;
+ }
+
+ public IOffloadConfig getOffloadConfig() {
+ try {
+ return IOffloadConfig.getService(true /*retry*/);
+ } catch (RemoteException | NoSuchElementException e) {
+ mLog.e("getIOffloadConfig error " + e);
+ return null;
+ }
+ }
+
+ public IOffloadControl getOffloadControl() {
+ try {
+ return IOffloadControl.getService(true /*retry*/);
+ } catch (RemoteException | NoSuchElementException e) {
+ mLog.e("tethering offload control not supported: " + e);
+ return null;
+ }
+ }
+
+ public NativeHandle createConntrackSocket(final int groups) {
+ final FileDescriptor fd;
+ try {
+ fd = NetlinkSocket.forProto(OsConstants.NETLINK_NETFILTER);
+ } catch (ErrnoException e) {
+ mLog.e("Unable to create conntrack socket " + e);
+ return null;
+ }
+
+ final SocketAddress sockAddr = SocketUtils.makeNetlinkSocketAddress(0, groups);
+ try {
+ Os.bind(fd, sockAddr);
+ } catch (ErrnoException | SocketException e) {
+ mLog.e("Unable to bind conntrack socket for groups " + groups + " error: " + e);
+ try {
+ SocketUtils.closeSocket(fd);
+ } catch (IOException ie) {
+ // Nothing we can do here
+ }
+ return null;
+ }
+ try {
+ Os.connect(fd, sockAddr);
+ } catch (ErrnoException | SocketException e) {
+ mLog.e("connect to kernel fail for groups " + groups + " error: " + e);
+ try {
+ SocketUtils.closeSocket(fd);
+ } catch (IOException ie) {
+ // Nothing we can do here
+ }
+ return null;
+ }
+
+ return new NativeHandle(fd, true);
+ }
}
/** Get default value indicating whether offload is supported. */
@@ -141,13 +210,7 @@ public class OffloadHardwareInterface {
* share them with offload management process.
*/
public boolean initOffloadConfig() {
- IOffloadConfig offloadConfig;
- try {
- offloadConfig = IOffloadConfig.getService(true /*retry*/);
- } catch (RemoteException | NoSuchElementException e) {
- mLog.e("getIOffloadConfig error " + e);
- return false;
- }
+ final IOffloadConfig offloadConfig = mDeps.getOffloadConfig();
if (offloadConfig == null) {
mLog.e("Could not find IOffloadConfig service");
return false;
@@ -159,11 +222,11 @@ public class OffloadHardwareInterface {
//
// h2 provides a file descriptor bound to the following netlink groups
// (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY).
- final NativeHandle h1 = createConntrackSocket(
+ final NativeHandle h1 = mDeps.createConntrackSocket(
NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
if (h1 == null) return false;
- final NativeHandle h2 = createConntrackSocket(
+ final NativeHandle h2 = mDeps.createConntrackSocket(
NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY);
if (h2 == null) {
closeFdInNativeHandle(h1);
@@ -198,53 +261,12 @@ public class OffloadHardwareInterface {
}
}
- private NativeHandle createConntrackSocket(final int groups) {
- FileDescriptor fd;
- try {
- fd = NetlinkSocket.forProto(OsConstants.NETLINK_NETFILTER);
- } catch (ErrnoException e) {
- mLog.e("Unable to create conntrack socket " + e);
- return null;
- }
-
- final SocketAddress sockAddr = SocketUtils.makeNetlinkSocketAddress(0, groups);
- try {
- Os.bind(fd, sockAddr);
- } catch (ErrnoException | SocketException e) {
- mLog.e("Unable to bind conntrack socket for groups " + groups + " error: " + e);
- try {
- SocketUtils.closeSocket(fd);
- } catch (IOException ie) {
- // Nothing we can do here
- }
- return null;
- }
- try {
- Os.connect(fd, sockAddr);
- } catch (ErrnoException | SocketException e) {
- mLog.e("connect to kernel fail for groups " + groups + " error: " + e);
- try {
- SocketUtils.closeSocket(fd);
- } catch (IOException ie) {
- // Nothing we can do here
- }
- return null;
- }
-
- return new NativeHandle(fd, true);
- }
-
/** Initialize the tethering offload HAL. */
public boolean initOffloadControl(ControlCallback controlCb) {
mControlCallback = controlCb;
if (mOffloadControl == null) {
- try {
- mOffloadControl = IOffloadControl.getService(true /*retry*/);
- } catch (RemoteException | NoSuchElementException e) {
- mLog.e("tethering offload control not supported: " + e);
- return false;
- }
+ mOffloadControl = mDeps.getOffloadControl();
if (mOffloadControl == null) {
mLog.e("tethering IOffloadControl.getService() returned null");
return false;
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
index d1440a7c7be9..3ce3b4506c3f 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -109,8 +109,10 @@ import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceSpecificException;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -228,6 +230,7 @@ public class Tethering {
private final ConnectedClientsTracker mConnectedClientsTracker;
private final TetheringThreadExecutor mExecutor;
private final TetheringNotificationUpdater mNotificationUpdater;
+ private final UserManager mUserManager;
private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
// All the usage of mTetheringEventCallback should run in the same thread.
private ITetheringEventCallback mTetheringEventCallback = null;
@@ -305,23 +308,24 @@ public class Tethering {
mStateReceiver = new StateReceiver();
- final UserManager userManager = (UserManager) mContext.getSystemService(
- Context.USER_SERVICE);
+ mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
mTetheringRestriction = new UserRestrictionActionListener(
- userManager, this, mNotificationUpdater);
+ mUserManager, this, mNotificationUpdater);
mExecutor = new TetheringThreadExecutor(mHandler);
mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
mNetdCallback = new NetdCallback();
// Load tethering configuration.
updateConfiguration();
+
+ startStateMachineUpdaters();
}
/**
* Start to register callbacks.
* Call this function when tethering is ready to handle callback events.
*/
- public void startStateMachineUpdaters() {
+ private void startStateMachineUpdaters() {
try {
mNetd.registerUnsolicitedEventListener(mNetdCallback);
} catch (RemoteException e) {
@@ -779,7 +783,7 @@ public class Tethering {
// TODO: Figure out how to update for local hotspot mode interfaces.
private void sendTetherStateChangedBroadcast() {
- if (!mDeps.isTetheringSupported()) return;
+ if (!isTetheringSupported()) return;
final ArrayList<String> availableList = new ArrayList<>();
final ArrayList<String> tetherList = new ArrayList<>();
@@ -1020,14 +1024,14 @@ public class Tethering {
@VisibleForTesting
protected static class UserRestrictionActionListener {
- private final UserManager mUserManager;
+ private final UserManager mUserMgr;
private final Tethering mWrapper;
private final TetheringNotificationUpdater mNotificationUpdater;
public boolean mDisallowTethering;
public UserRestrictionActionListener(@NonNull UserManager um, @NonNull Tethering wrapper,
@NonNull TetheringNotificationUpdater updater) {
- mUserManager = um;
+ mUserMgr = um;
mWrapper = wrapper;
mNotificationUpdater = updater;
mDisallowTethering = false;
@@ -1037,7 +1041,7 @@ public class Tethering {
// getUserRestrictions gets restriction for this process' user, which is the primary
// user. This is fine because DISALLOW_CONFIG_TETHERING can only be set on the primary
// user. See UserManager.DISALLOW_CONFIG_TETHERING.
- final Bundle restrictions = mUserManager.getUserRestrictions();
+ final Bundle restrictions = mUserMgr.getUserRestrictions();
final boolean newlyDisallowed =
restrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING);
final boolean prevDisallowed = mDisallowTethering;
@@ -1988,7 +1992,7 @@ public class Tethering {
mHandler.post(() -> {
mTetheringEventCallbacks.register(callback, new CallbackCookie(hasListPermission));
final TetheringCallbackStartedParcel parcel = new TetheringCallbackStartedParcel();
- parcel.tetheringSupported = mDeps.isTetheringSupported();
+ parcel.tetheringSupported = isTetheringSupported();
parcel.upstreamNetwork = mTetherUpstream;
parcel.config = mConfig.toStableParcelable();
parcel.states =
@@ -2111,6 +2115,20 @@ public class Tethering {
}
}
+ // if ro.tether.denied = true we default to no tethering
+ // gservices could set the secure setting to 1 though to enable it on a build where it
+ // had previously been turned off.
+ boolean isTetheringSupported() {
+ final int defaultVal =
+ SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1;
+ final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.TETHER_SUPPORTED, defaultVal) != 0;
+ final boolean tetherEnabledInSettings = tetherSupported
+ && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
+
+ return tetherEnabledInSettings && hasTetherableConfiguration();
+ }
+
void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) {
// Binder.java closes the resource for us.
@SuppressWarnings("resource")
@@ -2296,7 +2314,7 @@ public class Tethering {
final TetherState tetherState = new TetherState(
new IpServer(iface, mLooper, interfaceType, mLog, mNetd,
makeControlCallback(), mConfig.enableLegacyDhcpServer,
- mDeps.getIpServerDependencies()));
+ mConfig.enableBpfOffload, mDeps.getIpServerDependencies()));
mTetherStates.put(iface, tetherState);
tetherState.ipServer.start();
}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
index 9d4e74732729..48a600dfe6e1 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
@@ -73,6 +73,12 @@ public class TetheringConfiguration {
private static final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"};
/**
+ * Override enabling BPF offload configuration for tethering.
+ */
+ public static final String OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD =
+ "override_tether_enable_bpf_offload";
+
+ /**
* Use the old dnsmasq DHCP server for tethering instead of the framework implementation.
*/
public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER =
@@ -95,6 +101,8 @@ public class TetheringConfiguration {
public final String[] legacyDhcpRanges;
public final String[] defaultIPv4DNS;
public final boolean enableLegacyDhcpServer;
+ // TODO: Add to TetheringConfigurationParcel if required.
+ public final boolean enableBpfOffload;
public final String[] provisioningApp;
public final String provisioningAppNoUi;
@@ -124,11 +132,12 @@ public class TetheringConfiguration {
isDunRequired = checkDunRequired(ctx);
chooseUpstreamAutomatically = getResourceBoolean(
- res, R.bool.config_tether_upstream_automatic);
+ res, R.bool.config_tether_upstream_automatic, false /** defaultValue */);
preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired);
legacyDhcpRanges = getLegacyDhcpRanges(res);
defaultIPv4DNS = copy(DEFAULT_IPV4_DNS);
+ enableBpfOffload = getEnableBpfOffload(res);
enableLegacyDhcpServer = getEnableLegacyDhcpServer(res);
provisioningApp = getResourceStringArray(res, R.array.config_mobile_hotspot_provision_app);
@@ -208,6 +217,9 @@ public class TetheringConfiguration {
pw.print("provisioningAppNoUi: ");
pw.println(provisioningAppNoUi);
+ pw.print("enableBpfOffload: ");
+ pw.println(enableBpfOffload);
+
pw.print("enableLegacyDhcpServer: ");
pw.println(enableLegacyDhcpServer);
}
@@ -228,6 +240,7 @@ public class TetheringConfiguration {
toIntArray(preferredUpstreamIfaceTypes)));
sj.add(String.format("provisioningApp:%s", makeString(provisioningApp)));
sj.add(String.format("provisioningAppNoUi:%s", provisioningAppNoUi));
+ sj.add(String.format("enableBpfOffload:%s", enableBpfOffload));
sj.add(String.format("enableLegacyDhcpServer:%s", enableLegacyDhcpServer));
return String.format("TetheringConfiguration{%s}", sj.toString());
}
@@ -332,11 +345,11 @@ public class TetheringConfiguration {
}
}
- private static boolean getResourceBoolean(Resources res, int resId) {
+ private static boolean getResourceBoolean(Resources res, int resId, boolean defaultValue) {
try {
return res.getBoolean(resId);
} catch (Resources.NotFoundException e404) {
- return false;
+ return defaultValue;
}
}
@@ -357,14 +370,36 @@ public class TetheringConfiguration {
}
}
+ private boolean getEnableBpfOffload(final Resources res) {
+ // Get BPF offload config
+ // Priority 1: Device config
+ // Priority 2: Resource config
+ // Priority 3: Default value
+ final boolean defaultValue = getResourceBoolean(
+ res, R.bool.config_tether_enable_bpf_offload, true /** default value */);
+
+ return getDeviceConfigBoolean(OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD, defaultValue);
+ }
+
private boolean getEnableLegacyDhcpServer(final Resources res) {
- return getResourceBoolean(res, R.bool.config_tether_enable_legacy_dhcp_server)
- || getDeviceConfigBoolean(TETHER_ENABLE_LEGACY_DHCP_SERVER);
+ return getResourceBoolean(
+ res, R.bool.config_tether_enable_legacy_dhcp_server, false /** defaultValue */)
+ || getDeviceConfigBoolean(
+ TETHER_ENABLE_LEGACY_DHCP_SERVER, false /** defaultValue */);
+ }
+
+ private boolean getDeviceConfigBoolean(final String name, final boolean defaultValue) {
+ // Due to the limitation of static mock for testing, using #getDeviceConfigProperty instead
+ // of DeviceConfig#getBoolean. If using #getBoolean here, the test can't know that the
+ // returned boolean value comes from device config or default value (because of null
+ // property string). See the test case testBpfOffload{*} in TetheringConfigurationTest.java.
+ final String value = getDeviceConfigProperty(name);
+ return value != null ? Boolean.parseBoolean(value) : defaultValue;
}
@VisibleForTesting
- protected boolean getDeviceConfigBoolean(final String name) {
- return DeviceConfig.getBoolean(NAMESPACE_CONNECTIVITY, name, false /** defaultValue */);
+ protected String getDeviceConfigProperty(String name) {
+ return DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, name);
}
private Resources getResources(Context ctx, int subId) {
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
index af349f2b92a2..7d012738425b 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
@@ -40,15 +40,12 @@ import android.net.TetheringRequestParcel;
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.ip.IpServer;
-import android.net.util.SharedLog;
import android.os.Binder;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ResultReceiver;
-import android.os.SystemProperties;
-import android.os.UserManager;
import android.provider.Settings;
import android.util.Log;
@@ -68,21 +65,14 @@ import java.io.PrintWriter;
public class TetheringService extends Service {
private static final String TAG = TetheringService.class.getSimpleName();
- private final SharedLog mLog = new SharedLog(TAG);
private TetheringConnector mConnector;
- private Context mContext;
- private TetheringDependencies mDeps;
- private Tethering mTethering;
- private UserManager mUserManager;
@Override
public void onCreate() {
- mLog.mark("onCreate");
- mDeps = getTetheringDependencies();
- mContext = mDeps.getContext();
- mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- mTethering = makeTethering(mDeps);
- mTethering.startStateMachineUpdaters();
+ final TetheringDependencies deps = makeTetheringDependencies();
+ // The Tethering object needs a fully functional context to start, so this can't be done
+ // in the constructor.
+ mConnector = new TetheringConnector(makeTethering(deps), TetheringService.this);
}
/**
@@ -94,21 +84,10 @@ public class TetheringService extends Service {
return new Tethering(deps);
}
- /**
- * Create a binder connector for the system server to communicate with the tethering.
- */
- private synchronized IBinder makeConnector() {
- if (mConnector == null) {
- mConnector = new TetheringConnector(mTethering, TetheringService.this);
- }
- return mConnector;
- }
-
@NonNull
@Override
public IBinder onBind(Intent intent) {
- mLog.mark("onBind");
- return makeConnector();
+ return mConnector;
}
private static class TetheringConnector extends ITetheringConnector.Stub {
@@ -248,7 +227,7 @@ public class TetheringService extends Service {
listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
return true;
}
- if (!mService.isTetheringSupported()) {
+ if (!mTethering.isTetheringSupported()) {
listener.onResult(TETHER_ERROR_UNSUPPORTED);
return true;
}
@@ -266,7 +245,7 @@ public class TetheringService extends Service {
receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null);
return true;
}
- if (!mService.isTetheringSupported()) {
+ if (!mTethering.isTetheringSupported()) {
receiver.send(TETHER_ERROR_UNSUPPORTED, null);
return true;
}
@@ -300,20 +279,6 @@ public class TetheringService extends Service {
}
}
- // if ro.tether.denied = true we default to no tethering
- // gservices could set the secure setting to 1 though to enable it on a build where it
- // had previously been turned off.
- private boolean isTetheringSupported() {
- final int defaultVal =
- SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1;
- final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.TETHER_SUPPORTED, defaultVal) != 0;
- final boolean tetherEnabledInSettings = tetherSupported
- && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
-
- return tetherEnabledInSettings && mTethering.hasTetherableConfiguration();
- }
-
/**
* Check if the package is a allowed to write settings. This also accounts that such an access
* happened.
@@ -332,87 +297,79 @@ public class TetheringService extends Service {
* An injection method for testing.
*/
@VisibleForTesting
- public TetheringDependencies getTetheringDependencies() {
- if (mDeps == null) {
- mDeps = new TetheringDependencies() {
- @Override
- public NetworkRequest getDefaultNetworkRequest() {
- // TODO: b/147280869, add a proper system API to replace this.
- final NetworkRequest trackDefaultRequest = new NetworkRequest.Builder()
- .clearCapabilities()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- .build();
- return trackDefaultRequest;
- }
-
- @Override
- public Looper getTetheringLooper() {
- final HandlerThread tetherThread = new HandlerThread("android.tethering");
- tetherThread.start();
- return tetherThread.getLooper();
- }
+ public TetheringDependencies makeTetheringDependencies() {
+ return new TetheringDependencies() {
+ @Override
+ public NetworkRequest getDefaultNetworkRequest() {
+ // TODO: b/147280869, add a proper system API to replace this.
+ final NetworkRequest trackDefaultRequest = new NetworkRequest.Builder()
+ .clearCapabilities()
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
+ return trackDefaultRequest;
+ }
- @Override
- public boolean isTetheringSupported() {
- return TetheringService.this.isTetheringSupported();
- }
+ @Override
+ public Looper getTetheringLooper() {
+ final HandlerThread tetherThread = new HandlerThread("android.tethering");
+ tetherThread.start();
+ return tetherThread.getLooper();
+ }
- @Override
- public Context getContext() {
- return TetheringService.this;
- }
+ @Override
+ public Context getContext() {
+ return TetheringService.this;
+ }
- @Override
- public IpServer.Dependencies getIpServerDependencies() {
- return new IpServer.Dependencies() {
- @Override
- public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
- DhcpServerCallbacks cb) {
+ @Override
+ public IpServer.Dependencies getIpServerDependencies() {
+ return new IpServer.Dependencies() {
+ @Override
+ public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
+ DhcpServerCallbacks cb) {
+ try {
+ final INetworkStackConnector service = getNetworkStackConnector();
+ if (service == null) return;
+
+ service.makeDhcpServer(ifName, params, cb);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Fail to make dhcp server");
try {
- final INetworkStackConnector service = getNetworkStackConnector();
- if (service == null) return;
-
- service.makeDhcpServer(ifName, params, cb);
- } catch (RemoteException e) {
- Log.e(TAG, "Fail to make dhcp server");
- try {
- cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null);
- } catch (RemoteException re) { }
- }
+ cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null);
+ } catch (RemoteException re) { }
}
- };
- }
+ }
+ };
+ }
- // TODO: replace this by NetworkStackClient#getRemoteConnector after refactoring
- // networkStackClient.
- static final int NETWORKSTACK_TIMEOUT_MS = 60_000;
- private INetworkStackConnector getNetworkStackConnector() {
- IBinder connector;
- try {
- final long before = System.currentTimeMillis();
- while ((connector = NetworkStack.getService()) == null) {
- if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
- Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector");
- return null;
- }
- Thread.sleep(200);
+ // TODO: replace this by NetworkStackClient#getRemoteConnector after refactoring
+ // networkStackClient.
+ static final int NETWORKSTACK_TIMEOUT_MS = 60_000;
+ private INetworkStackConnector getNetworkStackConnector() {
+ IBinder connector;
+ try {
+ final long before = System.currentTimeMillis();
+ while ((connector = NetworkStack.getService()) == null) {
+ if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
+ Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector");
+ return null;
}
- } catch (InterruptedException e) {
- Log.wtf(TAG, "Interrupted, fail to get INetworkStackConnector");
- return null;
+ Thread.sleep(200);
}
- return INetworkStackConnector.Stub.asInterface(connector);
+ } catch (InterruptedException e) {
+ Log.wtf(TAG, "Interrupted, fail to get INetworkStackConnector");
+ return null;
}
+ return INetworkStackConnector.Stub.asInterface(connector);
+ }
- @Override
- public BluetoothAdapter getBluetoothAdapter() {
- return BluetoothAdapter.getDefaultAdapter();
- }
- };
- }
- return mDeps;
+ @Override
+ public BluetoothAdapter getBluetoothAdapter() {
+ return BluetoothAdapter.getDefaultAdapter();
+ }
+ };
}
}
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index f9be7b9d3664..cd1ff607b475 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -18,6 +18,7 @@ package android.net.ip;
import static android.net.INetd.IF_STATE_UP;
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
+import static android.net.TetheringManager.TETHERING_NCM;
import static android.net.TetheringManager.TETHERING_USB;
import static android.net.TetheringManager.TETHERING_WIFI;
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
@@ -38,6 +39,7 @@ import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -67,6 +69,7 @@ import android.net.MacAddress;
import android.net.RouteInfo;
import android.net.TetherOffloadRuleParcel;
import android.net.dhcp.DhcpServingParamsParcel;
+import android.net.dhcp.IDhcpEventCallbacks;
import android.net.dhcp.IDhcpServer;
import android.net.dhcp.IDhcpServerCallbacks;
import android.net.ip.IpNeighborMonitor.NeighborEvent;
@@ -94,6 +97,7 @@ import org.mockito.MockitoAnnotations;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.Arrays;
+import java.util.List;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -106,6 +110,7 @@ public class IpServerTest {
private static final String BLUETOOTH_IFACE_ADDR = "192.168.42.1";
private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24;
private static final int DHCP_LEASE_TIME_SECS = 3600;
+ private static final boolean DEFAULT_USING_BPF_OFFLOAD = true;
private static final InterfaceParams TEST_IFACE_PARAMS = new InterfaceParams(
IFACE_NAME, 42 /* index */, MacAddress.ALL_ZEROS_ADDRESS, 1500 /* defaultMtu */);
@@ -130,10 +135,11 @@ public class IpServerTest {
private NeighborEventConsumer mNeighborEventConsumer;
private void initStateMachine(int interfaceType) throws Exception {
- initStateMachine(interfaceType, false /* usingLegacyDhcp */);
+ initStateMachine(interfaceType, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD);
}
- private void initStateMachine(int interfaceType, boolean usingLegacyDhcp) throws Exception {
+ private void initStateMachine(int interfaceType, boolean usingLegacyDhcp,
+ boolean usingBpfOffload) throws Exception {
doAnswer(inv -> {
final IDhcpServerCallbacks cb = inv.getArgument(2);
new Thread(() -> {
@@ -165,7 +171,7 @@ public class IpServerTest {
mIpServer = new IpServer(
IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd,
- mCallback, usingLegacyDhcp, mDependencies);
+ mCallback, usingLegacyDhcp, usingBpfOffload, mDependencies);
mIpServer.start();
mNeighborEventConsumer = neighborCaptor.getValue();
@@ -179,12 +185,13 @@ public class IpServerTest {
private void initTetheredStateMachine(int interfaceType, String upstreamIface)
throws Exception {
- initTetheredStateMachine(interfaceType, upstreamIface, false);
+ initTetheredStateMachine(interfaceType, upstreamIface, false,
+ DEFAULT_USING_BPF_OFFLOAD);
}
private void initTetheredStateMachine(int interfaceType, String upstreamIface,
- boolean usingLegacyDhcp) throws Exception {
- initStateMachine(interfaceType, usingLegacyDhcp);
+ boolean usingLegacyDhcp, boolean usingBpfOffload) throws Exception {
+ initStateMachine(interfaceType, usingLegacyDhcp, usingBpfOffload);
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
if (upstreamIface != null) {
LinkProperties lp = new LinkProperties();
@@ -204,7 +211,8 @@ public class IpServerTest {
when(mDependencies.getIpNeighborMonitor(any(), any(), any()))
.thenReturn(mIpNeighborMonitor);
mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), TETHERING_BLUETOOTH, mSharedLog,
- mNetd, mCallback, false /* usingLegacyDhcp */, mDependencies);
+ mNetd, mCallback, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD,
+ mDependencies);
mIpServer.start();
mLooper.dispatchAll();
verify(mCallback).updateInterfaceState(
@@ -493,8 +501,62 @@ public class IpServerTest {
}
@Test
+ public void startsDhcpServerOnNcm() throws Exception {
+ initStateMachine(TETHERING_NCM);
+ dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY);
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE);
+
+ assertDhcpStarted(new IpPrefix("192.168.42.0/24"));
+ }
+
+ @Test
+ public void testOnNewPrefixRequest() throws Exception {
+ initStateMachine(TETHERING_NCM);
+ dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY);
+
+ final IDhcpEventCallbacks eventCallbacks;
+ final ArgumentCaptor<IDhcpEventCallbacks> dhcpEventCbsCaptor =
+ ArgumentCaptor.forClass(IDhcpEventCallbacks.class);
+ verify(mDhcpServer, timeout(MAKE_DHCPSERVER_TIMEOUT_MS).times(1)).startWithCallbacks(
+ any(), dhcpEventCbsCaptor.capture());
+ eventCallbacks = dhcpEventCbsCaptor.getValue();
+ assertDhcpStarted(new IpPrefix("192.168.42.0/24"));
+
+ // Simulate the DHCP server receives DHCPDECLINE on MirrorLink and then signals
+ // onNewPrefixRequest callback.
+ eventCallbacks.onNewPrefixRequest(new IpPrefix("192.168.42.0/24"));
+ mLooper.dispatchAll();
+
+ final ArgumentCaptor<LinkProperties> lpCaptor =
+ ArgumentCaptor.forClass(LinkProperties.class);
+ InOrder inOrder = inOrder(mNetd, mCallback);
+ inOrder.verify(mCallback).updateInterfaceState(
+ mIpServer, STATE_LOCAL_ONLY, TETHER_ERROR_NO_ERROR);
+ inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture());
+ inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
+ // One for ipv4 route, one for ipv6 link local route.
+ inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME),
+ any(), any());
+ inOrder.verify(mNetd).tetherApplyDnsInterfaces();
+ inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture());
+ verifyNoMoreInteractions(mCallback);
+
+ final LinkProperties linkProperties = lpCaptor.getValue();
+ final List<LinkAddress> linkAddresses = linkProperties.getLinkAddresses();
+ assertEquals(1, linkProperties.getLinkAddresses().size());
+ assertEquals(1, linkProperties.getRoutes().size());
+ final IpPrefix prefix = new IpPrefix(linkAddresses.get(0).getAddress(),
+ linkAddresses.get(0).getPrefixLength());
+ assertNotEquals(prefix, new IpPrefix("192.168.42.0/24"));
+
+ verify(mDhcpServer).updateParams(mDhcpParamsCaptor.capture(), any());
+ assertDhcpServingParams(mDhcpParamsCaptor.getValue(), prefix);
+ }
+
+ @Test
public void doesNotStartDhcpServerIfDisabled() throws Exception {
- initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */);
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, true /* usingLegacyDhcp */,
+ DEFAULT_USING_BPF_OFFLOAD);
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
verify(mDependencies, never()).makeDhcpServer(any(), any(), any());
@@ -577,7 +639,8 @@ public class IpServerTest {
@Test
public void addRemoveipv6ForwardingRules() throws Exception {
- initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */);
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
+ DEFAULT_USING_BPF_OFFLOAD);
final int myIfindex = TEST_IFACE_PARAMS.index;
final int notMyIfindex = myIfindex - 1;
@@ -678,19 +741,73 @@ public class IpServerTest {
reset(mNetd);
}
- private void assertDhcpStarted(IpPrefix expectedPrefix) throws Exception {
- verify(mDependencies, times(1)).makeDhcpServer(eq(IFACE_NAME), any(), any());
- verify(mDhcpServer, timeout(MAKE_DHCPSERVER_TIMEOUT_MS).times(1)).startWithCallbacks(
- any(), any());
- final DhcpServingParamsParcel params = mDhcpParamsCaptor.getValue();
+ @Test
+ public void enableDisableUsingBpfOffload() throws Exception {
+ final int myIfindex = TEST_IFACE_PARAMS.index;
+ final InetAddress neigh = InetAddresses.parseNumericAddress("2001:db8::1");
+ final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a");
+ final MacAddress macNull = MacAddress.fromString("00:00:00:00:00:00");
+
+ reset(mNetd);
+
+ // Expect that rules can be only added/removed when the BPF offload config is enabled.
+ // Note that the usingBpfOffload false case is not a realistic test case. Because IP
+ // neighbor monitor doesn't start if BPF offload is disabled, there should have no
+ // neighbor event listening. This is used for testing the protection check just in case.
+ // TODO: Perhaps remove this test once we don't need this check anymore.
+ for (boolean usingBpfOffload : new boolean[]{true, false}) {
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
+ usingBpfOffload);
+
+ // A neighbor is added.
+ recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA);
+ if (usingBpfOffload) {
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neigh, macA));
+ } else {
+ verify(mNetd, never()).tetherOffloadRuleAdd(any());
+ }
+ reset(mNetd);
+
+ // A neighbor is deleted.
+ recvDelNeigh(myIfindex, neigh, NUD_STALE, macA);
+ if (usingBpfOffload) {
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neigh, macNull));
+ } else {
+ verify(mNetd, never()).tetherOffloadRuleRemove(any());
+ }
+ reset(mNetd);
+ }
+ }
+
+ @Test
+ public void doesNotStartIpNeighborMonitorIfBpfOffloadDisabled() throws Exception {
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */,
+ false /* usingBpfOffload */);
+
+ // IP neighbor monitor doesn't start if BPF offload is disabled.
+ verify(mIpNeighborMonitor, never()).start();
+ }
+
+ private void assertDhcpServingParams(final DhcpServingParamsParcel params,
+ final IpPrefix prefix) {
// Last address byte is random
- assertTrue(expectedPrefix.contains(intToInet4AddressHTH(params.serverAddr)));
- assertEquals(expectedPrefix.getPrefixLength(), params.serverAddrPrefixLength);
+ assertTrue(prefix.contains(intToInet4AddressHTH(params.serverAddr)));
+ assertEquals(prefix.getPrefixLength(), params.serverAddrPrefixLength);
assertEquals(1, params.defaultRouters.length);
assertEquals(params.serverAddr, params.defaultRouters[0]);
assertEquals(1, params.dnsServers.length);
assertEquals(params.serverAddr, params.dnsServers[0]);
assertEquals(DHCP_LEASE_TIME_SECS, params.dhcpLeaseTimeSecs);
+ if (mIpServer.interfaceType() == TETHERING_NCM) {
+ assertTrue(params.changePrefixOnDecline);
+ }
+ }
+
+ private void assertDhcpStarted(IpPrefix expectedPrefix) throws Exception {
+ verify(mDependencies, times(1)).makeDhcpServer(eq(IFACE_NAME), any(), any());
+ verify(mDhcpServer, timeout(MAKE_DHCPSERVER_TIMEOUT_MS).times(1)).startWithCallbacks(
+ any(), any());
+ assertDhcpServingParams(mDhcpParamsCaptor.getValue(), expectedPrefix);
}
/**
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
index cdd0e243e31f..72fa916b9e42 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/EntitlementManagerTest.java
@@ -147,9 +147,8 @@ public final class EntitlementManagerTest {
doReturn(false).when(
() -> SystemProperties.getBoolean(
eq(EntitlementManager.DISABLE_PROVISIONING_SYSPROP_KEY), anyBoolean()));
- doReturn(false).when(
- () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY),
- eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean()));
+ doReturn(null).when(
+ () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY), anyString()));
when(mResources.getStringArray(R.array.config_tether_dhcp_range))
.thenReturn(new String[0]);
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
new file mode 100644
index 000000000000..f8ff1cb29c23
--- /dev/null
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/OffloadHardwareInterfaceTest.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.networkstack.tethering;
+
+import static android.net.util.TetheringUtils.uint16;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
+import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
+import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
+import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
+import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
+import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
+import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.NativeHandle;
+import android.os.test.TestLooper;
+import android.system.OsConstants;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class OffloadHardwareInterfaceTest {
+ private static final String RMNET0 = "test_rmnet_data0";
+
+ private final TestLooper mTestLooper = new TestLooper();
+
+ private OffloadHardwareInterface mOffloadHw;
+ private ITetheringOffloadCallback mTetheringOffloadCallback;
+ private OffloadHardwareInterface.ControlCallback mControlCallback;
+
+ @Mock private IOffloadConfig mIOffloadConfig;
+ @Mock private IOffloadControl mIOffloadControl;
+ @Mock private NativeHandle mNativeHandle;
+
+ class MyDependencies extends OffloadHardwareInterface.Dependencies {
+ MyDependencies(SharedLog log) {
+ super(log);
+ }
+
+ @Override
+ public IOffloadConfig getOffloadConfig() {
+ return mIOffloadConfig;
+ }
+
+ @Override
+ public IOffloadControl getOffloadControl() {
+ return mIOffloadControl;
+ }
+
+ @Override
+ public NativeHandle createConntrackSocket(final int groups) {
+ return mNativeHandle;
+ }
+ }
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ final SharedLog log = new SharedLog("test");
+ mOffloadHw = new OffloadHardwareInterface(new Handler(mTestLooper.getLooper()), log,
+ new MyDependencies(log));
+ mControlCallback = spy(new OffloadHardwareInterface.ControlCallback());
+ }
+
+ private void startOffloadHardwareInterface() throws Exception {
+ mOffloadHw.initOffloadConfig();
+ mOffloadHw.initOffloadControl(mControlCallback);
+ final ArgumentCaptor<ITetheringOffloadCallback> mOffloadCallbackCaptor =
+ ArgumentCaptor.forClass(ITetheringOffloadCallback.class);
+ verify(mIOffloadControl).initOffload(mOffloadCallbackCaptor.capture(), any());
+ mTetheringOffloadCallback = mOffloadCallbackCaptor.getValue();
+ }
+
+ @Test
+ public void testGetForwardedStats() throws Exception {
+ startOffloadHardwareInterface();
+ final OffloadHardwareInterface.ForwardedStats stats = mOffloadHw.getForwardedStats(RMNET0);
+ verify(mIOffloadControl).getForwardedStats(eq(RMNET0), any());
+ assertNotNull(stats);
+ }
+
+ @Test
+ public void testSetLocalPrefixes() throws Exception {
+ startOffloadHardwareInterface();
+ final ArrayList<String> localPrefixes = new ArrayList<>();
+ localPrefixes.add("127.0.0.0/8");
+ localPrefixes.add("fe80::/64");
+ mOffloadHw.setLocalPrefixes(localPrefixes);
+ verify(mIOffloadControl).setLocalPrefixes(eq(localPrefixes), any());
+ }
+
+ @Test
+ public void testSetDataLimit() throws Exception {
+ startOffloadHardwareInterface();
+ final long limit = 12345;
+ mOffloadHw.setDataLimit(RMNET0, limit);
+ verify(mIOffloadControl).setDataLimit(eq(RMNET0), eq(limit), any());
+ }
+
+ @Test
+ public void testSetUpstreamParameters() throws Exception {
+ startOffloadHardwareInterface();
+ final String v4addr = "192.168.10.1";
+ final String v4gateway = "192.168.10.255";
+ final ArrayList<String> v6gws = new ArrayList<>(0);
+ v6gws.add("2001:db8::1");
+ mOffloadHw.setUpstreamParameters(RMNET0, v4addr, v4gateway, v6gws);
+ verify(mIOffloadControl).setUpstreamParameters(eq(RMNET0), eq(v4addr), eq(v4gateway),
+ eq(v6gws), any());
+
+ final ArgumentCaptor<ArrayList<String>> mArrayListCaptor =
+ ArgumentCaptor.forClass(ArrayList.class);
+ mOffloadHw.setUpstreamParameters(null, null, null, null);
+ verify(mIOffloadControl).setUpstreamParameters(eq(""), eq(""), eq(""),
+ mArrayListCaptor.capture(), any());
+ assertEquals(mArrayListCaptor.getValue().size(), 0);
+ }
+
+ @Test
+ public void testUpdateDownstreamPrefix() throws Exception {
+ startOffloadHardwareInterface();
+ final String ifName = "wlan1";
+ final String prefix = "192.168.43.0/24";
+ mOffloadHw.addDownstreamPrefix(ifName, prefix);
+ verify(mIOffloadControl).addDownstream(eq(ifName), eq(prefix), any());
+
+ mOffloadHw.removeDownstreamPrefix(ifName, prefix);
+ verify(mIOffloadControl).removeDownstream(eq(ifName), eq(prefix), any());
+ }
+
+ @Test
+ public void testTetheringOffloadCallback() throws Exception {
+ startOffloadHardwareInterface();
+
+ mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STARTED);
+ mTestLooper.dispatchAll();
+ verify(mControlCallback).onStarted();
+
+ mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR);
+ mTestLooper.dispatchAll();
+ verify(mControlCallback).onStoppedError();
+
+ mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED);
+ mTestLooper.dispatchAll();
+ verify(mControlCallback).onStoppedUnsupported();
+
+ mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE);
+ mTestLooper.dispatchAll();
+ verify(mControlCallback).onSupportAvailable();
+
+ mTetheringOffloadCallback.onEvent(OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED);
+ mTestLooper.dispatchAll();
+ verify(mControlCallback).onStoppedLimitReached();
+
+ final NatTimeoutUpdate tcpParams = buildNatTimeoutUpdate(NetworkProtocol.TCP);
+ mTetheringOffloadCallback.updateTimeout(tcpParams);
+ mTestLooper.dispatchAll();
+ verify(mControlCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_TCP),
+ eq(tcpParams.src.addr),
+ eq(uint16(tcpParams.src.port)),
+ eq(tcpParams.dst.addr),
+ eq(uint16(tcpParams.dst.port)));
+
+ final NatTimeoutUpdate udpParams = buildNatTimeoutUpdate(NetworkProtocol.UDP);
+ mTetheringOffloadCallback.updateTimeout(udpParams);
+ mTestLooper.dispatchAll();
+ verify(mControlCallback).onNatTimeoutUpdate(eq(OsConstants.IPPROTO_UDP),
+ eq(udpParams.src.addr),
+ eq(uint16(udpParams.src.port)),
+ eq(udpParams.dst.addr),
+ eq(uint16(udpParams.dst.port)));
+ }
+
+ private NatTimeoutUpdate buildNatTimeoutUpdate(final int proto) {
+ final NatTimeoutUpdate params = new NatTimeoutUpdate();
+ params.proto = proto;
+ params.src.addr = "192.168.43.200";
+ params.src.port = 100;
+ params.dst.addr = "172.50.46.169";
+ params.dst.port = 150;
+ return params;
+ }
+}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
index e8ba5b8168d7..1999ad786ed4 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringConfigurationTest.java
@@ -30,7 +30,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSess
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;
@@ -109,9 +108,9 @@ public class TetheringConfigurationTest {
.mockStatic(DeviceConfig.class)
.strictness(Strictness.WARN)
.startMocking();
- doReturn(false).when(
- () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY),
- eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean()));
+ doReturn(null).when(
+ () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY),
+ eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER)));
when(mResources.getStringArray(R.array.config_tether_dhcp_range)).thenReturn(
new String[0]);
@@ -127,6 +126,8 @@ public class TetheringConfigurationTest {
.thenReturn(new String[0]);
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
false);
+ initializeBpfOffloadConfiguration(true, null /* unset */);
+
mHasTelephonyManager = true;
mMockContext = new MockContext(mContext);
mEnableLegacyDhcpServer = false;
@@ -278,13 +279,57 @@ public class TetheringConfigurationTest {
assertFalse(upstreamIterator.hasNext());
}
+ private void initializeBpfOffloadConfiguration(
+ final boolean fromRes, final String fromDevConfig) {
+ when(mResources.getBoolean(R.bool.config_tether_enable_bpf_offload)).thenReturn(fromRes);
+ doReturn(fromDevConfig).when(
+ () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY),
+ eq(TetheringConfiguration.OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD)));
+ }
+
+ @Test
+ public void testBpfOffloadEnabledByResource() {
+ initializeBpfOffloadConfiguration(true, null /* unset */);
+ final TetheringConfiguration enableByRes =
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertTrue(enableByRes.enableBpfOffload);
+ }
+
+ @Test
+ public void testBpfOffloadEnabledByDeviceConfigOverride() {
+ for (boolean res : new boolean[]{true, false}) {
+ initializeBpfOffloadConfiguration(res, "true");
+ final TetheringConfiguration enableByDevConOverride =
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertTrue(enableByDevConOverride.enableBpfOffload);
+ }
+ }
+
+ @Test
+ public void testBpfOffloadDisabledByResource() {
+ initializeBpfOffloadConfiguration(false, null /* unset */);
+ final TetheringConfiguration disableByRes =
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertFalse(disableByRes.enableBpfOffload);
+ }
+
+ @Test
+ public void testBpfOffloadDisabledByDeviceConfigOverride() {
+ for (boolean res : new boolean[]{true, false}) {
+ initializeBpfOffloadConfiguration(res, "false");
+ final TetheringConfiguration disableByDevConOverride =
+ new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
+ assertFalse(disableByDevConOverride.enableBpfOffload);
+ }
+ }
+
@Test
public void testNewDhcpServerDisabled() {
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
true);
- doReturn(false).when(
- () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY),
- eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean()));
+ doReturn("false").when(
+ () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY),
+ eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER)));
final TetheringConfiguration enableByRes =
new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
@@ -292,9 +337,9 @@ public class TetheringConfigurationTest {
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
false);
- doReturn(true).when(
- () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY),
- eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean()));
+ doReturn("true").when(
+ () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY),
+ eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER)));
final TetheringConfiguration enableByDevConfig =
new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
@@ -305,9 +350,9 @@ public class TetheringConfigurationTest {
public void testNewDhcpServerEnabled() {
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
false);
- doReturn(false).when(
- () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY),
- eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean()));
+ doReturn("false").when(
+ () -> DeviceConfig.getProperty(eq(NAMESPACE_CONNECTIVITY),
+ eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER)));
final TetheringConfiguration cfg =
new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
index 7df9fc685053..3dc6a1300de5 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
@@ -83,8 +83,7 @@ public final class TetheringServiceTest {
mTetheringConnector = mockConnector.getTetheringConnector();
final MockTetheringService service = mockConnector.getService();
mTethering = service.getTethering();
- verify(mTethering).startStateMachineUpdaters();
- when(mTethering.hasTetherableConfiguration()).thenReturn(true);
+ when(mTethering.isTetheringSupported()).thenReturn(true);
}
@After
@@ -97,7 +96,7 @@ public final class TetheringServiceTest {
when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR);
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).tether(TEST_IFACE_NAME);
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -109,7 +108,7 @@ public final class TetheringServiceTest {
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).untether(TEST_IFACE_NAME);
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -121,7 +120,7 @@ public final class TetheringServiceTest {
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG,
TEST_ATTRIBUTION_TAG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).setUsbTethering(true /* enable */);
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -133,7 +132,7 @@ public final class TetheringServiceTest {
final TetheringRequestParcel request = new TetheringRequestParcel();
request.tetheringType = TETHERING_WIFI;
mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).startTethering(eq(request), eq(result));
verifyNoMoreInteractions(mTethering);
}
@@ -143,7 +142,7 @@ public final class TetheringServiceTest {
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).stopTethering(TETHERING_WIFI);
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -154,7 +153,7 @@ public final class TetheringServiceTest {
final ResultReceiver result = new ResultReceiver(null);
mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result,
true /* showEntitlementUi */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).requestLatestTetheringEntitlementResult(eq(TETHERING_WIFI),
eq(result), eq(true) /* showEntitlementUi */);
verifyNoMoreInteractions(mTethering);
@@ -181,7 +180,7 @@ public final class TetheringServiceTest {
public void testStopAllTethering() throws Exception {
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verify(mTethering).untetherAll();
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
@@ -191,7 +190,7 @@ public final class TetheringServiceTest {
public void testIsTetheringSupported() throws Exception {
final TestTetheringResult result = new TestTetheringResult();
mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
- verify(mTethering).hasTetherableConfiguration();
+ verify(mTethering).isTetheringSupported();
verifyNoMoreInteractions(mTethering);
result.assertResult(TETHER_ERROR_NO_ERROR);
}
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 85c2f2b984ae..7734a3c61eaf 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -312,8 +312,8 @@ public class TetheringTest {
}
@Override
- protected boolean getDeviceConfigBoolean(final String name) {
- return false;
+ protected String getDeviceConfigProperty(final String name) {
+ return null;
}
@Override
@@ -485,18 +485,6 @@ public class TetheringTest {
MockitoAnnotations.initMocks(this);
when(mResources.getStringArray(R.array.config_tether_dhcp_range))
.thenReturn(new String[0]);
- when(mResources.getStringArray(R.array.config_tether_usb_regexs))
- .thenReturn(new String[] { "test_rndis\\d" });
- when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
- .thenReturn(new String[]{ "test_wlan\\d" });
- when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs))
- .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" });
- when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
- .thenReturn(new String[0]);
- when(mResources.getStringArray(R.array.config_tether_ncm_regexs))
- .thenReturn(new String[] { "test_ncm\\d" });
- when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]);
- when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(false);
when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn(
false);
when(mNetd.interfaceGetList())
@@ -515,6 +503,7 @@ public class TetheringTest {
mServiceContext = new TestContext(mContext);
mContentResolver = new MockContentResolver(mServiceContext);
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ setTetheringSupported(true /* supported */);
mIntents = new Vector<>();
mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -525,7 +514,6 @@ public class TetheringTest {
mServiceContext.registerReceiver(mBroadcastReceiver,
new IntentFilter(ACTION_TETHER_STATE_CHANGED));
mTethering = makeTethering();
- mTethering.startStateMachineUpdaters();
verify(mStatsManager, times(1)).registerNetworkStatsProvider(anyString(), any());
verify(mNetd).registerUnsolicitedEventListener(any());
final ArgumentCaptor<PhoneStateListener> phoneListenerCaptor =
@@ -536,6 +524,31 @@ public class TetheringTest {
mPhoneStateListener = phoneListenerCaptor.getValue();
}
+ private void setTetheringSupported(final boolean supported) {
+ Settings.Global.putInt(mContentResolver, Settings.Global.TETHER_SUPPORTED,
+ supported ? 1 : 0);
+ when(mUserManager.hasUserRestriction(
+ UserManager.DISALLOW_CONFIG_TETHERING)).thenReturn(!supported);
+ // Setup tetherable configuration.
+ when(mResources.getStringArray(R.array.config_tether_usb_regexs))
+ .thenReturn(new String[] { "test_rndis\\d" });
+ when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
+ .thenReturn(new String[]{ "test_wlan\\d" });
+ when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs))
+ .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" });
+ when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
+ .thenReturn(new String[0]);
+ when(mResources.getStringArray(R.array.config_tether_ncm_regexs))
+ .thenReturn(new String[] { "test_ncm\\d" });
+ when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]);
+ when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(true);
+ }
+
+ private void initTetheringUpstream(UpstreamNetworkState upstreamState) {
+ when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
+ when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState);
+ }
+
private Tethering makeTethering() {
mTetheringDependencies.reset();
return new Tethering(mTetheringDependencies);
@@ -672,9 +685,7 @@ public class TetheringTest {
}
private void prepareUsbTethering(UpstreamNetworkState upstreamState) {
- when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
- when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
- .thenReturn(upstreamState);
+ initTetheringUpstream(upstreamState);
// Emulate pressing the USB tethering button in Settings UI.
mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB), null);
@@ -700,7 +711,7 @@ public class TetheringTest {
verify(mNetd, times(1)).interfaceGetList();
// UpstreamNetworkMonitor should receive selected upstream
- verify(mUpstreamNetworkMonitor, times(1)).selectPreferredUpstreamType(any());
+ verify(mUpstreamNetworkMonitor, times(1)).getCurrentPreferredUpstream();
verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(upstreamState.network);
}
@@ -872,8 +883,7 @@ public class TetheringTest {
// Then 464xlat comes up
upstreamState = buildMobile464xlatUpstreamState();
- when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
- .thenReturn(upstreamState);
+ initTetheringUpstream(upstreamState);
// Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES.
mTetheringDependencies.mUpstreamNetworkMonitorMasterSM.sendMessage(
@@ -1344,9 +1354,7 @@ public class TetheringTest {
callback.expectOffloadStatusChanged(TETHER_HARDWARE_OFFLOAD_STOPPED);
// 2. Enable wifi tethering.
UpstreamNetworkState upstreamState = buildMobileDualStackUpstreamState();
- when(mUpstreamNetworkMonitor.getCurrentPreferredUpstream()).thenReturn(upstreamState);
- when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
- .thenReturn(upstreamState);
+ initTetheringUpstream(upstreamState);
when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
mTethering.interfaceStatusChanged(TEST_WLAN_IFNAME, true);
mLooper.dispatchAll();
@@ -1723,7 +1731,7 @@ public class TetheringTest {
final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
- when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState);
+ initTetheringUpstream(upstreamState);
stateMachine.chooseUpstreamType(true);
verify(mUpstreamNetworkMonitor, times(1)).setCurrentUpstream(eq(upstreamState.network));
@@ -1735,7 +1743,7 @@ public class TetheringTest {
final Tethering.TetherMasterSM stateMachine = (Tethering.TetherMasterSM)
mTetheringDependencies.mUpstreamNetworkMonitorMasterSM;
final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState();
- when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any())).thenReturn(upstreamState);
+ initTetheringUpstream(upstreamState);
stateMachine.chooseUpstreamType(true);
stateMachine.handleUpstreamNetworkMonitorCallback(EVENT_ON_CAPABILITIES, upstreamState);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 08aab2aea6f9..635f184ce80c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2732,7 +2732,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// the Messenger, but if this ever changes, not making a defensive copy
// here will give attack vectors to clients using this code path.
networkCapabilities = new NetworkCapabilities(networkCapabilities);
- networkCapabilities.restrictCapabilitesForTestNetwork();
+ networkCapabilities.restrictCapabilitesForTestNetwork(nai.creatorUid);
}
updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
break;
@@ -3079,10 +3079,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public void notifyDataStallSuspected(DataStallReportParcelable p) {
- final Message msg = mConnectivityDiagnosticsHandler.obtainMessage(
- ConnectivityDiagnosticsHandler.EVENT_DATA_STALL_SUSPECTED,
- p.detectionMethod, mNetId, p.timestampMillis);
-
final PersistableBundle extras = new PersistableBundle();
switch (p.detectionMethod) {
case DETECTION_METHOD_DNS_EVENTS:
@@ -3097,12 +3093,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
log("Unknown data stall detection method, ignoring: " + p.detectionMethod);
return;
}
- msg.setData(new Bundle(extras));
- // NetworkStateTrackerHandler currently doesn't take any actions based on data
- // stalls so send the message directly to ConnectivityDiagnosticsHandler and avoid
- // the cost of going through two handlers.
- mConnectivityDiagnosticsHandler.sendMessage(msg);
+ proxyDataStallToConnectivityDiagnosticsHandler(
+ p.detectionMethod, mNetId, p.timestampMillis, extras);
}
@Override
@@ -3116,6 +3109,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ private void proxyDataStallToConnectivityDiagnosticsHandler(int detectionMethod, int netId,
+ long timestampMillis, @NonNull PersistableBundle extras) {
+ final Message msg = mConnectivityDiagnosticsHandler.obtainMessage(
+ ConnectivityDiagnosticsHandler.EVENT_DATA_STALL_SUSPECTED,
+ detectionMethod, netId, timestampMillis);
+ msg.setData(new Bundle(extras));
+
+ // NetworkStateTrackerHandler currently doesn't take any actions based on data
+ // stalls so send the message directly to ConnectivityDiagnosticsHandler and avoid
+ // the cost of going through two handlers.
+ mConnectivityDiagnosticsHandler.sendMessage(msg);
+ }
+
private boolean networkRequiresPrivateDnsValidation(NetworkAgentInfo nai) {
return isPrivateDnsValidationRequired(nai.networkCapabilities);
}
@@ -5855,7 +5861,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// the call to mixInCapabilities below anyway, but sanitizing here means the NAI never
// sees capabilities that may be malicious, which might prevent mistakes in the future.
networkCapabilities = new NetworkCapabilities(networkCapabilities);
- networkCapabilities.restrictCapabilitesForTestNetwork();
+ networkCapabilities.restrictCapabilitesForTestNetwork(Binder.getCallingUid());
} else {
enforceNetworkFactoryPermission();
}
@@ -5868,7 +5874,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
- this, mNetd, mDnsResolver, mNMS, providerId);
+ this, mNetd, mDnsResolver, mNMS, providerId, Binder.getCallingUid());
// Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
@@ -5969,7 +5975,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Start or stop DNS64 detection and 464xlat according to network state.
networkAgent.clatd.update();
notifyIfacesChangedForNetworkStats();
- networkAgent.networkMonitor().notifyLinkPropertiesChanged(newLp);
+ networkAgent.networkMonitor().notifyLinkPropertiesChanged(
+ new LinkProperties(newLp, true /* parcelSensitiveFields */));
if (networkAgent.everConnected) {
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
}
@@ -7157,7 +7164,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
networkAgent.networkMonitor().setAcceptPartialConnectivity();
}
networkAgent.networkMonitor().notifyNetworkConnected(
- networkAgent.linkProperties, networkAgent.networkCapabilities);
+ new LinkProperties(networkAgent.linkProperties,
+ true /* parcelSensitiveFields */),
+ networkAgent.networkCapabilities);
scheduleUnvalidatedPrompt(networkAgent);
// Whether a particular NetworkRequest listen should cause signal strength thresholds to
@@ -8155,4 +8164,24 @@ public class ConnectivityService extends IConnectivityManager.Stub
0,
callback));
}
+
+ @Override
+ public void simulateDataStall(int detectionMethod, long timestampMillis,
+ @NonNull Network network, @NonNull PersistableBundle extras) {
+ enforceAnyPermissionOf(android.Manifest.permission.MANAGE_TEST_NETWORKS,
+ android.Manifest.permission.NETWORK_STACK);
+ final NetworkCapabilities nc = getNetworkCapabilitiesInternal(network);
+ if (!nc.hasTransport(TRANSPORT_TEST)) {
+ throw new SecurityException("Data Stall simluation is only possible for test networks");
+ }
+
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+ if (nai == null || nai.creatorUid != Binder.getCallingUid()) {
+ throw new SecurityException("Data Stall simulation is only possible for network "
+ + "creators");
+ }
+
+ proxyDataStallToConnectivityDiagnosticsHandler(
+ detectionMethod, network.netId, timestampMillis, extras);
+ }
}
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index 0ea73460e105..d6bd5a1d7c4c 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -317,39 +317,34 @@ class TestNetworkService extends ITestNetworkManager.Stub {
"Cannot create network for non ipsec, non-testtun interface");
}
- // Setup needs to be done with NETWORK_STACK privileges.
- int callingUid = Binder.getCallingUid();
- Binder.withCleanCallingIdentity(
- () -> {
- try {
- mNMS.setInterfaceUp(iface);
-
- // Synchronize all accesses to mTestNetworkTracker to prevent the case
- // where:
- // 1. TestNetworkAgent successfully binds to death of binder
- // 2. Before it is added to the mTestNetworkTracker, binder dies,
- // binderDied() is called (on a different thread)
- // 3. This thread is pre-empted, put() is called after remove()
- synchronized (mTestNetworkTracker) {
- TestNetworkAgent agent =
- registerTestNetworkAgent(
- mHandler.getLooper(),
- mContext,
- iface,
- lp,
- isMetered,
- callingUid,
- administratorUids,
- binder);
-
- mTestNetworkTracker.put(agent.getNetwork().netId, agent);
- }
- } catch (SocketException e) {
- throw new UncheckedIOException(e);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- });
+ try {
+ // This requires NETWORK_STACK privileges.
+ Binder.withCleanCallingIdentity(() -> mNMS.setInterfaceUp(iface));
+
+ // Synchronize all accesses to mTestNetworkTracker to prevent the case where:
+ // 1. TestNetworkAgent successfully binds to death of binder
+ // 2. Before it is added to the mTestNetworkTracker, binder dies, binderDied() is called
+ // (on a different thread)
+ // 3. This thread is pre-empted, put() is called after remove()
+ synchronized (mTestNetworkTracker) {
+ TestNetworkAgent agent =
+ registerTestNetworkAgent(
+ mHandler.getLooper(),
+ mContext,
+ iface,
+ lp,
+ isMetered,
+ Binder.getCallingUid(),
+ administratorUids,
+ binder);
+
+ mTestNetworkTracker.put(agent.getNetwork().netId, agent);
+ }
+ } catch (SocketException e) {
+ throw new UncheckedIOException(e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
/** Teardown a test network */
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ece21f667418..166c4f3c749b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -12857,7 +12857,9 @@ public class ActivityManagerService extends IActivityManager.Stub
pw.print(" unmapped + ");
pw.print(stringifyKBSize(ionPool));
pw.println(" pools)");
- kernelUsed += ionUnmapped;
+ // Note: mapped ION memory is not accounted in PSS due to VM_PFNMAP flag being
+ // set on ION VMAs, therefore consider the entire ION heap as used kernel memory
+ kernelUsed += ionHeap;
}
final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
@@ -13594,7 +13596,9 @@ public class ActivityManagerService extends IActivityManager.Stub
memInfoBuilder.append(" ION: ");
memInfoBuilder.append(stringifyKBSize(ionHeap + ionPool));
memInfoBuilder.append("\n");
- kernelUsed += ionUnmapped;
+ // Note: mapped ION memory is not accounted in PSS due to VM_PFNMAP flag being
+ // set on ION VMAs, therefore consider the entire ION heap as used kernel memory
+ kernelUsed += ionHeap;
}
memInfoBuilder.append(" Used RAM: ");
memInfoBuilder.append(stringifyKBSize(
diff --git a/services/core/java/com/android/server/compat/OWNERS b/services/core/java/com/android/server/compat/OWNERS
index 2b7cdb0cbce9..cfd0a4b079ad 100644
--- a/services/core/java/com/android/server/compat/OWNERS
+++ b/services/core/java/com/android/server/compat/OWNERS
@@ -2,6 +2,5 @@
platform-compat-eng+reviews@google.com
andreionea@google.com
-atrost@google.com
mathewi@google.com
satayev@google.com
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 2d1f553ab8cd..a9f62d91592d 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -168,6 +168,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
// Obtained by ConnectivityService and merged into NetworkAgent-provided information.
public CaptivePortalData captivePortalData;
+ // The UID of the remote entity that created this Network.
+ public final int creatorUid;
+
// Networks are lingered when they become unneeded as a result of their NetworkRequests being
// satisfied by a higher-scoring network. so as to allow communication to wrap up before the
// network is taken down. This usually only happens to the default network. Lingering ends with
@@ -268,7 +271,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, int score, Context context,
Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
- IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber) {
+ IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber,
+ int creatorUid) {
this.messenger = messenger;
asyncChannel = ac;
network = net;
@@ -282,6 +286,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
mHandler = handler;
networkAgentConfig = config;
this.factorySerialNumber = factorySerialNumber;
+ this.creatorUid = creatorUid;
}
/**
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 0114b5bb1331..730da28ba8a2 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -65,6 +65,7 @@ import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkProvider;
+import android.net.NetworkRequest;
import android.net.RouteInfo;
import android.net.UidRange;
import android.net.VpnManager;
@@ -2225,12 +2226,27 @@ public class Vpn {
@Override
public void run() {
- // Explicitly use only the network that ConnectivityService thinks is the "best." In
- // other words, only ever use the currently selected default network. This does mean
- // that in both onLost() and onConnected(), any old sessions MUST be torn down. This
- // does NOT include VPNs.
+ // Unless the profile is restricted to test networks, explicitly use only the network
+ // that ConnectivityService thinks is the "best." In other words, only ever use the
+ // currently selected default network. This does mean that in both onLost() and
+ // onConnected(), any old sessions MUST be torn down. This does NOT include VPNs.
+ //
+ // When restricted to test networks, select any network with TRANSPORT_TEST. Since the
+ // creator of the profile and the test network creator both have MANAGE_TEST_NETWORKS,
+ // this is considered safe.
final ConnectivityManager cm = ConnectivityManager.from(mContext);
- cm.requestNetwork(cm.getDefaultRequest(), mNetworkCallback);
+ final NetworkRequest req;
+
+ if (mProfile.isRestrictedToTestNetworks()) {
+ req = new NetworkRequest.Builder()
+ .clearCapabilities()
+ .addTransportType(NetworkCapabilities.TRANSPORT_TEST)
+ .build();
+ } else {
+ req = cm.getDefaultRequest();
+ }
+
+ cm.requestNetwork(req, mNetworkCallback);
}
private boolean isActiveNetwork(@Nullable Network network) {
@@ -2868,6 +2884,11 @@ public class Vpn {
verifyCallingUidAndPackage(packageName);
enforceNotRestrictedUser();
+ if (profile.isRestrictedToTestNetworks) {
+ mContext.enforceCallingPermission(Manifest.permission.MANAGE_TEST_NETWORKS,
+ "Test-mode profiles require the MANAGE_TEST_NETWORKS permission");
+ }
+
final byte[] encodedProfile = profile.encode();
if (encodedProfile.length > MAX_VPN_PROFILE_SIZE_BYTES) {
throw new IllegalArgumentException("Profile too big");
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index e21a01d2048f..5d1cc2a5c24a 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -119,7 +119,6 @@ import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.PowerManager;
-import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
@@ -160,6 +159,7 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@@ -227,12 +227,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private static final String PREFIX_UID_TAG = "uid_tag";
/**
- * Virtual network interface for video telephony. This is for VT data usage counting purpose.
- */
- // TODO: Remove this after no one is using it.
- public static final String VT_INTERFACE = NetworkStats.IFACE_VT;
-
- /**
* Settings that can be changed externally.
*/
public interface NetworkStatsSettings {
@@ -304,8 +298,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
new DropBoxNonMonotonicObserver();
private static final int MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS = 100;
- private final RemoteCallbackList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList =
- new RemoteCallbackList<>();
+ private final CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList =
+ new CopyOnWriteArrayList<>();
/** Semaphore used to wait for stats provider to respond to request stats update. */
private final Semaphore mStatsProviderSem = new Semaphore(0, true);
@@ -1461,10 +1455,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0;
// Request asynchronous stats update from all providers for next poll. And wait a bit of
- // time to allow providers report-in given that normally binder call should be fast.
+ // time to allow providers report-in given that normally binder call should be fast. Note
+ // that size of list might be changed because addition/removing at the same time. For
+ // addition, the stats of the missed provider can only be collected in next poll;
+ // for removal, wait might take up to MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS
+ // once that happened.
// TODO: request with a valid token.
Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate");
- final int registeredCallbackCount = mStatsProviderCbList.getRegisteredCallbackCount();
+ final int registeredCallbackCount = mStatsProviderCbList.size();
mStatsProviderSem.drainPermits();
invokeForAllStatsProviderCallbacks(
(cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */));
@@ -1638,7 +1636,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public void setStatsProviderLimitAsync(@NonNull String iface, long quota) {
- Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")");
+ if (LOGV) Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")");
invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota));
}
}
@@ -1929,7 +1927,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
NetworkStatsProviderCallbackImpl callback = new NetworkStatsProviderCallbackImpl(
tag, provider, mStatsProviderSem, mAlertObserver,
mStatsProviderCbList);
- mStatsProviderCbList.register(callback);
+ mStatsProviderCbList.add(callback);
Log.d(TAG, "registerNetworkStatsProvider from " + callback.mTag + " uid/pid="
+ getCallingUid() + "/" + getCallingPid());
return callback;
@@ -1953,20 +1951,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private void invokeForAllStatsProviderCallbacks(
@NonNull ThrowingConsumer<NetworkStatsProviderCallbackImpl, RemoteException> task) {
- synchronized (mStatsLock) {
- final int length = mStatsProviderCbList.beginBroadcast();
+ for (final NetworkStatsProviderCallbackImpl cb : mStatsProviderCbList) {
try {
- for (int i = 0; i < length; i++) {
- final NetworkStatsProviderCallbackImpl cb =
- mStatsProviderCbList.getBroadcastItem(i);
- try {
- task.accept(cb);
- } catch (RemoteException e) {
- Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e);
- }
- }
- } finally {
- mStatsProviderCbList.finishBroadcast();
+ task.accept(cb);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e);
}
}
}
@@ -1978,7 +1967,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@NonNull final INetworkStatsProvider mProvider;
@NonNull private final Semaphore mSemaphore;
@NonNull final INetworkManagementEventObserver mAlertObserver;
- @NonNull final RemoteCallbackList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList;
+ @NonNull final CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> mStatsProviderCbList;
@NonNull private final Object mProviderStatsLock = new Object();
@@ -1992,7 +1981,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@NonNull String tag, @NonNull INetworkStatsProvider provider,
@NonNull Semaphore semaphore,
@NonNull INetworkManagementEventObserver alertObserver,
- @NonNull RemoteCallbackList<NetworkStatsProviderCallbackImpl> cbList)
+ @NonNull CopyOnWriteArrayList<NetworkStatsProviderCallbackImpl> cbList)
throws RemoteException {
mTag = tag;
mProvider = provider;
@@ -2049,13 +2038,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public void binderDied() {
Log.d(TAG, mTag + ": binderDied");
- mStatsProviderCbList.unregister(this);
+ mStatsProviderCbList.remove(this);
}
@Override
public void unregister() {
Log.d(TAG, mTag + ": unregister");
- mStatsProviderCbList.unregister(this);
+ mStatsProviderCbList.remove(this);
}
}
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 4e14fd3d59a1..d9605522b3b0 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -106,6 +106,7 @@ public abstract class Conference extends Conferenceable {
private int mCallerDisplayNamePresentation;
private int mCallDirection;
private boolean mRingbackRequested = false;
+ private boolean mIsMultiparty = true;
private final Connection.Listener mConnectionDeathListener = new Connection.Listener() {
@Override
@@ -998,8 +999,8 @@ public abstract class Conference extends Conferenceable {
public void onExtrasChanged(Bundle extras) {}
/**
- * Set whether Telecom should treat this {@link Conference} as a conference call or if it
- * should treat it as a single-party call.
+ * Set whether Telecom should treat this {@link Conference} as a multiparty conference call or
+ * if it should treat it as a single-party call.
* This method is used as part of a workaround regarding IMS conference calls and user
* expectation. In IMS, once a conference is formed, the UE is connected to an IMS conference
* server. If all participants of the conference drop out of the conference except for one, the
@@ -1020,6 +1021,7 @@ public abstract class Conference extends Conferenceable {
@TestApi
@RequiresPermission(MODIFY_PHONE_STATE)
public void setConferenceState(boolean isConference) {
+ mIsMultiparty = isConference;
for (Listener l : mListeners) {
l.onConferenceStateChanged(this, isConference);
}
@@ -1043,6 +1045,20 @@ public abstract class Conference extends Conferenceable {
}
}
+ /**
+ * Determines if the {@link Conference} is considered "multiparty" or not. By default all
+ * conferences are considered multiparty. A multiparty conference is one where there are
+ * multiple conference participants (other than the host) in the conference.
+ * This is tied to {@link #setConferenceState(boolean)}, which is used for some use cases to
+ * have a conference appear as if it is a standalone call, in which case the conference will
+ * no longer be multiparty.
+ * @return {@code true} if conference is treated as a conference (i.e. it is multiparty),
+ * {@code false} if it should emulate a standalone call (i.e. not multiparty).
+ * @hide
+ */
+ public boolean isMultiparty() {
+ return mIsMultiparty;
+ }
/**
* Sets the address of this {@link Conference}. Used when {@link #setConferenceState(boolean)}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 73296986d82e..1b60e4820ad0 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -2505,6 +2505,11 @@ public abstract class ConnectionService extends Service {
mAdapter.addConferenceCall(id, parcelableConference);
mAdapter.setVideoProvider(id, conference.getVideoProvider());
mAdapter.setVideoState(id, conference.getVideoState());
+ // In some instances a conference can start its life as a standalone call with just a
+ // single participant; ensure we signal to Telecom in this case.
+ if (!conference.isMultiparty()) {
+ mAdapter.setConferenceState(id, conference.isMultiparty());
+ }
// Go through any child calls and set the parent.
for (Connection connection : conference.getConnections()) {
diff --git a/telecomm/java/android/telecom/GatewayInfo.java b/telecomm/java/android/telecom/GatewayInfo.java
index 0faa4fd2027a..31c24d54918a 100644
--- a/telecomm/java/android/telecom/GatewayInfo.java
+++ b/telecomm/java/android/telecom/GatewayInfo.java
@@ -111,7 +111,7 @@ public class GatewayInfo implements Parcelable {
@Override
public void writeToParcel(Parcel destination, int flags) {
destination.writeString(mGatewayProviderPackageName);
- mGatewayAddress.writeToParcel(destination, 0);
- mOriginalAddress.writeToParcel(destination, 0);
+ Uri.writeToParcel(destination, mGatewayAddress);
+ Uri.writeToParcel(destination, mOriginalAddress);
}
}
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 415a817b58d5..182dc8bb8325 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -629,7 +629,7 @@ public final class ParcelableCall implements Parcelable {
int capabilities = source.readInt();
int properties = source.readInt();
long connectTimeMillis = source.readLong();
- Uri handle = source.readParcelable(classLoader);
+ Uri handle = Uri.CREATOR.createFromParcel(source);
int handlePresentation = source.readInt();
String callerDisplayName = source.readString();
int callerDisplayNamePresentation = source.readInt();
@@ -711,7 +711,7 @@ public final class ParcelableCall implements Parcelable {
destination.writeInt(mCapabilities);
destination.writeInt(mProperties);
destination.writeLong(mConnectTimeMillis);
- destination.writeParcelable(mHandle, 0);
+ Uri.writeToParcel(destination, mHandle);
destination.writeInt(mHandlePresentation);
destination.writeString(mCallerDisplayName);
destination.writeInt(mCallerDisplayNamePresentation);
diff --git a/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java b/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java
new file mode 100644
index 000000000000..6c6375586225
--- /dev/null
+++ b/telephony/common/com/android/internal/telephony/CellBroadcastUtils.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.provider.Telephony;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * This class provides utility functions related to CellBroadcast.
+ */
+public class CellBroadcastUtils {
+ private static final String TAG = "CellBroadcastUtils";
+ private static final boolean VDBG = false;
+
+ /**
+ * Utility method to query the default CBR's package name.
+ */
+ public static String getDefaultCellBroadcastReceiverPackageName(Context context) {
+ PackageManager packageManager = context.getPackageManager();
+ ResolveInfo resolveInfo = packageManager.resolveActivity(
+ new Intent(Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION),
+ PackageManager.MATCH_SYSTEM_ONLY);
+ String packageName;
+
+ if (resolveInfo == null) {
+ Log.e(TAG, "getDefaultCellBroadcastReceiverPackageName: no package found");
+ return null;
+ }
+
+ packageName = resolveInfo.activityInfo.applicationInfo.packageName;
+
+ if (VDBG) {
+ Log.d(TAG, "getDefaultCellBroadcastReceiverPackageName: found package: " + packageName);
+ }
+
+ if (TextUtils.isEmpty(packageName) || packageManager.checkPermission(
+ android.Manifest.permission.READ_CELL_BROADCASTS, packageName)
+ == PackageManager.PERMISSION_DENIED) {
+ Log.e(TAG, "getDefaultCellBroadcastReceiverPackageName: returning null; "
+ + "permission check failed for : " + packageName);
+ return null;
+ }
+
+ return packageName;
+ }
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 41bab25af115..4d15a93c2dbe 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4108,10 +4108,10 @@ public class CarrierConfigManager {
});
sDefaults.putIntArray(KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY,
new int[] {
- -19, /* SIGNAL_STRENGTH_POOR */
+ -20, /* SIGNAL_STRENGTH_POOR */
-17, /* SIGNAL_STRENGTH_MODERATE */
-14, /* SIGNAL_STRENGTH_GOOD */
- -12 /* SIGNAL_STRENGTH_GREAT */
+ -11 /* SIGNAL_STRENGTH_GREAT */
});
sDefaults.putIntArray(KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY,
new int[] {
@@ -4139,9 +4139,9 @@ public class CarrierConfigManager {
// Boundaries: [-20 dB, -3 dB]
new int[] {
-16, /* SIGNAL_STRENGTH_POOR */
- -11, /* SIGNAL_STRENGTH_MODERATE */
+ -12, /* SIGNAL_STRENGTH_MODERATE */
-9, /* SIGNAL_STRENGTH_GOOD */
- -7 /* SIGNAL_STRENGTH_GREAT */
+ -6 /* SIGNAL_STRENGTH_GREAT */
});
sDefaults.putIntArray(KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY,
// Boundaries: [-23 dB, 40 dB]
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 8562df1d015f..95fe90a47654 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -57,9 +57,9 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa
// Boundaries: [-20 dB, -3 dB]
private int[] mSsRsrqThresholds = new int[] {
-16, /* SIGNAL_STRENGTH_POOR */
- -11, /* SIGNAL_STRENGTH_MODERATE */
+ -12, /* SIGNAL_STRENGTH_MODERATE */
-9, /* SIGNAL_STRENGTH_GOOD */
- -7 /* SIGNAL_STRENGTH_GREAT */
+ -6 /* SIGNAL_STRENGTH_GREAT */
};
// Lifted from Default carrier configs and max range of SSSINR
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index a269bd1809d4..5c84297d3b86 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1392,15 +1392,16 @@ public class ServiceState implements Parcelable {
/** @hide */
public boolean isUsingCarrierAggregation() {
+ boolean isUsingCa = false;
NetworkRegistrationInfo nri = getNetworkRegistrationInfo(
NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
if (nri != null) {
DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
if (dsri != null) {
- return dsri.isUsingCarrierAggregation();
+ isUsingCa = dsri.isUsingCarrierAggregation();
}
}
- return false;
+ return isUsingCa || getCellBandwidths().length > 1;
}
/** @hide */
diff --git a/test-base/api/lint-baseline.txt b/test-base/api/lint-baseline.txt
new file mode 100644
index 000000000000..86c8a910d20a
--- /dev/null
+++ b/test-base/api/lint-baseline.txt
@@ -0,0 +1,3 @@
+// Baseline format: 1.0
+MissingNullability: junit.framework.ComparisonFailure#getMessage():
+ Missing nullability on method `getMessage` return
diff --git a/test-mock/api/lint-baseline.txt b/test-mock/api/lint-baseline.txt
new file mode 100644
index 000000000000..c6ba3f5d8fd8
--- /dev/null
+++ b/test-mock/api/lint-baseline.txt
@@ -0,0 +1,143 @@
+// Baseline format: 1.0
+ArrayReturn: android.test.mock.MockContentProvider#bulkInsert(android.net.Uri, android.content.ContentValues[]) parameter #1:
+ Method parameter should be Collection<ContentValues> (or subclass) instead of raw array; was `android.content.ContentValues[]`
+ArrayReturn: android.test.mock.MockResources#getTextArray(int):
+ Method should return Collection<CharSequence> (or subclass) instead of raw array; was `java.lang.CharSequence[]`
+
+
+MissingNullability: android.test.mock.MockApplication#onConfigurationChanged(android.content.res.Configuration) parameter #0:
+ Missing nullability on parameter `newConfig` in method `onConfigurationChanged`
+MissingNullability: android.test.mock.MockContentProvider#attachInfo(android.content.Context, android.content.pm.ProviderInfo) parameter #0:
+ Missing nullability on parameter `context` in method `attachInfo`
+MissingNullability: android.test.mock.MockContentProvider#attachInfo(android.content.Context, android.content.pm.ProviderInfo) parameter #1:
+ Missing nullability on parameter `info` in method `attachInfo`
+MissingNullability: android.test.mock.MockContentProvider#bulkInsert(android.net.Uri, android.content.ContentValues[]) parameter #0:
+ Missing nullability on parameter `uri` in method `bulkInsert`
+MissingNullability: android.test.mock.MockContentProvider#bulkInsert(android.net.Uri, android.content.ContentValues[]) parameter #1:
+ Missing nullability on parameter `values` in method `bulkInsert`
+MissingNullability: android.test.mock.MockContentProvider#getStreamTypes(android.net.Uri, String):
+ Missing nullability on method `getStreamTypes` return
+MissingNullability: android.test.mock.MockContentProvider#getStreamTypes(android.net.Uri, String) parameter #0:
+ Missing nullability on parameter `url` in method `getStreamTypes`
+MissingNullability: android.test.mock.MockContentProvider#getStreamTypes(android.net.Uri, String) parameter #1:
+ Missing nullability on parameter `mimeTypeFilter` in method `getStreamTypes`
+MissingNullability: android.test.mock.MockContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean) parameter #0:
+ Missing nullability on parameter `uri` in method `notifyChange`
+MissingNullability: android.test.mock.MockContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean) parameter #1:
+ Missing nullability on parameter `observer` in method `notifyChange`
+MissingNullability: android.test.mock.MockContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #0:
+ Missing nullability on parameter `service` in method `bindIsolatedService`
+MissingNullability: android.test.mock.MockContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #2:
+ Missing nullability on parameter `instanceName` in method `bindIsolatedService`
+MissingNullability: android.test.mock.MockContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #3:
+ Missing nullability on parameter `executor` in method `bindIsolatedService`
+MissingNullability: android.test.mock.MockContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #4:
+ Missing nullability on parameter `conn` in method `bindIsolatedService`
+MissingNullability: android.test.mock.MockContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #0:
+ Missing nullability on parameter `service` in method `bindService`
+MissingNullability: android.test.mock.MockContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #2:
+ Missing nullability on parameter `executor` in method `bindService`
+MissingNullability: android.test.mock.MockContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #3:
+ Missing nullability on parameter `conn` in method `bindService`
+MissingNullability: android.test.mock.MockContext#getMainExecutor():
+ Missing nullability on method `getMainExecutor` return
+MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #0:
+ Missing nullability on parameter `intent` in method `sendOrderedBroadcast`
+MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #1:
+ Missing nullability on parameter `receiverPermission` in method `sendOrderedBroadcast`
+MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #2:
+ Missing nullability on parameter `receiverAppOp` in method `sendOrderedBroadcast`
+MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #3:
+ Missing nullability on parameter `resultReceiver` in method `sendOrderedBroadcast`
+MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #4:
+ Missing nullability on parameter `scheduler` in method `sendOrderedBroadcast`
+MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #6:
+ Missing nullability on parameter `initialData` in method `sendOrderedBroadcast`
+MissingNullability: android.test.mock.MockContext#sendOrderedBroadcast(android.content.Intent, String, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle) parameter #7:
+ Missing nullability on parameter `initialExtras` in method `sendOrderedBroadcast`
+MissingNullability: android.test.mock.MockContext#updateServiceGroup(android.content.ServiceConnection, int, int) parameter #0:
+ Missing nullability on parameter `conn` in method `updateServiceGroup`
+MissingNullability: android.test.mock.MockCursor#getNotificationUris():
+ Missing nullability on method `getNotificationUris` return
+MissingNullability: android.test.mock.MockCursor#setNotificationUris(android.content.ContentResolver, java.util.List<android.net.Uri>) parameter #0:
+ Missing nullability on parameter `cr` in method `setNotificationUris`
+MissingNullability: android.test.mock.MockCursor#setNotificationUris(android.content.ContentResolver, java.util.List<android.net.Uri>) parameter #1:
+ Missing nullability on parameter `uris` in method `setNotificationUris`
+MissingNullability: android.test.mock.MockPackageManager#getPackageArchiveInfo(String, int):
+ Missing nullability on method `getPackageArchiveInfo` return
+MissingNullability: android.test.mock.MockPackageManager#getPackageArchiveInfo(String, int) parameter #0:
+ Missing nullability on parameter `archiveFilePath` in method `getPackageArchiveInfo`
+MissingNullability: android.test.mock.MockPackageManager#hasSigningCertificate(String, byte[], int) parameter #0:
+ Missing nullability on parameter `packageName` in method `hasSigningCertificate`
+MissingNullability: android.test.mock.MockPackageManager#hasSigningCertificate(String, byte[], int) parameter #1:
+ Missing nullability on parameter `certificate` in method `hasSigningCertificate`
+MissingNullability: android.test.mock.MockPackageManager#hasSigningCertificate(int, byte[], int) parameter #1:
+ Missing nullability on parameter `certificate` in method `hasSigningCertificate`
+MissingNullability: android.test.mock.MockResources#getAnimation(int):
+ Missing nullability on method `getAnimation` return
+MissingNullability: android.test.mock.MockResources#getConfiguration():
+ Missing nullability on method `getConfiguration` return
+MissingNullability: android.test.mock.MockResources#getDisplayMetrics():
+ Missing nullability on method `getDisplayMetrics` return
+MissingNullability: android.test.mock.MockResources#getIdentifier(String, String, String) parameter #0:
+ Missing nullability on parameter `name` in method `getIdentifier`
+MissingNullability: android.test.mock.MockResources#getIdentifier(String, String, String) parameter #1:
+ Missing nullability on parameter `defType` in method `getIdentifier`
+MissingNullability: android.test.mock.MockResources#getIdentifier(String, String, String) parameter #2:
+ Missing nullability on parameter `defPackage` in method `getIdentifier`
+MissingNullability: android.test.mock.MockResources#getIntArray(int):
+ Missing nullability on method `getIntArray` return
+MissingNullability: android.test.mock.MockResources#getLayout(int):
+ Missing nullability on method `getLayout` return
+MissingNullability: android.test.mock.MockResources#getQuantityString(int, int):
+ Missing nullability on method `getQuantityString` return
+MissingNullability: android.test.mock.MockResources#getQuantityString(int, int, java.lang.Object...):
+ Missing nullability on method `getQuantityString` return
+MissingNullability: android.test.mock.MockResources#getQuantityString(int, int, java.lang.Object...) parameter #2:
+ Missing nullability on parameter `formatArgs` in method `getQuantityString`
+MissingNullability: android.test.mock.MockResources#getQuantityText(int, int):
+ Missing nullability on method `getQuantityText` return
+MissingNullability: android.test.mock.MockResources#getResourceEntryName(int):
+ Missing nullability on method `getResourceEntryName` return
+MissingNullability: android.test.mock.MockResources#getResourceName(int):
+ Missing nullability on method `getResourceName` return
+MissingNullability: android.test.mock.MockResources#getResourcePackageName(int):
+ Missing nullability on method `getResourcePackageName` return
+MissingNullability: android.test.mock.MockResources#getResourceTypeName(int):
+ Missing nullability on method `getResourceTypeName` return
+MissingNullability: android.test.mock.MockResources#getString(int):
+ Missing nullability on method `getString` return
+MissingNullability: android.test.mock.MockResources#getString(int, java.lang.Object...):
+ Missing nullability on method `getString` return
+MissingNullability: android.test.mock.MockResources#getString(int, java.lang.Object...) parameter #1:
+ Missing nullability on parameter `formatArgs` in method `getString`
+MissingNullability: android.test.mock.MockResources#getStringArray(int):
+ Missing nullability on method `getStringArray` return
+MissingNullability: android.test.mock.MockResources#getText(int):
+ Missing nullability on method `getText` return
+MissingNullability: android.test.mock.MockResources#getText(int, CharSequence):
+ Missing nullability on method `getText` return
+MissingNullability: android.test.mock.MockResources#getText(int, CharSequence) parameter #1:
+ Missing nullability on parameter `def` in method `getText`
+MissingNullability: android.test.mock.MockResources#getTextArray(int):
+ Missing nullability on method `getTextArray` return
+MissingNullability: android.test.mock.MockResources#getValue(String, android.util.TypedValue, boolean) parameter #0:
+ Missing nullability on parameter `name` in method `getValue`
+MissingNullability: android.test.mock.MockResources#getValue(String, android.util.TypedValue, boolean) parameter #1:
+ Missing nullability on parameter `outValue` in method `getValue`
+MissingNullability: android.test.mock.MockResources#getValue(int, android.util.TypedValue, boolean) parameter #1:
+ Missing nullability on parameter `outValue` in method `getValue`
+MissingNullability: android.test.mock.MockResources#getXml(int):
+ Missing nullability on method `getXml` return
+MissingNullability: android.test.mock.MockResources#obtainAttributes(android.util.AttributeSet, int[]):
+ Missing nullability on method `obtainAttributes` return
+MissingNullability: android.test.mock.MockResources#obtainAttributes(android.util.AttributeSet, int[]) parameter #0:
+ Missing nullability on parameter `set` in method `obtainAttributes`
+MissingNullability: android.test.mock.MockResources#obtainAttributes(android.util.AttributeSet, int[]) parameter #1:
+ Missing nullability on parameter `attrs` in method `obtainAttributes`
+MissingNullability: android.test.mock.MockResources#obtainTypedArray(int):
+ Missing nullability on method `obtainTypedArray` return
+MissingNullability: android.test.mock.MockResources#openRawResource(int):
+ Missing nullability on method `openRawResource` return
+MissingNullability: android.test.mock.MockResources#openRawResourceFd(int):
+ Missing nullability on method `openRawResourceFd` return
diff --git a/test-mock/api/system-lint-baseline.txt b/test-mock/api/system-lint-baseline.txt
new file mode 100644
index 000000000000..466bc5376ed6
--- /dev/null
+++ b/test-mock/api/system-lint-baseline.txt
@@ -0,0 +1,15 @@
+// Baseline format: 1.0
+IntentBuilderName: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler):
+ Methods creating an Intent should be named `create<Foo>Intent()`, was `registerReceiverForAllUsers`
+
+
+MissingNullability: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler):
+ Missing nullability on method `registerReceiverForAllUsers` return
+MissingNullability: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler) parameter #0:
+ Missing nullability on parameter `receiver` in method `registerReceiverForAllUsers`
+MissingNullability: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler) parameter #1:
+ Missing nullability on parameter `filter` in method `registerReceiverForAllUsers`
+MissingNullability: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler) parameter #2:
+ Missing nullability on parameter `broadcastPermission` in method `registerReceiverForAllUsers`
+MissingNullability: android.test.mock.MockContext#registerReceiverForAllUsers(android.content.BroadcastReceiver, android.content.IntentFilter, String, android.os.Handler) parameter #3:
+ Missing nullability on parameter `scheduler` in method `registerReceiverForAllUsers`
diff --git a/test-runner/api/lint-baseline.txt b/test-runner/api/lint-baseline.txt
new file mode 100644
index 000000000000..54947fe687c0
--- /dev/null
+++ b/test-runner/api/lint-baseline.txt
@@ -0,0 +1,173 @@
+// Baseline format: 1.0
+GenericException: android.test.ActivityInstrumentationTestCase#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ActivityInstrumentationTestCase#tearDown():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ActivityInstrumentationTestCase2#runTest():
+ Methods must not throw generic exceptions (`java.lang.Throwable`)
+GenericException: android.test.ActivityInstrumentationTestCase2#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ActivityInstrumentationTestCase2#tearDown():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ActivityUnitTestCase#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ActivityUnitTestCase#tearDown():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ApplicationTestCase#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ApplicationTestCase#tearDown():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ProviderTestCase#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ProviderTestCase#tearDown():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ProviderTestCase2#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ProviderTestCase2#tearDown():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ServiceTestCase#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.ServiceTestCase#tearDown():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.SingleLaunchActivityTestCase#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.SingleLaunchActivityTestCase#tearDown():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+GenericException: android.test.SyncBaseInstrumentation#setUp():
+ Methods must not throw generic exceptions (`java.lang.Exception`)
+
+
+IntentBuilderName: android.test.IsolatedContext#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter):
+ Methods creating an Intent should be named `create<Foo>Intent()`, was `registerReceiver`
+
+
+MissingNullability: android.test.ComparisonFailure#getMessage():
+ Missing nullability on method `getMessage` return
+MissingNullability: android.test.InstrumentationTestRunner#onCreate(android.os.Bundle) parameter #0:
+ Missing nullability on parameter `arguments` in method `onCreate`
+MissingNullability: android.test.IsolatedContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #0:
+ Missing nullability on parameter `service` in method `bindIsolatedService`
+MissingNullability: android.test.IsolatedContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #2:
+ Missing nullability on parameter `instanceName` in method `bindIsolatedService`
+MissingNullability: android.test.IsolatedContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #3:
+ Missing nullability on parameter `executor` in method `bindIsolatedService`
+MissingNullability: android.test.IsolatedContext#bindIsolatedService(android.content.Intent, int, String, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #4:
+ Missing nullability on parameter `conn` in method `bindIsolatedService`
+MissingNullability: android.test.IsolatedContext#bindService(android.content.Intent, android.content.ServiceConnection, int) parameter #0:
+ Missing nullability on parameter `service` in method `bindService`
+MissingNullability: android.test.IsolatedContext#bindService(android.content.Intent, android.content.ServiceConnection, int) parameter #1:
+ Missing nullability on parameter `conn` in method `bindService`
+MissingNullability: android.test.IsolatedContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #0:
+ Missing nullability on parameter `service` in method `bindService`
+MissingNullability: android.test.IsolatedContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #2:
+ Missing nullability on parameter `executor` in method `bindService`
+MissingNullability: android.test.IsolatedContext#bindService(android.content.Intent, int, java.util.concurrent.Executor, android.content.ServiceConnection) parameter #3:
+ Missing nullability on parameter `conn` in method `bindService`
+MissingNullability: android.test.IsolatedContext#checkUriPermission(android.net.Uri, String, String, int, int, int) parameter #0:
+ Missing nullability on parameter `uri` in method `checkUriPermission`
+MissingNullability: android.test.IsolatedContext#checkUriPermission(android.net.Uri, String, String, int, int, int) parameter #1:
+ Missing nullability on parameter `readPermission` in method `checkUriPermission`
+MissingNullability: android.test.IsolatedContext#checkUriPermission(android.net.Uri, String, String, int, int, int) parameter #2:
+ Missing nullability on parameter `writePermission` in method `checkUriPermission`
+MissingNullability: android.test.IsolatedContext#checkUriPermission(android.net.Uri, int, int, int) parameter #0:
+ Missing nullability on parameter `uri` in method `checkUriPermission`
+MissingNullability: android.test.IsolatedContext#getContentResolver():
+ Missing nullability on method `getContentResolver` return
+MissingNullability: android.test.IsolatedContext#getFilesDir():
+ Missing nullability on method `getFilesDir` return
+MissingNullability: android.test.IsolatedContext#getSystemService(String):
+ Missing nullability on method `getSystemService` return
+MissingNullability: android.test.IsolatedContext#getSystemService(String) parameter #0:
+ Missing nullability on parameter `name` in method `getSystemService`
+MissingNullability: android.test.IsolatedContext#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter):
+ Missing nullability on method `registerReceiver` return
+MissingNullability: android.test.IsolatedContext#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter) parameter #0:
+ Missing nullability on parameter `receiver` in method `registerReceiver`
+MissingNullability: android.test.IsolatedContext#registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter) parameter #1:
+ Missing nullability on parameter `filter` in method `registerReceiver`
+MissingNullability: android.test.IsolatedContext#sendBroadcast(android.content.Intent) parameter #0:
+ Missing nullability on parameter `intent` in method `sendBroadcast`
+MissingNullability: android.test.IsolatedContext#sendOrderedBroadcast(android.content.Intent, String) parameter #0:
+ Missing nullability on parameter `intent` in method `sendOrderedBroadcast`
+MissingNullability: android.test.IsolatedContext#sendOrderedBroadcast(android.content.Intent, String) parameter #1:
+ Missing nullability on parameter `receiverPermission` in method `sendOrderedBroadcast`
+MissingNullability: android.test.IsolatedContext#unregisterReceiver(android.content.BroadcastReceiver) parameter #0:
+ Missing nullability on parameter `receiver` in method `unregisterReceiver`
+MissingNullability: android.test.RenamingDelegatingContext#databaseList():
+ Missing nullability on method `databaseList` return
+MissingNullability: android.test.RenamingDelegatingContext#deleteDatabase(String) parameter #0:
+ Missing nullability on parameter `name` in method `deleteDatabase`
+MissingNullability: android.test.RenamingDelegatingContext#deleteFile(String) parameter #0:
+ Missing nullability on parameter `name` in method `deleteFile`
+MissingNullability: android.test.RenamingDelegatingContext#fileList():
+ Missing nullability on method `fileList` return
+MissingNullability: android.test.RenamingDelegatingContext#getCacheDir():
+ Missing nullability on method `getCacheDir` return
+MissingNullability: android.test.RenamingDelegatingContext#getDatabasePath(String):
+ Missing nullability on method `getDatabasePath` return
+MissingNullability: android.test.RenamingDelegatingContext#getDatabasePath(String) parameter #0:
+ Missing nullability on parameter `name` in method `getDatabasePath`
+MissingNullability: android.test.RenamingDelegatingContext#getFileStreamPath(String):
+ Missing nullability on method `getFileStreamPath` return
+MissingNullability: android.test.RenamingDelegatingContext#getFileStreamPath(String) parameter #0:
+ Missing nullability on parameter `name` in method `getFileStreamPath`
+MissingNullability: android.test.RenamingDelegatingContext#openFileInput(String):
+ Missing nullability on method `openFileInput` return
+MissingNullability: android.test.RenamingDelegatingContext#openFileInput(String) parameter #0:
+ Missing nullability on parameter `name` in method `openFileInput`
+MissingNullability: android.test.RenamingDelegatingContext#openFileOutput(String, int):
+ Missing nullability on method `openFileOutput` return
+MissingNullability: android.test.RenamingDelegatingContext#openFileOutput(String, int) parameter #0:
+ Missing nullability on parameter `name` in method `openFileOutput`
+MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory):
+ Missing nullability on method `openOrCreateDatabase` return
+MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory) parameter #0:
+ Missing nullability on parameter `name` in method `openOrCreateDatabase`
+MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory) parameter #2:
+ Missing nullability on parameter `factory` in method `openOrCreateDatabase`
+MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler):
+ Missing nullability on method `openOrCreateDatabase` return
+MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler) parameter #0:
+ Missing nullability on parameter `name` in method `openOrCreateDatabase`
+MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler) parameter #2:
+ Missing nullability on parameter `factory` in method `openOrCreateDatabase`
+MissingNullability: android.test.RenamingDelegatingContext#openOrCreateDatabase(String, int, android.database.sqlite.SQLiteDatabase.CursorFactory, android.database.DatabaseErrorHandler) parameter #3:
+ Missing nullability on parameter `errorHandler` in method `openOrCreateDatabase`
+
+
+ProtectedMember: android.test.ActivityInstrumentationTestCase#setUp():
+ Protected methods not allowed; must be public: method android.test.ActivityInstrumentationTestCase.setUp()}
+ProtectedMember: android.test.ActivityInstrumentationTestCase#tearDown():
+ Protected methods not allowed; must be public: method android.test.ActivityInstrumentationTestCase.tearDown()}
+ProtectedMember: android.test.ActivityInstrumentationTestCase2#runTest():
+ Protected methods not allowed; must be public: method android.test.ActivityInstrumentationTestCase2.runTest()}
+ProtectedMember: android.test.ActivityInstrumentationTestCase2#setUp():
+ Protected methods not allowed; must be public: method android.test.ActivityInstrumentationTestCase2.setUp()}
+ProtectedMember: android.test.ActivityInstrumentationTestCase2#tearDown():
+ Protected methods not allowed; must be public: method android.test.ActivityInstrumentationTestCase2.tearDown()}
+ProtectedMember: android.test.ActivityUnitTestCase#setUp():
+ Protected methods not allowed; must be public: method android.test.ActivityUnitTestCase.setUp()}
+ProtectedMember: android.test.ActivityUnitTestCase#tearDown():
+ Protected methods not allowed; must be public: method android.test.ActivityUnitTestCase.tearDown()}
+ProtectedMember: android.test.ApplicationTestCase#setUp():
+ Protected methods not allowed; must be public: method android.test.ApplicationTestCase.setUp()}
+ProtectedMember: android.test.ApplicationTestCase#tearDown():
+ Protected methods not allowed; must be public: method android.test.ApplicationTestCase.tearDown()}
+ProtectedMember: android.test.ProviderTestCase#setUp():
+ Protected methods not allowed; must be public: method android.test.ProviderTestCase.setUp()}
+ProtectedMember: android.test.ProviderTestCase#tearDown():
+ Protected methods not allowed; must be public: method android.test.ProviderTestCase.tearDown()}
+ProtectedMember: android.test.ProviderTestCase2#setUp():
+ Protected methods not allowed; must be public: method android.test.ProviderTestCase2.setUp()}
+ProtectedMember: android.test.ProviderTestCase2#tearDown():
+ Protected methods not allowed; must be public: method android.test.ProviderTestCase2.tearDown()}
+ProtectedMember: android.test.ServiceTestCase#setUp():
+ Protected methods not allowed; must be public: method android.test.ServiceTestCase.setUp()}
+ProtectedMember: android.test.ServiceTestCase#tearDown():
+ Protected methods not allowed; must be public: method android.test.ServiceTestCase.tearDown()}
+ProtectedMember: android.test.SingleLaunchActivityTestCase#setUp():
+ Protected methods not allowed; must be public: method android.test.SingleLaunchActivityTestCase.setUp()}
+ProtectedMember: android.test.SingleLaunchActivityTestCase#tearDown():
+ Protected methods not allowed; must be public: method android.test.SingleLaunchActivityTestCase.tearDown()}
+ProtectedMember: android.test.SyncBaseInstrumentation#setUp():
+ Protected methods not allowed; must be public: method android.test.SyncBaseInstrumentation.setUp()}
diff --git a/tests/net/java/com/android/internal/net/VpnProfileTest.java b/tests/net/java/com/android/internal/net/VpnProfileTest.java
index ceca6f028866..e5daa71c30ea 100644
--- a/tests/net/java/com/android/internal/net/VpnProfileTest.java
+++ b/tests/net/java/com/android/internal/net/VpnProfileTest.java
@@ -33,7 +33,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
/** Unit tests for {@link VpnProfile}. */
@SmallTest
@@ -41,6 +43,9 @@ import java.util.Arrays;
public class VpnProfileTest {
private static final String DUMMY_PROFILE_KEY = "Test";
+ private static final int ENCODED_INDEX_AUTH_PARAMS_INLINE = 23;
+ private static final int ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS = 24;
+
@Test
public void testDefaults() throws Exception {
final VpnProfile p = new VpnProfile(DUMMY_PROFILE_KEY);
@@ -67,10 +72,11 @@ public class VpnProfileTest {
assertFalse(p.isMetered);
assertEquals(1360, p.maxMtu);
assertFalse(p.areAuthParamsInline);
+ assertFalse(p.isRestrictedToTestNetworks);
}
private VpnProfile getSampleIkev2Profile(String key) {
- final VpnProfile p = new VpnProfile(key);
+ final VpnProfile p = new VpnProfile(key, true /* isRestrictedToTestNetworks */);
p.name = "foo";
p.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
@@ -116,7 +122,7 @@ public class VpnProfileTest {
@Test
public void testParcelUnparcel() {
- assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 22);
+ assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 23);
}
@Test
@@ -159,14 +165,41 @@ public class VpnProfileTest {
assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooManyValues));
}
+ private String getEncodedDecodedIkev2ProfileMissingValues(int... missingIndices) {
+ // Sort to ensure when we remove, we can do it from greatest first.
+ Arrays.sort(missingIndices);
+
+ final String encoded = new String(getSampleIkev2Profile(DUMMY_PROFILE_KEY).encode());
+ final List<String> parts =
+ new ArrayList<>(Arrays.asList(encoded.split(VpnProfile.VALUE_DELIMITER)));
+
+ // Remove from back first to ensure indexing is consistent.
+ for (int i = missingIndices.length - 1; i >= 0; i--) {
+ parts.remove(missingIndices[i]);
+ }
+
+ return String.join(VpnProfile.VALUE_DELIMITER, parts.toArray(new String[0]));
+ }
+
@Test
public void testEncodeDecodeInvalidNumberOfValues() {
- final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY);
- final String encoded = new String(profile.encode());
- final byte[] tooFewValues =
- encoded.substring(0, encoded.lastIndexOf(VpnProfile.VALUE_DELIMITER)).getBytes();
+ final String tooFewValues =
+ getEncodedDecodedIkev2ProfileMissingValues(
+ ENCODED_INDEX_AUTH_PARAMS_INLINE,
+ ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */);
- assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues));
+ assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()));
+ }
+
+ @Test
+ public void testEncodeDecodeMissingIsRestrictedToTestNetworks() {
+ final String tooFewValues =
+ getEncodedDecodedIkev2ProfileMissingValues(
+ ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */);
+
+ // Verify decoding without isRestrictedToTestNetworks defaults to false
+ final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes());
+ assertFalse(decoded.isRestrictedToTestNetworks);
}
@Test
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 3282c76290cd..e66e26452602 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -75,6 +75,7 @@ import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import static android.net.RouteInfo.RTN_UNREACHABLE;
+import static android.os.Process.INVALID_UID;
import static android.system.OsConstants.IPPROTO_TCP;
import static com.android.server.ConnectivityServiceTestUtilsKt.transportToLegacyType;
@@ -7048,7 +7049,7 @@ public class ConnectivityServiceTest {
final NetworkAgentInfo naiWithoutUid =
new NetworkAgentInfo(
null, null, null, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0);
+ mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
mServiceContext.setPermission(
android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED);
@@ -7064,7 +7065,7 @@ public class ConnectivityServiceTest {
final NetworkAgentInfo naiWithoutUid =
new NetworkAgentInfo(
null, null, null, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0);
+ mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
@@ -7080,7 +7081,7 @@ public class ConnectivityServiceTest {
final NetworkAgentInfo naiWithoutUid =
new NetworkAgentInfo(
null, null, null, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0);
+ mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
@@ -7097,7 +7098,7 @@ public class ConnectivityServiceTest {
final NetworkAgentInfo naiWithoutUid =
new NetworkAgentInfo(
null, null, network, null, null, new NetworkCapabilities(), 0,
- mServiceContext, null, null, mService, null, null, null, 0);
+ mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID);
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
@@ -7131,7 +7132,7 @@ public class ConnectivityServiceTest {
final NetworkAgentInfo naiWithUid =
new NetworkAgentInfo(
null, null, null, null, null, nc, 0, mServiceContext, null, null,
- mService, null, null, null, 0);
+ mService, null, null, null, 0, INVALID_UID);
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
@@ -7153,7 +7154,7 @@ public class ConnectivityServiceTest {
final NetworkAgentInfo naiWithUid =
new NetworkAgentInfo(
null, null, null, null, null, nc, 0, mServiceContext, null, null,
- mService, null, null, null, 0);
+ mService, null, null, null, 0, INVALID_UID);
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 24a87177224e..aafa18a532fa 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -38,6 +38,7 @@ import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkProvider;
+import android.os.Binder;
import android.os.INetworkManagementService;
import android.text.format.DateUtils;
@@ -354,7 +355,7 @@ public class LingerMonitorTest {
caps.addTransportType(transport);
NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
caps, 50, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS,
- NetworkProvider.ID_NONE);
+ NetworkProvider.ID_NONE, Binder.getCallingUid());
nai.everValidated = true;
return nai;
}
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 77e2a6bb21de..e8970d48e404 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -1669,6 +1669,16 @@ class Linker {
context_->SetCompilationPackage(app_info.package);
}
+ // Determine the package name under which to merge resources.
+ if (options_.rename_resources_package) {
+ if (!options_.custom_java_package) {
+ // Generate the R.java under the original package name instead of the package name specified
+ // through --rename-resources-package.
+ options_.custom_java_package = context_->GetCompilationPackage();
+ }
+ context_->SetCompilationPackage(options_.rename_resources_package.value());
+ }
+
// Now that the compilation package is set, load the dependencies. This will also extract
// the Android framework's versionCode and versionName, if they exist.
if (!LoadSymbolsFromIncludePaths()) {