Gracefully handle integer overflows.
Avoid recording negative data by doing integer-based
math as much as possible, but switch to double-based
math if we detect that we'd end up causing an overflow.
Test :
- Builds, Boots
- High data throughput scenarios
- NetworkStatsHistoryTest, NetworkStatsCollectionTest,
NetworkStatsTest
Bug: 119527458
Change-Id: I355fc9bd127da83c1dc70ab3b1261346d4fa5de0
This commit is contained in:
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package android.net;
|
package android.net;
|
||||||
|
|
||||||
|
import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational;
|
||||||
|
|
||||||
import android.annotation.IntDef;
|
import android.annotation.IntDef;
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
@@ -1553,32 +1555,37 @@ public final class NetworkStats implements Parcelable {
|
|||||||
// processes this every time device has transmitted/received amount equivalent to
|
// processes this every time device has transmitted/received amount equivalent to
|
||||||
// global threshold alert (~ 2MB) across all interfaces.
|
// global threshold alert (~ 2MB) across all interfaces.
|
||||||
final long rxBytesAcrossUnderlyingIfaces =
|
final long rxBytesAcrossUnderlyingIfaces =
|
||||||
underlyingIfacesTotal.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes;
|
multiplySafeByRational(underlyingIfacesTotal.rxBytes,
|
||||||
|
rxBytes[i], tunIfaceTotal.rxBytes);
|
||||||
// app must not be blamed for more than it consumed on tunIface
|
// app must not be blamed for more than it consumed on tunIface
|
||||||
totalRxBytes = Math.min(rxBytes[i], rxBytesAcrossUnderlyingIfaces);
|
totalRxBytes = Math.min(rxBytes[i], rxBytesAcrossUnderlyingIfaces);
|
||||||
}
|
}
|
||||||
long totalRxPackets = 0;
|
long totalRxPackets = 0;
|
||||||
if (tunIfaceTotal.rxPackets > 0) {
|
if (tunIfaceTotal.rxPackets > 0) {
|
||||||
final long rxPacketsAcrossUnderlyingIfaces =
|
final long rxPacketsAcrossUnderlyingIfaces =
|
||||||
underlyingIfacesTotal.rxPackets * rxPackets[i] / tunIfaceTotal.rxPackets;
|
multiplySafeByRational(underlyingIfacesTotal.rxPackets,
|
||||||
|
rxPackets[i], tunIfaceTotal.rxPackets);
|
||||||
totalRxPackets = Math.min(rxPackets[i], rxPacketsAcrossUnderlyingIfaces);
|
totalRxPackets = Math.min(rxPackets[i], rxPacketsAcrossUnderlyingIfaces);
|
||||||
}
|
}
|
||||||
long totalTxBytes = 0;
|
long totalTxBytes = 0;
|
||||||
if (tunIfaceTotal.txBytes > 0) {
|
if (tunIfaceTotal.txBytes > 0) {
|
||||||
final long txBytesAcrossUnderlyingIfaces =
|
final long txBytesAcrossUnderlyingIfaces =
|
||||||
underlyingIfacesTotal.txBytes * txBytes[i] / tunIfaceTotal.txBytes;
|
multiplySafeByRational(underlyingIfacesTotal.txBytes,
|
||||||
|
txBytes[i], tunIfaceTotal.txBytes);
|
||||||
totalTxBytes = Math.min(txBytes[i], txBytesAcrossUnderlyingIfaces);
|
totalTxBytes = Math.min(txBytes[i], txBytesAcrossUnderlyingIfaces);
|
||||||
}
|
}
|
||||||
long totalTxPackets = 0;
|
long totalTxPackets = 0;
|
||||||
if (tunIfaceTotal.txPackets > 0) {
|
if (tunIfaceTotal.txPackets > 0) {
|
||||||
final long txPacketsAcrossUnderlyingIfaces =
|
final long txPacketsAcrossUnderlyingIfaces =
|
||||||
underlyingIfacesTotal.txPackets * txPackets[i] / tunIfaceTotal.txPackets;
|
multiplySafeByRational(underlyingIfacesTotal.txPackets,
|
||||||
|
txPackets[i], tunIfaceTotal.txPackets);
|
||||||
totalTxPackets = Math.min(txPackets[i], txPacketsAcrossUnderlyingIfaces);
|
totalTxPackets = Math.min(txPackets[i], txPacketsAcrossUnderlyingIfaces);
|
||||||
}
|
}
|
||||||
long totalOperations = 0;
|
long totalOperations = 0;
|
||||||
if (tunIfaceTotal.operations > 0) {
|
if (tunIfaceTotal.operations > 0) {
|
||||||
final long operationsAcrossUnderlyingIfaces =
|
final long operationsAcrossUnderlyingIfaces =
|
||||||
underlyingIfacesTotal.operations * operations[i] / tunIfaceTotal.operations;
|
multiplySafeByRational(underlyingIfacesTotal.operations,
|
||||||
|
operations[i], tunIfaceTotal.operations);
|
||||||
totalOperations = Math.min(operations[i], operationsAcrossUnderlyingIfaces);
|
totalOperations = Math.min(operations[i], operationsAcrossUnderlyingIfaces);
|
||||||
}
|
}
|
||||||
// In a second pass, distribute these values across interfaces in the proportion that
|
// In a second pass, distribute these values across interfaces in the proportion that
|
||||||
@@ -1590,37 +1597,37 @@ public final class NetworkStats implements Parcelable {
|
|||||||
tmpEntry.set = set[i];
|
tmpEntry.set = set[i];
|
||||||
if (underlyingIfacesTotal.rxBytes > 0) {
|
if (underlyingIfacesTotal.rxBytes > 0) {
|
||||||
tmpEntry.rxBytes =
|
tmpEntry.rxBytes =
|
||||||
totalRxBytes
|
multiplySafeByRational(totalRxBytes,
|
||||||
* perInterfaceTotal[j].rxBytes
|
perInterfaceTotal[j].rxBytes,
|
||||||
/ underlyingIfacesTotal.rxBytes;
|
underlyingIfacesTotal.rxBytes);
|
||||||
}
|
}
|
||||||
tmpEntry.rxPackets = 0;
|
tmpEntry.rxPackets = 0;
|
||||||
if (underlyingIfacesTotal.rxPackets > 0) {
|
if (underlyingIfacesTotal.rxPackets > 0) {
|
||||||
tmpEntry.rxPackets =
|
tmpEntry.rxPackets =
|
||||||
totalRxPackets
|
multiplySafeByRational(totalRxPackets,
|
||||||
* perInterfaceTotal[j].rxPackets
|
perInterfaceTotal[j].rxPackets,
|
||||||
/ underlyingIfacesTotal.rxPackets;
|
underlyingIfacesTotal.rxPackets);
|
||||||
}
|
}
|
||||||
tmpEntry.txBytes = 0;
|
tmpEntry.txBytes = 0;
|
||||||
if (underlyingIfacesTotal.txBytes > 0) {
|
if (underlyingIfacesTotal.txBytes > 0) {
|
||||||
tmpEntry.txBytes =
|
tmpEntry.txBytes =
|
||||||
totalTxBytes
|
multiplySafeByRational(totalTxBytes,
|
||||||
* perInterfaceTotal[j].txBytes
|
perInterfaceTotal[j].txBytes,
|
||||||
/ underlyingIfacesTotal.txBytes;
|
underlyingIfacesTotal.txBytes);
|
||||||
}
|
}
|
||||||
tmpEntry.txPackets = 0;
|
tmpEntry.txPackets = 0;
|
||||||
if (underlyingIfacesTotal.txPackets > 0) {
|
if (underlyingIfacesTotal.txPackets > 0) {
|
||||||
tmpEntry.txPackets =
|
tmpEntry.txPackets =
|
||||||
totalTxPackets
|
multiplySafeByRational(totalTxPackets,
|
||||||
* perInterfaceTotal[j].txPackets
|
perInterfaceTotal[j].txPackets,
|
||||||
/ underlyingIfacesTotal.txPackets;
|
underlyingIfacesTotal.txPackets);
|
||||||
}
|
}
|
||||||
tmpEntry.operations = 0;
|
tmpEntry.operations = 0;
|
||||||
if (underlyingIfacesTotal.operations > 0) {
|
if (underlyingIfacesTotal.operations > 0) {
|
||||||
tmpEntry.operations =
|
tmpEntry.operations =
|
||||||
totalOperations
|
multiplySafeByRational(totalOperations,
|
||||||
* perInterfaceTotal[j].operations
|
perInterfaceTotal[j].operations,
|
||||||
/ underlyingIfacesTotal.operations;
|
underlyingIfacesTotal.operations);
|
||||||
}
|
}
|
||||||
// tmpEntry now contains the migrated data of the i-th entry for the j-th underlying
|
// tmpEntry now contains the migrated data of the i-th entry for the j-th underlying
|
||||||
// interface. Add that data usage to this object.
|
// interface. Add that data usage to this object.
|
||||||
|
|||||||
Reference in New Issue
Block a user