1 /* 2 * Copyright (C) 2018 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.server.wifi.util; 18 19 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; 20 import android.util.SparseIntArray; 21 22 import com.android.server.wifi.WifiBlocklistMonitor; 23 import com.android.server.wifi.proto.nano.WifiMetricsProto.NetworkDisableReason; 24 25 /** 26 * Utilities for Metrics collections. 27 */ 28 public class MetricsUtils { 29 /** 30 * A generic bucket containing a start, end, and count. The utility classes will convert to 31 * such a generic bucket which can then be copied into the specific bucket of the proto. 32 */ 33 public static class GenericBucket { 34 public long start; 35 public long end; 36 public int count; 37 } 38 39 /** 40 * Specifies a ~log histogram consisting of two levels of buckets - a set of N big buckets: 41 * 42 * Buckets starts at: B + P * M^i, where i=0, ... , N-1 (N big buckets) 43 * Each big bucket is divided into S sub-buckets 44 * 45 * Each (big) bucket is M times bigger than the previous one. 46 * 47 * The buckets are then: 48 * #0: B + P * M^0 with S buckets each of width (P*M^1-P*M^0)/S 49 * #1: B + P * M^1 with S buckets each of width (P*M^2-P*M^1)/S 50 * ... 51 * #N-1: B + P * M^(N-1) with S buckets each of width (P*M^N-P*M^(N-1))/S 52 */ 53 public static class LogHistParms { LogHistParms(int b, int p, int m, int s, int n)54 public LogHistParms(int b, int p, int m, int s, int n) { 55 this.b = b; 56 this.p = p; 57 this.m = m; 58 this.s = s; 59 this.n = n; 60 61 // derived values 62 mLog = Math.log(m); 63 bb = new double[n]; 64 sbw = new double[n]; 65 bb[0] = b + p; 66 sbw[0] = p * (m - 1.0) / (double) s; 67 for (int i = 1; i < n; ++i) { 68 bb[i] = m * (bb[i - 1] - b) + b; 69 sbw[i] = m * sbw[i - 1]; 70 } 71 } 72 73 // spec 74 public int b; 75 public int p; 76 public int m; 77 public int s; 78 public int n; 79 80 // derived 81 public double mLog; 82 public double[] bb; // bucket base 83 public double[] sbw; // sub-bucket width 84 } 85 86 /** 87 * Adds the input value to the log histogram based on the histogram parameters. 88 */ addValueToLogHistogram(long x, SparseIntArray histogram, LogHistParms hp)89 public static int addValueToLogHistogram(long x, SparseIntArray histogram, LogHistParms hp) { 90 double logArg = (double) (x - hp.b) / (double) hp.p; 91 int bigBucketIndex = -1; 92 if (logArg > 0) { 93 bigBucketIndex = (int) (Math.log(logArg) / hp.mLog); 94 } 95 int subBucketIndex; 96 if (bigBucketIndex < 0) { 97 bigBucketIndex = 0; 98 subBucketIndex = 0; 99 } else if (bigBucketIndex >= hp.n) { 100 bigBucketIndex = hp.n - 1; 101 subBucketIndex = hp.s - 1; 102 } else { 103 subBucketIndex = (int) ((x - hp.bb[bigBucketIndex]) / hp.sbw[bigBucketIndex]); 104 if (subBucketIndex >= hp.s) { // probably a rounding error so move to next big bucket 105 bigBucketIndex++; 106 if (bigBucketIndex >= hp.n) { 107 bigBucketIndex = hp.n - 1; 108 subBucketIndex = hp.s - 1; 109 } else { 110 subBucketIndex = (int) ((x - hp.bb[bigBucketIndex]) / hp.sbw[bigBucketIndex]); 111 } 112 } 113 } 114 int key = bigBucketIndex * hp.s + subBucketIndex; 115 116 // note that get() returns 0 if index not there already 117 int newValue = histogram.get(key) + 1; 118 histogram.put(key, newValue); 119 120 return newValue; 121 } 122 123 /** 124 * Converts the log histogram (with the specified histogram parameters) to an array of generic 125 * histogram buckets. 126 */ logHistogramToGenericBuckets(SparseIntArray histogram, LogHistParms hp)127 public static GenericBucket[] logHistogramToGenericBuckets(SparseIntArray histogram, 128 LogHistParms hp) { 129 GenericBucket[] protoArray = new GenericBucket[histogram.size()]; 130 for (int i = 0; i < histogram.size(); ++i) { 131 int key = histogram.keyAt(i); 132 133 protoArray[i] = new GenericBucket(); 134 protoArray[i].start = (long) (hp.bb[key / hp.s] + hp.sbw[key / hp.s] * (key % hp.s)); 135 protoArray[i].end = (long) (protoArray[i].start + hp.sbw[key / hp.s]); 136 protoArray[i].count = histogram.valueAt(i); 137 } 138 139 return protoArray; 140 } 141 142 /** 143 * Adds the input value to the histogram based on the lineaer histogram parameters. 144 * 145 * The 'int[] hp' contains a list of bucket limits. The number of buckets is hp.length() + 1 146 * where buckets are: 147 * - < hp[0] 148 * - [hp[0], hp[1]) 149 * ... 150 * - >= hp[hp.length() - 1] 151 */ addValueToLinearHistogram(int x, SparseIntArray histogram, int[] hp)152 public static int addValueToLinearHistogram(int x, SparseIntArray histogram, int[] hp) { 153 int bucket = 0; 154 for (int limit : hp) { 155 if (x >= limit) { 156 bucket++; 157 continue; 158 } 159 break; 160 } 161 162 // note that get() returns 0 if index not there already 163 int newValue = histogram.get(bucket) + 1; 164 histogram.put(bucket, newValue); 165 166 return newValue; 167 } 168 169 /** 170 * Converts the histogram (with the specified linear histogram parameters) to an array of 171 * generic histogram buckets. 172 */ linearHistogramToGenericBuckets(SparseIntArray histogram, int[] linearHistParams)173 public static GenericBucket[] linearHistogramToGenericBuckets(SparseIntArray histogram, 174 int[] linearHistParams) { 175 GenericBucket[] protoArray = new GenericBucket[histogram.size()]; 176 for (int i = 0; i < histogram.size(); ++i) { 177 int bucket = histogram.keyAt(i); 178 179 protoArray[i] = new GenericBucket(); 180 if (bucket == 0) { 181 protoArray[i].start = Integer.MIN_VALUE; 182 protoArray[i].end = linearHistParams[0]; 183 } else if (bucket != linearHistParams.length) { 184 protoArray[i].start = linearHistParams[bucket - 1]; 185 protoArray[i].end = linearHistParams[bucket]; 186 } else { 187 protoArray[i].start = linearHistParams[linearHistParams.length - 1]; 188 protoArray[i].end = Integer.MAX_VALUE; 189 } 190 protoArray[i].count = histogram.valueAt(i); 191 } 192 193 return protoArray; 194 } 195 196 /** 197 * Converts NetworkSelectionStatus.NetworkSelectionDisableReason to 198 * WifiMetricsProto.NetworkDisableReason.DisableReason 199 */ convertNetworkSelectionDisableReasonToWifiProtoEnum(int reason)200 public static int convertNetworkSelectionDisableReasonToWifiProtoEnum(int reason) { 201 switch (reason) { 202 case NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION: 203 return NetworkDisableReason.REASON_ASSOCIATION_REJECTION; 204 case NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE: 205 return NetworkDisableReason.REASON_AUTHENTICATION_FAILURE; 206 case NetworkSelectionStatus.DISABLED_DHCP_FAILURE: 207 return NetworkDisableReason.REASON_DHCP_FAILURE; 208 case NetworkSelectionStatus.DISABLED_NO_INTERNET_TEMPORARY: 209 case NetworkSelectionStatus.DISABLED_NO_INTERNET_PERMANENT: 210 return NetworkDisableReason.REASON_NETWORK_VALIDATION_FAILURE; 211 case NetworkSelectionStatus.DISABLED_AUTHENTICATION_NO_CREDENTIALS: 212 return NetworkDisableReason.REASON_AUTHENTICATION_NO_CREDENTIALS; 213 case NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD: 214 return NetworkDisableReason.REASON_WRONG_PASSWORD; 215 case NetworkSelectionStatus.DISABLED_AUTHENTICATION_NO_SUBSCRIPTION: 216 return NetworkDisableReason.REASON_AUTHENTICATION_NO_SUBSCRIPTION; 217 default: 218 return NetworkDisableReason.REASON_UNKNOWN; 219 } 220 } 221 222 /** 223 * Converts WifiBlocklistMonitor.FailureReason to 224 * WifiMetricsProto.NetworkDisableReason.DisableReason 225 */ convertBssidBlocklistReasonToWifiProtoEnum(int reason)226 public static int convertBssidBlocklistReasonToWifiProtoEnum(int reason) { 227 switch (reason) { 228 case WifiBlocklistMonitor.REASON_AP_UNABLE_TO_HANDLE_NEW_STA: 229 return NetworkDisableReason.REASON_AP_UNABLE_TO_HANDLE_NEW_STA; 230 case WifiBlocklistMonitor.REASON_NETWORK_VALIDATION_FAILURE: 231 return NetworkDisableReason.REASON_NETWORK_VALIDATION_FAILURE; 232 case WifiBlocklistMonitor.REASON_WRONG_PASSWORD: 233 return NetworkDisableReason.REASON_WRONG_PASSWORD; 234 case WifiBlocklistMonitor.REASON_EAP_FAILURE: 235 return NetworkDisableReason.REASON_EAP_FAILURE; 236 case WifiBlocklistMonitor.REASON_ASSOCIATION_REJECTION: 237 return NetworkDisableReason.REASON_ASSOCIATION_REJECTION; 238 case WifiBlocklistMonitor.REASON_ASSOCIATION_TIMEOUT: 239 return NetworkDisableReason.REASON_ASSOCIATION_TIMEOUT; 240 case WifiBlocklistMonitor.REASON_AUTHENTICATION_FAILURE: 241 return NetworkDisableReason.REASON_AUTHENTICATION_FAILURE; 242 case WifiBlocklistMonitor.REASON_DHCP_FAILURE: 243 return NetworkDisableReason.REASON_DHCP_FAILURE; 244 case WifiBlocklistMonitor.REASON_ABNORMAL_DISCONNECT: 245 return NetworkDisableReason.REASON_ABNORMAL_DISCONNECT; 246 case WifiBlocklistMonitor.REASON_FRAMEWORK_DISCONNECT_MBO_OCE: 247 return NetworkDisableReason.REASON_FRAMEWORK_DISCONNECT_MBO_OCE; 248 case WifiBlocklistMonitor.REASON_FRAMEWORK_DISCONNECT_FAST_RECONNECT: 249 return NetworkDisableReason.REASON_FRAMEWORK_DISCONNECT_FAST_RECONNECT; 250 case WifiBlocklistMonitor.REASON_FRAMEWORK_DISCONNECT_CONNECTED_SCORE: 251 return NetworkDisableReason.REASON_FRAMEWORK_DISCONNECT_CONNECTED_SCORE; 252 default: 253 return NetworkDisableReason.REASON_UNKNOWN; 254 } 255 } 256 } 257