Merge "Improve dumpsys logs for NetworkProvider and NetworkOffer"
diff --git a/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java b/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java
index 22d2c5d..b865a8e 100644
--- a/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java
+++ b/Tethering/apishim/30/com/android/networkstack/tethering/apishim/api30/BpfCoordinatorShimImpl.java
@@ -30,9 +30,9 @@
import com.android.net.module.util.IBpfMap.ThrowingBiConsumer;
import com.android.net.module.util.bpf.Tether4Key;
import com.android.net.module.util.bpf.Tether4Value;
+import com.android.net.module.util.bpf.TetherStatsValue;
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
-import com.android.networkstack.tethering.TetherStatsValue;
/**
* Bpf coordinator class for API shims.
diff --git a/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java b/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
index 5afb862..0683e5e 100644
--- a/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
+++ b/Tethering/apishim/31/com/android/networkstack/tethering/apishim/api31/BpfCoordinatorShimImpl.java
@@ -33,6 +33,8 @@
import com.android.net.module.util.IBpfMap.ThrowingBiConsumer;
import com.android.net.module.util.bpf.Tether4Key;
import com.android.net.module.util.bpf.Tether4Value;
+import com.android.net.module.util.bpf.TetherStatsKey;
+import com.android.net.module.util.bpf.TetherStatsValue;
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
import com.android.networkstack.tethering.BpfUtils;
@@ -42,8 +44,6 @@
import com.android.networkstack.tethering.TetherDownstream6Key;
import com.android.networkstack.tethering.TetherLimitKey;
import com.android.networkstack.tethering.TetherLimitValue;
-import com.android.networkstack.tethering.TetherStatsKey;
-import com.android.networkstack.tethering.TetherStatsValue;
import com.android.networkstack.tethering.TetherUpstream6Key;
import java.io.FileDescriptor;
diff --git a/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java b/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
index 915e210..69cbab5 100644
--- a/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
+++ b/Tethering/apishim/common/com/android/networkstack/tethering/apishim/common/BpfCoordinatorShim.java
@@ -25,9 +25,9 @@
import com.android.net.module.util.IBpfMap.ThrowingBiConsumer;
import com.android.net.module.util.bpf.Tether4Key;
import com.android.net.module.util.bpf.Tether4Value;
+import com.android.net.module.util.bpf.TetherStatsValue;
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
-import com.android.networkstack.tethering.TetherStatsValue;
/**
* Bpf coordinator class for API shims.
diff --git a/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl b/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
index b4e3ba4..836761f 100644
--- a/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
+++ b/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
@@ -36,4 +36,5 @@
void onTetherStatesChanged(in TetherStatesParcel states);
void onTetherClientsChanged(in List<TetheredClient> clients);
void onOffloadStatusChanged(int status);
+ void onSupportedTetheringTypes(long supportedBitmap);
}
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl b/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
index 253eacb..f33f846 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
@@ -26,7 +26,7 @@
* @hide
*/
parcelable TetheringCallbackStartedParcel {
- boolean tetheringSupported;
+ long supportedTypes;
Network upstreamNetwork;
TetheringConfigurationParcel config;
TetherStatesParcel states;
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 6f9b33e..b3f0cf2 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -183,6 +183,12 @@
*/
public static final int TETHERING_WIGIG = 6;
+ /**
+ * The int value of last tethering type.
+ * @hide
+ */
+ public static final int MAX_TETHERING_TYPE = TETHERING_WIGIG;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
@@ -520,6 +526,9 @@
}
@Override
+ public void onSupportedTetheringTypes(long supportedBitmap) { }
+
+ @Override
public void onUpstreamChanged(Network network) { }
@Override
@@ -1033,15 +1042,29 @@
/**
* Called when tethering supported status changed.
*
+ * <p>This callback will be called immediately after the callback is
+ * registered, and never be called if there is changes afterward.
+ *
+ * <p>Tethering may be disabled via system properties, device configuration, or device
+ * policy restrictions.
+ *
+ * @param supported whether any tethering type is supported.
+ */
+ default void onTetheringSupported(boolean supported) {}
+
+ /**
+ * Called when tethering supported status changed.
+ *
* <p>This will be called immediately after the callback is registered, and may be called
* multiple times later upon changes.
*
* <p>Tethering may be disabled via system properties, device configuration, or device
* policy restrictions.
*
- * @param supported The new supported status
+ * @param supportedTypes a set of @TetheringType which is supported.
+ * @hide
*/
- default void onTetheringSupported(boolean supported) {}
+ default void onSupportedTetheringTypes(@NonNull Set<Integer> supportedTypes) {}
/**
* Called when tethering upstream changed.
@@ -1339,7 +1362,8 @@
@Override
public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
executor.execute(() -> {
- callback.onTetheringSupported(parcel.tetheringSupported);
+ callback.onSupportedTetheringTypes(unpackBits(parcel.supportedTypes));
+ callback.onTetheringSupported(parcel.supportedTypes != 0);
callback.onUpstreamChanged(parcel.upstreamNetwork);
sendErrorCallbacks(parcel.states);
sendRegexpsChanged(parcel.config);
@@ -1358,6 +1382,13 @@
});
}
+ @Override
+ public void onSupportedTetheringTypes(long supportedBitmap) {
+ executor.execute(() -> {
+ callback.onSupportedTetheringTypes(unpackBits(supportedBitmap));
+ });
+ }
+
private void sendRegexpsChanged(TetheringConfigurationParcel parcel) {
callback.onTetherableInterfaceRegexpsChanged(new TetheringInterfaceRegexps(
parcel.tetherableBluetoothRegexs,
@@ -1396,6 +1427,23 @@
}
/**
+ * Unpack bitmap to a set of bit position intergers.
+ * @hide
+ */
+ public static ArraySet<Integer> unpackBits(long val) {
+ final ArraySet<Integer> result = new ArraySet<>(Long.bitCount(val));
+ int bitPos = 0;
+ while (val != 0) {
+ if ((val & 1) == 1) result.add(bitPos);
+
+ val = val >>> 1;
+ bitPos++;
+ }
+
+ return result;
+ }
+
+ /**
* Remove tethering event callback previously registered with
* {@link #registerTetheringEventCallback}.
*
diff --git a/Tethering/proguard.flags b/Tethering/proguard.flags
index 7b5ae0d..2905e28 100644
--- a/Tethering/proguard.flags
+++ b/Tethering/proguard.flags
@@ -12,6 +12,11 @@
native <methods>;
}
+# Ensure runtime-visible field annotations are kept when using R8 full mode.
+-keepattributes RuntimeVisibleAnnotations,AnnotationDefault
+-keep interface com.android.networkstack.tethering.util.Struct$Field {
+ *;
+}
-keepclassmembers public class * extends com.android.networkstack.tethering.util.Struct {
*;
}
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index f8a1094..60949a2 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -65,9 +65,12 @@
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.InterfaceParams;
import com.android.net.module.util.NetworkStackConstants;
+import com.android.net.module.util.Struct;
import com.android.net.module.util.Struct.U32;
import com.android.net.module.util.bpf.Tether4Key;
import com.android.net.module.util.bpf.Tether4Value;
+import com.android.net.module.util.bpf.TetherStatsKey;
+import com.android.net.module.util.bpf.TetherStatsValue;
import com.android.net.module.util.netlink.ConntrackMessage;
import com.android.net.module.util.netlink.NetlinkConstants;
import com.android.net.module.util.netlink.NetlinkSocket;
@@ -118,6 +121,7 @@
private static final String TETHER_LIMIT_MAP_PATH = makeMapPath("limit");
private static final String TETHER_ERROR_MAP_PATH = makeMapPath("error");
private static final String TETHER_DEV_MAP_PATH = makeMapPath("dev");
+ private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4";
// Using "," as a separator is safe because base64 characters are [0-9a-zA-Z/=+].
private static final String DUMP_BASE64_DELIMITER = ",";
@@ -1072,7 +1076,8 @@
}
}
- private String ipv4RuleToBase64String(Tether4Key key, Tether4Value value) {
+ private <K extends Struct, V extends Struct> String bpfMapEntryToBase64String(
+ final K key, final V value) {
final byte[] keyBytes = key.writeToBytes();
final String keyBase64Str = Base64.encodeToString(keyBytes, Base64.DEFAULT)
.replace("\n", "");
@@ -1093,18 +1098,27 @@
pw.println("No rules");
return;
}
- map.forEach((k, v) -> pw.println(ipv4RuleToBase64String(k, v)));
+ map.forEach((k, v) -> pw.println(bpfMapEntryToBase64String(k, v)));
}
/**
* Dump raw BPF map in base64 encoded strings. For test only.
+ * Only allow to dump one map path once.
+ * Format:
+ * $ dumpsys tethering bpfRawMap --<map name>
*/
- public void dumpRawMap(@NonNull IndentingPrintWriter pw) {
- try (BpfMap<Tether4Key, Tether4Value> upstreamMap = mDeps.getBpfUpstream4Map()) {
- // TODO: dump downstream map.
- dumpRawIpv4ForwardingRuleMap(upstreamMap, pw);
- } catch (ErrnoException e) {
- pw.println("Error dumping IPv4 map: " + e);
+ public void dumpRawMap(@NonNull IndentingPrintWriter pw, @Nullable String[] args) {
+ // TODO: consider checking the arg order that <map name> is after "bpfRawMap". Probably
+ // it is okay for now because this is used by test only and test is supposed to use
+ // expected argument order.
+ // TODO: dump downstream4 map.
+ if (CollectionUtils.contains(args, DUMPSYS_RAWMAP_ARG_UPSTREAM4)) {
+ try (BpfMap<Tether4Key, Tether4Value> upstreamMap = mDeps.getBpfUpstream4Map()) {
+ dumpRawIpv4ForwardingRuleMap(upstreamMap, pw);
+ } catch (ErrnoException e) {
+ pw.println("Error dumping IPv4 map: " + e);
+ }
+ return;
}
}
diff --git a/Tethering/src/com/android/networkstack/tethering/TetherStatsKey.java b/Tethering/src/com/android/networkstack/tethering/TetherStatsKey.java
deleted file mode 100644
index 5442480..0000000
--- a/Tethering/src/com/android/networkstack/tethering/TetherStatsKey.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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 com.android.net.module.util.Struct;
-import com.android.net.module.util.Struct.Field;
-import com.android.net.module.util.Struct.Type;
-
-/** The key of BpfMap which is used for tethering stats. */
-public class TetherStatsKey extends Struct {
- @Field(order = 0, type = Type.U32)
- public final long ifindex; // upstream interface index
-
- public TetherStatsKey(final long ifindex) {
- this.ifindex = ifindex;
- }
-
- // TODO: remove equals, hashCode and toString once aosp/1536721 is merged.
- @Override
- public boolean equals(Object obj) {
- if (this == obj) return true;
-
- if (!(obj instanceof TetherStatsKey)) return false;
-
- final TetherStatsKey that = (TetherStatsKey) obj;
-
- return ifindex == that.ifindex;
- }
-
- @Override
- public int hashCode() {
- return Long.hashCode(ifindex);
- }
-
- @Override
- public String toString() {
- return String.format("ifindex: %d", ifindex);
- }
-}
diff --git a/Tethering/src/com/android/networkstack/tethering/TetherStatsValue.java b/Tethering/src/com/android/networkstack/tethering/TetherStatsValue.java
deleted file mode 100644
index 844d2e8..0000000
--- a/Tethering/src/com/android/networkstack/tethering/TetherStatsValue.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * 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 com.android.net.module.util.Struct;
-import com.android.net.module.util.Struct.Field;
-import com.android.net.module.util.Struct.Type;
-
-/** The key of BpfMap which is used for tethering stats. */
-public class TetherStatsValue extends Struct {
- // Use the signed long variable to store the uint64 stats from stats BPF map.
- // U63 is enough for each data element even at 5Gbps for ~468 years.
- // 2^63 / (5 * 1000 * 1000 * 1000) * 8 / 86400 / 365 = 468.
- @Field(order = 0, type = Type.U63)
- public final long rxPackets;
- @Field(order = 1, type = Type.U63)
- public final long rxBytes;
- @Field(order = 2, type = Type.U63)
- public final long rxErrors;
- @Field(order = 3, type = Type.U63)
- public final long txPackets;
- @Field(order = 4, type = Type.U63)
- public final long txBytes;
- @Field(order = 5, type = Type.U63)
- public final long txErrors;
-
- public TetherStatsValue(final long rxPackets, final long rxBytes, final long rxErrors,
- final long txPackets, final long txBytes, final long txErrors) {
- this.rxPackets = rxPackets;
- this.rxBytes = rxBytes;
- this.rxErrors = rxErrors;
- this.txPackets = txPackets;
- this.txBytes = txBytes;
- this.txErrors = txErrors;
- }
-
- // TODO: remove equals, hashCode and toString once aosp/1536721 is merged.
- @Override
- public boolean equals(Object obj) {
- if (this == obj) return true;
-
- if (!(obj instanceof TetherStatsValue)) return false;
-
- final TetherStatsValue that = (TetherStatsValue) obj;
-
- return rxPackets == that.rxPackets
- && rxBytes == that.rxBytes
- && rxErrors == that.rxErrors
- && txPackets == that.txPackets
- && txBytes == that.txBytes
- && txErrors == that.txErrors;
- }
-
- @Override
- public int hashCode() {
- return Long.hashCode(rxPackets) ^ Long.hashCode(rxBytes) ^ Long.hashCode(rxErrors)
- ^ Long.hashCode(txPackets) ^ Long.hashCode(txBytes) ^ Long.hashCode(txErrors);
- }
-
- @Override
- public String toString() {
- return String.format("rxPackets: %s, rxBytes: %s, rxErrors: %s, txPackets: %s, "
- + "txBytes: %s, txErrors: %s", rxPackets, rxBytes, rxErrors, txPackets,
- txBytes, txErrors);
- }
-}
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 0b607bd..491e0dc 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -278,6 +278,11 @@
private BluetoothPan mBluetoothPan;
private PanServiceListener mBluetoothPanListener;
private ArrayList<Pair<Boolean, IIntResultListener>> mPendingPanRequests;
+ // AIDL doesn't support Set<Integer>. Maintain a int bitmap here. When the bitmap is passed to
+ // TetheringManager, TetheringManager would convert it to a set of Integer types.
+ // mSupportedTypeBitmap should always be updated inside tethering internal thread but it may be
+ // read from binder thread which called TetheringService directly.
+ private volatile long mSupportedTypeBitmap;
public Tethering(TetheringDependencies deps) {
mLog.mark("Tethering.constructed");
@@ -494,6 +499,8 @@
mUpstreamNetworkMonitor.setUpstreamConfig(mConfig.chooseUpstreamAutomatically,
mConfig.isDunRequired);
reportConfigurationChanged(mConfig.toStableParcelable());
+
+ updateSupportedDownstreams(mConfig);
}
private void maybeDunSettingChanged() {
@@ -1513,26 +1520,6 @@
return mConfig;
}
- boolean hasAnySupportedDownstream() {
- if ((mConfig.tetherableUsbRegexs.length != 0)
- || (mConfig.tetherableWifiRegexs.length != 0)
- || (mConfig.tetherableBluetoothRegexs.length != 0)) {
- return true;
- }
-
- // Before T, isTetheringSupported would return true if wifi, usb and bluetooth tethering are
- // disabled (whole tethering settings would be hidden). This means tethering would also not
- // support wifi p2p, ethernet tethering and mirrorlink. This is wrong but probably there are
- // some devices in the field rely on this to disable tethering entirely.
- if (!SdkLevel.isAtLeastT()) return false;
-
- return (mConfig.tetherableWifiP2pRegexs.length != 0)
- || (mConfig.tetherableNcmRegexs.length != 0)
- || isEthernetSupported();
- }
-
- // TODO: using EtherentManager new API to check whether ethernet is supported when the API is
- // ready to use.
private boolean isEthernetSupported() {
return mContext.getSystemService(Context.ETHERNET_SERVICE) != null;
}
@@ -2322,7 +2309,7 @@
mHandler.post(() -> {
mTetheringEventCallbacks.register(callback, new CallbackCookie(hasListPermission));
final TetheringCallbackStartedParcel parcel = new TetheringCallbackStartedParcel();
- parcel.tetheringSupported = isTetheringSupported();
+ parcel.supportedTypes = mSupportedTypeBitmap;
parcel.upstreamNetwork = mTetherUpstream;
parcel.config = mConfig.toStableParcelable();
parcel.states =
@@ -2361,6 +2348,22 @@
});
}
+ private void reportTetheringSupportedChange(final long supportedBitmap) {
+ final int length = mTetheringEventCallbacks.beginBroadcast();
+ try {
+ for (int i = 0; i < length; i++) {
+ try {
+ mTetheringEventCallbacks.getBroadcastItem(i).onSupportedTetheringTypes(
+ supportedBitmap);
+ } catch (RemoteException e) {
+ // Not really very much to do here.
+ }
+ }
+ } finally {
+ mTetheringEventCallbacks.finishBroadcast();
+ }
+ }
+
private void reportUpstreamChanged(UpstreamNetworkState ns) {
final int length = mTetheringEventCallbacks.beginBroadcast();
final Network network = (ns != null) ? ns.network : null;
@@ -2445,18 +2448,56 @@
}
}
+ private void updateSupportedDownstreams(final TetheringConfiguration config) {
+ final long preSupportedBitmap = mSupportedTypeBitmap;
+
+ if (!isTetheringAllowed() || mEntitlementMgr.isProvisioningNeededButUnavailable()) {
+ mSupportedTypeBitmap = 0;
+ } else {
+ mSupportedTypeBitmap = makeSupportedDownstreams(config);
+ }
+
+ if (preSupportedBitmap != mSupportedTypeBitmap) {
+ reportTetheringSupportedChange(mSupportedTypeBitmap);
+ }
+ }
+
+ private long makeSupportedDownstreams(final TetheringConfiguration config) {
+ long types = 0;
+ if (config.tetherableUsbRegexs.length != 0) types |= (1 << TETHERING_USB);
+
+ if (config.tetherableWifiRegexs.length != 0) types |= (1 << TETHERING_WIFI);
+
+ if (config.tetherableBluetoothRegexs.length != 0) types |= (1 << TETHERING_BLUETOOTH);
+
+ // Before T, isTetheringSupported would return true if wifi, usb and bluetooth tethering are
+ // disabled (whole tethering settings would be hidden). This means tethering would also not
+ // support wifi p2p, ethernet tethering and mirrorlink. This is wrong but probably there are
+ // some devices in the field rely on this to disable tethering entirely.
+ if (!SdkLevel.isAtLeastT() && types == 0) return types;
+
+ if (config.tetherableNcmRegexs.length != 0) types |= (1 << TETHERING_NCM);
+
+ if (config.tetherableWifiP2pRegexs.length != 0) types |= (1 << TETHERING_WIFI_P2P);
+
+ if (isEthernetSupported()) types |= (1 << TETHERING_ETHERNET);
+
+ return types;
+ }
+
// 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() {
+ private boolean isTetheringAllowed() {
final int defaultVal = mDeps.isTetheringDenied() ? 0 : 1;
final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.TETHER_SUPPORTED, defaultVal) != 0;
- final boolean tetherEnabledInSettings = tetherSupported
+ return tetherSupported
&& !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
+ }
- return tetherEnabledInSettings && hasAnySupportedDownstream()
- && !mEntitlementMgr.isProvisioningNeededButUnavailable();
+ boolean isTetheringSupported() {
+ return mSupportedTypeBitmap > 0;
}
private void dumpBpf(IndentingPrintWriter pw) {
@@ -2472,9 +2513,8 @@
writer, " ");
// Used for testing instead of human debug.
- // TODO: add options to choose which map to dump.
if (argsContain(args, "bpfRawMap")) {
- mBpfCoordinator.dumpRawMap(pw);
+ mBpfCoordinator.dumpRawMap(pw, args);
return;
}
diff --git a/Tethering/src/com/android/networkstack/tethering/util/TetheringUtils.java b/Tethering/src/com/android/networkstack/tethering/util/TetheringUtils.java
index 66d67a1..e6236df 100644
--- a/Tethering/src/com/android/networkstack/tethering/util/TetheringUtils.java
+++ b/Tethering/src/com/android/networkstack/tethering/util/TetheringUtils.java
@@ -22,7 +22,7 @@
import androidx.annotation.NonNull;
import com.android.net.module.util.JniUtil;
-import com.android.networkstack.tethering.TetherStatsValue;
+import com.android.net.module.util.bpf.TetherStatsValue;
import java.io.FileDescriptor;
import java.net.Inet6Address;
diff --git a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index de81a38..1d71557 100644
--- a/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -136,6 +136,7 @@
ByteBuffer.wrap(new byte[] { (byte) 0x55, (byte) 0xaa });
private static final String DUMPSYS_TETHERING_RAWMAP_ARG = "bpfRawMap";
+ private static final String DUMPSYS_RAWMAP_ARG_UPSTREAM4 = "--upstream4";
private static final String BASE64_DELIMITER = ",";
private static final String LINE_DELIMITER = "\\n";
@@ -168,12 +169,13 @@
mUiAutomation.adoptShellPermissionIdentity(
MANAGE_TEST_NETWORKS, NETWORK_SETTINGS, TETHER_PRIVILEGED, ACCESS_NETWORK_STATE,
CONNECTIVITY_USE_RESTRICTED_NETWORKS, DUMP);
- mRunTests = mTm.isTetheringSupported() && mEm != null;
- assumeTrue(mRunTests);
-
mHandlerThread = new HandlerThread(getClass().getSimpleName());
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
+
+ mRunTests = isEthernetTetheringSupported();
+ assumeTrue(mRunTests);
+
mTetheredInterfaceRequester = new TetheredInterfaceRequester(mHandler, mEm);
}
@@ -201,7 +203,6 @@
mHandler.post(() -> reader.stop());
mDownstreamReader = null;
}
- mHandlerThread.quitSafely();
mTetheredInterfaceRequester.release();
mEm.setIncludeTestInterfaces(false);
maybeDeleteTestInterface();
@@ -212,6 +213,7 @@
try {
if (mRunTests) cleanUp();
} finally {
+ mHandlerThread.quitSafely();
mUiAutomation.dropShellPermissionIdentity();
}
}
@@ -400,6 +402,23 @@
// client, which is not possible in this test.
}
+ private boolean isEthernetTetheringSupported() throws Exception {
+ final CompletableFuture<Boolean> future = new CompletableFuture<>();
+ final TetheringEventCallback callback = new TetheringEventCallback() {
+ @Override
+ public void onSupportedTetheringTypes(Set<Integer> supportedTypes) {
+ future.complete(supportedTypes.contains(TETHERING_ETHERNET));
+ }
+ };
+
+ try {
+ mTm.registerTetheringEventCallback(mHandler::post, callback);
+ return future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } finally {
+ mTm.unregisterTetheringEventCallback(callback);
+ }
+ }
+
private static final class MyTetheringEventCallback implements TetheringEventCallback {
private final TetheringManager mTm;
private final CountDownLatch mTetheringStartedLatch = new CountDownLatch(1);
@@ -938,7 +957,8 @@
return isExpectedUdpPacket(p, false /* hasEther */, PAYLOAD3);
});
- final HashMap<Tether4Key, Tether4Value> upstreamMap = pollIpv4UpstreamMapFromDump();
+ final HashMap<Tether4Key, Tether4Value> upstreamMap = pollRawMapFromDump(
+ Tether4Key.class, Tether4Value.class, DUMPSYS_RAWMAP_ARG_UPSTREAM4);
assertNotNull(upstreamMap);
assertEquals(1, upstreamMap.size());
@@ -1003,7 +1023,8 @@
}
@Nullable
- private Pair<Tether4Key, Tether4Value> parseTether4KeyValue(@NonNull String dumpStr) {
+ private <K extends Struct, V extends Struct> Pair<K, V> parseMapKeyValue(
+ Class<K> keyClass, Class<V> valueClass, @NonNull String dumpStr) {
Log.w(TAG, "Parsing string: " + dumpStr);
String[] keyValueStrs = dumpStr.split(BASE64_DELIMITER);
@@ -1016,36 +1037,38 @@
Log.d(TAG, "keyBytes: " + dumpHexString(keyBytes));
final ByteBuffer keyByteBuffer = ByteBuffer.wrap(keyBytes);
keyByteBuffer.order(ByteOrder.nativeOrder());
- final Tether4Key tether4Key = Struct.parse(Tether4Key.class, keyByteBuffer);
- Log.w(TAG, "tether4Key: " + tether4Key);
+ final K k = Struct.parse(keyClass, keyByteBuffer);
final byte[] valueBytes = Base64.decode(keyValueStrs[1], Base64.DEFAULT);
Log.d(TAG, "valueBytes: " + dumpHexString(valueBytes));
final ByteBuffer valueByteBuffer = ByteBuffer.wrap(valueBytes);
valueByteBuffer.order(ByteOrder.nativeOrder());
- final Tether4Value tether4Value = Struct.parse(Tether4Value.class, valueByteBuffer);
- Log.w(TAG, "tether4Value: " + tether4Value);
+ final V v = Struct.parse(valueClass, valueByteBuffer);
- return new Pair<>(tether4Key, tether4Value);
+ return new Pair<>(k, v);
}
@NonNull
- private HashMap<Tether4Key, Tether4Value> dumpIpv4UpstreamMap() throws Exception {
- final String rawMapStr = DumpTestUtils.dumpService(Context.TETHERING_SERVICE,
- DUMPSYS_TETHERING_RAWMAP_ARG);
- final HashMap<Tether4Key, Tether4Value> map = new HashMap<>();
+ private <K extends Struct, V extends Struct> HashMap<K, V> dumpAndParseRawMap(
+ Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)
+ throws Exception {
+ final String[] args = new String[] {DUMPSYS_TETHERING_RAWMAP_ARG, mapArg};
+ final String rawMapStr = DumpTestUtils.dumpService(Context.TETHERING_SERVICE, args);
+ final HashMap<K, V> map = new HashMap<>();
for (final String line : rawMapStr.split(LINE_DELIMITER)) {
- final Pair<Tether4Key, Tether4Value> rule = parseTether4KeyValue(line.trim());
+ final Pair<K, V> rule = parseMapKeyValue(keyClass, valueClass, line.trim());
map.put(rule.first, rule.second);
}
return map;
}
@Nullable
- private HashMap<Tether4Key, Tether4Value> pollIpv4UpstreamMapFromDump() throws Exception {
+ private <K extends Struct, V extends Struct> HashMap<K, V> pollRawMapFromDump(
+ Class<K> keyClass, Class<V> valueClass, @NonNull String mapArg)
+ throws Exception {
for (int retryCount = 0; retryCount < DUMP_POLLING_MAX_RETRY; retryCount++) {
- final HashMap<Tether4Key, Tether4Value> map = dumpIpv4UpstreamMap();
+ final HashMap<K, V> map = dumpAndParseRawMap(keyClass, valueClass, mapArg);
if (!map.isEmpty()) return map;
Thread.sleep(DUMP_POLLING_INTERVAL_MS);
diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 43f1eaa..aac531a 100644
--- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -103,6 +103,8 @@
import com.android.net.module.util.NetworkStackConstants;
import com.android.net.module.util.bpf.Tether4Key;
import com.android.net.module.util.bpf.Tether4Value;
+import com.android.net.module.util.bpf.TetherStatsKey;
+import com.android.net.module.util.bpf.TetherStatsValue;
import com.android.networkstack.tethering.BpfCoordinator;
import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
import com.android.networkstack.tethering.PrivateAddressCoordinator;
@@ -112,8 +114,6 @@
import com.android.networkstack.tethering.TetherDownstream6Key;
import com.android.networkstack.tethering.TetherLimitKey;
import com.android.networkstack.tethering.TetherLimitValue;
-import com.android.networkstack.tethering.TetherStatsKey;
-import com.android.networkstack.tethering.TetherStatsValue;
import com.android.networkstack.tethering.TetherUpstream6Key;
import com.android.networkstack.tethering.TetheringConfiguration;
import com.android.networkstack.tethering.util.InterfaceSet;
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
index 4967d27..3630f24 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
@@ -102,6 +102,8 @@
import com.android.net.module.util.NetworkStackConstants;
import com.android.net.module.util.bpf.Tether4Key;
import com.android.net.module.util.bpf.Tether4Value;
+import com.android.net.module.util.bpf.TetherStatsKey;
+import com.android.net.module.util.bpf.TetherStatsValue;
import com.android.net.module.util.netlink.ConntrackMessage;
import com.android.net.module.util.netlink.NetlinkConstants;
import com.android.net.module.util.netlink.NetlinkSocket;
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index 0388758..2fd7f48 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -142,6 +142,7 @@
import android.net.TetheringCallbackStartedParcel;
import android.net.TetheringConfigurationParcel;
import android.net.TetheringInterface;
+import android.net.TetheringManager;
import android.net.TetheringRequestParcel;
import android.net.dhcp.DhcpLeaseParcelable;
import android.net.dhcp.DhcpServerCallbacks;
@@ -175,6 +176,7 @@
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.test.mock.MockContentResolver;
+import android.util.ArraySet;
import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
@@ -211,6 +213,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.Set;
import java.util.Vector;
@RunWith(AndroidJUnit4.class)
@@ -1696,6 +1699,7 @@
private final ArrayList<TetherStatesParcel> mTetherStates = new ArrayList<>();
private final ArrayList<Integer> mOffloadStatus = new ArrayList<>();
private final ArrayList<List<TetheredClient>> mTetheredClients = new ArrayList<>();
+ private final ArrayList<Long> mSupportedBitmaps = new ArrayList<>();
// This function will remove the recorded callbacks, so it must be called once for
// each callback. If this is called after multiple callback, the order matters.
@@ -1748,6 +1752,10 @@
assertTrue(leases.containsAll(result));
}
+ public void expectSupportedTetheringTypes(Set<Integer> expectedTypes) {
+ assertEquals(expectedTypes, TetheringManager.unpackBits(mSupportedBitmaps.remove(0)));
+ }
+
@Override
public void onUpstreamChanged(Network network) {
mActualUpstreams.add(network);
@@ -1780,11 +1788,17 @@
mTetherStates.add(parcel.states);
mOffloadStatus.add(parcel.offloadStatus);
mTetheredClients.add(parcel.tetheredClients);
+ mSupportedBitmaps.add(parcel.supportedTypes);
}
@Override
public void onCallbackStopped(int errorCode) { }
+ @Override
+ public void onSupportedTetheringTypes(long supportedBitmap) {
+ mSupportedBitmaps.add(supportedBitmap);
+ }
+
public void assertNoUpstreamChangeCallback() {
assertTrue(mActualUpstreams.isEmpty());
}
@@ -2836,53 +2850,81 @@
runStopUSBTethering();
}
+ public static ArraySet<Integer> getAllSupportedTetheringTypes() {
+ return new ArraySet<>(new Integer[] { TETHERING_USB, TETHERING_NCM, TETHERING_WIFI,
+ TETHERING_WIFI_P2P, TETHERING_BLUETOOTH, TETHERING_ETHERNET });
+ }
+
@Test
public void testTetheringSupported() throws Exception {
+ final ArraySet<Integer> expectedTypes = getAllSupportedTetheringTypes();
+ // Check tethering is supported after initialization.
setTetheringSupported(true /* supported */);
- updateConfigAndVerifySupported(true /* supported */);
+ TestTetheringEventCallback callback = new TestTetheringEventCallback();
+ mTethering.registerTetheringEventCallback(callback);
+ mLooper.dispatchAll();
+ updateConfigAndVerifySupported(callback, expectedTypes);
// Could disable tethering supported by settings.
Settings.Global.putInt(mContentResolver, Settings.Global.TETHER_SUPPORTED, 0);
- updateConfigAndVerifySupported(false /* supported */);
+ updateConfigAndVerifySupported(callback, new ArraySet<>());
// Could disable tethering supported by user restriction.
setTetheringSupported(true /* supported */);
+ updateConfigAndVerifySupported(callback, expectedTypes);
when(mUserManager.hasUserRestriction(
UserManager.DISALLOW_CONFIG_TETHERING)).thenReturn(true);
- updateConfigAndVerifySupported(false /* supported */);
+ updateConfigAndVerifySupported(callback, new ArraySet<>());
// Tethering is supported if it has any supported downstream.
setTetheringSupported(true /* supported */);
+ updateConfigAndVerifySupported(callback, expectedTypes);
+ // Usb tethering is not supported:
+ expectedTypes.remove(TETHERING_USB);
when(mResources.getStringArray(R.array.config_tether_usb_regexs))
.thenReturn(new String[0]);
- updateConfigAndVerifySupported(true /* supported */);
+ updateConfigAndVerifySupported(callback, expectedTypes);
+ // Wifi tethering is not supported:
+ expectedTypes.remove(TETHERING_WIFI);
when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
.thenReturn(new String[0]);
- updateConfigAndVerifySupported(true /* supported */);
-
+ updateConfigAndVerifySupported(callback, expectedTypes);
+ // Bluetooth tethering is not supported:
+ expectedTypes.remove(TETHERING_BLUETOOTH);
+ when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
+ .thenReturn(new String[0]);
if (isAtLeastT()) {
- when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
- .thenReturn(new String[0]);
- updateConfigAndVerifySupported(true /* supported */);
+ updateConfigAndVerifySupported(callback, expectedTypes);
+
+ // P2p tethering is not supported:
+ expectedTypes.remove(TETHERING_WIFI_P2P);
when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs))
.thenReturn(new String[0]);
- updateConfigAndVerifySupported(true /* supported */);
+ updateConfigAndVerifySupported(callback, expectedTypes);
+ // Ncm tethering is not supported:
+ expectedTypes.remove(TETHERING_NCM);
when(mResources.getStringArray(R.array.config_tether_ncm_regexs))
.thenReturn(new String[0]);
- updateConfigAndVerifySupported(true /* supported */);
+ updateConfigAndVerifySupported(callback, expectedTypes);
+ // Ethernet tethering (last supported type) is not supported:
+ expectedTypes.remove(TETHERING_ETHERNET);
mForceEthernetServiceUnavailable = true;
- updateConfigAndVerifySupported(false /* supported */);
+ updateConfigAndVerifySupported(callback, new ArraySet<>());
+
} else {
- when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
- .thenReturn(new String[0]);
- updateConfigAndVerifySupported(false /* supported */);
+ // If wifi, usb and bluetooth are all not supported, all the types are not supported.
+ expectedTypes.clear();
+ updateConfigAndVerifySupported(callback, expectedTypes);
}
}
- private void updateConfigAndVerifySupported(boolean supported) {
+ private void updateConfigAndVerifySupported(final TestTetheringEventCallback callback,
+ final ArraySet<Integer> expectedTypes) {
sendConfigurationChanged();
- assertEquals(supported, mTethering.isTetheringSupported());
+
+ assertEquals(expectedTypes.size() > 0, mTethering.isTetheringSupported());
+ callback.expectSupportedTetheringTypes(expectedTypes);
}
// TODO: Test that a request for hotspot mode doesn't interfere with an
// already operating tethering mode interface.
diff --git a/framework-t/api/current.txt b/framework-t/api/current.txt
index 1b47481..eb77288 100644
--- a/framework-t/api/current.txt
+++ b/framework-t/api/current.txt
@@ -3,7 +3,7 @@
public final class NetworkStats implements java.lang.AutoCloseable {
method public void close();
- method public boolean getNextBucket(android.app.usage.NetworkStats.Bucket);
+ method public boolean getNextBucket(@Nullable android.app.usage.NetworkStats.Bucket);
method public boolean hasNextBucket();
}
@@ -40,21 +40,21 @@
}
public class NetworkStatsManager {
- method @WorkerThread public android.app.usage.NetworkStats queryDetails(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
- method @WorkerThread public android.app.usage.NetworkStats queryDetailsForUid(int, String, long, long, int) throws java.lang.SecurityException;
- method @WorkerThread public android.app.usage.NetworkStats queryDetailsForUidTag(int, String, long, long, int, int) throws java.lang.SecurityException;
- method @WorkerThread public android.app.usage.NetworkStats queryDetailsForUidTagState(int, String, long, long, int, int, int) throws java.lang.SecurityException;
- method @WorkerThread public android.app.usage.NetworkStats querySummary(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
- method @WorkerThread public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
- method @WorkerThread public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
- method public void registerUsageCallback(int, String, long, android.app.usage.NetworkStatsManager.UsageCallback);
- method public void registerUsageCallback(int, String, long, android.app.usage.NetworkStatsManager.UsageCallback, @Nullable android.os.Handler);
- method public void unregisterUsageCallback(android.app.usage.NetworkStatsManager.UsageCallback);
+ method @WorkerThread public android.app.usage.NetworkStats queryDetails(int, @Nullable String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method @NonNull @WorkerThread public android.app.usage.NetworkStats queryDetailsForUid(int, @Nullable String, long, long, int) throws java.lang.SecurityException;
+ method @NonNull @WorkerThread public android.app.usage.NetworkStats queryDetailsForUidTag(int, @Nullable String, long, long, int, int) throws java.lang.SecurityException;
+ method @NonNull @WorkerThread public android.app.usage.NetworkStats queryDetailsForUidTagState(int, @Nullable String, long, long, int, int, int) throws java.lang.SecurityException;
+ method @WorkerThread public android.app.usage.NetworkStats querySummary(int, @Nullable String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method @WorkerThread public android.app.usage.NetworkStats.Bucket querySummaryForDevice(int, @Nullable String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method @WorkerThread public android.app.usage.NetworkStats.Bucket querySummaryForUser(int, @Nullable String, long, long) throws android.os.RemoteException, java.lang.SecurityException;
+ method public void registerUsageCallback(int, @Nullable String, long, @NonNull android.app.usage.NetworkStatsManager.UsageCallback);
+ method public void registerUsageCallback(int, @Nullable String, long, @NonNull android.app.usage.NetworkStatsManager.UsageCallback, @Nullable android.os.Handler);
+ method public void unregisterUsageCallback(@NonNull android.app.usage.NetworkStatsManager.UsageCallback);
}
public abstract static class NetworkStatsManager.UsageCallback {
ctor public NetworkStatsManager.UsageCallback();
- method public abstract void onThresholdReached(int, String);
+ method public abstract void onThresholdReached(int, @Nullable String);
}
}
@@ -173,12 +173,12 @@
method public static void incrementOperationCount(int, int);
method public static void setThreadStatsTag(int);
method public static void setThreadStatsUid(int);
- method public static void tagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
- method public static void tagFileDescriptor(java.io.FileDescriptor) throws java.io.IOException;
- method public static void tagSocket(java.net.Socket) throws java.net.SocketException;
- method public static void untagDatagramSocket(java.net.DatagramSocket) throws java.net.SocketException;
- method public static void untagFileDescriptor(java.io.FileDescriptor) throws java.io.IOException;
- method public static void untagSocket(java.net.Socket) throws java.net.SocketException;
+ method public static void tagDatagramSocket(@NonNull java.net.DatagramSocket) throws java.net.SocketException;
+ method public static void tagFileDescriptor(@NonNull java.io.FileDescriptor) throws java.io.IOException;
+ method public static void tagSocket(@NonNull java.net.Socket) throws java.net.SocketException;
+ method public static void untagDatagramSocket(@NonNull java.net.DatagramSocket) throws java.net.SocketException;
+ method public static void untagFileDescriptor(@NonNull java.io.FileDescriptor) throws java.io.IOException;
+ method public static void untagSocket(@NonNull java.net.Socket) throws java.net.SocketException;
field public static final int UNSUPPORTED = -1; // 0xffffffff
}
diff --git a/framework-t/api/lint-baseline.txt b/framework-t/api/lint-baseline.txt
index 53e1beb..2996a3e 100644
--- a/framework-t/api/lint-baseline.txt
+++ b/framework-t/api/lint-baseline.txt
@@ -41,86 +41,18 @@
android.net.IpSecTransform.Builder does not declare a `build()` method, but builder classes are expected to
-MissingNullability: android.app.usage.NetworkStats#getNextBucket(android.app.usage.NetworkStats.Bucket) parameter #0:
- Missing nullability on parameter `bucketOut` in method `getNextBucket`
MissingNullability: android.app.usage.NetworkStatsManager#queryDetails(int, String, long, long):
Missing nullability on method `queryDetails` return
-MissingNullability: android.app.usage.NetworkStatsManager#queryDetails(int, String, long, long) parameter #1:
- Missing nullability on parameter `subscriberId` in method `queryDetails`
-MissingNullability: android.app.usage.NetworkStatsManager#queryDetailsForUid(int, String, long, long, int):
- Missing nullability on method `queryDetailsForUid` return
-MissingNullability: android.app.usage.NetworkStatsManager#queryDetailsForUid(int, String, long, long, int) parameter #1:
- Missing nullability on parameter `subscriberId` in method `queryDetailsForUid`
-MissingNullability: android.app.usage.NetworkStatsManager#queryDetailsForUidTag(int, String, long, long, int, int):
- Missing nullability on method `queryDetailsForUidTag` return
-MissingNullability: android.app.usage.NetworkStatsManager#queryDetailsForUidTag(int, String, long, long, int, int) parameter #1:
- Missing nullability on parameter `subscriberId` in method `queryDetailsForUidTag`
-MissingNullability: android.app.usage.NetworkStatsManager#queryDetailsForUidTagState(int, String, long, long, int, int, int):
- Missing nullability on method `queryDetailsForUidTagState` return
-MissingNullability: android.app.usage.NetworkStatsManager#queryDetailsForUidTagState(int, String, long, long, int, int, int) parameter #1:
- Missing nullability on parameter `subscriberId` in method `queryDetailsForUidTagState`
MissingNullability: android.app.usage.NetworkStatsManager#querySummary(int, String, long, long):
Missing nullability on method `querySummary` return
-MissingNullability: android.app.usage.NetworkStatsManager#querySummary(int, String, long, long) parameter #1:
- Missing nullability on parameter `subscriberId` in method `querySummary`
MissingNullability: android.app.usage.NetworkStatsManager#querySummaryForDevice(int, String, long, long):
Missing nullability on method `querySummaryForDevice` return
-MissingNullability: android.app.usage.NetworkStatsManager#querySummaryForDevice(int, String, long, long) parameter #1:
- Missing nullability on parameter `subscriberId` in method `querySummaryForDevice`
MissingNullability: android.app.usage.NetworkStatsManager#querySummaryForUser(int, String, long, long):
Missing nullability on method `querySummaryForUser` return
-MissingNullability: android.app.usage.NetworkStatsManager#querySummaryForUser(int, String, long, long) parameter #1:
- Missing nullability on parameter `subscriberId` in method `querySummaryForUser`
-MissingNullability: android.app.usage.NetworkStatsManager#registerUsageCallback(int, String, long, android.app.usage.NetworkStatsManager.UsageCallback) parameter #1:
- Missing nullability on parameter `subscriberId` in method `registerUsageCallback`
-MissingNullability: android.app.usage.NetworkStatsManager#registerUsageCallback(int, String, long, android.app.usage.NetworkStatsManager.UsageCallback) parameter #3:
- Missing nullability on parameter `callback` in method `registerUsageCallback`
-MissingNullability: android.app.usage.NetworkStatsManager#registerUsageCallback(int, String, long, android.app.usage.NetworkStatsManager.UsageCallback, android.os.Handler) parameter #1:
- Missing nullability on parameter `subscriberId` in method `registerUsageCallback`
-MissingNullability: android.app.usage.NetworkStatsManager#registerUsageCallback(int, String, long, android.app.usage.NetworkStatsManager.UsageCallback, android.os.Handler) parameter #3:
- Missing nullability on parameter `callback` in method `registerUsageCallback`
-MissingNullability: android.app.usage.NetworkStatsManager#unregisterUsageCallback(android.app.usage.NetworkStatsManager.UsageCallback) parameter #0:
- Missing nullability on parameter `callback` in method `unregisterUsageCallback`
-MissingNullability: android.app.usage.NetworkStatsManager.UsageCallback#onThresholdReached(int, String) parameter #1:
- Missing nullability on parameter `subscriberId` in method `onThresholdReached`
MissingNullability: android.net.IpSecAlgorithm#writeToParcel(android.os.Parcel, int) parameter #0:
Missing nullability on parameter `out` in method `writeToParcel`
MissingNullability: android.net.IpSecManager.UdpEncapsulationSocket#getFileDescriptor():
Missing nullability on method `getFileDescriptor` return
-MissingNullability: android.net.TrafficStats#tagDatagramSocket(java.net.DatagramSocket) parameter #0:
- Missing nullability on parameter `socket` in method `tagDatagramSocket`
-MissingNullability: android.net.TrafficStats#tagFileDescriptor(java.io.FileDescriptor) parameter #0:
- Missing nullability on parameter `fd` in method `tagFileDescriptor`
-MissingNullability: android.net.TrafficStats#tagSocket(java.net.Socket) parameter #0:
- Missing nullability on parameter `socket` in method `tagSocket`
-MissingNullability: android.net.TrafficStats#untagDatagramSocket(java.net.DatagramSocket) parameter #0:
- Missing nullability on parameter `socket` in method `untagDatagramSocket`
-MissingNullability: android.net.TrafficStats#untagFileDescriptor(java.io.FileDescriptor) parameter #0:
- Missing nullability on parameter `fd` in method `untagFileDescriptor`
-MissingNullability: android.net.TrafficStats#untagSocket(java.net.Socket) parameter #0:
- Missing nullability on parameter `socket` in method `untagSocket`
-MissingNullability: com.android.internal.util.FileRotator#FileRotator(java.io.File, String, long, long) parameter #0:
- Missing nullability on parameter `basePath` in method `FileRotator`
-MissingNullability: com.android.internal.util.FileRotator#FileRotator(java.io.File, String, long, long) parameter #1:
- Missing nullability on parameter `prefix` in method `FileRotator`
-MissingNullability: com.android.internal.util.FileRotator#dumpAll(java.io.OutputStream) parameter #0:
- Missing nullability on parameter `os` in method `dumpAll`
-MissingNullability: com.android.internal.util.FileRotator#readMatching(com.android.internal.util.FileRotator.Reader, long, long) parameter #0:
- Missing nullability on parameter `reader` in method `readMatching`
-MissingNullability: com.android.internal.util.FileRotator#rewriteActive(com.android.internal.util.FileRotator.Rewriter, long) parameter #0:
- Missing nullability on parameter `rewriter` in method `rewriteActive`
-MissingNullability: com.android.internal.util.FileRotator#rewriteAll(com.android.internal.util.FileRotator.Rewriter) parameter #0:
- Missing nullability on parameter `rewriter` in method `rewriteAll`
-MissingNullability: com.android.internal.util.FileRotator.Reader#read(java.io.InputStream) parameter #0:
- Missing nullability on parameter `in` in method `read`
-MissingNullability: com.android.internal.util.FileRotator.Writer#write(java.io.OutputStream) parameter #0:
- Missing nullability on parameter `out` in method `write`
-MissingNullability: com.android.server.NetworkManagementSocketTagger#kernelToTag(String) parameter #0:
- Missing nullability on parameter `string` in method `kernelToTag`
-MissingNullability: com.android.server.NetworkManagementSocketTagger#tag(java.io.FileDescriptor) parameter #0:
- Missing nullability on parameter `fd` in method `tag`
-MissingNullability: com.android.server.NetworkManagementSocketTagger#untag(java.io.FileDescriptor) parameter #0:
- Missing nullability on parameter `fd` in method `untag`
RethrowRemoteException: android.app.usage.NetworkStatsManager#queryDetails(int, String, long, long):
diff --git a/framework-t/api/module-lib-current.txt b/framework-t/api/module-lib-current.txt
index 658c625..c1f7b39 100644
--- a/framework-t/api/module-lib-current.txt
+++ b/framework-t/api/module-lib-current.txt
@@ -4,6 +4,8 @@
public class NetworkStatsManager {
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void forceUpdate();
method public static int getCollapsedRatType(int);
+ method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public android.net.NetworkStats getMobileUidStats();
+ method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public android.net.NetworkStats getWifiUidStats();
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void noteUidForeground(int, boolean);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyNetworkStatus(@NonNull java.util.List<android.net.Network>, @NonNull java.util.List<android.net.NetworkStateSnapshot>, @Nullable String, @NonNull java.util.List<android.net.UnderlyingNetworkInfo>);
method @NonNull @WorkerThread public android.app.usage.NetworkStats queryDetailsForDevice(@NonNull android.net.NetworkTemplate, long, long);
@@ -182,6 +184,7 @@
public class TrafficStats {
method public static void attachSocketTagger();
method public static void init(@NonNull android.content.Context);
+ method public static void setThreadStatsTagDownload();
}
public final class UnderlyingNetworkInfo implements android.os.Parcelable {
diff --git a/framework-t/api/system-current.txt b/framework-t/api/system-current.txt
index 0f37b6f..6460fed 100644
--- a/framework-t/api/system-current.txt
+++ b/framework-t/api/system-current.txt
@@ -2,10 +2,8 @@
package android.app.usage {
public class NetworkStatsManager {
- method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public android.net.NetworkStats getMobileUidStats();
- method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public android.net.NetworkStats getWifiUidStats();
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STATS_PROVIDER, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void registerNetworkStatsProvider(@NonNull String, @NonNull android.net.netstats.provider.NetworkStatsProvider);
- method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STATS_PROVIDER, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void unregisterNetworkStatsProvider(@NonNull android.net.netstats.provider.NetworkStatsProvider);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STATS_PROVIDER, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void registerNetworkStatsProvider(@NonNull String, @NonNull android.net.netstats.provider.NetworkStatsProvider);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STATS_PROVIDER, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void unregisterNetworkStatsProvider(@NonNull android.net.netstats.provider.NetworkStatsProvider);
}
}
@@ -113,7 +111,6 @@
public class TrafficStats {
method public static void setThreadStatsTagApp();
method public static void setThreadStatsTagBackup();
- method public static void setThreadStatsTagDownload();
method public static void setThreadStatsTagRestore();
field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_END = -113; // 0xffffff8f
field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_START = -128; // 0xffffff80
diff --git a/framework-t/src/android/app/usage/NetworkStats.java b/framework-t/src/android/app/usage/NetworkStats.java
index 2b6570a..74fe4bd 100644
--- a/framework-t/src/android/app/usage/NetworkStats.java
+++ b/framework-t/src/android/app/usage/NetworkStats.java
@@ -17,6 +17,7 @@
package android.app.usage;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.content.Context;
import android.net.INetworkStatsService;
import android.net.INetworkStatsSession;
@@ -474,10 +475,11 @@
/**
* Fills the recycled bucket with data of the next bin in the enumeration.
- * @param bucketOut Bucket to be filled with data.
+ * @param bucketOut Bucket to be filled with data. If null, the method does
+ * nothing and returning false.
* @return true if successfully filled the bucket, false otherwise.
*/
- public boolean getNextBucket(Bucket bucketOut) {
+ public boolean getNextBucket(@Nullable Bucket bucketOut) {
if (mSummary != null) {
return getNextSummaryBucket(bucketOut);
} else {
@@ -651,7 +653,7 @@
* @param bucketOut Next item will be set here.
* @return true if a next item could be set.
*/
- private boolean getNextSummaryBucket(Bucket bucketOut) {
+ private boolean getNextSummaryBucket(@Nullable Bucket bucketOut) {
if (bucketOut != null && mEnumerationIndex < mSummary.size()) {
mRecycledSummaryEntry = mSummary.getValues(mEnumerationIndex++, mRecycledSummaryEntry);
fillBucketFromSummaryEntry(bucketOut);
@@ -678,7 +680,7 @@
* @param bucketOut Next item will be set here.
* @return true if a next item could be set.
*/
- private boolean getNextHistoryBucket(Bucket bucketOut) {
+ private boolean getNextHistoryBucket(@Nullable Bucket bucketOut) {
if (bucketOut != null && mHistory != null) {
if (mEnumerationIndex < mHistory.size()) {
mRecycledHistoryEntry = mHistory.getValues(mEnumerationIndex++,
diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java
index bf518b2..f41475b 100644
--- a/framework-t/src/android/app/usage/NetworkStatsManager.java
+++ b/framework-t/src/android/app/usage/NetworkStatsManager.java
@@ -290,7 +290,7 @@
* statistics collection.
*/
@WorkerThread
- public Bucket querySummaryForDevice(int networkType, String subscriberId,
+ public Bucket querySummaryForDevice(int networkType, @Nullable String subscriberId,
long startTime, long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
try {
@@ -335,8 +335,8 @@
* statistics collection.
*/
@WorkerThread
- public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime,
- long endTime) throws SecurityException, RemoteException {
+ public Bucket querySummaryForUser(int networkType, @Nullable String subscriberId,
+ long startTime, long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
try {
template = createTemplate(networkType, subscriberId);
@@ -384,7 +384,7 @@
* statistics collection.
*/
@WorkerThread
- public NetworkStats querySummary(int networkType, String subscriberId, long startTime,
+ public NetworkStats querySummary(int networkType, @Nullable String subscriberId, long startTime,
long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
try {
@@ -508,15 +508,17 @@
*
* @see #queryDetailsForUidTagState(int, String, long, long, int, int, int)
*/
+ @NonNull
@WorkerThread
- public NetworkStats queryDetailsForUid(int networkType, String subscriberId,
+ public NetworkStats queryDetailsForUid(int networkType, @Nullable String subscriberId,
long startTime, long endTime, int uid) throws SecurityException {
return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid,
NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL);
}
/** @hide */
- public NetworkStats queryDetailsForUid(NetworkTemplate template,
+ @NonNull
+ public NetworkStats queryDetailsForUid(@NonNull NetworkTemplate template,
long startTime, long endTime, int uid) throws SecurityException {
return queryDetailsForUidTagState(template, startTime, endTime, uid,
NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL);
@@ -524,23 +526,59 @@
/**
* Query network usage statistics details for a given uid and tag.
+ *
+ * This may take a long time, and apps should avoid calling this on their main thread.
+ * Only usable for uids belonging to calling user. Result is not aggregated over time.
+ * This means buckets' start and end timestamps are going to be between 'startTime' and
+ * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag
+ * the same as the 'tag' parameter, and the state the same as the 'state' parameter.
+ * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
+ * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and
+ * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
+ * <p>Only includes buckets that atomically occur in the inclusive time range. Doesn't
+ * interpolate across partial buckets. Since bucket length is in the order of hours, this
+ * method cannot be used to measure data usage on a fine grained time scale.
* This may take a long time, and apps should avoid calling this on their main thread.
*
- * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int)
+ * @param networkType As defined in {@link ConnectivityManager}, e.g.
+ * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI}
+ * etc.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * <p>Starting with API level 29, the {@code subscriberId} is guarded by
+ * additional restrictions. Calling apps that do not meet the new
+ * requirements to access the {@code subscriberId} can provide a {@code
+ * null} value when querying for the mobile network type to receive usage
+ * for all mobile networks. For additional details see {@link
+ * TelephonyManager#getSubscriberId()}.
+ * <p>Starting with API level 31, calling apps can provide a
+ * {@code subscriberId} with wifi network type to receive usage for
+ * wifi networks which is under the given subscription if applicable.
+ * Otherwise, pass {@code null} when querying all wifi networks.
+ * @param startTime Start of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param endTime End of period. Defined in terms of "Unix time", see
+ * {@link java.lang.System#currentTimeMillis}.
+ * @param uid UID of app
+ * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data
+ * across all the tags.
+ * @return Statistics which is described above.
+ * @throws SecurityException if permissions are insufficient to read network statistics.
*/
+ @NonNull
@WorkerThread
- public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId,
+ public NetworkStats queryDetailsForUidTag(int networkType, @Nullable String subscriberId,
long startTime, long endTime, int uid, int tag) throws SecurityException {
return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid,
tag, NetworkStats.Bucket.STATE_ALL);
}
/**
- * Query network usage statistics details for a given uid, tag, and state. Only usable for uids
- * belonging to calling user. Result is not aggregated over time. This means buckets' start and
- * end timestamps are going to be between 'startTime' and 'endTime' parameters. The uid is going
- * to be the same as the 'uid' parameter, the tag the same as the 'tag' parameter, and the state
- * the same as the 'state' parameter.
+ * Query network usage statistics details for a given uid, tag, and state.
+ *
+ * Only usable for uids belonging to calling user. Result is not aggregated over time.
+ * This means buckets' start and end timestamps are going to be between 'startTime' and
+ * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag
+ * the same as the 'tag' parameter, and the state the same as the 'state' parameter.
* defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL},
* metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and
* roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}.
@@ -572,11 +610,12 @@
* across all the tags.
* @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate
* traffic from all states.
- * @return Statistics object or null if an error happened during statistics collection.
+ * @return Statistics which is described above.
* @throws SecurityException if permissions are insufficient to read network statistics.
*/
+ @NonNull
@WorkerThread
- public NetworkStats queryDetailsForUidTagState(int networkType, String subscriberId,
+ public NetworkStats queryDetailsForUidTagState(int networkType, @Nullable String subscriberId,
long startTime, long endTime, int uid, int tag, int state) throws SecurityException {
NetworkTemplate template;
template = createTemplate(networkType, subscriberId);
@@ -669,7 +708,7 @@
* statistics collection.
*/
@WorkerThread
- public NetworkStats queryDetails(int networkType, String subscriberId, long startTime,
+ public NetworkStats queryDetails(int networkType, @Nullable String subscriberId, long startTime,
long endTime) throws SecurityException, RemoteException {
NetworkTemplate template;
try {
@@ -698,7 +737,7 @@
*
* @hide
*/
- @SystemApi
+ @SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_STACK})
@@ -724,7 +763,7 @@
*
* @hide
*/
- @SystemApi
+ @SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_STACK})
@@ -785,10 +824,28 @@
/**
* Registers to receive notifications about data usage on specified networks.
*
- * @see #registerUsageCallback(int, String, long, UsageCallback, Handler)
+ * <p>The callbacks will continue to be called as long as the process is live or
+ * {@link #unregisterUsageCallback} is called.
+ *
+ * @param networkType Type of network to monitor. Either
+ {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}.
+ * @param subscriberId If applicable, the subscriber id of the network interface.
+ * <p>Starting with API level 29, the {@code subscriberId} is guarded by
+ * additional restrictions. Calling apps that do not meet the new
+ * requirements to access the {@code subscriberId} can provide a {@code
+ * null} value when registering for the mobile network type to receive
+ * notifications for all mobile networks. For additional details see {@link
+ * TelephonyManager#getSubscriberId()}.
+ * <p>Starting with API level 31, calling apps can provide a
+ * {@code subscriberId} with wifi network type to receive usage for
+ * wifi networks which is under the given subscription if applicable.
+ * Otherwise, pass {@code null} when querying all wifi networks.
+ * @param thresholdBytes Threshold in bytes to be notified on.
+ * @param callback The {@link UsageCallback} that the system will call when data usage
+ * has exceeded the specified threshold.
*/
- public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
- UsageCallback callback) {
+ public void registerUsageCallback(int networkType, @Nullable String subscriberId,
+ long thresholdBytes, @NonNull UsageCallback callback) {
registerUsageCallback(networkType, subscriberId, thresholdBytes, callback,
null /* handler */);
}
@@ -818,8 +875,8 @@
* @param handler to dispatch callback events through, otherwise if {@code null} it uses
* the calling thread.
*/
- public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes,
- UsageCallback callback, @Nullable Handler handler) {
+ public void registerUsageCallback(int networkType, @Nullable String subscriberId,
+ long thresholdBytes, @NonNull UsageCallback callback, @Nullable Handler handler) {
NetworkTemplate template = createTemplate(networkType, subscriberId);
if (DBG) {
Log.d(TAG, "registerUsageCallback called with: {"
@@ -839,7 +896,7 @@
*
* @param callback The {@link UsageCallback} used when registering.
*/
- public void unregisterUsageCallback(UsageCallback callback) {
+ public void unregisterUsageCallback(@NonNull UsageCallback callback) {
if (callback == null || callback.request == null
|| callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) {
throw new IllegalArgumentException("Invalid UsageCallback");
@@ -880,7 +937,7 @@
/**
* Called when data usage has reached the given threshold.
*/
- public abstract void onThresholdReached(int networkType, String subscriberId);
+ public abstract void onThresholdReached(int networkType, @Nullable String subscriberId);
/**
* @hide used for internal bookkeeping
@@ -924,7 +981,7 @@
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_STATS_PROVIDER,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
- @NonNull public void registerNetworkStatsProvider(
+ public void registerNetworkStatsProvider(
@NonNull String tag,
@NonNull NetworkStatsProvider provider) {
try {
@@ -950,7 +1007,7 @@
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_STATS_PROVIDER,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK})
- @NonNull public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) {
+ public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) {
try {
provider.getProviderCallbackBinderOrThrow().unregister();
} catch (RemoteException e) {
@@ -958,7 +1015,7 @@
}
}
- private static NetworkTemplate createTemplate(int networkType, String subscriberId) {
+ private static NetworkTemplate createTemplate(int networkType, @Nullable String subscriberId) {
final NetworkTemplate template;
switch (networkType) {
case ConnectivityManager.TYPE_MOBILE:
diff --git a/framework-t/src/android/net/NetworkIdentitySet.java b/framework-t/src/android/net/NetworkIdentitySet.java
index ad3a958..d88408e 100644
--- a/framework-t/src/android/net/NetworkIdentitySet.java
+++ b/framework-t/src/android/net/NetworkIdentitySet.java
@@ -206,6 +206,7 @@
public static int compare(@NonNull NetworkIdentitySet left, @NonNull NetworkIdentitySet right) {
Objects.requireNonNull(left);
Objects.requireNonNull(right);
+ if (left.isEmpty() && right.isEmpty()) return 0;
if (left.isEmpty()) return -1;
if (right.isEmpty()) return 1;
diff --git a/framework-t/src/android/net/NetworkStats.java b/framework-t/src/android/net/NetworkStats.java
index 06f2a62..51ff5ec 100644
--- a/framework-t/src/android/net/NetworkStats.java
+++ b/framework-t/src/android/net/NetworkStats.java
@@ -124,7 +124,6 @@
public @Nullable static final String[] INTERFACES_ALL = null;
/** {@link #tag} value for total data across all tags. */
- // TODO: Rename TAG_NONE to TAG_ALL.
public static final int TAG_NONE = 0;
/** {@link #metered} value to account for all metered states. */
@@ -412,21 +411,24 @@
/**
* @return the metered state.
*/
- @Meteredness public int getMetered() {
+ @Meteredness
+ public int getMetered() {
return metered;
}
/**
* @return the roaming state.
*/
- @Roaming public int getRoaming() {
+ @Roaming
+ public int getRoaming() {
return roaming;
}
/**
* @return the default network state.
*/
- @DefaultNetwork public int getDefaultNetwork() {
+ @DefaultNetwork
+ public int getDefaultNetwork() {
return defaultNetwork;
}
diff --git a/framework-t/src/android/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java
index e385b33..b59a890 100644
--- a/framework-t/src/android/net/NetworkStatsCollection.java
+++ b/framework-t/src/android/net/NetworkStatsCollection.java
@@ -776,7 +776,7 @@
if (!templateMatches(groupTemplate, key.ident)) continue;
if (key.set >= NetworkStats.SET_DEBUG_START) continue;
- final Key groupKey = new Key(null, key.uid, key.set, key.tag);
+ final Key groupKey = new Key(new NetworkIdentitySet(), key.uid, key.set, key.tag);
NetworkStatsHistory groupHistory = grouped.get(groupKey);
if (groupHistory == null) {
groupHistory = new NetworkStatsHistory(value.getBucketDuration());
diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java
index 7b5afd7..b82a126 100644
--- a/framework-t/src/android/net/NetworkTemplate.java
+++ b/framework-t/src/android/net/NetworkTemplate.java
@@ -393,8 +393,9 @@
//constructor passes METERED_YES for these types.
this(matchRule, subscriberId, matchSubscriberIds,
wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0],
- (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES
- : METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
+ (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD
+ || matchRule == MATCH_CARRIER) ? METERED_YES : METERED_ALL,
+ ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
OEM_MANAGED_ALL, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT);
}
diff --git a/framework-t/src/android/net/TrafficStats.java b/framework-t/src/android/net/TrafficStats.java
index bc836d8..dc4ac55 100644
--- a/framework-t/src/android/net/TrafficStats.java
+++ b/framework-t/src/android/net/TrafficStats.java
@@ -205,7 +205,7 @@
* server context.
* @hide
*/
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ @SystemApi(client = MODULE_LIBRARIES)
@SuppressLint("VisiblySynchronized")
public static synchronized void init(@NonNull final Context context) {
if (sStatsService != null) {
@@ -376,7 +376,7 @@
*
* @hide
*/
- @SystemApi
+ @SystemApi(client = MODULE_LIBRARIES)
public static void setThreadStatsTagDownload() {
setThreadStatsTag(TAG_SYSTEM_DOWNLOAD);
}
@@ -468,7 +468,7 @@
*
* @see #setThreadStatsTag(int)
*/
- public static void tagSocket(Socket socket) throws SocketException {
+ public static void tagSocket(@NonNull Socket socket) throws SocketException {
SocketTagger.get().tag(socket);
}
@@ -483,7 +483,7 @@
* calling {@code untagSocket()} before sending the socket to another
* process.
*/
- public static void untagSocket(Socket socket) throws SocketException {
+ public static void untagSocket(@NonNull Socket socket) throws SocketException {
SocketTagger.get().untag(socket);
}
@@ -496,14 +496,14 @@
*
* @see #setThreadStatsTag(int)
*/
- public static void tagDatagramSocket(DatagramSocket socket) throws SocketException {
+ public static void tagDatagramSocket(@NonNull DatagramSocket socket) throws SocketException {
SocketTagger.get().tag(socket);
}
/**
* Remove any statistics parameters from the given {@link DatagramSocket}.
*/
- public static void untagDatagramSocket(DatagramSocket socket) throws SocketException {
+ public static void untagDatagramSocket(@NonNull DatagramSocket socket) throws SocketException {
SocketTagger.get().untag(socket);
}
@@ -516,7 +516,7 @@
*
* @see #setThreadStatsTag(int)
*/
- public static void tagFileDescriptor(FileDescriptor fd) throws IOException {
+ public static void tagFileDescriptor(@NonNull FileDescriptor fd) throws IOException {
SocketTagger.get().tag(fd);
}
@@ -524,7 +524,7 @@
* Remove any statistics parameters from the given {@link FileDescriptor}
* socket.
*/
- public static void untagFileDescriptor(FileDescriptor fd) throws IOException {
+ public static void untagFileDescriptor(@NonNull FileDescriptor fd) throws IOException {
SocketTagger.get().untag(fd);
}
diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl b/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl
index 28437c2..e7b2815 100644
--- a/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl
+++ b/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl
@@ -28,5 +28,5 @@
void sendNotification(int notificationId, String notificationType);
void registerNetworkCallback(in NetworkRequest request, in INetworkCallback cb);
void unregisterNetworkCallback();
- void scheduleJob(in JobInfo jobInfo);
+ int scheduleJob(in JobInfo jobInfo);
}
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index f460180..96ce65f 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -16,6 +16,7 @@
package com.android.cts.net.hostside;
+import static android.app.job.JobScheduler.RESULT_SUCCESS;
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
import static android.os.BatteryManager.BATTERY_PLUGGED_AC;
import static android.os.BatteryManager.BATTERY_PLUGGED_USB;
@@ -151,7 +152,7 @@
protected static final long TEMP_POWERSAVE_WHITELIST_DURATION_MS = 20_000; // 20 sec
- private static final long BROADCAST_TIMEOUT_MS = 15_000;
+ private static final long BROADCAST_TIMEOUT_MS = 5_000;
protected Context mContext;
protected Instrumentation mInstrumentation;
@@ -855,7 +856,8 @@
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setTransientExtras(extras)
.build();
- mServiceClient.scheduleJob(jobInfo);
+ assertEquals("Error scheduling " + jobInfo,
+ RESULT_SUCCESS, mServiceClient.scheduleJob(jobInfo));
forceRunJob(TEST_APP2_PKG, TEST_JOB_ID);
if (latch.await(JOB_NETWORK_STATE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
final int resultCode = result.get(0).first;
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java
index 8b70f9b..0610774 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java
@@ -107,7 +107,7 @@
mService.unregisterNetworkCallback();
}
- public void scheduleJob(JobInfo jobInfo) throws RemoteException {
- mService.scheduleJob(jobInfo);
+ public int scheduleJob(JobInfo jobInfo) throws RemoteException {
+ return mService.scheduleJob(jobInfo);
}
}
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java
index f2a7b3f..3ed5391 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java
@@ -165,10 +165,10 @@
}
@Override
- public void scheduleJob(JobInfo jobInfo) {
+ public int scheduleJob(JobInfo jobInfo) {
final JobScheduler jobScheduler = getApplicationContext()
.getSystemService(JobScheduler.class);
- jobScheduler.schedule(jobInfo);
+ return jobScheduler.schedule(jobInfo);
}
};
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index 545f7b9..5b926de 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -63,6 +63,7 @@
"java/android/net/IpSecManagerTest.java",
"java/android/net/IpSecTransformTest.java",
"java/android/net/KeepalivePacketDataUtilTest.java",
+ "java/android/net/NetworkIdentitySetTest.kt",
"java/android/net/NetworkIdentityTest.kt",
"java/android/net/NetworkStats*.java",
"java/android/net/NetworkTemplateTest.kt",
diff --git a/tests/unit/java/android/net/NetworkIdentitySetTest.kt b/tests/unit/java/android/net/NetworkIdentitySetTest.kt
new file mode 100644
index 0000000..d61ebf9
--- /dev/null
+++ b/tests/unit/java/android/net/NetworkIdentitySetTest.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net
+
+import android.content.Context
+import android.net.ConnectivityManager.TYPE_MOBILE
+import android.os.Build
+import android.telephony.TelephonyManager
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRunner
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import kotlin.test.assertEquals
+
+private const val TEST_IMSI1 = "testimsi1"
+
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
+@RunWith(DevSdkIgnoreRunner::class)
+class NetworkIdentitySetTest {
+ private val mockContext = mock(Context::class.java)
+
+ private fun buildMobileNetworkStateSnapshot(
+ caps: NetworkCapabilities,
+ subscriberId: String
+ ): NetworkStateSnapshot {
+ return NetworkStateSnapshot(mock(Network::class.java), caps,
+ LinkProperties(), subscriberId, TYPE_MOBILE)
+ }
+
+ @Test
+ fun testCompare() {
+ val ident1 = NetworkIdentity.buildNetworkIdentity(mockContext,
+ buildMobileNetworkStateSnapshot(NetworkCapabilities(), TEST_IMSI1),
+ false /* defaultNetwork */, TelephonyManager.NETWORK_TYPE_UMTS)
+ val ident2 = NetworkIdentity.buildNetworkIdentity(mockContext,
+ buildMobileNetworkStateSnapshot(NetworkCapabilities(), TEST_IMSI1),
+ true /* defaultNetwork */, TelephonyManager.NETWORK_TYPE_UMTS)
+
+ // Verify that the results of comparing two empty sets are equal
+ assertEquals(0, NetworkIdentitySet.compare(NetworkIdentitySet(), NetworkIdentitySet()))
+
+ val identSet1 = NetworkIdentitySet()
+ val identSet2 = NetworkIdentitySet()
+ identSet1.add(ident1)
+ identSet2.add(ident2)
+ assertEquals(-1, NetworkIdentitySet.compare(NetworkIdentitySet(), identSet1))
+ assertEquals(1, NetworkIdentitySet.compare(identSet1, NetworkIdentitySet()))
+ assertEquals(0, NetworkIdentitySet.compare(identSet1, identSet1))
+ assertEquals(-1, NetworkIdentitySet.compare(identSet1, identSet2))
+ }
+}