Merge "Use assumeTrue in VpnTest"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 06d4416..6996ad9 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -28,6 +28,10 @@
"postsubmit": [
{
"name": "TetheringPrivilegedTests"
+ },
+ // TODO: move to presubmit when known green.
+ {
+ "name": "bpf_existence_test"
}
],
"mainline-presubmit": [
@@ -54,6 +58,10 @@
},
{
"name": "TetheringCoverageTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
+ },
+ // TODO: move to mainline-presubmit when known green.
+ {
+ "name": "bpf_existence_test[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
}
],
"imports": [
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index bb435d8..2921e78 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -21,6 +21,7 @@
java_defaults {
name: "TetheringApiLevel",
sdk_version: "module_current",
+ target_sdk_version: "31",
min_sdk_version: "30",
}
diff --git a/Tethering/AndroidManifest.xml b/Tethering/AndroidManifest.xml
index e6444f3..6deb345 100644
--- a/Tethering/AndroidManifest.xml
+++ b/Tethering/AndroidManifest.xml
@@ -19,14 +19,16 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.networkstack.tethering"
android:sharedUserId="android.uid.networkstack">
- <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
<!-- Permissions must be defined here, and not in the base manifest, as the tethering
running in the system server process does not need any permission, and having
privileged permissions added would cause crashes on startup unless they are also
- added to the privileged permissions allowlist for that package. -->
+ added to the privileged permissions allowlist for that package. EntitlementManager
+ would set exact alarm but declare SCHEDULE_EXACT_ALARM is not necessary here because
+ privilege application would be in the allowlist. -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
+ <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
diff --git a/Tethering/tests/integration/Android.bp b/Tethering/tests/integration/Android.bp
index a2bd1a5..d2188d1 100644
--- a/Tethering/tests/integration/Android.bp
+++ b/Tethering/tests/integration/Android.bp
@@ -48,7 +48,7 @@
// Use with NetworkStackJarJarRules.
android_library {
name: "TetheringIntegrationTestsLatestSdkLib",
- target_sdk_version: "30",
+ target_sdk_version: "31",
platform_apis: true,
defaults: ["TetheringIntegrationTestsDefaults"],
visibility: [
@@ -128,7 +128,7 @@
name: "TetheringCoverageTests",
platform_apis: true,
min_sdk_version: "30",
- target_sdk_version: "30",
+ target_sdk_version: "31",
test_suites: ["device-tests", "mts-tethering"],
test_config: "AndroidTest_Coverage.xml",
defaults: ["libnetworkstackutilsjni_deps"],
diff --git a/Tethering/tests/mts/Android.bp b/Tethering/tests/mts/Android.bp
index e51d531..18fd63b 100644
--- a/Tethering/tests/mts/Android.bp
+++ b/Tethering/tests/mts/Android.bp
@@ -22,7 +22,7 @@
name: "MtsTetheringTestLatestSdk",
min_sdk_version: "30",
- target_sdk_version: "30",
+ target_sdk_version: "31",
libs: [
"android.test.base",
diff --git a/Tethering/tests/unit/Android.bp b/Tethering/tests/unit/Android.bp
index 5150d39..ecd1a39 100644
--- a/Tethering/tests/unit/Android.bp
+++ b/Tethering/tests/unit/Android.bp
@@ -87,7 +87,7 @@
static_libs: [
"TetheringApiStableLib",
],
- target_sdk_version: "30",
+ target_sdk_version: "31",
visibility: [
"//packages/modules/Connectivity/tests:__subpackages__",
"//packages/modules/Connectivity/Tethering/tests:__subpackages__",
diff --git a/framework/aidl-export/android/net/ProfileNetworkPreference.aidl b/framework/aidl-export/android/net/ProfileNetworkPreference.aidl
new file mode 100644
index 0000000..d7f2402
--- /dev/null
+++ b/framework/aidl-export/android/net/ProfileNetworkPreference.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable ProfileNetworkPreference;
diff --git a/framework/api/module-lib-current.txt b/framework/api/module-lib-current.txt
index 81a1e5d..fea880a 100644
--- a/framework/api/module-lib-current.txt
+++ b/framework/api/module-lib-current.txt
@@ -19,11 +19,14 @@
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network);
method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setLegacyLockdownVpnEnabled(boolean);
- method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreferences(@NonNull android.os.UserHandle, @NonNull java.util.List<android.net.ProfileNetworkPreference>, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setRequireVpnForUids(boolean, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void startCaptivePortalApp(@NonNull android.net.Network);
method public void systemReady();
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void updateMeteredNetworkAllowList(int, boolean);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void updateMeteredNetworkDenyList(int, boolean);
field public static final String ACTION_CLEAR_DNS_CACHE = "android.net.action.CLEAR_DNS_CACHE";
field public static final String ACTION_PROMPT_LOST_VALIDATION = "android.net.action.PROMPT_LOST_VALIDATION";
field public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY = "android.net.action.PROMPT_PARTIAL_CONNECTIVITY";
@@ -149,6 +152,19 @@
method @NonNull public android.net.NetworkRequest.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
}
+ public final class ProfileNetworkPreference implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getPreference();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.ProfileNetworkPreference> CREATOR;
+ }
+
+ public static final class ProfileNetworkPreference.Builder {
+ ctor public ProfileNetworkPreference.Builder();
+ method @NonNull public android.net.ProfileNetworkPreference build();
+ method @NonNull public android.net.ProfileNetworkPreference.Builder setPreference(int);
+ }
+
public final class TestNetworkInterface implements android.os.Parcelable {
ctor public TestNetworkInterface(@NonNull android.os.ParcelFileDescriptor, @NonNull String);
method public int describeContents();
diff --git a/framework/src/android/net/ConnectivityManager.java b/framework/src/android/net/ConnectivityManager.java
index c21bcfa..465595f 100644
--- a/framework/src/android/net/ConnectivityManager.java
+++ b/framework/src/android/net/ConnectivityManager.java
@@ -1101,7 +1101,7 @@
PROFILE_NETWORK_PREFERENCE_DEFAULT,
PROFILE_NETWORK_PREFERENCE_ENTERPRISE
})
- public @interface ProfileNetworkPreference {
+ public @interface ProfileNetworkPreferencePolicy {
}
/**
@@ -5461,6 +5461,8 @@
* @param listener an optional listener to listen for completion of the operation.
* @throws IllegalArgumentException if {@code profile} is not a valid user profile.
* @throws SecurityException if missing the appropriate permissions.
+ * @deprecated Use {@link #setProfileNetworkPreferences(UserHandle, List, Executor, Runnable)}
+ * instead as it provides a more flexible API with more options.
* @hide
*/
// This function is for establishing per-profile default networking and can only be called by
@@ -5470,8 +5472,45 @@
@SuppressLint({"UserHandle"})
@SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
+ @Deprecated
public void setProfileNetworkPreference(@NonNull final UserHandle profile,
- @ProfileNetworkPreference final int preference,
+ @ProfileNetworkPreferencePolicy final int preference,
+ @Nullable @CallbackExecutor final Executor executor,
+ @Nullable final Runnable listener) {
+
+ ProfileNetworkPreference.Builder preferenceBuilder =
+ new ProfileNetworkPreference.Builder();
+ preferenceBuilder.setPreference(preference);
+ setProfileNetworkPreferences(profile,
+ List.of(preferenceBuilder.build()), executor, listener);
+ }
+
+ /**
+ * Set a list of default network selection policies for a user profile.
+ *
+ * Calling this API with a user handle defines the entire policy for that user handle.
+ * It will overwrite any setting previously set for the same user profile,
+ * and not affect previously set settings for other handles.
+ *
+ * Call this API with an empty list to remove settings for this user profile.
+ *
+ * See {@link ProfileNetworkPreference} for more details on each preference
+ * parameter.
+ *
+ * @param profile the user profile for which the preference is being set.
+ * @param profileNetworkPreferences the list of profile network preferences for the
+ * provided profile.
+ * @param executor an executor to execute the listener on. Optional if listener is null.
+ * @param listener an optional listener to listen for completion of the operation.
+ * @throws IllegalArgumentException if {@code profile} is not a valid user profile.
+ * @throws SecurityException if missing the appropriate permissions.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
+ public void setProfileNetworkPreferences(
+ @NonNull final UserHandle profile,
+ @NonNull List<ProfileNetworkPreference> profileNetworkPreferences,
@Nullable @CallbackExecutor final Executor executor,
@Nullable final Runnable listener) {
if (null != listener) {
@@ -5489,7 +5528,7 @@
};
}
try {
- mService.setProfileNetworkPreference(profile, preference, proxy);
+ mService.setProfileNetworkPreferences(profile, profileNetworkPreferences, proxy);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -5511,4 +5550,48 @@
public static Range<Integer> getIpSecNetIdRange() {
return new Range(TUN_INTF_NETID_START, TUN_INTF_NETID_START + TUN_INTF_NETID_RANGE - 1);
}
+
+ /**
+ * Allow target application using metered network.
+ *
+ * @param uid uid of target app
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+ })
+ public void updateMeteredNetworkAllowList(final int uid, final boolean add) {
+ try {
+ mService.updateMeteredNetworkAllowList(uid, add);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (IllegalStateException ie) {
+ throw ie;
+ }
+ }
+
+ /**
+ * Disallow target application using metered network.
+ *
+ * @param uid uid of target app
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK
+ })
+ public void updateMeteredNetworkDenyList(final int uid, final boolean add) {
+ try {
+ mService.updateMeteredNetworkDenyList(uid, add);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (IllegalStateException ie) {
+ throw ie;
+ }
+ }
}
diff --git a/framework/src/android/net/IConnectivityManager.aidl b/framework/src/android/net/IConnectivityManager.aidl
index 50ec781..5740d85 100644
--- a/framework/src/android/net/IConnectivityManager.aidl
+++ b/framework/src/android/net/IConnectivityManager.aidl
@@ -36,6 +36,7 @@
import android.net.NetworkState;
import android.net.NetworkStateSnapshot;
import android.net.OemNetworkPreferences;
+import android.net.ProfileNetworkPreference;
import android.net.ProxyInfo;
import android.net.UidRange;
import android.net.QosSocketInfo;
@@ -218,7 +219,8 @@
void setOemNetworkPreference(in OemNetworkPreferences preference,
in IOnCompleteListener listener);
- void setProfileNetworkPreference(in UserHandle profile, int preference,
+ void setProfileNetworkPreferences(in UserHandle profile,
+ in List<ProfileNetworkPreference> preferences,
in IOnCompleteListener listener);
int getRestrictBackgroundStatusByCaller();
@@ -228,4 +230,8 @@
void unofferNetwork(in INetworkOfferCallback callback);
void setTestAllowBadWifiUntil(long timeMs);
+
+ void updateMeteredNetworkAllowList(int uid, boolean add);
+
+ void updateMeteredNetworkDenyList(int uid, boolean add);
}
diff --git a/framework/src/android/net/ProfileNetworkPreference.java b/framework/src/android/net/ProfileNetworkPreference.java
new file mode 100644
index 0000000..d580209
--- /dev/null
+++ b/framework/src/android/net/ProfileNetworkPreference.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.net.ConnectivityManager.ProfileNetworkPreferencePolicy;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Network preferences to be set for the user profile
+ * {@link ProfileNetworkPreferencePolicy}.
+ * @hide
+ */
+@SystemApi(client = MODULE_LIBRARIES)
+public final class ProfileNetworkPreference implements Parcelable {
+ private final @ProfileNetworkPreferencePolicy int mPreference;
+
+ private ProfileNetworkPreference(int preference) {
+ mPreference = preference;
+ }
+
+ private ProfileNetworkPreference(Parcel in) {
+ mPreference = in.readInt();
+ }
+
+ public int getPreference() {
+ return mPreference;
+ }
+
+ @Override
+ public String toString() {
+ return "ProfileNetworkPreference{"
+ + "mPreference=" + getPreference()
+ + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ final ProfileNetworkPreference that = (ProfileNetworkPreference) o;
+ return mPreference == that.mPreference;
+ }
+
+ @Override
+ public int hashCode() {
+ return (mPreference);
+ }
+
+ /**
+ * Builder used to create {@link ProfileNetworkPreference} objects.
+ * Specify the preferred Network preference
+ */
+ public static final class Builder {
+ private @ProfileNetworkPreferencePolicy int mPreference =
+ PROFILE_NETWORK_PREFERENCE_DEFAULT;
+
+ /**
+ * Constructs an empty Builder with PROFILE_NETWORK_PREFERENCE_DEFAULT profile preference
+ */
+ public Builder() {}
+
+ /**
+ * Set the profile network preference
+ * See the documentation for the individual preferences for a description of the supported
+ * behaviors. Default value is PROFILE_NETWORK_PREFERENCE_DEFAULT.
+ * @param preference the desired network preference to use
+ * @return The builder to facilitate chaining.
+ */
+ @NonNull
+ public Builder setPreference(@ProfileNetworkPreferencePolicy int preference) {
+ mPreference = preference;
+ return this;
+ }
+ /**
+ * Returns an instance of {@link ProfileNetworkPreference} created from the
+ * fields set on this builder.
+ */
+ @NonNull
+ public ProfileNetworkPreference build() {
+ return new ProfileNetworkPreference(mPreference);
+ }
+ }
+
+ @Override
+ public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ dest.writeInt(mPreference);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Creator<ProfileNetworkPreference> CREATOR =
+ new Creator<ProfileNetworkPreference>() {
+ @Override
+ public ProfileNetworkPreference[] newArray(int size) {
+ return new ProfileNetworkPreference[size];
+ }
+
+ @Override
+ public ProfileNetworkPreference createFromParcel(
+ @NonNull android.os.Parcel in) {
+ return new ProfileNetworkPreference(in);
+ }
+ };
+}
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index a59b5d6..578fabe 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -166,6 +166,7 @@
import android.net.NetworkWatchlistManager;
import android.net.OemNetworkPreferences;
import android.net.PrivateDnsConfigParcel;
+import android.net.ProfileNetworkPreference;
import android.net.ProxyInfo;
import android.net.QosCallbackException;
import android.net.QosFilter;
@@ -258,7 +259,7 @@
import com.android.server.connectivity.NetworkOffer;
import com.android.server.connectivity.NetworkRanker;
import com.android.server.connectivity.PermissionMonitor;
-import com.android.server.connectivity.ProfileNetworkPreferences;
+import com.android.server.connectivity.ProfileNetworkPreferenceList;
import com.android.server.connectivity.ProxyTracker;
import com.android.server.connectivity.QosCallbackTracker;
@@ -4041,11 +4042,11 @@
config = new NativeNetworkConfig(nai.network.getNetId(), NativeNetworkType.VIRTUAL,
INetd.PERMISSION_NONE,
(nai.networkAgentConfig == null || !nai.networkAgentConfig.allowBypass),
- getVpnType(nai));
+ getVpnType(nai), /*excludeLocalRoutes=*/ false);
} else {
config = new NativeNetworkConfig(nai.network.getNetId(), NativeNetworkType.PHYSICAL,
getNetworkPermission(nai.networkCapabilities), /*secure=*/ false,
- VpnManager.TYPE_VPN_NONE);
+ VpnManager.TYPE_VPN_NONE, /*excludeLocalRoutes=*/ false);
}
mNetd.networkCreate(config);
mDnsResolver.createNetworkCache(nai.network.getNetId());
@@ -5046,9 +5047,10 @@
break;
}
case EVENT_SET_PROFILE_NETWORK_PREFERENCE: {
- final Pair<ProfileNetworkPreferences.Preference, IOnCompleteListener> arg =
- (Pair<ProfileNetworkPreferences.Preference, IOnCompleteListener>)
- msg.obj;
+ final Pair<List<ProfileNetworkPreferenceList.Preference>,
+ IOnCompleteListener> arg =
+ (Pair<List<ProfileNetworkPreferenceList.Preference>,
+ IOnCompleteListener>) msg.obj;
handleSetProfileNetworkPreference(arg.first, arg.second);
break;
}
@@ -5671,7 +5673,8 @@
private void onUserRemoved(@NonNull final UserHandle user) {
mPermissionMonitor.onUserRemoved(user);
// If there was a network preference for this user, remove it.
- handleSetProfileNetworkPreference(new ProfileNetworkPreferences.Preference(user, null),
+ handleSetProfileNetworkPreference(
+ List.of(new ProfileNetworkPreferenceList.Preference(user, null)),
null /* listener */);
if (mOemNetworkPreferences.getNetworkPreferences().size() > 0) {
handleSetOemNetworkPreference(mOemNetworkPreferences, null);
@@ -6605,7 +6608,8 @@
// Current per-profile network preferences. This object follows the same threading rules as
// the OEM network preferences above.
@NonNull
- private ProfileNetworkPreferences mProfileNetworkPreferences = new ProfileNetworkPreferences();
+ private ProfileNetworkPreferenceList mProfileNetworkPreferences =
+ new ProfileNetworkPreferenceList();
// A set of UIDs that should use mobile data preferentially if available. This object follows
// the same threading rules as the OEM network preferences above.
@@ -10103,19 +10107,26 @@
* See the documentation for the individual preferences for a description of the supported
* behaviors.
*
- * @param profile the profile concerned.
- * @param preference the preference for this profile, as one of the PROFILE_NETWORK_PREFERENCE_*
- * constants.
+ * @param profile the user profile for whih the preference is being set.
+ * @param preferences the list of profile network preferences for the
+ * provided profile.
* @param listener an optional listener to listen for completion of the operation.
*/
@Override
- public void setProfileNetworkPreference(@NonNull final UserHandle profile,
- @ConnectivityManager.ProfileNetworkPreference final int preference,
+ public void setProfileNetworkPreferences(
+ @NonNull final UserHandle profile,
+ @NonNull List<ProfileNetworkPreference> preferences,
@Nullable final IOnCompleteListener listener) {
+ Objects.requireNonNull(preferences);
Objects.requireNonNull(profile);
+
+ if (preferences.size() == 0) {
+ preferences.add((new ProfileNetworkPreference.Builder()).build());
+ }
+
PermissionUtils.enforceNetworkStackPermission(mContext);
if (DBG) {
- log("setProfileNetworkPreference " + profile + " to " + preference);
+ log("setProfileNetworkPreferences " + profile + " to " + preferences);
}
if (profile.getIdentifier() < 0) {
throw new IllegalArgumentException("Must explicitly specify a user handle ("
@@ -10126,23 +10137,29 @@
throw new IllegalArgumentException("Profile must be a managed profile");
}
- final NetworkCapabilities nc;
- switch (preference) {
- case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT:
- nc = null;
- break;
- case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE:
- final UidRange uids = UidRange.createForUser(profile);
- nc = createDefaultNetworkCapabilitiesForUidRange(uids);
- nc.addCapability(NET_CAPABILITY_ENTERPRISE);
- nc.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
- break;
- default:
- throw new IllegalArgumentException(
- "Invalid preference in setProfileNetworkPreference");
+ final List<ProfileNetworkPreferenceList.Preference> preferenceList =
+ new ArrayList<ProfileNetworkPreferenceList.Preference>();
+ for (final ProfileNetworkPreference preference : preferences) {
+ final NetworkCapabilities nc;
+ switch (preference.getPreference()) {
+ case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_DEFAULT:
+ nc = null;
+ break;
+ case ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE:
+ final UidRange uids = UidRange.createForUser(profile);
+ nc = createDefaultNetworkCapabilitiesForUidRange(uids);
+ nc.addCapability(NET_CAPABILITY_ENTERPRISE);
+ nc.removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Invalid preference in setProfileNetworkPreferences");
+ }
+ preferenceList.add(
+ new ProfileNetworkPreferenceList.Preference(profile, nc));
}
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_PROFILE_NETWORK_PREFERENCE,
- new Pair<>(new ProfileNetworkPreferences.Preference(profile, nc), listener)));
+ new Pair<>(preferenceList, listener)));
}
private void validateNetworkCapabilitiesOfProfileNetworkPreference(
@@ -10152,9 +10169,9 @@
}
private ArraySet<NetworkRequestInfo> createNrisFromProfileNetworkPreferences(
- @NonNull final ProfileNetworkPreferences prefs) {
+ @NonNull final ProfileNetworkPreferenceList prefs) {
final ArraySet<NetworkRequestInfo> result = new ArraySet<>();
- for (final ProfileNetworkPreferences.Preference pref : prefs.preferences) {
+ for (final ProfileNetworkPreferenceList.Preference pref : prefs.preferences) {
// The NRI for a user should be comprised of two layers:
// - The request for the capabilities
// - The request for the default network, for fallback. Create an image of it to
@@ -10175,11 +10192,12 @@
}
private void handleSetProfileNetworkPreference(
- @NonNull final ProfileNetworkPreferences.Preference preference,
+ @NonNull final List<ProfileNetworkPreferenceList.Preference> preferenceList,
@Nullable final IOnCompleteListener listener) {
- validateNetworkCapabilitiesOfProfileNetworkPreference(preference.capabilities);
-
- mProfileNetworkPreferences = mProfileNetworkPreferences.plus(preference);
+ for (final ProfileNetworkPreferenceList.Preference preference : preferenceList) {
+ validateNetworkCapabilitiesOfProfileNetworkPreference(preference.capabilities);
+ mProfileNetworkPreferences = mProfileNetworkPreferences.plus(preference);
+ }
removeDefaultNetworkRequestsForPreference(PREFERENCE_ORDER_PROFILE);
addPerAppDefaultNetworkRequests(
createNrisFromProfileNetworkPreferences(mProfileNetworkPreferences));
@@ -10562,4 +10580,34 @@
return createNetworkRequest(NetworkRequest.Type.REQUEST, netcap);
}
}
+
+ @Override
+ public void updateMeteredNetworkAllowList(final int uid, final boolean add) {
+ enforceNetworkStackOrSettingsPermission();
+
+ try {
+ if (add) {
+ mNetd.bandwidthAddNiceApp(uid);
+ } else {
+ mNetd.bandwidthRemoveNiceApp(uid);
+ }
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ public void updateMeteredNetworkDenyList(final int uid, final boolean add) {
+ enforceNetworkStackOrSettingsPermission();
+
+ try {
+ if (add) {
+ mNetd.bandwidthAddNaughtyApp(uid);
+ } else {
+ mNetd.bandwidthRemoveNaughtyApp(uid);
+ }
+ } catch (RemoteException | ServiceSpecificException e) {
+ throw new IllegalStateException(e);
+ }
+ }
}
diff --git a/service/src/com/android/server/connectivity/ProfileNetworkPreferences.java b/service/src/com/android/server/connectivity/ProfileNetworkPreferenceList.java
similarity index 89%
rename from service/src/com/android/server/connectivity/ProfileNetworkPreferences.java
rename to service/src/com/android/server/connectivity/ProfileNetworkPreferenceList.java
index dd2815d..b345ede 100644
--- a/service/src/com/android/server/connectivity/ProfileNetworkPreferences.java
+++ b/service/src/com/android/server/connectivity/ProfileNetworkPreferenceList.java
@@ -30,7 +30,7 @@
*
* A given profile can only have one preference.
*/
-public class ProfileNetworkPreferences {
+public class ProfileNetworkPreferenceList {
/**
* A single preference, as it applies to a given user profile.
*/
@@ -53,11 +53,11 @@
@NonNull public final List<Preference> preferences;
- public ProfileNetworkPreferences() {
+ public ProfileNetworkPreferenceList() {
preferences = Collections.EMPTY_LIST;
}
- private ProfileNetworkPreferences(@NonNull final List<Preference> list) {
+ private ProfileNetworkPreferenceList(@NonNull final List<Preference> list) {
preferences = Collections.unmodifiableList(list);
}
@@ -68,7 +68,7 @@
* preference. Passing a Preference object containing a null capabilities object is equivalent
* to (and indeed, implemented as) removing the preference for this user.
*/
- public ProfileNetworkPreferences plus(@NonNull final Preference pref) {
+ public ProfileNetworkPreferenceList plus(@NonNull final Preference pref) {
final ArrayList<Preference> newPrefs = new ArrayList<>();
for (final Preference existingPref : preferences) {
if (!existingPref.user.equals(pref.user)) {
@@ -78,7 +78,7 @@
if (null != pref.capabilities) {
newPrefs.add(pref);
}
- return new ProfileNetworkPreferences(newPrefs);
+ return new ProfileNetworkPreferenceList(newPrefs);
}
public boolean isEmpty() {
diff --git a/tests/mts/Android.bp b/tests/mts/Android.bp
new file mode 100644
index 0000000..a56f76e
--- /dev/null
+++ b/tests/mts/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+ name: "bpf_existence_test",
+ test_suites: [
+ "general-tests",
+ "mts-tethering",
+ ],
+ require_root: true,
+ static_libs: [
+ "libbase",
+ "libmodules-utils-build",
+ ],
+ srcs: [
+ "bpf_existence_test.cpp",
+ ],
+ compile_multilib: "first",
+ min_sdk_version: "29", // Ensure test runs on Q and above.
+}
diff --git a/tests/mts/bpf_existence_test.cpp b/tests/mts/bpf_existence_test.cpp
new file mode 100644
index 0000000..5e3df57
--- /dev/null
+++ b/tests/mts/bpf_existence_test.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * bpf_existence_test.cpp - checks that the device runs expected BPF programs
+ */
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include <android-base/strings.h>
+#include <android-base/properties.h>
+#include <android-modules-utils/sdk_level.h>
+
+#include <gtest/gtest.h>
+
+using std::find;
+using std::string;
+using std::vector;
+
+using android::modules::sdklevel::IsAtLeastR;
+using android::modules::sdklevel::IsAtLeastS;
+using android::modules::sdklevel::IsAtLeastT;
+
+class BpfExistenceTest : public ::testing::Test {
+};
+
+static const vector<string> INTRODUCED_R = {
+ "/sys/fs/bpf/prog_offload_schedcls_ingress_tether_ether",
+ "/sys/fs/bpf/prog_offload_schedcls_ingress_tether_rawip",
+};
+
+static const vector<string> INTRODUCED_S = {
+ "/sys/fs/bpf/tethering/prog_offload_schedcls_tether_downstream4_ether",
+ "/sys/fs/bpf/tethering/prog_offload_schedcls_tether_downstream4_rawip",
+ "/sys/fs/bpf/tethering/prog_offload_schedcls_tether_downstream6_ether",
+ "/sys/fs/bpf/tethering/prog_offload_schedcls_tether_downstream6_rawip",
+ "/sys/fs/bpf/tethering/prog_offload_schedcls_tether_upstream4_ether",
+ "/sys/fs/bpf/tethering/prog_offload_schedcls_tether_upstream4_rawip",
+ "/sys/fs/bpf/tethering/prog_offload_schedcls_tether_upstream6_ether",
+ "/sys/fs/bpf/tethering/prog_offload_schedcls_tether_upstream6_rawip",
+};
+
+static const vector<string> REMOVED_S = {
+ "/sys/fs/bpf/prog_offload_schedcls_ingress_tether_ether",
+ "/sys/fs/bpf/prog_offload_schedcls_ingress_tether_rawip",
+};
+
+static const vector<string> INTRODUCED_T = {
+};
+
+static const vector<string> REMOVED_T = {
+};
+
+void addAll(vector<string>* a, const vector<string>& b) {
+ a->insert(a->end(), b.begin(), b.end());
+}
+
+void removeAll(vector<string>* a, const vector<string> b) {
+ for (const auto& toRemove : b) {
+ auto iter = find(a->begin(), a->end(), toRemove);
+ while (iter != a->end()) {
+ a->erase(iter);
+ iter = find(a->begin(), a->end(), toRemove);
+ }
+ }
+}
+
+void getFileLists(vector<string>* expected, vector<string>* unexpected) {
+ unexpected->clear();
+ expected->clear();
+
+ addAll(unexpected, INTRODUCED_R);
+ addAll(unexpected, INTRODUCED_S);
+ addAll(unexpected, INTRODUCED_T);
+
+ if (IsAtLeastR()) {
+ addAll(expected, INTRODUCED_R);
+ removeAll(unexpected, INTRODUCED_R);
+ // Nothing removed in R.
+ }
+
+ if (IsAtLeastS()) {
+ addAll(expected, INTRODUCED_S);
+ removeAll(expected, REMOVED_S);
+
+ addAll(unexpected, REMOVED_S);
+ removeAll(unexpected, INTRODUCED_S);
+ }
+
+ // Nothing added or removed in SCv2.
+
+ if (IsAtLeastT()) {
+ addAll(expected, INTRODUCED_T);
+ removeAll(expected, REMOVED_T);
+
+ addAll(unexpected, REMOVED_T);
+ removeAll(unexpected, INTRODUCED_T);
+ }
+}
+
+void checkFiles() {
+ vector<string> mustExist;
+ vector<string> mustNotExist;
+
+ getFileLists(&mustExist, &mustNotExist);
+
+ for (const auto& file : mustExist) {
+ EXPECT_EQ(0, access(file.c_str(), R_OK)) << file << " does not exist";
+ }
+ for (const auto& file : mustNotExist) {
+ int ret = access(file.c_str(), R_OK);
+ int err = errno;
+ EXPECT_EQ(-1, ret) << file << " unexpectedly exists";
+ if (ret == -1) {
+ EXPECT_EQ(ENOENT, err) << " accessing " << file << " failed with errno " << err;
+ }
+ }
+}
+
+TEST_F(BpfExistenceTest, TestPrograms) {
+ // Pre-flight check to ensure test has been updated.
+ uint64_t buildVersionSdk = android::base::GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
+ ASSERT_NE(0, buildVersionSdk) << "Unable to determine device SDK version";
+ if (buildVersionSdk > 33 && buildVersionSdk != 10000) {
+ FAIL() << "Unknown OS version " << buildVersionSdk << ", please update this test";
+ }
+
+ // Only unconfined root is guaranteed to be able to access everything in /sys/fs/bpf.
+ ASSERT_EQ(0, getuid()) << "This test must run as root.";
+
+ checkFiles();
+}
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index c47604c..8d91552 100644
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -3386,12 +3386,12 @@
private NativeNetworkConfig nativeNetworkConfigPhysical(int netId, int permission) {
return new NativeNetworkConfig(netId, NativeNetworkType.PHYSICAL, permission,
- /*secure=*/ false, VpnManager.TYPE_VPN_NONE);
+ /*secure=*/ false, VpnManager.TYPE_VPN_NONE, /*excludeLocalRoutes=*/ false);
}
private NativeNetworkConfig nativeNetworkConfigVpn(int netId, boolean secure, int vpnType) {
return new NativeNetworkConfig(netId, NativeNetworkType.VIRTUAL, INetd.PERMISSION_NONE,
- secure, vpnType);
+ secure, vpnType, /*excludeLocalRoutes=*/ false);
}
@Test
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
index d82a756..40587c5 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -41,7 +41,6 @@
import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.SET_FOREGROUND;
-import static android.net.NetworkStats.STATS_PER_UID;
import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
@@ -86,7 +85,7 @@
import android.content.Intent;
import android.database.ContentObserver;
import android.net.DataUsageRequest;
-import android.net.INetworkManagementEventObserver;
+import android.net.INetd;
import android.net.INetworkStatsSession;
import android.net.LinkProperties;
import android.net.Network;
@@ -96,6 +95,7 @@
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TelephonyNetworkSpecifier;
+import android.net.TetherStatsParcel;
import android.net.TetheringManager;
import android.net.UnderlyingNetworkInfo;
import android.net.netstats.provider.INetworkStatsProviderCallback;
@@ -105,7 +105,6 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
-import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
@@ -120,6 +119,7 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.test.BroadcastInterceptingContext;
+import com.android.server.net.NetworkStatsService.AlertObserver;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
import com.android.testutils.DevSdkIgnoreRule;
@@ -184,7 +184,7 @@
private MockContext mServiceContext;
private @Mock TelephonyManager mTelephonyManager;
private static @Mock WifiInfo sWifiInfo;
- private @Mock INetworkManagementService mNetManager;
+ private @Mock INetd mNetd;
private @Mock TetheringManager mTetheringManager;
private @Mock NetworkStatsFactory mStatsFactory;
private @Mock NetworkStatsSettings mSettings;
@@ -196,7 +196,7 @@
private NetworkStatsService mService;
private INetworkStatsSession mSession;
- private INetworkManagementEventObserver mNetworkObserver;
+ private AlertObserver mAlertObserver;
private ContentObserver mContentObserver;
private Handler mHandler;
private TetheringManager.TetheringEventCallback mTetheringEventCallback;
@@ -243,6 +243,20 @@
return currentTimeMillis();
}
};
+
+ @NonNull
+ private static TetherStatsParcel buildTetherStatsParcel(String iface, long rxBytes,
+ long rxPackets, long txBytes, long txPackets, int ifIndex) {
+ TetherStatsParcel parcel = new TetherStatsParcel();
+ parcel.iface = iface;
+ parcel.rxBytes = rxBytes;
+ parcel.rxPackets = rxPackets;
+ parcel.txBytes = txBytes;
+ parcel.txPackets = txPackets;
+ parcel.ifIndex = ifIndex;
+ return parcel;
+ }
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -258,7 +272,7 @@
mHandlerThread = new HandlerThread("HandlerThread");
final NetworkStatsService.Dependencies deps = makeDependencies();
- mService = new NetworkStatsService(mServiceContext, mNetManager, mAlarmManager, wakeLock,
+ mService = new NetworkStatsService(mServiceContext, mNetd, mAlarmManager, wakeLock,
mClock, mSettings, mStatsFactory, new NetworkStatsObservers(), mStatsDir,
getBaseDir(mStatsDir), deps);
@@ -283,11 +297,11 @@
mSession = mService.openSession();
assertNotNull("openSession() failed", mSession);
- // Catch INetworkManagementEventObserver during systemReady().
- ArgumentCaptor<INetworkManagementEventObserver> networkObserver =
- ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
- verify(mNetManager).registerObserver(networkObserver.capture());
- mNetworkObserver = networkObserver.getValue();
+ // Catch AlertObserver during systemReady().
+ final ArgumentCaptor<AlertObserver> alertObserver =
+ ArgumentCaptor.forClass(AlertObserver.class);
+ verify(mNetd).registerUnsolicitedEventListener(alertObserver.capture());
+ mAlertObserver = alertObserver.getValue();
// Catch TetheringEventCallback during systemReady().
ArgumentCaptor<TetheringManager.TetheringEventCallback> tetheringEventCbCaptor =
@@ -328,7 +342,7 @@
mServiceContext = null;
mStatsDir = null;
- mNetManager = null;
+ mNetd = null;
mSettings = null;
mSession.close();
@@ -1026,13 +1040,15 @@
new UnderlyingNetworkInfo[0]);
NetworkStats.Entry uidStats = new NetworkStats.Entry(
- TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
+ TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L);
// Stacked on matching interface
NetworkStats.Entry tetheredStats1 = new NetworkStats.Entry(
- stackedIface, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
+ stackedIface, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L);
+ TetherStatsParcel tetherStatsParcel1 =
+ buildTetherStatsParcel(stackedIface, 1024L, 8L, 512L, 4L, 0);
// Different interface
- NetworkStats.Entry tetheredStats2 = new NetworkStats.Entry(
- "otherif", UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L);
+ TetherStatsParcel tetherStatsParcel2 =
+ buildTetherStatsParcel("otherif", 1024L, 8L, 512L, 4L, 0);
final String[] ifaceFilter = new String[] { TEST_IFACE };
final String[] augmentedIfaceFilter = new String[] { stackedIface, TEST_IFACE };
@@ -1044,10 +1060,8 @@
when(mStatsFactory.readNetworkStatsDetail(eq(UID_ALL), any(), eq(TAG_ALL)))
.thenReturn(new NetworkStats(getElapsedRealtime(), 1)
.insertEntry(uidStats));
- when(mNetManager.getNetworkStatsTethering(STATS_PER_UID))
- .thenReturn(new NetworkStats(getElapsedRealtime(), 2)
- .insertEntry(tetheredStats1)
- .insertEntry(tetheredStats2));
+ final TetherStatsParcel[] tetherStatsParcels = {tetherStatsParcel1, tetherStatsParcel2};
+ when(mNetd.tetherGetStats()).thenReturn(tetherStatsParcels);
NetworkStats stats = mService.getDetailedUidStats(ifaceFilter);
@@ -1249,12 +1263,11 @@
final NetworkStats localUidStats = new NetworkStats(now, 1)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L);
// Software per-uid tethering traffic.
- final NetworkStats tetherSwUidStats = new NetworkStats(now, 1)
- .insertEntry(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1408L, 10L, 256L, 1L,
- 0L);
+ final TetherStatsParcel[] tetherStatsParcels =
+ {buildTetherStatsParcel(TEST_IFACE, 1408L, 10L, 256L, 1L, 0)};
expectNetworkStatsSummary(swIfaceStats);
- expectNetworkStatsUidDetail(localUidStats, tetherSwUidStats);
+ expectNetworkStatsUidDetail(localUidStats, tetherStatsParcels);
forcePollAndWaitForIdle();
// verify service recorded history
@@ -1748,16 +1761,17 @@
}
private void expectNetworkStatsUidDetail(NetworkStats detail) throws Exception {
- expectNetworkStatsUidDetail(detail, new NetworkStats(0L, 0));
+ final TetherStatsParcel[] tetherStatsParcels = {};
+ expectNetworkStatsUidDetail(detail, tetherStatsParcels);
}
- private void expectNetworkStatsUidDetail(NetworkStats detail, NetworkStats tetherStats)
- throws Exception {
+ private void expectNetworkStatsUidDetail(NetworkStats detail,
+ TetherStatsParcel[] tetherStatsParcels) throws Exception {
when(mStatsFactory.readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL))
.thenReturn(detail);
// also include tethering details, since they are folded into UID
- when(mNetManager.getNetworkStatsTethering(STATS_PER_UID)).thenReturn(tetherStats);
+ when(mNetd.tetherGetStats()).thenReturn(tetherStatsParcels);
}
private void expectDefaultSettings() throws Exception {