1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.net.module.util; 18 19 import android.app.usage.NetworkStats; 20 21 import com.android.internal.annotations.VisibleForTesting; 22 23 /** 24 * Various utilities used for NetworkStats related code. 25 * 26 * @hide 27 */ 28 public class NetworkStatsUtils { 29 // These constants must be synced with the definition in android.net.NetworkStats. 30 // TODO: update to formal APIs once all downstreams have these APIs. 31 private static final int SET_ALL = -1; 32 private static final int METERED_ALL = -1; 33 private static final int ROAMING_ALL = -1; 34 private static final int DEFAULT_NETWORK_ALL = -1; 35 36 /** 37 * Safely multiple a value by a rational. 38 * <p> 39 * Internally it uses integer-based math whenever possible, but switches 40 * over to double-based math if values would overflow. 41 * @hide 42 */ multiplySafeByRational(long value, long num, long den)43 public static long multiplySafeByRational(long value, long num, long den) { 44 if (den == 0) { 45 throw new ArithmeticException("Invalid Denominator"); 46 } 47 long x = value; 48 long y = num; 49 50 // Logic shamelessly borrowed from Math.multiplyExact() 51 long r = x * y; 52 long ax = Math.abs(x); 53 long ay = Math.abs(y); 54 if (((ax | ay) >>> 31 != 0)) { 55 // Some bits greater than 2^31 that might cause overflow 56 // Check the result using the divide operator 57 // and check for the special case of Long.MIN_VALUE * -1 58 if (((y != 0) && (r / y != x)) 59 || (x == Long.MIN_VALUE && y == -1)) { 60 // Use double math to avoid overflowing 61 return (long) (((double) num / den) * value); 62 } 63 } 64 return r / den; 65 } 66 67 /** 68 * Value of the match rule of the subscriberId to match networks with specific subscriberId. 69 * 70 * @hide 71 */ 72 public static final int SUBSCRIBER_ID_MATCH_RULE_EXACT = 0; 73 /** 74 * Value of the match rule of the subscriberId to match networks with any subscriberId which 75 * includes null and non-null. 76 * 77 * @hide 78 */ 79 public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1; 80 81 /** 82 * Name representing {@link #bandwidthSetGlobalAlert(long)} limit when delivered to 83 * {@link AlertObserver#onQuotaLimitReached(String, String)}. 84 */ 85 public static final String LIMIT_GLOBAL_ALERT = "globalAlert"; 86 87 /** 88 * Return the constrained value by given the lower and upper bounds. 89 */ constrain(int amount, int low, int high)90 public static int constrain(int amount, int low, int high) { 91 if (low > high) throw new IllegalArgumentException("low(" + low + ") > high(" + high + ")"); 92 return amount < low ? low : (amount > high ? high : amount); 93 } 94 95 /** 96 * Return the constrained value by given the lower and upper bounds. 97 */ constrain(long amount, long low, long high)98 public static long constrain(long amount, long low, long high) { 99 if (low > high) throw new IllegalArgumentException("low(" + low + ") > high(" + high + ")"); 100 return amount < low ? low : (amount > high ? high : amount); 101 } 102 103 /** 104 * Convert structure from android.app.usage.NetworkStats to android.net.NetworkStats. 105 */ fromPublicNetworkStats( NetworkStats publiceNetworkStats)106 public static android.net.NetworkStats fromPublicNetworkStats( 107 NetworkStats publiceNetworkStats) { 108 android.net.NetworkStats stats = new android.net.NetworkStats(0L, 0); 109 while (publiceNetworkStats.hasNextBucket()) { 110 NetworkStats.Bucket bucket = new NetworkStats.Bucket(); 111 publiceNetworkStats.getNextBucket(bucket); 112 final android.net.NetworkStats.Entry entry = fromBucket(bucket); 113 stats = stats.addEntry(entry); 114 } 115 return stats; 116 } 117 118 @VisibleForTesting fromBucket(NetworkStats.Bucket bucket)119 public static android.net.NetworkStats.Entry fromBucket(NetworkStats.Bucket bucket) { 120 return new android.net.NetworkStats.Entry( 121 null /* IFACE_ALL */, bucket.getUid(), convertBucketState(bucket.getState()), 122 convertBucketTag(bucket.getTag()), convertBucketMetered(bucket.getMetered()), 123 convertBucketRoaming(bucket.getRoaming()), 124 convertBucketDefaultNetworkStatus(bucket.getDefaultNetworkStatus()), 125 bucket.getRxBytes(), bucket.getRxPackets(), 126 bucket.getTxBytes(), bucket.getTxPackets(), 0 /* operations */); 127 } 128 convertBucketState(int networkStatsSet)129 private static int convertBucketState(int networkStatsSet) { 130 switch (networkStatsSet) { 131 case NetworkStats.Bucket.STATE_ALL: return SET_ALL; 132 case NetworkStats.Bucket.STATE_DEFAULT: return android.net.NetworkStats.SET_DEFAULT; 133 case NetworkStats.Bucket.STATE_FOREGROUND: 134 return android.net.NetworkStats.SET_FOREGROUND; 135 } 136 return 0; 137 } 138 convertBucketTag(int tag)139 private static int convertBucketTag(int tag) { 140 switch (tag) { 141 case NetworkStats.Bucket.TAG_NONE: return android.net.NetworkStats.TAG_NONE; 142 } 143 return tag; 144 } 145 convertBucketMetered(int metered)146 private static int convertBucketMetered(int metered) { 147 switch (metered) { 148 case NetworkStats.Bucket.METERED_ALL: return METERED_ALL; 149 case NetworkStats.Bucket.METERED_NO: return android.net.NetworkStats.METERED_NO; 150 case NetworkStats.Bucket.METERED_YES: return android.net.NetworkStats.METERED_YES; 151 } 152 return 0; 153 } 154 convertBucketRoaming(int roaming)155 private static int convertBucketRoaming(int roaming) { 156 switch (roaming) { 157 case NetworkStats.Bucket.ROAMING_ALL: return ROAMING_ALL; 158 case NetworkStats.Bucket.ROAMING_NO: return android.net.NetworkStats.ROAMING_NO; 159 case NetworkStats.Bucket.ROAMING_YES: return android.net.NetworkStats.ROAMING_YES; 160 } 161 return 0; 162 } 163 convertBucketDefaultNetworkStatus(int defaultNetworkStatus)164 private static int convertBucketDefaultNetworkStatus(int defaultNetworkStatus) { 165 switch (defaultNetworkStatus) { 166 case NetworkStats.Bucket.DEFAULT_NETWORK_ALL: 167 return DEFAULT_NETWORK_ALL; 168 case NetworkStats.Bucket.DEFAULT_NETWORK_NO: 169 return android.net.NetworkStats.DEFAULT_NETWORK_NO; 170 case NetworkStats.Bucket.DEFAULT_NETWORK_YES: 171 return android.net.NetworkStats.DEFAULT_NETWORK_YES; 172 } 173 return 0; 174 } 175 } 176