/* * Copyright (C) 2018 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.server.wifi.util; import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; import android.util.SparseIntArray; import com.android.server.wifi.WifiBlocklistMonitor; import com.android.server.wifi.proto.nano.WifiMetricsProto.NetworkDisableReason; /** * Utilities for Metrics collections. */ public class MetricsUtils { /** * A generic bucket containing a start, end, and count. The utility classes will convert to * such a generic bucket which can then be copied into the specific bucket of the proto. */ public static class GenericBucket { public long start; public long end; public int count; } /** * Specifies a ~log histogram consisting of two levels of buckets - a set of N big buckets: * * Buckets starts at: B + P * M^i, where i=0, ... , N-1 (N big buckets) * Each big bucket is divided into S sub-buckets * * Each (big) bucket is M times bigger than the previous one. * * The buckets are then: * #0: B + P * M^0 with S buckets each of width (P*M^1-P*M^0)/S * #1: B + P * M^1 with S buckets each of width (P*M^2-P*M^1)/S * ... * #N-1: B + P * M^(N-1) with S buckets each of width (P*M^N-P*M^(N-1))/S */ public static class LogHistParms { public LogHistParms(int b, int p, int m, int s, int n) { this.b = b; this.p = p; this.m = m; this.s = s; this.n = n; // derived values mLog = Math.log(m); bb = new double[n]; sbw = new double[n]; bb[0] = b + p; sbw[0] = p * (m - 1.0) / (double) s; for (int i = 1; i < n; ++i) { bb[i] = m * (bb[i - 1] - b) + b; sbw[i] = m * sbw[i - 1]; } } // spec public int b; public int p; public int m; public int s; public int n; // derived public double mLog; public double[] bb; // bucket base public double[] sbw; // sub-bucket width } /** * Adds the input value to the log histogram based on the histogram parameters. */ public static int addValueToLogHistogram(long x, SparseIntArray histogram, LogHistParms hp) { double logArg = (double) (x - hp.b) / (double) hp.p; int bigBucketIndex = -1; if (logArg > 0) { bigBucketIndex = (int) (Math.log(logArg) / hp.mLog); } int subBucketIndex; if (bigBucketIndex < 0) { bigBucketIndex = 0; subBucketIndex = 0; } else if (bigBucketIndex >= hp.n) { bigBucketIndex = hp.n - 1; subBucketIndex = hp.s - 1; } else { subBucketIndex = (int) ((x - hp.bb[bigBucketIndex]) / hp.sbw[bigBucketIndex]); if (subBucketIndex >= hp.s) { // probably a rounding error so move to next big bucket bigBucketIndex++; if (bigBucketIndex >= hp.n) { bigBucketIndex = hp.n - 1; subBucketIndex = hp.s - 1; } else { subBucketIndex = (int) ((x - hp.bb[bigBucketIndex]) / hp.sbw[bigBucketIndex]); } } } int key = bigBucketIndex * hp.s + subBucketIndex; // note that get() returns 0 if index not there already int newValue = histogram.get(key) + 1; histogram.put(key, newValue); return newValue; } /** * Converts the log histogram (with the specified histogram parameters) to an array of generic * histogram buckets. */ public static GenericBucket[] logHistogramToGenericBuckets(SparseIntArray histogram, LogHistParms hp) { GenericBucket[] protoArray = new GenericBucket[histogram.size()]; for (int i = 0; i < histogram.size(); ++i) { int key = histogram.keyAt(i); protoArray[i] = new GenericBucket(); protoArray[i].start = (long) (hp.bb[key / hp.s] + hp.sbw[key / hp.s] * (key % hp.s)); protoArray[i].end = (long) (protoArray[i].start + hp.sbw[key / hp.s]); protoArray[i].count = histogram.valueAt(i); } return protoArray; } /** * Adds the input value to the histogram based on the lineaer histogram parameters. * * The 'int[] hp' contains a list of bucket limits. The number of buckets is hp.length() + 1 * where buckets are: * - < hp[0] * - [hp[0], hp[1]) * ... * - >= hp[hp.length() - 1] */ public static int addValueToLinearHistogram(int x, SparseIntArray histogram, int[] hp) { int bucket = 0; for (int limit : hp) { if (x >= limit) { bucket++; continue; } break; } // note that get() returns 0 if index not there already int newValue = histogram.get(bucket) + 1; histogram.put(bucket, newValue); return newValue; } /** * Converts the histogram (with the specified linear histogram parameters) to an array of * generic histogram buckets. */ public static GenericBucket[] linearHistogramToGenericBuckets(SparseIntArray histogram, int[] linearHistParams) { GenericBucket[] protoArray = new GenericBucket[histogram.size()]; for (int i = 0; i < histogram.size(); ++i) { int bucket = histogram.keyAt(i); protoArray[i] = new GenericBucket(); if (bucket == 0) { protoArray[i].start = Integer.MIN_VALUE; protoArray[i].end = linearHistParams[0]; } else if (bucket != linearHistParams.length) { protoArray[i].start = linearHistParams[bucket - 1]; protoArray[i].end = linearHistParams[bucket]; } else { protoArray[i].start = linearHistParams[linearHistParams.length - 1]; protoArray[i].end = Integer.MAX_VALUE; } protoArray[i].count = histogram.valueAt(i); } return protoArray; } /** * Converts NetworkSelectionStatus.NetworkSelectionDisableReason to * WifiMetricsProto.NetworkDisableReason.DisableReason */ public static int convertNetworkSelectionDisableReasonToWifiProtoEnum(int reason) { switch (reason) { case NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION: return NetworkDisableReason.REASON_ASSOCIATION_REJECTION; case NetworkSelectionStatus.DISABLED_AUTHENTICATION_FAILURE: return NetworkDisableReason.REASON_AUTHENTICATION_FAILURE; case NetworkSelectionStatus.DISABLED_DHCP_FAILURE: return NetworkDisableReason.REASON_DHCP_FAILURE; case NetworkSelectionStatus.DISABLED_NO_INTERNET_TEMPORARY: case NetworkSelectionStatus.DISABLED_NO_INTERNET_PERMANENT: return NetworkDisableReason.REASON_NETWORK_VALIDATION_FAILURE; case NetworkSelectionStatus.DISABLED_AUTHENTICATION_NO_CREDENTIALS: return NetworkDisableReason.REASON_AUTHENTICATION_NO_CREDENTIALS; case NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD: return NetworkDisableReason.REASON_WRONG_PASSWORD; case NetworkSelectionStatus.DISABLED_AUTHENTICATION_NO_SUBSCRIPTION: return NetworkDisableReason.REASON_AUTHENTICATION_NO_SUBSCRIPTION; default: return NetworkDisableReason.REASON_UNKNOWN; } } /** * Converts WifiBlocklistMonitor.FailureReason to * WifiMetricsProto.NetworkDisableReason.DisableReason */ public static int convertBssidBlocklistReasonToWifiProtoEnum(int reason) { switch (reason) { case WifiBlocklistMonitor.REASON_AP_UNABLE_TO_HANDLE_NEW_STA: return NetworkDisableReason.REASON_AP_UNABLE_TO_HANDLE_NEW_STA; case WifiBlocklistMonitor.REASON_NETWORK_VALIDATION_FAILURE: return NetworkDisableReason.REASON_NETWORK_VALIDATION_FAILURE; case WifiBlocklistMonitor.REASON_WRONG_PASSWORD: return NetworkDisableReason.REASON_WRONG_PASSWORD; case WifiBlocklistMonitor.REASON_EAP_FAILURE: return NetworkDisableReason.REASON_EAP_FAILURE; case WifiBlocklistMonitor.REASON_ASSOCIATION_REJECTION: return NetworkDisableReason.REASON_ASSOCIATION_REJECTION; case WifiBlocklistMonitor.REASON_ASSOCIATION_TIMEOUT: return NetworkDisableReason.REASON_ASSOCIATION_TIMEOUT; case WifiBlocklistMonitor.REASON_AUTHENTICATION_FAILURE: return NetworkDisableReason.REASON_AUTHENTICATION_FAILURE; case WifiBlocklistMonitor.REASON_DHCP_FAILURE: return NetworkDisableReason.REASON_DHCP_FAILURE; case WifiBlocklistMonitor.REASON_ABNORMAL_DISCONNECT: return NetworkDisableReason.REASON_ABNORMAL_DISCONNECT; case WifiBlocklistMonitor.REASON_FRAMEWORK_DISCONNECT_MBO_OCE: return NetworkDisableReason.REASON_FRAMEWORK_DISCONNECT_MBO_OCE; case WifiBlocklistMonitor.REASON_FRAMEWORK_DISCONNECT_FAST_RECONNECT: return NetworkDisableReason.REASON_FRAMEWORK_DISCONNECT_FAST_RECONNECT; case WifiBlocklistMonitor.REASON_FRAMEWORK_DISCONNECT_CONNECTED_SCORE: return NetworkDisableReason.REASON_FRAMEWORK_DISCONNECT_CONNECTED_SCORE; default: return NetworkDisableReason.REASON_UNKNOWN; } } }