| /* |
| * Copyright (C) 2016 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; |
| |
| import static android.net.wifi.WifiConfiguration.MeteredOverride; |
| |
| import static java.lang.StrictMath.toIntExact; |
| |
| import android.annotation.IntDef; |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.app.ActivityManager; |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.content.pm.PackageManager; |
| import android.content.pm.ResolveInfo; |
| import android.hardware.wifi.supplicant.V1_0.ISupplicantStaIfaceCallback; |
| import android.net.wifi.EAPConstants; |
| import android.net.wifi.IOnWifiUsabilityStatsListener; |
| import android.net.wifi.ScanResult; |
| import android.net.wifi.SoftApCapability; |
| import android.net.wifi.SoftApConfiguration; |
| import android.net.wifi.SoftApInfo; |
| import android.net.wifi.SupplicantState; |
| import android.net.wifi.WifiConfiguration; |
| import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; |
| import android.net.wifi.WifiEnterpriseConfig; |
| import android.net.wifi.WifiInfo; |
| import android.net.wifi.WifiManager; |
| import android.net.wifi.WifiManager.DeviceMobilityState; |
| import android.net.wifi.WifiUsabilityStatsEntry.ProbeStatus; |
| import android.net.wifi.hotspot2.PasspointConfiguration; |
| import android.net.wifi.hotspot2.ProvisioningCallback; |
| import android.net.wifi.hotspot2.ProvisioningCallback.OsuFailure; |
| import android.net.wifi.nl80211.WifiNl80211Manager; |
| import android.os.Handler; |
| import android.os.Looper; |
| import android.os.Message; |
| import android.os.PowerManager; |
| import android.os.RemoteCallbackList; |
| import android.os.RemoteException; |
| import android.os.SystemProperties; |
| import android.os.WorkSource; |
| import android.provider.Settings; |
| import android.telephony.TelephonyManager; |
| import android.text.TextUtils; |
| import android.util.ArrayMap; |
| import android.util.ArraySet; |
| import android.util.Base64; |
| import android.util.Log; |
| import android.util.Pair; |
| import android.util.SparseArray; |
| import android.util.SparseBooleanArray; |
| import android.util.SparseIntArray; |
| |
| import com.android.internal.annotations.VisibleForTesting; |
| import com.android.server.wifi.aware.WifiAwareMetrics; |
| import com.android.server.wifi.hotspot2.ANQPNetworkKey; |
| import com.android.server.wifi.hotspot2.NetworkDetail; |
| import com.android.server.wifi.hotspot2.PasspointManager; |
| import com.android.server.wifi.hotspot2.PasspointMatch; |
| import com.android.server.wifi.hotspot2.PasspointProvider; |
| import com.android.server.wifi.hotspot2.Utils; |
| import com.android.server.wifi.p2p.WifiP2pMetrics; |
| import com.android.server.wifi.proto.WifiStatsLog; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.ConnectToNetworkNotificationAndActionCount; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.ContentionTimeStats; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.DeviceMobilityStatePnoScanStats; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.ExperimentValues; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.FirstConnectAfterBootStats; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.FirstConnectAfterBootStats.Attempt; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.HealthMonitorMetrics; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.InitPartialScanStats; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.LinkProbeStats; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.LinkProbeStats.ExperimentProbeCounts; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.LinkProbeStats.LinkProbeFailureReasonCount; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.LinkSpeedCount; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.MeteredNetworkStats; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.NetworkDisableReason; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.NetworkSelectionExperimentDecisions; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.PasspointProfileTypeCount; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.PasspointProvisionStats; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.PasspointProvisionStats.ProvisionFailureCount; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.PnoScanMetrics; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.RadioStats; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.RateStats; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.SoftApConnectedClientsEvent; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.StaEvent; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.StaEvent.ConfigInfo; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.TargetNetworkInfo; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.UserActionEvent; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.UserReactionToApprovalUiEvent; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.UserReactionToApprovalUiEvent.UserReaction; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiIsUnusableEvent; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiLinkLayerUsageStats; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiLockStats; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiNetworkRequestApiLog; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiNetworkSuggestionApiLog; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiNetworkSuggestionApiLog.SuggestionAppCount; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiStatus; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiToWifiSwitchStats; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiToggleStats; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiUsabilityStats; |
| import com.android.server.wifi.proto.nano.WifiMetricsProto.WifiUsabilityStatsEntry; |
| import com.android.server.wifi.rtt.RttMetrics; |
| import com.android.server.wifi.scanner.KnownBandsChannelHelper; |
| import com.android.server.wifi.util.InformationElementUtil; |
| import com.android.server.wifi.util.IntCounter; |
| import com.android.server.wifi.util.IntHistogram; |
| import com.android.server.wifi.util.MetricsUtils; |
| import com.android.server.wifi.util.ObjectCounter; |
| import com.android.server.wifi.util.ScanResultUtil; |
| import com.android.wifi.resources.R; |
| |
| import org.json.JSONArray; |
| import org.json.JSONException; |
| import org.json.JSONObject; |
| |
| import java.io.FileDescriptor; |
| import java.io.PrintWriter; |
| import java.time.Duration; |
| import java.util.ArrayDeque; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.BitSet; |
| import java.util.Calendar; |
| import java.util.Deque; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Random; |
| import java.util.Set; |
| |
| /** |
| * Provides storage for wireless connectivity metrics, as they are generated. |
| * Metrics logged by this class include: |
| * Aggregated connection stats (num of connections, num of failures, ...) |
| * Discrete connection event stats (time, duration, failure codes, ...) |
| * Router details (technology type, authentication type, ...) |
| * Scan stats |
| */ |
| public class WifiMetrics { |
| private static final String TAG = "WifiMetrics"; |
| private static final boolean DBG = false; |
| |
| /** |
| * Clamp the RSSI poll counts to values between [MIN,MAX]_RSSI_POLL |
| */ |
| private static final int MAX_RSSI_POLL = 0; |
| private static final int MIN_RSSI_POLL = -127; |
| public static final int MAX_RSSI_DELTA = 127; |
| public static final int MIN_RSSI_DELTA = -127; |
| /** Minimum link speed (Mbps) to count for link_speed_counts */ |
| public static final int MIN_LINK_SPEED_MBPS = 0; |
| /** Maximum time period between ScanResult and RSSI poll to generate rssi delta datapoint */ |
| public static final long TIMEOUT_RSSI_DELTA_MILLIS = 3000; |
| private static final int MIN_WIFI_SCORE = 0; |
| private static final int MAX_WIFI_SCORE = ConnectedScore.WIFI_MAX_SCORE; |
| private static final int MIN_WIFI_USABILITY_SCORE = 0; // inclusive |
| private static final int MAX_WIFI_USABILITY_SCORE = 100; // inclusive |
| @VisibleForTesting |
| static final int LOW_WIFI_SCORE = 50; // Mobile data score |
| @VisibleForTesting |
| static final int LOW_WIFI_USABILITY_SCORE = 50; // Mobile data score |
| private final Object mLock = new Object(); |
| private static final int MAX_CONNECTION_EVENTS = 256; |
| // Largest bucket in the NumConnectableNetworkCount histogram, |
| // anything large will be stored in this bucket |
| public static final int MAX_CONNECTABLE_SSID_NETWORK_BUCKET = 20; |
| public static final int MAX_CONNECTABLE_BSSID_NETWORK_BUCKET = 50; |
| public static final int MAX_TOTAL_SCAN_RESULT_SSIDS_BUCKET = 100; |
| public static final int MAX_TOTAL_SCAN_RESULTS_BUCKET = 250; |
| public static final int MAX_TOTAL_PASSPOINT_APS_BUCKET = 50; |
| public static final int MAX_TOTAL_PASSPOINT_UNIQUE_ESS_BUCKET = 20; |
| public static final int MAX_PASSPOINT_APS_PER_UNIQUE_ESS_BUCKET = 50; |
| public static final int MAX_TOTAL_80211MC_APS_BUCKET = 20; |
| private static final int CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER = 1000; |
| // Max limit for number of soft AP related events, extra events will be dropped. |
| private static final int MAX_NUM_SOFT_AP_EVENTS = 256; |
| // Maximum number of WifiIsUnusableEvent |
| public static final int MAX_UNUSABLE_EVENTS = 20; |
| // Minimum time wait before generating next WifiIsUnusableEvent from data stall |
| public static final int MIN_DATA_STALL_WAIT_MS = 120 * 1000; // 2 minutes |
| // Max number of WifiUsabilityStatsEntry elements to store in the ringbuffer. |
| public static final int MAX_WIFI_USABILITY_STATS_ENTRIES_LIST_SIZE = 40; |
| // Max number of WifiUsabilityStats elements to store for each type. |
| public static final int MAX_WIFI_USABILITY_STATS_LIST_SIZE_PER_TYPE = 10; |
| // Max number of WifiUsabilityStats per labeled type to upload to server |
| public static final int MAX_WIFI_USABILITY_STATS_PER_TYPE_TO_UPLOAD = 2; |
| public static final int NUM_WIFI_USABILITY_STATS_ENTRIES_PER_WIFI_GOOD = 100; |
| public static final int MIN_WIFI_GOOD_USABILITY_STATS_PERIOD_MS = 1000 * 3600; // 1 hour |
| public static final int PASSPOINT_DEAUTH_IMMINENT_SCOPE_ESS = 0; |
| public static final int PASSPOINT_DEAUTH_IMMINENT_SCOPE_BSS = 1; |
| // Histogram for WifiConfigStore IO duration times. Indicates the following 5 buckets (in ms): |
| // < 50 |
| // [50, 100) |
| // [100, 150) |
| // [150, 200) |
| // [200, 300) |
| // >= 300 |
| private static final int[] WIFI_CONFIG_STORE_IO_DURATION_BUCKET_RANGES_MS = |
| {50, 100, 150, 200, 300}; |
| // Minimum time wait before generating a LABEL_GOOD stats after score breaching low. |
| public static final int MIN_SCORE_BREACH_TO_GOOD_STATS_WAIT_TIME_MS = 60 * 1000; // 1 minute |
| // Maximum time that a score breaching low event stays valid. |
| public static final int VALIDITY_PERIOD_OF_SCORE_BREACH_LOW_MS = 90 * 1000; // 1.5 minutes |
| |
| private static final int WIFI_RECONNECT_DURATION_SHORT_MILLIS = 10 * 1000; |
| private static final int WIFI_RECONNECT_DURATION_MEDIUM_MILLIS = 60 * 1000; |
| // Number of WME Access Categories |
| private static final int NUM_WME_ACCESS_CATEGORIES = 4; |
| private static final int MBB_LINGERING_DURATION_MAX_SECONDS = 30; |
| |
| private Clock mClock; |
| private boolean mScreenOn; |
| private int mWifiState; |
| private WifiAwareMetrics mWifiAwareMetrics; |
| private RttMetrics mRttMetrics; |
| private final PnoScanMetrics mPnoScanMetrics = new PnoScanMetrics(); |
| private final WifiLinkLayerUsageStats mWifiLinkLayerUsageStats = new WifiLinkLayerUsageStats(); |
| /** Mapping of radio id values to RadioStats objects. */ |
| private final SparseArray<RadioStats> mRadioStats = new SparseArray<>(); |
| private final ExperimentValues mExperimentValues = new ExperimentValues(); |
| private Handler mHandler; |
| private ScoringParams mScoringParams; |
| private WifiConfigManager mWifiConfigManager; |
| private WifiBlocklistMonitor mWifiBlocklistMonitor; |
| private WifiNetworkSelector mWifiNetworkSelector; |
| private PasspointManager mPasspointManager; |
| private Context mContext; |
| private FrameworkFacade mFacade; |
| private WifiDataStall mWifiDataStall; |
| private WifiLinkLayerStats mLastLinkLayerStats; |
| private WifiHealthMonitor mWifiHealthMonitor; |
| private WifiScoreCard mWifiScoreCard; |
| private SessionData mPreviousSession; |
| private SessionData mCurrentSession; |
| private String mLastBssid; |
| private int mLastFrequency = -1; |
| private int mSeqNumInsideFramework = 0; |
| private int mLastWifiUsabilityScore = -1; |
| private int mLastWifiUsabilityScoreNoReset = -1; |
| private int mLastPredictionHorizonSec = -1; |
| private int mLastPredictionHorizonSecNoReset = -1; |
| private int mSeqNumToFramework = -1; |
| @ProbeStatus private int mProbeStatusSinceLastUpdate = |
| android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE; |
| private int mProbeElapsedTimeSinceLastUpdateMs = -1; |
| private int mProbeMcsRateSinceLastUpdate = -1; |
| private long mScoreBreachLowTimeMillis = -1; |
| |
| public static final int MAX_STA_EVENTS = 768; |
| @VisibleForTesting static final int MAX_USER_ACTION_EVENTS = 200; |
| private LinkedList<StaEventWithTime> mStaEventList = new LinkedList<>(); |
| private LinkedList<UserActionEventWithTime> mUserActionEventList = new LinkedList<>(); |
| private WifiStatusBuilder mWifiStatusBuilder = new WifiStatusBuilder(); |
| private int mLastPollRssi = -127; |
| private int mLastPollLinkSpeed = -1; |
| private int mLastPollRxLinkSpeed = -1; |
| private int mLastPollFreq = -1; |
| private int mLastScore = -1; |
| private boolean mAdaptiveConnectivityEnabled = true; |
| private ScanMetrics mScanMetrics; |
| private WifiChannelUtilization mWifiChannelUtilization; |
| private WifiSettingsStore mWifiSettingsStore; |
| private IntCounter mPasspointDeauthImminentScope = new IntCounter(); |
| private IntCounter mRecentFailureAssociationStatus = new IntCounter(); |
| private boolean mFirstConnectionAfterBoot = true; |
| |
| /** |
| * Metrics are stored within an instance of the WifiLog proto during runtime, |
| * The ConnectionEvent, SystemStateEntries & ScanReturnEntries metrics are stored during |
| * runtime in member lists of this WifiMetrics class, with the final WifiLog proto being pieced |
| * together at dump-time |
| */ |
| private final WifiMetricsProto.WifiLog mWifiLogProto = new WifiMetricsProto.WifiLog(); |
| /** |
| * Session information that gets logged for every Wifi connection attempt. |
| */ |
| private final Deque<ConnectionEvent> mConnectionEventList = new ArrayDeque<>(); |
| /** |
| * The latest started (but un-ended) connection attempt per interface. |
| */ |
| private final Map<String, ConnectionEvent> mCurrentConnectionEventPerIface = new ArrayMap<>(); |
| /** |
| * Count of number of times each scan return code, indexed by WifiLog.ScanReturnCode |
| */ |
| private final SparseIntArray mScanReturnEntries = new SparseIntArray(); |
| /** |
| * Mapping of system state to the counts of scans requested in that wifi state * screenOn |
| * combination. Indexed by WifiLog.WifiState * (1 + screenOn) |
| */ |
| private final SparseIntArray mWifiSystemStateEntries = new SparseIntArray(); |
| /** Mapping of channel frequency to its RSSI distribution histogram **/ |
| private final Map<Integer, SparseIntArray> mRssiPollCountsMap = new HashMap<>(); |
| /** Mapping of RSSI scan-poll delta values to counts. */ |
| private final SparseIntArray mRssiDeltaCounts = new SparseIntArray(); |
| /** Mapping of link speed values to LinkSpeedCount objects. */ |
| private final SparseArray<LinkSpeedCount> mLinkSpeedCounts = new SparseArray<>(); |
| |
| private final IntCounter mTxLinkSpeedCount2g = new IntCounter(); |
| private final IntCounter mTxLinkSpeedCount5gLow = new IntCounter(); |
| private final IntCounter mTxLinkSpeedCount5gMid = new IntCounter(); |
| private final IntCounter mTxLinkSpeedCount5gHigh = new IntCounter(); |
| private final IntCounter mTxLinkSpeedCount6gLow = new IntCounter(); |
| private final IntCounter mTxLinkSpeedCount6gMid = new IntCounter(); |
| private final IntCounter mTxLinkSpeedCount6gHigh = new IntCounter(); |
| |
| private final IntCounter mRxLinkSpeedCount2g = new IntCounter(); |
| private final IntCounter mRxLinkSpeedCount5gLow = new IntCounter(); |
| private final IntCounter mRxLinkSpeedCount5gMid = new IntCounter(); |
| private final IntCounter mRxLinkSpeedCount5gHigh = new IntCounter(); |
| private final IntCounter mRxLinkSpeedCount6gLow = new IntCounter(); |
| private final IntCounter mRxLinkSpeedCount6gMid = new IntCounter(); |
| private final IntCounter mRxLinkSpeedCount6gHigh = new IntCounter(); |
| |
| private final IntCounter mMakeBeforeBreakLingeringDurationSeconds = new IntCounter(); |
| |
| /** RSSI of the scan result for the last connection event*/ |
| private int mScanResultRssi = 0; |
| /** Boot-relative timestamp when the last candidate scanresult was received, used to calculate |
| RSSI deltas. -1 designates no candidate scanResult being tracked */ |
| private long mScanResultRssiTimestampMillis = -1; |
| /** Mapping of alert reason to the respective alert count. */ |
| private final SparseIntArray mWifiAlertReasonCounts = new SparseIntArray(); |
| /** |
| * Records the getElapsedSinceBootMillis (in seconds) that represents the beginning of data |
| * capture for for this WifiMetricsProto |
| */ |
| private long mRecordStartTimeSec; |
| /** Mapping of Wifi Scores to counts */ |
| private final SparseIntArray mWifiScoreCounts = new SparseIntArray(); |
| /** Mapping of Wifi Usability Scores to counts */ |
| private final SparseIntArray mWifiUsabilityScoreCounts = new SparseIntArray(); |
| /** Mapping of SoftApManager start SoftAp return codes to counts */ |
| private final SparseIntArray mSoftApManagerReturnCodeCounts = new SparseIntArray(); |
| |
| private final SparseIntArray mTotalSsidsInScanHistogram = new SparseIntArray(); |
| private final SparseIntArray mTotalBssidsInScanHistogram = new SparseIntArray(); |
| private final SparseIntArray mAvailableOpenSsidsInScanHistogram = new SparseIntArray(); |
| private final SparseIntArray mAvailableOpenBssidsInScanHistogram = new SparseIntArray(); |
| private final SparseIntArray mAvailableSavedSsidsInScanHistogram = new SparseIntArray(); |
| private final SparseIntArray mAvailableSavedBssidsInScanHistogram = new SparseIntArray(); |
| private final SparseIntArray mAvailableOpenOrSavedSsidsInScanHistogram = new SparseIntArray(); |
| private final SparseIntArray mAvailableOpenOrSavedBssidsInScanHistogram = new SparseIntArray(); |
| private final SparseIntArray mAvailableSavedPasspointProviderProfilesInScanHistogram = |
| new SparseIntArray(); |
| private final SparseIntArray mAvailableSavedPasspointProviderBssidsInScanHistogram = |
| new SparseIntArray(); |
| |
| private final IntCounter mInstalledPasspointProfileTypeForR1 = new IntCounter(); |
| private final IntCounter mInstalledPasspointProfileTypeForR2 = new IntCounter(); |
| |
| /** Mapping of "Connect to Network" notifications to counts. */ |
| private final SparseIntArray mConnectToNetworkNotificationCount = new SparseIntArray(); |
| /** Mapping of "Connect to Network" notification user actions to counts. */ |
| private final SparseIntArray mConnectToNetworkNotificationActionCount = new SparseIntArray(); |
| private int mOpenNetworkRecommenderBlocklistSize = 0; |
| private boolean mIsWifiNetworksAvailableNotificationOn = false; |
| private int mNumOpenNetworkConnectMessageFailedToSend = 0; |
| private int mNumOpenNetworkRecommendationUpdates = 0; |
| /** List of soft AP events related to number of connected clients in tethered mode */ |
| private final List<SoftApConnectedClientsEvent> mSoftApEventListTethered = new ArrayList<>(); |
| /** List of soft AP events related to number of connected clients in local only mode */ |
| private final List<SoftApConnectedClientsEvent> mSoftApEventListLocalOnly = new ArrayList<>(); |
| |
| private final SparseIntArray mObservedHotspotR1ApInScanHistogram = new SparseIntArray(); |
| private final SparseIntArray mObservedHotspotR2ApInScanHistogram = new SparseIntArray(); |
| private final SparseIntArray mObservedHotspotR3ApInScanHistogram = new SparseIntArray(); |
| private final SparseIntArray mObservedHotspotR1EssInScanHistogram = new SparseIntArray(); |
| private final SparseIntArray mObservedHotspotR2EssInScanHistogram = new SparseIntArray(); |
| private final SparseIntArray mObservedHotspotR3EssInScanHistogram = new SparseIntArray(); |
| private final SparseIntArray mObservedHotspotR1ApsPerEssInScanHistogram = new SparseIntArray(); |
| private final SparseIntArray mObservedHotspotR2ApsPerEssInScanHistogram = new SparseIntArray(); |
| private final SparseIntArray mObservedHotspotR3ApsPerEssInScanHistogram = new SparseIntArray(); |
| |
| private final SparseIntArray mObserved80211mcApInScanHistogram = new SparseIntArray(); |
| |
| // link probing stats |
| private final IntCounter mLinkProbeSuccessRssiCounts = new IntCounter(-85, -65); |
| private final IntCounter mLinkProbeFailureRssiCounts = new IntCounter(-85, -65); |
| private final IntCounter mLinkProbeSuccessLinkSpeedCounts = new IntCounter(); |
| private final IntCounter mLinkProbeFailureLinkSpeedCounts = new IntCounter(); |
| |
| private static final int[] LINK_PROBE_TIME_SINCE_LAST_TX_SUCCESS_SECONDS_HISTOGRAM_BUCKETS = |
| {5, 15, 45, 135}; |
| private final IntHistogram mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram = |
| new IntHistogram(LINK_PROBE_TIME_SINCE_LAST_TX_SUCCESS_SECONDS_HISTOGRAM_BUCKETS); |
| private final IntHistogram mLinkProbeFailureSecondsSinceLastTxSuccessHistogram = |
| new IntHistogram(LINK_PROBE_TIME_SINCE_LAST_TX_SUCCESS_SECONDS_HISTOGRAM_BUCKETS); |
| |
| private static final int[] LINK_PROBE_ELAPSED_TIME_MS_HISTOGRAM_BUCKETS = |
| {5, 10, 15, 20, 25, 50, 100, 200, 400, 800}; |
| private final IntHistogram mLinkProbeSuccessElapsedTimeMsHistogram = new IntHistogram( |
| LINK_PROBE_ELAPSED_TIME_MS_HISTOGRAM_BUCKETS); |
| private final IntCounter mLinkProbeFailureReasonCounts = new IntCounter(); |
| private final MeteredNetworkStatsBuilder mMeteredNetworkStatsBuilder = |
| new MeteredNetworkStatsBuilder(); |
| |
| /** |
| * Maps a String link probe experiment ID to the number of link probes that were sent for this |
| * experiment. |
| */ |
| private final ObjectCounter<String> mLinkProbeExperimentProbeCounts = new ObjectCounter<>(); |
| private int mLinkProbeStaEventCount = 0; |
| @VisibleForTesting static final int MAX_LINK_PROBE_STA_EVENTS = MAX_STA_EVENTS / 4; |
| |
| private final LinkedList<WifiUsabilityStatsEntry> mWifiUsabilityStatsEntriesList = |
| new LinkedList<>(); |
| private final LinkedList<WifiUsabilityStats> mWifiUsabilityStatsListBad = new LinkedList<>(); |
| private final LinkedList<WifiUsabilityStats> mWifiUsabilityStatsListGood = new LinkedList<>(); |
| private int mWifiUsabilityStatsCounter = 0; |
| private final Random mRand = new Random(); |
| private final RemoteCallbackList<IOnWifiUsabilityStatsListener> mOnWifiUsabilityListeners; |
| |
| private final SparseArray<DeviceMobilityStatePnoScanStats> mMobilityStatePnoStatsMap = |
| new SparseArray<>(); |
| private int mCurrentDeviceMobilityState; |
| /** |
| * The timestamp of the start of the current device mobility state. |
| */ |
| private long mCurrentDeviceMobilityStateStartMs; |
| /** |
| * The timestamp of when the PNO scan started in the current device mobility state. |
| */ |
| private long mCurrentDeviceMobilityStatePnoScanStartMs; |
| |
| /** Wifi power metrics*/ |
| private WifiPowerMetrics mWifiPowerMetrics; |
| |
| /** Wifi Wake metrics */ |
| private final WifiWakeMetrics mWifiWakeMetrics = new WifiWakeMetrics(); |
| |
| /** Wifi P2p metrics */ |
| private final WifiP2pMetrics mWifiP2pMetrics; |
| |
| /** DPP */ |
| private final DppMetrics mDppMetrics; |
| |
| private final WifiMonitor mWifiMonitor; |
| private ActiveModeWarden mActiveModeWarden; |
| private final Map<String, ActiveModeManager.ClientRole> mIfaceToRoleMap = new ArrayMap<>(); |
| |
| /** WifiConfigStore read duration histogram. */ |
| private SparseIntArray mWifiConfigStoreReadDurationHistogram = new SparseIntArray(); |
| |
| /** WifiConfigStore write duration histogram. */ |
| private SparseIntArray mWifiConfigStoreWriteDurationHistogram = new SparseIntArray(); |
| |
| /** New API surface metrics */ |
| private final WifiNetworkRequestApiLog mWifiNetworkRequestApiLog = |
| new WifiNetworkRequestApiLog(); |
| private static final int[] NETWORK_REQUEST_API_MATCH_SIZE_HISTOGRAM_BUCKETS = |
| {0, 1, 5, 10}; |
| private final IntHistogram mWifiNetworkRequestApiMatchSizeHistogram = |
| new IntHistogram(NETWORK_REQUEST_API_MATCH_SIZE_HISTOGRAM_BUCKETS); |
| |
| private static final int[] NETWORK_REQUEST_API_DURATION_SEC_BUCKETS = |
| {0, toIntExact(Duration.ofMinutes(3).getSeconds()), |
| toIntExact(Duration.ofMinutes(10).getSeconds()), |
| toIntExact(Duration.ofMinutes(30).getSeconds()), |
| toIntExact(Duration.ofHours(1).getSeconds()), |
| toIntExact(Duration.ofHours(6).getSeconds())}; |
| private final IntHistogram mWifiNetworkRequestApiConnectionDurationSecOnPrimaryIfaceHistogram = |
| new IntHistogram(NETWORK_REQUEST_API_DURATION_SEC_BUCKETS); |
| private final IntHistogram |
| mWifiNetworkRequestApiConnectionDurationSecOnSecondaryIfaceHistogram = |
| new IntHistogram(NETWORK_REQUEST_API_DURATION_SEC_BUCKETS); |
| private final IntHistogram mWifiNetworkRequestApiConcurrentConnectionDurationSecHistogram = |
| new IntHistogram(NETWORK_REQUEST_API_DURATION_SEC_BUCKETS); |
| |
| private final WifiNetworkSuggestionApiLog mWifiNetworkSuggestionApiLog = |
| new WifiNetworkSuggestionApiLog(); |
| private static final int[] NETWORK_SUGGESTION_API_LIST_SIZE_HISTOGRAM_BUCKETS = |
| {5, 20, 50, 100, 500}; |
| private final IntHistogram mWifiNetworkSuggestionApiListSizeHistogram = |
| new IntHistogram(NETWORK_SUGGESTION_API_LIST_SIZE_HISTOGRAM_BUCKETS); |
| private final IntCounter mWifiNetworkSuggestionApiAppTypeCounter = new IntCounter(); |
| private final List<UserReaction> mUserApprovalSuggestionAppUiReactionList = |
| new ArrayList<>(); |
| private final List<UserReaction> mUserApprovalCarrierUiReactionList = |
| new ArrayList<>(); |
| private final SparseBooleanArray mWifiNetworkSuggestionPriorityGroups = |
| new SparseBooleanArray(); |
| private final Set<String> mWifiNetworkSuggestionCoexistSavedNetworks = new ArraySet<>(); |
| |
| private final WifiLockStats mWifiLockStats = new WifiLockStats(); |
| private static final int[] WIFI_LOCK_SESSION_DURATION_HISTOGRAM_BUCKETS = |
| {1, 10, 60, 600, 3600}; |
| private final WifiToggleStats mWifiToggleStats = new WifiToggleStats(); |
| private BssidBlocklistStats mBssidBlocklistStats = new BssidBlocklistStats(); |
| |
| private final IntHistogram mWifiLockHighPerfAcqDurationSecHistogram = |
| new IntHistogram(WIFI_LOCK_SESSION_DURATION_HISTOGRAM_BUCKETS); |
| private final IntHistogram mWifiLockLowLatencyAcqDurationSecHistogram = |
| new IntHistogram(WIFI_LOCK_SESSION_DURATION_HISTOGRAM_BUCKETS); |
| |
| private final IntHistogram mWifiLockHighPerfActiveSessionDurationSecHistogram = |
| new IntHistogram(WIFI_LOCK_SESSION_DURATION_HISTOGRAM_BUCKETS); |
| private final IntHistogram mWifiLockLowLatencyActiveSessionDurationSecHistogram = |
| new IntHistogram(WIFI_LOCK_SESSION_DURATION_HISTOGRAM_BUCKETS); |
| |
| /** |
| * (experiment1Id, experiment2Id) => |
| * (sameSelectionNumChoicesCounter, differentSelectionNumChoicesCounter) |
| */ |
| private Map<Pair<Integer, Integer>, NetworkSelectionExperimentResults> |
| mNetworkSelectionExperimentPairNumChoicesCounts = new ArrayMap<>(); |
| |
| private int mNetworkSelectorExperimentId; |
| |
| /** |
| * Tracks the nominator for each network (i.e. which entity made the suggestion to connect). |
| * This object should not be cleared. |
| */ |
| private final SparseIntArray mNetworkIdToNominatorId = new SparseIntArray(); |
| |
| /** passpoint provision success count */ |
| private int mNumProvisionSuccess = 0; |
| |
| /** Mapping of failure code to the respective passpoint provision failure count. */ |
| private final IntCounter mPasspointProvisionFailureCounts = new IntCounter(); |
| |
| // Connection duration stats collected while link layer stats reports are on |
| private final ConnectionDurationStats mConnectionDurationStats = new ConnectionDurationStats(); |
| |
| private static final int[] CHANNEL_UTILIZATION_BUCKETS = |
| {25, 50, 75, 100, 125, 150, 175, 200, 225}; |
| |
| private final IntHistogram mChannelUtilizationHistogram2G = |
| new IntHistogram(CHANNEL_UTILIZATION_BUCKETS); |
| |
| private final IntHistogram mChannelUtilizationHistogramAbove2G = |
| new IntHistogram(CHANNEL_UTILIZATION_BUCKETS); |
| |
| private static final int[] THROUGHPUT_MBPS_BUCKETS = |
| {1, 5, 10, 15, 25, 50, 100, 150, 200, 300, 450, 600, 800, 1200, 1600}; |
| private final IntHistogram mTxThroughputMbpsHistogram2G = |
| new IntHistogram(THROUGHPUT_MBPS_BUCKETS); |
| private final IntHistogram mRxThroughputMbpsHistogram2G = |
| new IntHistogram(THROUGHPUT_MBPS_BUCKETS); |
| private final IntHistogram mTxThroughputMbpsHistogramAbove2G = |
| new IntHistogram(THROUGHPUT_MBPS_BUCKETS); |
| private final IntHistogram mRxThroughputMbpsHistogramAbove2G = |
| new IntHistogram(THROUGHPUT_MBPS_BUCKETS); |
| |
| // Init partial scan metrics |
| private int mInitPartialScanTotalCount; |
| private int mInitPartialScanSuccessCount; |
| private int mInitPartialScanFailureCount; |
| private static final int[] INIT_PARTIAL_SCAN_HISTOGRAM_BUCKETS = |
| {1, 3, 5, 10}; |
| private final IntHistogram mInitPartialScanSuccessHistogram = |
| new IntHistogram(INIT_PARTIAL_SCAN_HISTOGRAM_BUCKETS); |
| private final IntHistogram mInitPartialScanFailureHistogram = |
| new IntHistogram(INIT_PARTIAL_SCAN_HISTOGRAM_BUCKETS); |
| |
| // Wi-Fi off metrics |
| private final WifiOffMetrics mWifiOffMetrics = new WifiOffMetrics(); |
| |
| private final SoftApConfigLimitationMetrics mSoftApConfigLimitationMetrics = |
| new SoftApConfigLimitationMetrics(); |
| |
| private final CarrierWifiMetrics mCarrierWifiMetrics = |
| new CarrierWifiMetrics(); |
| |
| @Nullable |
| private FirstConnectAfterBootStats mFirstConnectAfterBootStats = |
| new FirstConnectAfterBootStats(); |
| private boolean mIsFirstConnectionAttemptComplete = false; |
| |
| private final WifiToWifiSwitchStats mWifiToWifiSwitchStats = new WifiToWifiSwitchStats(); |
| |
| @VisibleForTesting |
| static class NetworkSelectionExperimentResults { |
| public static final int MAX_CHOICES = 10; |
| |
| public IntCounter sameSelectionNumChoicesCounter = new IntCounter(0, MAX_CHOICES); |
| public IntCounter differentSelectionNumChoicesCounter = new IntCounter(0, MAX_CHOICES); |
| |
| @Override |
| public String toString() { |
| return "NetworkSelectionExperimentResults{" |
| + "sameSelectionNumChoicesCounter=" |
| + sameSelectionNumChoicesCounter |
| + ", differentSelectionNumChoicesCounter=" |
| + differentSelectionNumChoicesCounter |
| + '}'; |
| } |
| } |
| |
| private static class SessionData { |
| private String mSsid; |
| private long mSessionStartTimeMillis; |
| private long mSessionEndTimeMillis; |
| private int mBand; |
| private int mAuthType; |
| |
| SessionData(String ssid, long sessionStartTimeMillis, int band, int authType) { |
| mSsid = ssid; |
| mSessionStartTimeMillis = sessionStartTimeMillis; |
| mBand = band; |
| mAuthType = authType; |
| } |
| } |
| |
| class RouterFingerPrint { |
| private final WifiMetricsProto.RouterFingerPrint mRouterFingerPrintProto = |
| new WifiMetricsProto.RouterFingerPrint(); |
| |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| synchronized (mLock) { |
| sb.append("mConnectionEvent.roamType=" + mRouterFingerPrintProto.roamType); |
| sb.append(", mChannelInfo=" + mRouterFingerPrintProto.channelInfo); |
| sb.append(", mDtim=" + mRouterFingerPrintProto.dtim); |
| sb.append(", mAuthentication=" + mRouterFingerPrintProto.authentication); |
| sb.append(", mHidden=" + mRouterFingerPrintProto.hidden); |
| sb.append(", mRouterTechnology=" + mRouterFingerPrintProto.routerTechnology); |
| sb.append(", mSupportsIpv6=" + mRouterFingerPrintProto.supportsIpv6); |
| sb.append(", mEapMethod=" + mRouterFingerPrintProto.eapMethod); |
| sb.append(", mAuthPhase2Method=" + mRouterFingerPrintProto.authPhase2Method); |
| sb.append(", mOcspType=" + mRouterFingerPrintProto.ocspType); |
| sb.append(", mPmkCache=" + mRouterFingerPrintProto.pmkCacheEnabled); |
| sb.append(", mMaxSupportedTxLinkSpeedMbps=" + mRouterFingerPrintProto |
| .maxSupportedTxLinkSpeedMbps); |
| sb.append(", mMaxSupportedRxLinkSpeedMbps=" + mRouterFingerPrintProto |
| .maxSupportedRxLinkSpeedMbps); |
| } |
| return sb.toString(); |
| } |
| |
| public void setPmkCache(boolean isEnabled) { |
| synchronized (mLock) { |
| mRouterFingerPrintProto.pmkCacheEnabled = isEnabled; |
| } |
| } |
| |
| public void setMaxSupportedLinkSpeedMbps(int maxSupportedTxLinkSpeedMbps, |
| int maxSupportedRxLinkSpeedMbps) { |
| synchronized (mLock) { |
| mRouterFingerPrintProto.maxSupportedTxLinkSpeedMbps = maxSupportedTxLinkSpeedMbps; |
| mRouterFingerPrintProto.maxSupportedRxLinkSpeedMbps = maxSupportedRxLinkSpeedMbps; |
| } |
| } |
| } |
| private int getEapMethodProto(int eapMethod) { |
| switch (eapMethod) { |
| case WifiEnterpriseConfig.Eap.WAPI_CERT: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_WAPI_CERT; |
| case WifiEnterpriseConfig.Eap.TLS: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_TLS; |
| case WifiEnterpriseConfig.Eap.UNAUTH_TLS: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_UNAUTH_TLS; |
| case WifiEnterpriseConfig.Eap.PEAP: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_PEAP; |
| case WifiEnterpriseConfig.Eap.PWD: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_PWD; |
| case WifiEnterpriseConfig.Eap.TTLS: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_TTLS; |
| case WifiEnterpriseConfig.Eap.SIM: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_SIM; |
| case WifiEnterpriseConfig.Eap.AKA: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_AKA; |
| case WifiEnterpriseConfig.Eap.AKA_PRIME: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_AKA_PRIME; |
| default: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_EAP_UNKNOWN; |
| } |
| } |
| private int getAuthPhase2MethodProto(int phase2Method) { |
| switch (phase2Method) { |
| case WifiEnterpriseConfig.Phase2.PAP: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_PHASE2_PAP; |
| case WifiEnterpriseConfig.Phase2.MSCHAP: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_PHASE2_MSCHAP; |
| case WifiEnterpriseConfig.Phase2.MSCHAPV2: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_PHASE2_MSCHAPV2; |
| case WifiEnterpriseConfig.Phase2.GTC: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_PHASE2_GTC; |
| case WifiEnterpriseConfig.Phase2.SIM: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_PHASE2_SIM; |
| case WifiEnterpriseConfig.Phase2.AKA: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_PHASE2_AKA; |
| case WifiEnterpriseConfig.Phase2.AKA_PRIME: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_PHASE2_AKA_PRIME; |
| default: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_PHASE2_NONE; |
| } |
| } |
| |
| private int getOcspTypeProto(int ocspType) { |
| switch (ocspType) { |
| case WifiEnterpriseConfig.OCSP_NONE: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_OCSP_NONE; |
| case WifiEnterpriseConfig.OCSP_REQUEST_CERT_STATUS: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_OCSP_REQUEST_CERT_STATUS; |
| case WifiEnterpriseConfig.OCSP_REQUIRE_CERT_STATUS: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_OCSP_REQUIRE_CERT_STATUS; |
| case WifiEnterpriseConfig.OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS: |
| return WifiMetricsProto.RouterFingerPrint |
| .TYPE_OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS; |
| default: |
| return WifiMetricsProto.RouterFingerPrint.TYPE_OCSP_NONE; |
| } |
| } |
| |
| class BssidBlocklistStats { |
| public IntCounter networkSelectionFilteredBssidCount = new IntCounter(); |
| public int numHighMovementConnectionSkipped = 0; |
| public int numHighMovementConnectionStarted = 0; |
| private final IntCounter mBlockedBssidPerReasonCount = new IntCounter(); |
| private final IntCounter mBlockedConfigurationPerReasonCount = new IntCounter(); |
| |
| public WifiMetricsProto.BssidBlocklistStats toProto() { |
| WifiMetricsProto.BssidBlocklistStats proto = new WifiMetricsProto.BssidBlocklistStats(); |
| proto.networkSelectionFilteredBssidCount = networkSelectionFilteredBssidCount.toProto(); |
| proto.highMovementMultipleScansFeatureEnabled = mContext.getResources().getBoolean( |
| R.bool.config_wifiHighMovementNetworkSelectionOptimizationEnabled); |
| proto.numHighMovementConnectionSkipped = numHighMovementConnectionSkipped; |
| proto.numHighMovementConnectionStarted = numHighMovementConnectionStarted; |
| proto.bssidBlocklistPerReasonCount = mBlockedBssidPerReasonCount.toProto(); |
| proto.wifiConfigBlocklistPerReasonCount = mBlockedConfigurationPerReasonCount.toProto(); |
| return proto; |
| } |
| |
| public void incrementBssidBlocklistCount(int blockReason) { |
| mBlockedBssidPerReasonCount.increment(blockReason); |
| } |
| |
| public void incrementWificonfigurationBlocklistCount(int blockReason) { |
| mBlockedConfigurationPerReasonCount.increment(blockReason); |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("networkSelectionFilteredBssidCount=" + networkSelectionFilteredBssidCount); |
| sb.append("\nmBlockedBssidPerReasonCount=" + mBlockedBssidPerReasonCount); |
| sb.append("\nmBlockedConfigurationPerReasonCount=" |
| + mBlockedConfigurationPerReasonCount); |
| |
| sb.append(", highMovementMultipleScansFeatureEnabled=" |
| + mContext.getResources().getBoolean( |
| R.bool.config_wifiHighMovementNetworkSelectionOptimizationEnabled)); |
| sb.append(", numHighMovementConnectionSkipped=" + numHighMovementConnectionSkipped); |
| sb.append(", numHighMovementConnectionStarted=" + numHighMovementConnectionStarted); |
| sb.append(", mBlockedBssidPerReasonCount=" + mBlockedBssidPerReasonCount); |
| sb.append(", mBlockedConfigurationPerReasonCount=" |
| + mBlockedConfigurationPerReasonCount); |
| return sb.toString(); |
| } |
| } |
| |
| class ConnectionDurationStats { |
| private int mConnectionDurationCellularDataOffMs; |
| private int mConnectionDurationSufficientThroughputMs; |
| private int mConnectionDurationInSufficientThroughputMs; |
| private int mConnectionDurationInSufficientThroughputDefaultWifiMs; |
| |
| public WifiMetricsProto.ConnectionDurationStats toProto() { |
| WifiMetricsProto.ConnectionDurationStats proto = |
| new WifiMetricsProto.ConnectionDurationStats(); |
| proto.totalTimeSufficientThroughputMs = mConnectionDurationSufficientThroughputMs; |
| proto.totalTimeInsufficientThroughputMs = mConnectionDurationInSufficientThroughputMs; |
| proto.totalTimeInsufficientThroughputDefaultWifiMs = |
| mConnectionDurationInSufficientThroughputDefaultWifiMs; |
| proto.totalTimeCellularDataOffMs = mConnectionDurationCellularDataOffMs; |
| return proto; |
| } |
| public void clear() { |
| mConnectionDurationCellularDataOffMs = 0; |
| mConnectionDurationSufficientThroughputMs = 0; |
| mConnectionDurationInSufficientThroughputMs = 0; |
| mConnectionDurationInSufficientThroughputDefaultWifiMs = 0; |
| } |
| public void incrementDurationCount(int timeDeltaLastTwoPollsMs, |
| boolean isThroughputSufficient, boolean isCellularDataAvailable, |
| boolean isDefaultOnWifi) { |
| if (!isCellularDataAvailable) { |
| mConnectionDurationCellularDataOffMs += timeDeltaLastTwoPollsMs; |
| } else { |
| if (isThroughputSufficient) { |
| mConnectionDurationSufficientThroughputMs += timeDeltaLastTwoPollsMs; |
| } else { |
| mConnectionDurationInSufficientThroughputMs += timeDeltaLastTwoPollsMs; |
| if (isDefaultOnWifi) { |
| mConnectionDurationInSufficientThroughputDefaultWifiMs += |
| timeDeltaLastTwoPollsMs; |
| } |
| } |
| } |
| } |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("connectionDurationSufficientThroughputMs=") |
| .append(mConnectionDurationSufficientThroughputMs) |
| .append(", connectionDurationInSufficientThroughputMs=") |
| .append(mConnectionDurationInSufficientThroughputMs) |
| .append(", connectionDurationInSufficientThroughputDefaultWifiMs=") |
| .append(mConnectionDurationInSufficientThroughputDefaultWifiMs) |
| .append(", connectionDurationCellularDataOffMs=") |
| .append(mConnectionDurationCellularDataOffMs); |
| return sb.toString(); |
| } |
| } |
| |
| class WifiStatusBuilder { |
| private int mNetworkId = WifiConfiguration.INVALID_NETWORK_ID; |
| private boolean mConnected; |
| private boolean mValidated; |
| private int mRssi; |
| private int mEstimatedTxKbps; |
| private int mEstimatedRxKbps; |
| private boolean mIsStuckDueToUserChoice; |
| |
| public void setNetworkId(int networkId) { |
| mNetworkId = networkId; |
| } |
| |
| public int getNetworkId() { |
| return mNetworkId; |
| } |
| |
| public void setConnected(boolean connected) { |
| mConnected = connected; |
| } |
| |
| public void setValidated(boolean validated) { |
| mValidated = validated; |
| } |
| |
| public void setRssi(int rssi) { |
| mRssi = rssi; |
| } |
| |
| public void setEstimatedTxKbps(int estimatedTxKbps) { |
| mEstimatedTxKbps = estimatedTxKbps; |
| } |
| |
| public void setEstimatedRxKbps(int estimatedRxKbps) { |
| mEstimatedRxKbps = estimatedRxKbps; |
| } |
| |
| public void setUserChoice(boolean userChoice) { |
| mIsStuckDueToUserChoice = userChoice; |
| } |
| |
| public WifiStatus toProto() { |
| WifiStatus result = new WifiStatus(); |
| result.isConnected = mConnected; |
| result.isValidated = mValidated; |
| result.lastRssi = mRssi; |
| result.estimatedTxKbps = mEstimatedTxKbps; |
| result.estimatedRxKbps = mEstimatedRxKbps; |
| result.isStuckDueToUserConnectChoice = mIsStuckDueToUserChoice; |
| return result; |
| } |
| } |
| |
| private NetworkDisableReason convertToNetworkDisableReason( |
| WifiConfiguration config, Set<Integer> bssidBlocklistReasons) { |
| NetworkSelectionStatus status = config.getNetworkSelectionStatus(); |
| NetworkDisableReason result = new NetworkDisableReason(); |
| if (config.allowAutojoin) { |
| if (!status.isNetworkEnabled()) { |
| result.disableReason = |
| MetricsUtils.convertNetworkSelectionDisableReasonToWifiProtoEnum( |
| status.getNetworkSelectionDisableReason()); |
| if (status.isNetworkPermanentlyDisabled()) { |
| result.configPermanentlyDisabled = true; |
| } else { |
| result.configTemporarilyDisabled = true; |
| } |
| } |
| } else { |
| result.disableReason = NetworkDisableReason.REASON_AUTO_JOIN_DISABLED; |
| result.configPermanentlyDisabled = true; |
| } |
| |
| int[] convertedBssidBlockReasons = bssidBlocklistReasons.stream() |
| .mapToInt(i -> MetricsUtils.convertBssidBlocklistReasonToWifiProtoEnum(i)) |
| .toArray(); |
| if (convertedBssidBlockReasons.length > 0) { |
| result.bssidDisableReasons = convertedBssidBlockReasons; |
| } |
| return result; |
| } |
| |
| class UserActionEventWithTime { |
| private UserActionEvent mUserActionEvent; |
| private long mWallClockTimeMs = 0; // wall clock time for debugging only |
| |
| UserActionEventWithTime(int eventType, TargetNetworkInfo targetNetworkInfo) { |
| mUserActionEvent = new UserActionEvent(); |
| mUserActionEvent.eventType = eventType; |
| mUserActionEvent.startTimeMillis = mClock.getElapsedSinceBootMillis(); |
| mWallClockTimeMs = mClock.getWallClockMillis(); |
| mUserActionEvent.targetNetworkInfo = targetNetworkInfo; |
| mUserActionEvent.wifiStatus = mWifiStatusBuilder.toProto(); |
| } |
| |
| UserActionEventWithTime(int eventType, int targetNetId) { |
| this(eventType, null); |
| if (targetNetId >= 0) { |
| WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(targetNetId); |
| if (config != null) { |
| TargetNetworkInfo networkInfo = new TargetNetworkInfo(); |
| networkInfo.isEphemeral = config.isEphemeral(); |
| networkInfo.isPasspoint = config.isPasspoint(); |
| mUserActionEvent.targetNetworkInfo = networkInfo; |
| mUserActionEvent.networkDisableReason = convertToNetworkDisableReason( |
| config, mWifiBlocklistMonitor.getFailureReasonsForSsid(config.SSID)); |
| } |
| } |
| } |
| |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| Calendar c = Calendar.getInstance(); |
| c.setTimeInMillis(mWallClockTimeMs); |
| sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); |
| String eventType = "UNKNOWN"; |
| switch (mUserActionEvent.eventType) { |
| case UserActionEvent.EVENT_FORGET_WIFI: |
| eventType = "EVENT_FORGET_WIFI"; |
| break; |
| case UserActionEvent.EVENT_DISCONNECT_WIFI: |
| eventType = "EVENT_DISCONNECT_WIFI"; |
| break; |
| case UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_METERED: |
| eventType = "EVENT_CONFIGURE_METERED_STATUS_METERED"; |
| break; |
| case UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_UNMETERED: |
| eventType = "EVENT_CONFIGURE_METERED_STATUS_UNMETERED"; |
| break; |
| case UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_AUTO: |
| eventType = "EVENT_CONFIGURE_METERED_STATUS_AUTO"; |
| break; |
| case UserActionEvent.EVENT_CONFIGURE_MAC_RANDOMIZATION_ON: |
| eventType = "EVENT_CONFIGURE_MAC_RANDOMIZATION_ON"; |
| break; |
| case UserActionEvent.EVENT_CONFIGURE_MAC_RANDOMIZATION_OFF: |
| eventType = "EVENT_CONFIGURE_MAC_RANDOMIZATION_OFF"; |
| break; |
| case UserActionEvent.EVENT_CONFIGURE_AUTO_CONNECT_ON: |
| eventType = "EVENT_CONFIGURE_AUTO_CONNECT_ON"; |
| break; |
| case UserActionEvent.EVENT_CONFIGURE_AUTO_CONNECT_OFF: |
| eventType = "EVENT_CONFIGURE_AUTO_CONNECT_OFF"; |
| break; |
| case UserActionEvent.EVENT_TOGGLE_WIFI_ON: |
| eventType = "EVENT_TOGGLE_WIFI_ON"; |
| break; |
| case UserActionEvent.EVENT_TOGGLE_WIFI_OFF: |
| eventType = "EVENT_TOGGLE_WIFI_OFF"; |
| break; |
| case UserActionEvent.EVENT_MANUAL_CONNECT: |
| eventType = "EVENT_MANUAL_CONNECT"; |
| break; |
| case UserActionEvent.EVENT_ADD_OR_UPDATE_NETWORK: |
| eventType = "EVENT_ADD_OR_UPDATE_NETWORK"; |
| break; |
| case UserActionEvent.EVENT_RESTART_WIFI_SUB_SYSTEM: |
| eventType = "EVENT_RESTART_WIFI_SUB_SYSTEM"; |
| break; |
| } |
| sb.append(" eventType=").append(eventType); |
| sb.append(" startTimeMillis=").append(mUserActionEvent.startTimeMillis); |
| TargetNetworkInfo networkInfo = mUserActionEvent.targetNetworkInfo; |
| if (networkInfo != null) { |
| sb.append(" isEphemeral=").append(networkInfo.isEphemeral); |
| sb.append(" isPasspoint=").append(networkInfo.isPasspoint); |
| } |
| WifiStatus wifiStatus = mUserActionEvent.wifiStatus; |
| if (wifiStatus != null) { |
| sb.append("\nWifiStatus: isConnected=").append(wifiStatus.isConnected); |
| sb.append(" isValidated=").append(wifiStatus.isValidated); |
| sb.append(" lastRssi=").append(wifiStatus.lastRssi); |
| sb.append(" estimatedTxKbps=").append(wifiStatus.estimatedTxKbps); |
| sb.append(" estimatedRxKbps=").append(wifiStatus.estimatedRxKbps); |
| sb.append(" isStuckDueToUserConnectChoice=") |
| .append(wifiStatus.isStuckDueToUserConnectChoice); |
| } |
| NetworkDisableReason disableReason = mUserActionEvent.networkDisableReason; |
| if (disableReason != null) { |
| sb.append("\nNetworkDisableReason: DisableReason=") |
| .append(disableReason.disableReason); |
| sb.append(" configTemporarilyDisabled=") |
| .append(disableReason.configTemporarilyDisabled); |
| sb.append(" configPermanentlyDisabled=") |
| .append(disableReason.configPermanentlyDisabled); |
| sb.append(" bssidDisableReasons=") |
| .append(Arrays.toString(disableReason.bssidDisableReasons)); |
| } |
| return sb.toString(); |
| } |
| |
| public UserActionEvent toProto() { |
| return mUserActionEvent; |
| } |
| } |
| |
| /** |
| * Log event, tracking the start time, end time and result of a wireless connection attempt. |
| */ |
| class ConnectionEvent { |
| final WifiMetricsProto.ConnectionEvent mConnectionEvent; |
| //<TODO> Move these constants into a wifi.proto Enum, and create a new Failure Type field |
| //covering more than just l2 failures. see b/27652362 |
| /** |
| * Failure codes, used for the 'level_2_failure_code' Connection event field (covers a lot |
| * more failures than just l2 though, since the proto does not have a place to log |
| * framework failures) |
| */ |
| // Failure is unknown |
| public static final int FAILURE_UNKNOWN = 0; |
| // NONE |
| public static final int FAILURE_NONE = 1; |
| // ASSOCIATION_REJECTION_EVENT |
| public static final int FAILURE_ASSOCIATION_REJECTION = 2; |
| // AUTHENTICATION_FAILURE_EVENT |
| public static final int FAILURE_AUTHENTICATION_FAILURE = 3; |
| // SSID_TEMP_DISABLED (Also Auth failure) |
| public static final int FAILURE_SSID_TEMP_DISABLED = 4; |
| // reconnect() or reassociate() call to WifiNative failed |
| public static final int FAILURE_CONNECT_NETWORK_FAILED = 5; |
| // NETWORK_DISCONNECTION_EVENT |
| public static final int FAILURE_NETWORK_DISCONNECTION = 6; |
| // NEW_CONNECTION_ATTEMPT before previous finished |
| public static final int FAILURE_NEW_CONNECTION_ATTEMPT = 7; |
| // New connection attempt to the same network & bssid |
| public static final int FAILURE_REDUNDANT_CONNECTION_ATTEMPT = 8; |
| // Roam Watchdog timer triggered (Roaming timed out) |
| public static final int FAILURE_ROAM_TIMEOUT = 9; |
| // DHCP failure |
| public static final int FAILURE_DHCP = 10; |
| // ASSOCIATION_TIMED_OUT |
| public static final int FAILURE_ASSOCIATION_TIMED_OUT = 11; |
| // NETWORK_NOT_FOUND |
| public static final int FAILURE_NETWORK_NOT_FOUND = 12; |
| |
| RouterFingerPrint mRouterFingerPrint; |
| private String mConfigSsid; |
| private String mConfigBssid; |
| private int mWifiState; |
| private boolean mScreenOn; |
| private int mAuthType; |
| private int mTrigger; |
| private boolean mHasEverConnected; |
| |
| private ConnectionEvent() { |
| mConnectionEvent = new WifiMetricsProto.ConnectionEvent(); |
| mRouterFingerPrint = new RouterFingerPrint(); |
| mConnectionEvent.routerFingerprint = mRouterFingerPrint.mRouterFingerPrintProto; |
| mConfigSsid = "<NULL>"; |
| mConfigBssid = "<NULL>"; |
| mWifiState = WifiMetricsProto.WifiLog.WIFI_UNKNOWN; |
| mScreenOn = false; |
| } |
| |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("startTime="); |
| Calendar c = Calendar.getInstance(); |
| synchronized (mLock) { |
| c.setTimeInMillis(mConnectionEvent.startTimeMillis); |
| sb.append(mConnectionEvent.startTimeMillis == 0 ? " <null>" : |
| String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); |
| sb.append(", SSID="); |
| sb.append(mConfigSsid); |
| sb.append(", BSSID="); |
| sb.append(mConfigBssid); |
| sb.append(", durationMillis="); |
| sb.append(mConnectionEvent.durationTakenToConnectMillis); |
| sb.append(", roamType="); |
| switch(mConnectionEvent.roamType) { |
| case 1: |
| sb.append("ROAM_NONE"); |
| break; |
| case 2: |
| sb.append("ROAM_DBDC"); |
| break; |
| case 3: |
| sb.append("ROAM_ENTERPRISE"); |
| break; |
| case 4: |
| sb.append("ROAM_USER_SELECTED"); |
| break; |
| case 5: |
| sb.append("ROAM_UNRELATED"); |
| break; |
| default: |
| sb.append("ROAM_UNKNOWN"); |
| } |
| sb.append(", connectionResult="); |
| sb.append(mConnectionEvent.connectionResult); |
| sb.append(", level2FailureCode="); |
| switch(mConnectionEvent.level2FailureCode) { |
| case FAILURE_NONE: |
| sb.append("NONE"); |
| break; |
| case FAILURE_ASSOCIATION_REJECTION: |
| sb.append("ASSOCIATION_REJECTION"); |
| break; |
| case FAILURE_AUTHENTICATION_FAILURE: |
| sb.append("AUTHENTICATION_FAILURE"); |
| break; |
| case FAILURE_SSID_TEMP_DISABLED: |
| sb.append("SSID_TEMP_DISABLED"); |
| break; |
| case FAILURE_CONNECT_NETWORK_FAILED: |
| sb.append("CONNECT_NETWORK_FAILED"); |
| break; |
| case FAILURE_NETWORK_DISCONNECTION: |
| sb.append("NETWORK_DISCONNECTION"); |
| break; |
| case FAILURE_NEW_CONNECTION_ATTEMPT: |
| sb.append("NEW_CONNECTION_ATTEMPT"); |
| break; |
| case FAILURE_REDUNDANT_CONNECTION_ATTEMPT: |
| sb.append("REDUNDANT_CONNECTION_ATTEMPT"); |
| break; |
| case FAILURE_ROAM_TIMEOUT: |
| sb.append("ROAM_TIMEOUT"); |
| break; |
| case FAILURE_DHCP: |
| sb.append("DHCP"); |
| break; |
| case FAILURE_ASSOCIATION_TIMED_OUT: |
| sb.append("ASSOCIATION_TIMED_OUT"); |
| break; |
| case FAILURE_NETWORK_NOT_FOUND: |
| sb.append("FAILURE_NETWORK_NOT_FOUND"); |
| break; |
| default: |
| sb.append("UNKNOWN"); |
| break; |
| } |
| sb.append(", connectivityLevelFailureCode="); |
| switch(mConnectionEvent.connectivityLevelFailureCode) { |
| case WifiMetricsProto.ConnectionEvent.HLF_NONE: |
| sb.append("NONE"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.HLF_DHCP: |
| sb.append("DHCP"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.HLF_NO_INTERNET: |
| sb.append("NO_INTERNET"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.HLF_UNWANTED: |
| sb.append("UNWANTED"); |
| break; |
| default: |
| sb.append("UNKNOWN"); |
| break; |
| } |
| sb.append(", signalStrength="); |
| sb.append(mConnectionEvent.signalStrength); |
| sb.append(", wifiState="); |
| switch(mWifiState) { |
| case WifiMetricsProto.WifiLog.WIFI_DISABLED: |
| sb.append("WIFI_DISABLED"); |
| break; |
| case WifiMetricsProto.WifiLog.WIFI_DISCONNECTED: |
| sb.append("WIFI_DISCONNECTED"); |
| break; |
| case WifiMetricsProto.WifiLog.WIFI_ASSOCIATED: |
| sb.append("WIFI_ASSOCIATED"); |
| break; |
| default: |
| sb.append("WIFI_UNKNOWN"); |
| break; |
| } |
| sb.append(", screenOn="); |
| sb.append(mScreenOn); |
| sb.append(", mRouterFingerprint="); |
| sb.append(mRouterFingerPrint.toString()); |
| sb.append(", useRandomizedMac="); |
| sb.append(mConnectionEvent.useRandomizedMac); |
| sb.append(", useAggressiveMac=" + mConnectionEvent.useAggressiveMac); |
| sb.append(", connectionNominator="); |
| switch (mConnectionEvent.connectionNominator) { |
| case WifiMetricsProto.ConnectionEvent.NOMINATOR_UNKNOWN: |
| sb.append("NOMINATOR_UNKNOWN"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.NOMINATOR_MANUAL: |
| sb.append("NOMINATOR_MANUAL"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.NOMINATOR_SAVED: |
| sb.append("NOMINATOR_SAVED"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.NOMINATOR_SUGGESTION: |
| sb.append("NOMINATOR_SUGGESTION"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.NOMINATOR_PASSPOINT: |
| sb.append("NOMINATOR_PASSPOINT"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.NOMINATOR_CARRIER: |
| sb.append("NOMINATOR_CARRIER"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.NOMINATOR_EXTERNAL_SCORED: |
| sb.append("NOMINATOR_EXTERNAL_SCORED"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.NOMINATOR_SPECIFIER: |
| sb.append("NOMINATOR_SPECIFIER"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.NOMINATOR_SAVED_USER_CONNECT_CHOICE: |
| sb.append("NOMINATOR_SAVED_USER_CONNECT_CHOICE"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.NOMINATOR_OPEN_NETWORK_AVAILABLE: |
| sb.append("NOMINATOR_OPEN_NETWORK_AVAILABLE"); |
| break; |
| default: |
| sb.append(String.format("UnrecognizedNominator(%d)", |
| mConnectionEvent.connectionNominator)); |
| } |
| sb.append(", networkSelectorExperimentId="); |
| sb.append(mConnectionEvent.networkSelectorExperimentId); |
| sb.append(", numBssidInBlocklist=" + mConnectionEvent.numBssidInBlocklist); |
| sb.append(", level2FailureReason="); |
| switch(mConnectionEvent.level2FailureReason) { |
| case WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_NONE: |
| sb.append("AUTH_FAILURE_NONE"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_TIMEOUT: |
| sb.append("AUTH_FAILURE_TIMEOUT"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_WRONG_PSWD: |
| sb.append("AUTH_FAILURE_WRONG_PSWD"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_EAP_FAILURE: |
| sb.append("AUTH_FAILURE_EAP_FAILURE"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.DISCONNECTION_NON_LOCAL: |
| sb.append("DISCONNECTION_NON_LOCAL"); |
| break; |
| default: |
| sb.append("FAILURE_REASON_UNKNOWN"); |
| break; |
| } |
| sb.append(", networkType="); |
| switch(mConnectionEvent.networkType) { |
| case WifiMetricsProto.ConnectionEvent.TYPE_UNKNOWN: |
| sb.append("TYPE_UNKNOWN"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.TYPE_WPA2: |
| sb.append("TYPE_WPA2"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.TYPE_WPA3: |
| sb.append("TYPE_WPA3"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.TYPE_PASSPOINT: |
| sb.append("TYPE_PASSPOINT"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.TYPE_EAP: |
| sb.append("TYPE_EAP"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.TYPE_OWE: |
| sb.append("TYPE_OWE"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.TYPE_OPEN: |
| sb.append("TYPE_OPEN"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.TYPE_WAPI: |
| sb.append("TYPE_WAPI"); |
| break; |
| } |
| sb.append(", networkCreator="); |
| switch (mConnectionEvent.networkCreator) { |
| case WifiMetricsProto.ConnectionEvent.CREATOR_UNKNOWN: |
| sb.append("CREATOR_UNKNOWN"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.CREATOR_USER: |
| sb.append("CREATOR_USER"); |
| break; |
| case WifiMetricsProto.ConnectionEvent.CREATOR_CARRIER: |
| sb.append("CREATOR_CARRIER"); |
| break; |
| } |
| sb.append(", numConsecutiveConnectionFailure=" |
| + mConnectionEvent.numConsecutiveConnectionFailure); |
| sb.append(", isOsuProvisioned=" + mConnectionEvent.isOsuProvisioned); |
| sb.append(" interfaceName=").append(mConnectionEvent.interfaceName); |
| sb.append(" interfaceRole=").append( |
| clientRoleEnumToString(mConnectionEvent.interfaceRole)); |
| sb.append(", isFirstConnectionAfterBoot=" |
| + mConnectionEvent.isFirstConnectionAfterBoot); |
| return sb.toString(); |
| } |
| } |
| |
| private void updateFromWifiConfiguration(WifiConfiguration config) { |
| synchronized (mLock) { |
| if (config != null) { |
| // Is this a hidden network |
| mRouterFingerPrint.mRouterFingerPrintProto.hidden = config.hiddenSSID; |
| // Config may not have a valid dtimInterval set yet, in which case dtim will be |
| // zero (These are only populated from beacon frame scan results, which are |
| // returned as scan results from the chip far less frequently than |
| // Probe-responses) |
| if (config.dtimInterval > 0) { |
| mRouterFingerPrint.mRouterFingerPrintProto.dtim = config.dtimInterval; |
| } |
| |
| mConfigSsid = config.SSID; |
| // Get AuthType information from config (We do this again from ScanResult after |
| // associating with BSSID) |
| if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_OPEN)) { |
| mRouterFingerPrint.mRouterFingerPrintProto.authentication = |
| WifiMetricsProto.RouterFingerPrint.AUTH_OPEN; |
| } else if (config.isEnterprise()) { |
| mRouterFingerPrint.mRouterFingerPrintProto.authentication = |
| WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE; |
| } else { |
| mRouterFingerPrint.mRouterFingerPrintProto.authentication = |
| WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL; |
| } |
| mRouterFingerPrint.mRouterFingerPrintProto.passpoint = config.isPasspoint(); |
| mRouterFingerPrint.mRouterFingerPrintProto.isPasspointHomeProvider = |
| config.isHomeProviderNetwork; |
| // If there's a ScanResult candidate associated with this config already, get it |
| // and log (more accurate) metrics from it |
| ScanResult candidate = config.getNetworkSelectionStatus().getCandidate(); |
| if (candidate != null) { |
| updateMetricsFromScanResult(this, candidate); |
| } |
| if (mRouterFingerPrint.mRouterFingerPrintProto.authentication |
| == WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE |
| && config.enterpriseConfig != null) { |
| int eapMethod = config.enterpriseConfig.getEapMethod(); |
| mRouterFingerPrint.mRouterFingerPrintProto.eapMethod = |
| getEapMethodProto(eapMethod); |
| int phase2Method = config.enterpriseConfig.getPhase2Method(); |
| mRouterFingerPrint.mRouterFingerPrintProto.authPhase2Method = |
| getAuthPhase2MethodProto(phase2Method); |
| int ocspType = config.enterpriseConfig.getOcsp(); |
| mRouterFingerPrint.mRouterFingerPrintProto.ocspType = |
| getOcspTypeProto(ocspType); |
| } |
| } |
| } |
| } |
| } |
| |
| class WifiOffMetrics { |
| public int numWifiOff = 0; |
| public int numWifiOffDeferring = 0; |
| public int numWifiOffDeferringTimeout = 0; |
| public final IntCounter wifiOffDeferringTimeHistogram = new IntCounter(); |
| |
| public WifiMetricsProto.WifiOffMetrics toProto() { |
| WifiMetricsProto.WifiOffMetrics proto = |
| new WifiMetricsProto.WifiOffMetrics(); |
| proto.numWifiOff = numWifiOff; |
| proto.numWifiOffDeferring = numWifiOffDeferring; |
| proto.numWifiOffDeferringTimeout = numWifiOffDeferringTimeout; |
| proto.wifiOffDeferringTimeHistogram = wifiOffDeferringTimeHistogram.toProto(); |
| return proto; |
| } |
| |
| public void clear() { |
| numWifiOff = 0; |
| numWifiOffDeferring = 0; |
| numWifiOffDeferringTimeout = 0; |
| wifiOffDeferringTimeHistogram.clear(); |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("numWifiOff=") |
| .append(numWifiOff) |
| .append(", numWifiOffDeferring=") |
| .append(numWifiOffDeferring) |
| .append(", numWifiOffDeferringTimeout=") |
| .append(numWifiOffDeferringTimeout) |
| .append(", wifiOffDeferringTimeHistogram=") |
| .append(wifiOffDeferringTimeHistogram); |
| return sb.toString(); |
| } |
| } |
| |
| class SoftApConfigLimitationMetrics { |
| // Collect the number of softap security setting reset to default during the restore |
| public int numSecurityTypeResetToDefault = 0; |
| // Collect the number of softap max client setting reset to default during the restore |
| public int numMaxClientSettingResetToDefault = 0; |
| // Collect the number of softap client control setting reset to default during the restore |
| public int numClientControlByUserResetToDefault = 0; |
| // Collect the max client setting when reach it cause client is blocked |
| public final IntCounter maxClientSettingWhenReachHistogram = new IntCounter(); |
| |
| public WifiMetricsProto.SoftApConfigLimitationMetrics toProto() { |
| WifiMetricsProto.SoftApConfigLimitationMetrics proto = |
| new WifiMetricsProto.SoftApConfigLimitationMetrics(); |
| proto.numSecurityTypeResetToDefault = numSecurityTypeResetToDefault; |
| proto.numMaxClientSettingResetToDefault = numMaxClientSettingResetToDefault; |
| proto.numClientControlByUserResetToDefault = numClientControlByUserResetToDefault; |
| proto.maxClientSettingWhenReachHistogram = maxClientSettingWhenReachHistogram.toProto(); |
| return proto; |
| } |
| |
| public void clear() { |
| numSecurityTypeResetToDefault = 0; |
| numMaxClientSettingResetToDefault = 0; |
| numClientControlByUserResetToDefault = 0; |
| maxClientSettingWhenReachHistogram.clear(); |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("numSecurityTypeResetToDefault=") |
| .append(numSecurityTypeResetToDefault) |
| .append(", numMaxClientSettingResetToDefault=") |
| .append(numMaxClientSettingResetToDefault) |
| .append(", numClientControlByUserResetToDefault=") |
| .append(numClientControlByUserResetToDefault) |
| .append(", maxClientSettingWhenReachHistogram=") |
| .append(maxClientSettingWhenReachHistogram); |
| return sb.toString(); |
| } |
| } |
| |
| class CarrierWifiMetrics { |
| public int numConnectionSuccess = 0; |
| public int numConnectionAuthFailure = 0; |
| public int numConnectionNonAuthFailure = 0; |
| |
| public WifiMetricsProto.CarrierWifiMetrics toProto() { |
| WifiMetricsProto.CarrierWifiMetrics proto = |
| new WifiMetricsProto.CarrierWifiMetrics(); |
| proto.numConnectionSuccess = numConnectionSuccess; |
| proto.numConnectionAuthFailure = numConnectionAuthFailure; |
| proto.numConnectionNonAuthFailure = numConnectionNonAuthFailure; |
| return proto; |
| } |
| |
| public void clear() { |
| numConnectionSuccess = 0; |
| numConnectionAuthFailure = 0; |
| numConnectionNonAuthFailure = 0; |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("numConnectionSuccess=") |
| .append(numConnectionSuccess) |
| .append(", numConnectionAuthFailure=") |
| .append(numConnectionAuthFailure) |
| .append(", numConnectionNonAuthFailure") |
| .append(numConnectionNonAuthFailure); |
| return sb.toString(); |
| } |
| } |
| |
| public WifiMetrics(Context context, FrameworkFacade facade, Clock clock, Looper looper, |
| WifiAwareMetrics awareMetrics, RttMetrics rttMetrics, |
| WifiPowerMetrics wifiPowerMetrics, WifiP2pMetrics wifiP2pMetrics, |
| DppMetrics dppMetrics, WifiMonitor wifiMonitor) { |
| mContext = context; |
| mFacade = facade; |
| mClock = clock; |
| mWifiState = WifiMetricsProto.WifiLog.WIFI_DISABLED; |
| mRecordStartTimeSec = mClock.getElapsedSinceBootMillis() / 1000; |
| mWifiAwareMetrics = awareMetrics; |
| mRttMetrics = rttMetrics; |
| mWifiPowerMetrics = wifiPowerMetrics; |
| mWifiP2pMetrics = wifiP2pMetrics; |
| mDppMetrics = dppMetrics; |
| mWifiMonitor = wifiMonitor; |
| mHandler = new Handler(looper) { |
| public void handleMessage(Message msg) { |
| synchronized (mLock) { |
| processMessage(msg); |
| } |
| } |
| }; |
| |
| mCurrentDeviceMobilityState = WifiManager.DEVICE_MOBILITY_STATE_UNKNOWN; |
| DeviceMobilityStatePnoScanStats unknownStateStats = |
| getOrCreateDeviceMobilityStatePnoScanStats(mCurrentDeviceMobilityState); |
| unknownStateStats.numTimesEnteredState++; |
| mCurrentDeviceMobilityStateStartMs = mClock.getElapsedSinceBootMillis(); |
| mCurrentDeviceMobilityStatePnoScanStartMs = -1; |
| mOnWifiUsabilityListeners = new RemoteCallbackList<>(); |
| |
| IntentFilter filter = new IntentFilter(); |
| filter.addAction(Intent.ACTION_SCREEN_ON); |
| filter.addAction(Intent.ACTION_SCREEN_OFF); |
| context.registerReceiver( |
| new BroadcastReceiver() { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| String action = intent.getAction(); |
| if (action.equals(Intent.ACTION_SCREEN_ON)) { |
| setScreenState(true); |
| } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { |
| setScreenState(false); |
| } |
| } |
| }, filter, null, mHandler); |
| setScreenState(context.getSystemService(PowerManager.class).isInteractive()); |
| |
| mScanMetrics = new ScanMetrics(context, clock); |
| } |
| |
| /** Sets internal ScoringParams member */ |
| public void setScoringParams(ScoringParams scoringParams) { |
| mScoringParams = scoringParams; |
| } |
| |
| /** Sets internal WifiConfigManager member */ |
| public void setWifiConfigManager(WifiConfigManager wifiConfigManager) { |
| mWifiConfigManager = wifiConfigManager; |
| } |
| |
| /** Sets internal WifiNetworkSelector member */ |
| public void setWifiNetworkSelector(WifiNetworkSelector wifiNetworkSelector) { |
| mWifiNetworkSelector = wifiNetworkSelector; |
| } |
| |
| /** Sets internal PasspointManager member */ |
| public void setPasspointManager(PasspointManager passpointManager) { |
| mPasspointManager = passpointManager; |
| } |
| |
| /** Sets internal WifiDataStall member */ |
| public void setWifiDataStall(WifiDataStall wifiDataStall) { |
| mWifiDataStall = wifiDataStall; |
| } |
| |
| /** Sets internal WifiBlocklistMonitor member */ |
| public void setWifiBlocklistMonitor(WifiBlocklistMonitor wifiBlocklistMonitor) { |
| mWifiBlocklistMonitor = wifiBlocklistMonitor; |
| } |
| |
| /** Sets internal WifiHealthMonitor member */ |
| public void setWifiHealthMonitor(WifiHealthMonitor wifiHealthMonitor) { |
| mWifiHealthMonitor = wifiHealthMonitor; |
| } |
| |
| /** Sets internal WifiScoreCard member */ |
| public void setWifiScoreCard(WifiScoreCard wifiScoreCard) { |
| mWifiScoreCard = wifiScoreCard; |
| } |
| |
| /** Sets internal WifiChannelUtilization member */ |
| public void setWifiChannelUtilization(WifiChannelUtilization wifiChannelUtilization) { |
| mWifiChannelUtilization = wifiChannelUtilization; |
| } |
| |
| /** Sets internal WifiSettingsStore member */ |
| public void setWifiSettingsStore(WifiSettingsStore wifiSettingsStore) { |
| mWifiSettingsStore = wifiSettingsStore; |
| } |
| |
| /** Sets internal ActiveModeWarden member */ |
| public void setActiveModeWarden(ActiveModeWarden activeModeWarden) { |
| mActiveModeWarden = activeModeWarden; |
| mActiveModeWarden.registerModeChangeCallback(new ModeChangeCallback()); |
| } |
| |
| /** |
| * Implements callbacks that set the internal ifaceName to ClientRole mapping. |
| */ |
| @VisibleForTesting |
| private class ModeChangeCallback implements ActiveModeWarden.ModeChangeCallback { |
| @Override |
| public void onActiveModeManagerAdded(@NonNull ActiveModeManager activeModeManager) { |
| if (!(activeModeManager instanceof ConcreteClientModeManager)) { |
| return; |
| } |
| synchronized (mLock) { |
| ConcreteClientModeManager clientModeManager = |
| (ConcreteClientModeManager) activeModeManager; |
| mIfaceToRoleMap.put(clientModeManager.getInterfaceName(), |
| clientModeManager.getRole()); |
| } |
| } |
| |
| @Override |
| public void onActiveModeManagerRemoved(@NonNull ActiveModeManager activeModeManager) { |
| if (!(activeModeManager instanceof ConcreteClientModeManager)) { |
| return; |
| } |
| synchronized (mLock) { |
| ConcreteClientModeManager clientModeManager = |
| (ConcreteClientModeManager) activeModeManager; |
| mIfaceToRoleMap.remove(clientModeManager.getInterfaceName()); |
| } |
| } |
| |
| @Override |
| public void onActiveModeManagerRoleChanged(@NonNull ActiveModeManager activeModeManager) { |
| if (!(activeModeManager instanceof ConcreteClientModeManager)) { |
| return; |
| } |
| synchronized (mLock) { |
| ConcreteClientModeManager clientModeManager = |
| (ConcreteClientModeManager) activeModeManager; |
| mIfaceToRoleMap.put(clientModeManager.getInterfaceName(), |
| clientModeManager.getRole()); |
| } |
| } |
| } |
| |
| /** |
| * Increment cumulative counters for link layer stats. |
| * @param newStats |
| */ |
| public void incrementWifiLinkLayerUsageStats(String ifaceName, WifiLinkLayerStats newStats) { |
| // This is only collected for primary STA currently because RSSI polling is disabled for |
| // non-primary STAs. |
| if (!isPrimary(ifaceName)) { |
| return; |
| } |
| if (newStats == null) { |
| return; |
| } |
| if (mLastLinkLayerStats == null) { |
| mLastLinkLayerStats = newStats; |
| return; |
| } |
| if (!newLinkLayerStatsIsValid(mLastLinkLayerStats, newStats)) { |
| // This could mean the radio chip is reset or the data is incorrectly reported. |
| // Don't increment any counts and discard the possibly corrupt |newStats| completely. |
| mLastLinkLayerStats = null; |
| return; |
| } |
| mWifiLinkLayerUsageStats.loggingDurationMs += |
| (newStats.timeStampInMs - mLastLinkLayerStats.timeStampInMs); |
| mWifiLinkLayerUsageStats.radioOnTimeMs += (newStats.on_time - mLastLinkLayerStats.on_time); |
| mWifiLinkLayerUsageStats.radioTxTimeMs += (newStats.tx_time - mLastLinkLayerStats.tx_time); |
| mWifiLinkLayerUsageStats.radioRxTimeMs += (newStats.rx_time - mLastLinkLayerStats.rx_time); |
| mWifiLinkLayerUsageStats.radioScanTimeMs += |
| (newStats.on_time_scan - mLastLinkLayerStats.on_time_scan); |
| mWifiLinkLayerUsageStats.radioNanScanTimeMs += |
| (newStats.on_time_nan_scan - mLastLinkLayerStats.on_time_nan_scan); |
| mWifiLinkLayerUsageStats.radioBackgroundScanTimeMs += |
| (newStats.on_time_background_scan - mLastLinkLayerStats.on_time_background_scan); |
| mWifiLinkLayerUsageStats.radioRoamScanTimeMs += |
| (newStats.on_time_roam_scan - mLastLinkLayerStats.on_time_roam_scan); |
| mWifiLinkLayerUsageStats.radioPnoScanTimeMs += |
| (newStats.on_time_pno_scan - mLastLinkLayerStats.on_time_pno_scan); |
| mWifiLinkLayerUsageStats.radioHs20ScanTimeMs += |
| (newStats.on_time_hs20_scan - mLastLinkLayerStats.on_time_hs20_scan); |
| incrementPerRadioUsageStats(mLastLinkLayerStats, newStats); |
| |
| mLastLinkLayerStats = newStats; |
| } |
| |
| /** |
| * Increment individual radio stats usage |
| */ |
| private void incrementPerRadioUsageStats(WifiLinkLayerStats oldStats, |
| WifiLinkLayerStats newStats) { |
| if (newStats.radioStats != null && newStats.radioStats.length > 0 |
| && oldStats.radioStats != null && oldStats.radioStats.length > 0 |
| && newStats.radioStats.length == oldStats.radioStats.length) { |
| int numRadios = newStats.radioStats.length; |
| for (int i = 0; i < numRadios; i++) { |
| WifiLinkLayerStats.RadioStat newRadio = newStats.radioStats[i]; |
| WifiLinkLayerStats.RadioStat oldRadio = oldStats.radioStats[i]; |
| if (newRadio.radio_id != oldRadio.radio_id) { |
| continue; |
| } |
| RadioStats radioStats = mRadioStats.get(newRadio.radio_id); |
| if (radioStats == null) { |
| radioStats = new RadioStats(); |
| radioStats.radioId = newRadio.radio_id; |
| mRadioStats.put(newRadio.radio_id, radioStats); |
| } |
| radioStats.totalRadioOnTimeMs |
| += newRadio.on_time - oldRadio.on_time; |
| radioStats.totalRadioTxTimeMs |
| += newRadio.tx_time - oldRadio.tx_time; |
| radioStats.totalRadioRxTimeMs |
| += newRadio.rx_time - oldRadio.rx_time; |
| radioStats.totalScanTimeMs |
| += newRadio.on_time_scan - oldRadio.on_time_scan; |
| radioStats.totalNanScanTimeMs |
| += newRadio.on_time_nan_scan - oldRadio.on_time_nan_scan; |
| radioStats.totalBackgroundScanTimeMs |
| += newRadio.on_time_background_scan - oldRadio.on_time_background_scan; |
| radioStats.totalRoamScanTimeMs |
| += newRadio.on_time_roam_scan - oldRadio.on_time_roam_scan; |
| radioStats.totalPnoScanTimeMs |
| += newRadio.on_time_pno_scan - oldRadio.on_time_pno_scan; |
| radioStats.totalHotspot2ScanTimeMs |
| += newRadio.on_time_hs20_scan - oldRadio.on_time_hs20_scan; |
| } |
| } |
| } |
| |
| private boolean newLinkLayerStatsIsValid(WifiLinkLayerStats oldStats, |
| WifiLinkLayerStats newStats) { |
| if (newStats.on_time < oldStats.on_time |
| || newStats.tx_time < oldStats.tx_time |
| || newStats.rx_time < oldStats.rx_time |
| || newStats.on_time_scan < oldStats.on_time_scan) { |
| return false; |
| } |
| return true; |
| } |
| |
| /** |
| * Increment total number of attempts to start a pno scan |
| */ |
| public void incrementPnoScanStartAttemptCount() { |
| synchronized (mLock) { |
| mPnoScanMetrics.numPnoScanAttempts++; |
| } |
| } |
| |
| /** |
| * Increment total number of attempts with pno scan failed |
| */ |
| public void incrementPnoScanFailedCount() { |
| synchronized (mLock) { |
| mPnoScanMetrics.numPnoScanFailed++; |
| } |
| } |
| |
| /** |
| * Increment number of times pno scan found a result |
| */ |
| public void incrementPnoFoundNetworkEventCount() { |
| synchronized (mLock) { |
| mPnoScanMetrics.numPnoFoundNetworkEvents++; |
| } |
| } |
| |
| // Values used for indexing SystemStateEntries |
| private static final int SCREEN_ON = 1; |
| private static final int SCREEN_OFF = 0; |
| |
| /** |
| * Create a new connection event and check if the new one overlaps with previous one. |
| * Call when wifi attempts to make a new network connection |
| * If there is a current 'un-ended' connection event, it will be ended with UNKNOWN connectivity |
| * failure code. |
| * Gathers and sets the RouterFingerPrint data as well |
| * |
| * @param ifaceName interface name for this connection event |
| * @param config WifiConfiguration of the config used for the current connection attempt |
| * @param roamType Roam type that caused connection attempt, see WifiMetricsProto.WifiLog.ROAM_X |
| * @return The duration in ms since the last unfinished connection attempt, |
| * or 0 if there is no unfinished connection |
| */ |
| public int startConnectionEvent( |
| String ifaceName, WifiConfiguration config, String targetBSSID, int roamType) { |
| synchronized (mLock) { |
| int overlapWithLastConnectionMs = 0; |
| ConnectionEvent currentConnectionEvent = mCurrentConnectionEventPerIface.get(ifaceName); |
| if (currentConnectionEvent != null) { |
| overlapWithLastConnectionMs = (int) (mClock.getElapsedSinceBootMillis() |
| - currentConnectionEvent.mConnectionEvent.startTimeSinceBootMillis); |
| // Is this new Connection Event the same as the current one |
| if (currentConnectionEvent.mConfigSsid != null |
| && currentConnectionEvent.mConfigBssid != null |
| && config != null |
| && currentConnectionEvent.mConfigSsid.equals(config.SSID) |
| && (currentConnectionEvent.mConfigBssid.equals("any") |
| || currentConnectionEvent.mConfigBssid.equals(targetBSSID))) { |
| currentConnectionEvent.mConfigBssid = targetBSSID; |
| // End Connection Event due to new connection attempt to the same network |
| endConnectionEvent(ifaceName, |
| ConnectionEvent.FAILURE_REDUNDANT_CONNECTION_ATTEMPT, |
| WifiMetricsProto.ConnectionEvent.HLF_NONE, |
| WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN, 0); |
| } else { |
| // End Connection Event due to new connection attempt to different network |
| endConnectionEvent(ifaceName, |
| ConnectionEvent.FAILURE_NEW_CONNECTION_ATTEMPT, |
| WifiMetricsProto.ConnectionEvent.HLF_NONE, |
| WifiMetricsProto.ConnectionEvent.FAILURE_REASON_UNKNOWN, 0); |
| } |
| } |
| // If past maximum connection events, start removing the oldest |
| while(mConnectionEventList.size() >= MAX_CONNECTION_EVENTS) { |
| mConnectionEventList.removeFirst(); |
| } |
| currentConnectionEvent = new ConnectionEvent(); |
| mCurrentConnectionEventPerIface.put(ifaceName, currentConnectionEvent); |
| currentConnectionEvent.mConnectionEvent.interfaceName = ifaceName; |
| currentConnectionEvent.mConnectionEvent.interfaceRole = convertIfaceToEnum(ifaceName); |
| currentConnectionEvent.mConnectionEvent.startTimeMillis = |
| mClock.getWallClockMillis(); |
| currentConnectionEvent.mConnectionEvent.startTimeSinceBootMillis = |
| mClock.getElapsedSinceBootMillis(); |
| currentConnectionEvent.mConfigBssid = targetBSSID; |
| currentConnectionEvent.mConnectionEvent.roamType = roamType; |
| currentConnectionEvent.mConnectionEvent.networkSelectorExperimentId = |
| mNetworkSelectorExperimentId; |
| currentConnectionEvent.updateFromWifiConfiguration(config); |
| currentConnectionEvent.mConfigBssid = "any"; |
| currentConnectionEvent.mWifiState = mWifiState; |
| currentConnectionEvent.mScreenOn = mScreenOn; |
| currentConnectionEvent.mConnectionEvent.isFirstConnectionAfterBoot = |
| mFirstConnectionAfterBoot; |
| mFirstConnectionAfterBoot = false; |
| mConnectionEventList.add(currentConnectionEvent); |
| mScanResultRssiTimestampMillis = -1; |
| if (config != null) { |
| try { |
| currentConnectionEvent.mAuthType = config.getAuthType(); |
| } catch (IllegalStateException e) { |
| currentConnectionEvent.mAuthType = 0; |
| } |
| currentConnectionEvent.mHasEverConnected = |
| config.getNetworkSelectionStatus().hasEverConnected(); |
| currentConnectionEvent.mConnectionEvent.useRandomizedMac = |
| config.macRandomizationSetting |
| != WifiConfiguration.RANDOMIZATION_NONE; |
| currentConnectionEvent.mConnectionEvent.useAggressiveMac = |
| mWifiConfigManager.shouldUseEnhancedRandomization(config); |
| currentConnectionEvent.mConnectionEvent.connectionNominator = |
| mNetworkIdToNominatorId.get(config.networkId, |
| WifiMetricsProto.ConnectionEvent.NOMINATOR_UNKNOWN); |
| currentConnectionEvent.mConnectionEvent.isCarrierMerged = config.carrierMerged; |
| |
| ScanResult candidate = config.getNetworkSelectionStatus().getCandidate(); |
| if (candidate != null) { |
| // Cache the RSSI of the candidate, as the connection event level is updated |
| // from other sources (polls, bssid_associations) and delta requires the |
| // scanResult rssi |
| mScanResultRssi = candidate.level; |
| mScanResultRssiTimestampMillis = mClock.getElapsedSinceBootMillis(); |
| } |
| currentConnectionEvent.mConnectionEvent.numBssidInBlocklist = |
| mWifiBlocklistMonitor.updateAndGetNumBlockedBssidsForSsid(config.SSID); |
| currentConnectionEvent.mConnectionEvent.networkType = |
| WifiMetricsProto.ConnectionEvent.TYPE_UNKNOWN; |
| currentConnectionEvent.mConnectionEvent.isOsuProvisioned = false; |
| if (config.isPasspoint()) { |
| currentConnectionEvent.mConnectionEvent.networkType = |
| WifiMetricsProto.ConnectionEvent.TYPE_PASSPOINT; |
| currentConnectionEvent.mConnectionEvent.isOsuProvisioned = |
| !TextUtils.isEmpty(config.updateIdentifier); |
| } else if (WifiConfigurationUtil.isConfigForSaeNetwork(config)) { |
| currentConnectionEvent.mConnectionEvent.networkType = |
| WifiMetricsProto.ConnectionEvent.TYPE_WPA3; |
| } else if (WifiConfigurationUtil.isConfigForWapiPskNetwork(config)) { |
| currentConnectionEvent.mConnectionEvent.networkType = |
| WifiMetricsProto.ConnectionEvent.TYPE_WAPI; |
| } else if (WifiConfigurationUtil.isConfigForWapiCertNetwork(config)) { |
| currentConnectionEvent.mConnectionEvent.networkType = |
| WifiMetricsProto.ConnectionEvent.TYPE_WAPI; |
| } else if (WifiConfigurationUtil.isConfigForPskNetwork(config)) { |
| currentConnectionEvent.mConnectionEvent.networkType = |
| WifiMetricsProto.ConnectionEvent.TYPE_WPA2; |
| } else if (WifiConfigurationUtil.isConfigForEapNetwork(config)) { |
| currentConnectionEvent.mConnectionEvent.networkType = |
| WifiMetricsProto.ConnectionEvent.TYPE_EAP; |
| } else if (WifiConfigurationUtil.isConfigForOweNetwork(config)) { |
| currentConnectionEvent.mConnectionEvent.networkType = |
| WifiMetricsProto.ConnectionEvent.TYPE_OWE; |
| } else if (WifiConfigurationUtil.isConfigForOpenNetwork(config)) { |
| currentConnectionEvent.mConnectionEvent.networkType = |
| WifiMetricsProto.ConnectionEvent.TYPE_OPEN; |
| } |
| |
| if (!config.fromWifiNetworkSuggestion) { |
| currentConnectionEvent.mConnectionEvent.networkCreator = |
| WifiMetricsProto.ConnectionEvent.CREATOR_USER; |
| } else if (config.carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) { |
| currentConnectionEvent.mConnectionEvent.networkCreator = |
| WifiMetricsProto.ConnectionEvent.CREATOR_CARRIER; |
| } else { |
| currentConnectionEvent.mConnectionEvent.networkCreator = |
| WifiMetricsProto.ConnectionEvent.CREATOR_UNKNOWN; |
| } |
| |
| currentConnectionEvent.mConnectionEvent.screenOn = mScreenOn; |
| if (currentConnectionEvent.mConfigSsid != null) { |
| WifiScoreCard.NetworkConnectionStats recentStats = mWifiScoreCard.lookupNetwork( |
| currentConnectionEvent.mConfigSsid).getRecentStats(); |
| currentConnectionEvent.mConnectionEvent.numConsecutiveConnectionFailure = |
| recentStats.getCount(WifiScoreCard.CNT_CONSECUTIVE_CONNECTION_FAILURE); |
| } |
| |
| String ssid = currentConnectionEvent.mConfigSsid; |
| int nominator = currentConnectionEvent.mConnectionEvent.connectionNominator; |
| int trigger = WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__UNKNOWN; |
| |
| if (nominator == WifiMetricsProto.ConnectionEvent.NOMINATOR_MANUAL) { |
| trigger = WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__MANUAL; |
| } else if (mPreviousSession == null) { |
| trigger = WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__AUTOCONNECT_BOOT; |
| } else if (ssid != null && ssid.equals(mPreviousSession.mSsid)) { |
| trigger = WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__RECONNECT_SAME_NETWORK; |
| } else if (nominator != WifiMetricsProto.ConnectionEvent.NOMINATOR_UNKNOWN) { |
| trigger = WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__TRIGGER__AUTOCONNECT_CONFIGURED_NETWORK; |
| } |
| currentConnectionEvent.mTrigger = trigger; |
| } |
| |
| return overlapWithLastConnectionMs; |
| } |
| } |
| |
| /** |
| * Set AP related metrics from ScanDetail |
| */ |
| public void setConnectionScanDetail(String ifaceName, ScanDetail scanDetail) { |
| synchronized (mLock) { |
| ConnectionEvent currentConnectionEvent = mCurrentConnectionEventPerIface.get(ifaceName); |
| if (currentConnectionEvent == null || scanDetail == null) { |
| return; |
| } |
| NetworkDetail networkDetail = scanDetail.getNetworkDetail(); |
| ScanResult scanResult = scanDetail.getScanResult(); |
| // Ensure that we have a networkDetail, and that it corresponds to the currently |
| // tracked connection attempt |
| if (networkDetail == null || scanResult == null |
| || currentConnectionEvent.mConfigSsid == null |
| || !currentConnectionEvent.mConfigSsid |
| .equals("\"" + networkDetail.getSSID() + "\"")) { |
| return; |
| } |
| updateMetricsFromNetworkDetail(currentConnectionEvent, networkDetail); |
| updateMetricsFromScanResult(currentConnectionEvent, scanResult); |
| } |
| } |
| |
| /** |
| * Set PMK cache status for a connection event |
| */ |
| public void setConnectionPmkCache(String ifaceName, boolean isEnabled) { |
| synchronized (mLock) { |
| ConnectionEvent currentConnectionEvent = mCurrentConnectionEventPerIface.get(ifaceName); |
| if (currentConnectionEvent != null) { |
| currentConnectionEvent.mRouterFingerPrint.setPmkCache(isEnabled); |
| } |
| } |
| } |
| |
| /** |
| * Set the max link speed supported by current network |
| */ |
| public void setConnectionMaxSupportedLinkSpeedMbps( |
| String ifaceName, int maxSupportedTxLinkSpeedMbps, int maxSupportedRxLinkSpeedMbps) { |
| synchronized (mLock) { |
| ConnectionEvent currentConnectionEvent = mCurrentConnectionEventPerIface.get(ifaceName); |
| if (currentConnectionEvent != null) { |
| currentConnectionEvent.mRouterFingerPrint.setMaxSupportedLinkSpeedMbps( |
| maxSupportedTxLinkSpeedMbps, maxSupportedRxLinkSpeedMbps); |
| } |
| } |
| } |
| |
| /** |
| * End a Connection event record. Call when wifi connection attempt succeeds or fails. |
| * If a Connection event has not been started and is active when .end is called, then this |
| * method will do nothing. |
| * |
| * @param ifaceName |
| * @param level2FailureCode Level 2 failure code returned by supplicant |
| * @param connectivityFailureCode WifiMetricsProto.ConnectionEvent.HLF_X |
| * @param level2FailureReason Breakdown of level2FailureCode with more detailed reason |
| */ |
| public void endConnectionEvent( |
| String ifaceName, |
| int level2FailureCode, |
| int connectivityFailureCode, |
| int level2FailureReason, |
| int frequency) { |
| synchronized (mLock) { |
| ConnectionEvent currentConnectionEvent = mCurrentConnectionEventPerIface.get(ifaceName); |
| if (currentConnectionEvent != null) { |
| boolean connectionSucceeded = (level2FailureCode == 1) |
| && (connectivityFailureCode == WifiMetricsProto.ConnectionEvent.HLF_NONE); |
| |
| int band = KnownBandsChannelHelper.getBand(frequency); |
| int durationTakenToConnectMillis = |
| (int) (mClock.getElapsedSinceBootMillis() |
| - currentConnectionEvent.mConnectionEvent.startTimeSinceBootMillis); |
| |
| if (connectionSucceeded) { |
| mCurrentSession = new SessionData(currentConnectionEvent.mConfigSsid, |
| mClock.getElapsedSinceBootMillis(), |
| band, currentConnectionEvent.mAuthType); |
| |
| // TODO(b/166309727) need to add ifaceName to WifiStatsLog |
| WifiStatsLog.write(WifiStatsLog.WIFI_CONNECTION_STATE_CHANGED, |
| true, band, currentConnectionEvent.mAuthType); |
| } |
| |
| currentConnectionEvent.mConnectionEvent.connectionResult = |
| connectionSucceeded ? 1 : 0; |
| currentConnectionEvent.mConnectionEvent.durationTakenToConnectMillis = |
| durationTakenToConnectMillis; |
| currentConnectionEvent.mConnectionEvent.level2FailureCode = level2FailureCode; |
| currentConnectionEvent.mConnectionEvent.connectivityLevelFailureCode = |
| connectivityFailureCode; |
| currentConnectionEvent.mConnectionEvent.level2FailureReason = level2FailureReason; |
| |
| // Write metrics to statsd |
| int wwFailureCode = getConnectionResultFailureCode(level2FailureCode, |
| level2FailureReason); |
| |
| if (wwFailureCode != -1) { |
| int timeSinceConnectedSeconds = (int) ((mPreviousSession != null ? |
| (mClock.getElapsedSinceBootMillis() |
| - mPreviousSession.mSessionEndTimeMillis) : |
| mClock.getElapsedSinceBootMillis()) / 1000); |
| |
| WifiStatsLog.write(WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED, |
| connectionSucceeded, |
| wwFailureCode, currentConnectionEvent.mConnectionEvent.signalStrength, |
| durationTakenToConnectMillis, band, currentConnectionEvent.mAuthType, |
| currentConnectionEvent.mTrigger, |
| currentConnectionEvent.mHasEverConnected, |
| timeSinceConnectedSeconds |
| ); |
| } |
| |
| // ConnectionEvent already added to ConnectionEvents List. Safe to remove here. |
| mCurrentConnectionEventPerIface.remove(ifaceName); |
| if (!connectionSucceeded) { |
| mScanResultRssiTimestampMillis = -1; |
| } |
| mWifiStatusBuilder.setConnected(connectionSucceeded); |
| } |
| } |
| } |
| |
| /** |
| * Report that an active Wifi network connection was dropped. |
| * |
| * @param disconnectReason Error code for the disconnect. |
| * @param rssi Last seen RSSI. |
| * @param linkSpeed Last seen link speed. |
| */ |
| public void reportNetworkDisconnect(String ifaceName, int disconnectReason, int rssi, |
| int linkSpeed) { |
| synchronized (mLock) { |
| if (!isPrimary(ifaceName)) { |
| return; |
| } |
| WifiStatsLog.write(WifiStatsLog.WIFI_CONNECTION_STATE_CHANGED, |
| false, |
| mCurrentSession != null ? mCurrentSession.mBand : 0, |
| mCurrentSession != null ? mCurrentSession.mAuthType : 0); |
| |
| if (mCurrentSession != null) { |
| mCurrentSession.mSessionEndTimeMillis = mClock.getElapsedSinceBootMillis(); |
| int durationSeconds = (int) (mCurrentSession.mSessionEndTimeMillis |
| - mCurrentSession.mSessionStartTimeMillis) / 1000; |
| |
| WifiStatsLog.write(WifiStatsLog.WIFI_DISCONNECT_REPORTED, |
| durationSeconds, |
| disconnectReason, |
| mCurrentSession.mBand, |
| mCurrentSession.mAuthType, |
| rssi, |
| linkSpeed); |
| |
| mPreviousSession = mCurrentSession; |
| mCurrentSession = null; |
| } |
| } |
| } |
| |
| private int getConnectionResultFailureCode(int level2FailureCode, int level2FailureReason) { |
| switch (level2FailureCode) { |
| case ConnectionEvent.FAILURE_NONE: |
| return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_UNKNOWN; |
| case ConnectionEvent.FAILURE_ASSOCIATION_TIMED_OUT: |
| return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_ASSOCIATION_TIMEOUT; |
| case ConnectionEvent.FAILURE_ASSOCIATION_REJECTION: |
| return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_ASSOCIATION_REJECTION; |
| case ConnectionEvent.FAILURE_AUTHENTICATION_FAILURE: |
| switch (level2FailureReason) { |
| case WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_EAP_FAILURE: |
| return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_AUTHENTICATION_EAP; |
| case WifiMetricsProto.ConnectionEvent.AUTH_FAILURE_WRONG_PSWD: |
| return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_WRONG_PASSWORD; |
| default: |
| return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_AUTHENTICATION_GENERAL; |
| } |
| case ConnectionEvent.FAILURE_DHCP: |
| return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_DHCP; |
| case ConnectionEvent.FAILURE_NETWORK_DISCONNECTION: |
| return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_NETWORK_DISCONNECTION; |
| case ConnectionEvent.FAILURE_ROAM_TIMEOUT: |
| return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_ROAM_TIMEOUT; |
| case ConnectionEvent.FAILURE_NEW_CONNECTION_ATTEMPT: |
| case ConnectionEvent.FAILURE_REDUNDANT_CONNECTION_ATTEMPT: |
| return -1; |
| default: |
| return WifiStatsLog.WIFI_CONNECTION_RESULT_REPORTED__FAILURE_CODE__FAILURE_UNKNOWN; |
| } |
| } |
| |
| /** |
| * Set ConnectionEvent DTIM Interval (if set), and 802.11 Connection mode, from NetworkDetail |
| */ |
| private void updateMetricsFromNetworkDetail( |
| ConnectionEvent currentConnectionEvent, NetworkDetail networkDetail) { |
| int dtimInterval = networkDetail.getDtimInterval(); |
| if (dtimInterval > 0) { |
| currentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.dtim = |
| dtimInterval; |
| } |
| final int connectionWifiMode; |
| switch (networkDetail.getWifiMode()) { |
| case InformationElementUtil.WifiMode.MODE_UNDEFINED: |
| connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_UNKNOWN; |
| break; |
| case InformationElementUtil.WifiMode.MODE_11A: |
| connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_A; |
| break; |
| case InformationElementUtil.WifiMode.MODE_11B: |
| connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_B; |
| break; |
| case InformationElementUtil.WifiMode.MODE_11G: |
| connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_G; |
| break; |
| case InformationElementUtil.WifiMode.MODE_11N: |
| connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_N; |
| break; |
| case InformationElementUtil.WifiMode.MODE_11AC : |
| connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_AC; |
| break; |
| case InformationElementUtil.WifiMode.MODE_11AX : |
| connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_AX; |
| break; |
| default: |
| connectionWifiMode = WifiMetricsProto.RouterFingerPrint.ROUTER_TECH_OTHER; |
| break; |
| } |
| currentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.routerTechnology = |
| connectionWifiMode; |
| |
| if (networkDetail.isMboSupported()) { |
| mWifiLogProto.numConnectToNetworkSupportingMbo++; |
| if (networkDetail.isOceSupported()) { |
| mWifiLogProto.numConnectToNetworkSupportingOce++; |
| } |
| } |
| } |
| |
| /** |
| * Set ConnectionEvent RSSI and authentication type from ScanResult |
| */ |
| private void updateMetricsFromScanResult( |
| ConnectionEvent currentConnectionEvent, ScanResult scanResult) { |
| currentConnectionEvent.mConnectionEvent.signalStrength = scanResult.level; |
| currentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication = |
| WifiMetricsProto.RouterFingerPrint.AUTH_OPEN; |
| currentConnectionEvent.mConfigBssid = scanResult.BSSID; |
| if (scanResult.capabilities != null) { |
| if (ScanResultUtil.isScanResultForWepNetwork(scanResult)) { |
| currentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication = |
| WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL; |
| } else if (ScanResultUtil.isScanResultForPskNetwork(scanResult) |
| || ScanResultUtil.isScanResultForSaeNetwork(scanResult)) { |
| currentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication = |
| WifiMetricsProto.RouterFingerPrint.AUTH_PERSONAL; |
| } else if (ScanResultUtil.isScanResultForWpa3EnterpriseTransitionNetwork(scanResult) |
| || ScanResultUtil.isScanResultForWpa3EnterpriseOnlyNetwork(scanResult) |
| || ScanResultUtil.isScanResultForEapNetwork(scanResult) |
| || ScanResultUtil.isScanResultForEapSuiteBNetwork(scanResult)) { |
| currentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.authentication = |
| WifiMetricsProto.RouterFingerPrint.AUTH_ENTERPRISE; |
| } |
| } |
| currentConnectionEvent.mRouterFingerPrint.mRouterFingerPrintProto.channelInfo = |
| scanResult.frequency; |
| } |
| |
| void setIsLocationEnabled(boolean enabled) { |
| synchronized (mLock) { |
| mWifiLogProto.isLocationEnabled = enabled; |
| } |
| } |
| |
| void setIsScanningAlwaysEnabled(boolean enabled) { |
| synchronized (mLock) { |
| mWifiLogProto.isScanningAlwaysEnabled = enabled; |
| } |
| } |
| |
| /** |
| * Developer options toggle value for verbose logging. |
| */ |
| public void setVerboseLoggingEnabled(boolean enabled) { |
| synchronized (mLock) { |
| mWifiLogProto.isVerboseLoggingEnabled = enabled; |
| } |
| } |
| |
| /** |
| * Developer options toggle value for enhanced MAC randomization. |
| */ |
| public void setEnhancedMacRandomizationForceEnabled(boolean enabled) { |
| synchronized (mLock) { |
| mWifiLogProto.isEnhancedMacRandomizationForceEnabled = enabled; |
| } |
| } |
| |
| /** |
| * Wifi wake feature toggle. |
| */ |
| public void setWifiWakeEnabled(boolean enabled) { |
| synchronized (mLock) { |
| mWifiLogProto.isWifiWakeEnabled = enabled; |
| } |
| } |
| |
| /** |
| * Increment Non Empty Scan Results count |
| */ |
| public void incrementNonEmptyScanResultCount() { |
| if (DBG) Log.v(TAG, "incrementNonEmptyScanResultCount"); |
| synchronized (mLock) { |
| mWifiLogProto.numNonEmptyScanResults++; |
| } |
| } |
| |
| /** |
| * Increment Empty Scan Results count |
| */ |
| public void incrementEmptyScanResultCount() { |
| if (DBG) Log.v(TAG, "incrementEmptyScanResultCount"); |
| synchronized (mLock) { |
| mWifiLogProto.numEmptyScanResults++; |
| } |
| } |
| |
| /** |
| * Increment background scan count |
| */ |
| public void incrementBackgroundScanCount() { |
| if (DBG) Log.v(TAG, "incrementBackgroundScanCount"); |
| synchronized (mLock) { |
| mWifiLogProto.numBackgroundScans++; |
| } |
| } |
| |
| /** |
| * Get Background scan count |
| */ |
| public int getBackgroundScanCount() { |
| synchronized (mLock) { |
| return mWifiLogProto.numBackgroundScans; |
| } |
| } |
| |
| /** |
| * Increment oneshot scan count, and the associated WifiSystemScanStateCount entry |
| */ |
| public void incrementOneshotScanCount() { |
| synchronized (mLock) { |
| mWifiLogProto.numOneshotScans++; |
| } |
| incrementWifiSystemScanStateCount(mWifiState, mScreenOn); |
| } |
| |
| /** |
| * Increment the count of oneshot scans that include DFS channels. |
| */ |
| public void incrementOneshotScanWithDfsCount() { |
| synchronized (mLock) { |
| mWifiLogProto.numOneshotHasDfsChannelScans++; |
| } |
| } |
| |
| /** |
| * Increment connectivity oneshot scan count. |
| */ |
| public void incrementConnectivityOneshotScanCount() { |
| synchronized (mLock) { |
| mWifiLogProto.numConnectivityOneshotScans++; |
| } |
| } |
| |
| /** |
| * Get oneshot scan count |
| */ |
| public int getOneshotScanCount() { |
| synchronized (mLock) { |
| return mWifiLogProto.numOneshotScans; |
| } |
| } |
| |
| /** |
| * Get connectivity oneshot scan count |
| */ |
| public int getConnectivityOneshotScanCount() { |
| synchronized (mLock) { |
| return mWifiLogProto.numConnectivityOneshotScans; |
| } |
| } |
| |
| /** |
| * Get the count of oneshot scan requests that included DFS channels. |
| */ |
| public int getOneshotScanWithDfsCount() { |
| synchronized (mLock) { |
| return mWifiLogProto.numOneshotHasDfsChannelScans; |
| } |
| } |
| |
| /** |
| * Increment oneshot scan count for external apps. |
| */ |
| public void incrementExternalAppOneshotScanRequestsCount() { |
| synchronized (mLock) { |
| mWifiLogProto.numExternalAppOneshotScanRequests++; |
| } |
| } |
| /** |
| * Increment oneshot scan throttle count for external foreground apps. |
| */ |
| public void incrementExternalForegroundAppOneshotScanRequestsThrottledCount() { |
| synchronized (mLock) { |
| mWifiLogProto.numExternalForegroundAppOneshotScanRequestsThrottled++; |
| } |
| } |
| |
| /** |
| * Increment oneshot scan throttle count for external background apps. |
| */ |
| public void incrementExternalBackgroundAppOneshotScanRequestsThrottledCount() { |
| synchronized (mLock) { |
| mWifiLogProto.numExternalBackgroundAppOneshotScanRequestsThrottled++; |
| } |
| } |
| |
| private String returnCodeToString(int scanReturnCode) { |
| switch(scanReturnCode){ |
| case WifiMetricsProto.WifiLog.SCAN_UNKNOWN: |
| return "SCAN_UNKNOWN"; |
| case WifiMetricsProto.WifiLog.SCAN_SUCCESS: |
| return "SCAN_SUCCESS"; |
| case WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED: |
| return "SCAN_FAILURE_INTERRUPTED"; |
| case WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION: |
| return "SCAN_FAILURE_INVALID_CONFIGURATION"; |
| case WifiMetricsProto.WifiLog.FAILURE_WIFI_DISABLED: |
| return "FAILURE_WIFI_DISABLED"; |
| default: |
| return "<UNKNOWN>"; |
| } |
| } |
| |
| /** |
| * Increment count of scan return code occurrence |
| * |
| * @param scanReturnCode Return code from scan attempt WifiMetricsProto.WifiLog.SCAN_X |
| */ |
| public void incrementScanReturnEntry(int scanReturnCode, int countToAdd) { |
| synchronized (mLock) { |
| if (DBG) Log.v(TAG, "incrementScanReturnEntry " + returnCodeToString(scanReturnCode)); |
| int entry = mScanReturnEntries.get(scanReturnCode); |
| entry += countToAdd; |
| mScanReturnEntries.put(scanReturnCode, entry); |
| } |
| } |
| /** |
| * Get the count of this scanReturnCode |
| * @param scanReturnCode that we are getting the count for |
| */ |
| public int getScanReturnEntry(int scanReturnCode) { |
| synchronized (mLock) { |
| return mScanReturnEntries.get(scanReturnCode); |
| } |
| } |
| |
| private String wifiSystemStateToString(int state) { |
| switch(state){ |
| case WifiMetricsProto.WifiLog.WIFI_UNKNOWN: |
| return "WIFI_UNKNOWN"; |
| case WifiMetricsProto.WifiLog.WIFI_DISABLED: |
| return "WIFI_DISABLED"; |
| case WifiMetricsProto.WifiLog.WIFI_DISCONNECTED: |
| return "WIFI_DISCONNECTED"; |
| case WifiMetricsProto.WifiLog.WIFI_ASSOCIATED: |
| return "WIFI_ASSOCIATED"; |
| default: |
| return "default"; |
| } |
| } |
| |
| /** |
| * Increments the count of scans initiated by each wifi state, accounts for screenOn/Off |
| * |
| * @param state State of the system when scan was initiated, see WifiMetricsProto.WifiLog.WIFI_X |
| * @param screenOn Is the screen on |
| */ |
| public void incrementWifiSystemScanStateCount(int state, boolean screenOn) { |
| synchronized (mLock) { |
| if (DBG) { |
| Log.v(TAG, "incrementWifiSystemScanStateCount " + wifiSystemStateToString(state) |
| + " " + screenOn); |
| } |
| int index = (state * 2) + (screenOn ? SCREEN_ON : SCREEN_OFF); |
| int entry = mWifiSystemStateEntries.get(index); |
| entry++; |
| mWifiSystemStateEntries.put(index, entry); |
| } |
| } |
| |
| /** |
| * Get the count of this system State Entry |
| */ |
| public int getSystemStateCount(int state, boolean screenOn) { |
| synchronized (mLock) { |
| int index = state * 2 + (screenOn ? SCREEN_ON : SCREEN_OFF); |
| return mWifiSystemStateEntries.get(index); |
| } |
| } |
| |
| /** |
| * Increment number of times the Watchdog of Last Resort triggered, resetting the wifi stack |
| */ |
| public void incrementNumLastResortWatchdogTriggers() { |
| synchronized (mLock) { |
| mWifiLogProto.numLastResortWatchdogTriggers++; |
| } |
| } |
| /** |
| * @param count number of networks over bad association threshold when watchdog triggered |
| */ |
| public void addCountToNumLastResortWatchdogBadAssociationNetworksTotal(int count) { |
| synchronized (mLock) { |
| mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal += count; |
| } |
| } |
| /** |
| * @param count number of networks over bad authentication threshold when watchdog triggered |
| */ |
| public void addCountToNumLastResortWatchdogBadAuthenticationNetworksTotal(int count) { |
| synchronized (mLock) { |
| mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal += count; |
| } |
| } |
| /** |
| * @param count number of networks over bad dhcp threshold when watchdog triggered |
| */ |
| public void addCountToNumLastResortWatchdogBadDhcpNetworksTotal(int count) { |
| synchronized (mLock) { |
| mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal += count; |
| } |
| } |
| /** |
| * @param count number of networks over bad other threshold when watchdog triggered |
| */ |
| public void addCountToNumLastResortWatchdogBadOtherNetworksTotal(int count) { |
| synchronized (mLock) { |
| mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal += count; |
| } |
| } |
| /** |
| * @param count number of networks seen when watchdog triggered |
| */ |
| public void addCountToNumLastResortWatchdogAvailableNetworksTotal(int count) { |
| synchronized (mLock) { |
| mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal += count; |
| } |
| } |
| /** |
| * Increment count of triggers with atleast one bad association network |
| */ |
| public void incrementNumLastResortWatchdogTriggersWithBadAssociation() { |
| synchronized (mLock) { |
| mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation++; |
| } |
| } |
| /** |
| * Increment count of triggers with atleast one bad authentication network |
| */ |
| public void incrementNumLastResortWatchdogTriggersWithBadAuthentication() { |
| synchronized (mLock) { |
| mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication++; |
| } |
| } |
| /** |
| * Increment count of triggers with atleast one bad dhcp network |
| */ |
| public void incrementNumLastResortWatchdogTriggersWithBadDhcp() { |
| synchronized (mLock) { |
| mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp++; |
| } |
| } |
| /** |
| * Increment count of triggers with atleast one bad other network |
| */ |
| public void incrementNumLastResortWatchdogTriggersWithBadOther() { |
| synchronized (mLock) { |
| mWifiLogProto.numLastResortWatchdogTriggersWithBadOther++; |
| } |
| } |
| |
| /** |
| * Increment number of times connectivity watchdog confirmed pno is working |
| */ |
| public void incrementNumConnectivityWatchdogPnoGood() { |
| synchronized (mLock) { |
| mWifiLogProto.numConnectivityWatchdogPnoGood++; |
| } |
| } |
| /** |
| * Increment number of times connectivity watchdog found pno not working |
| */ |
| public void incrementNumConnectivityWatchdogPnoBad() { |
| synchronized (mLock) { |
| mWifiLogProto.numConnectivityWatchdogPnoBad++; |
| } |
| } |
| /** |
| * Increment number of times connectivity watchdog confirmed background scan is working |
| */ |
| public void incrementNumConnectivityWatchdogBackgroundGood() { |
| synchronized (mLock) { |
| mWifiLogProto.numConnectivityWatchdogBackgroundGood++; |
| } |
| } |
| /** |
| * Increment number of times connectivity watchdog found background scan not working |
| */ |
| public void incrementNumConnectivityWatchdogBackgroundBad() { |
| synchronized (mLock) { |
| mWifiLogProto.numConnectivityWatchdogBackgroundBad++; |
| } |
| } |
| |
| /** |
| * Increment various poll related metrics, and cache performance data for StaEvent logging |
| */ |
| public void handlePollResult(String ifaceName, WifiInfo wifiInfo) { |
| if (!isPrimary(ifaceName)) { |
| return; |
| } |
| mLastPollRssi = wifiInfo.getRssi(); |
| mLastPollLinkSpeed = wifiInfo.getLinkSpeed(); |
| mLastPollFreq = wifiInfo.getFrequency(); |
| incrementRssiPollRssiCount(mLastPollFreq, mLastPollRssi); |
| incrementLinkSpeedCount(mLastPollLinkSpeed, mLastPollRssi); |
| mLastPollRxLinkSpeed = wifiInfo.getRxLinkSpeedMbps(); |
| incrementTxLinkSpeedBandCount(mLastPollLinkSpeed, mLastPollFreq); |
| incrementRxLinkSpeedBandCount(mLastPollRxLinkSpeed, mLastPollFreq); |
| mWifiStatusBuilder.setRssi(mLastPollRssi); |
| mWifiStatusBuilder.setNetworkId(wifiInfo.getNetworkId()); |
| } |
| |
| /** |
| * Increment occurence count of RSSI level from RSSI poll for the given frequency. |
| * @param frequency (MHz) |
| * @param rssi |
| */ |
| @VisibleForTesting |
| public void incrementRssiPollRssiCount(int frequency, int rssi) { |
| if (!(rssi >= MIN_RSSI_POLL && rssi <= MAX_RSSI_POLL)) { |
| return; |
| } |
| synchronized (mLock) { |
| if (!mRssiPollCountsMap.containsKey(frequency)) { |
| mRssiPollCountsMap.put(frequency, new SparseIntArray()); |
| } |
| SparseIntArray sparseIntArray = mRssiPollCountsMap.get(frequency); |
| int count = sparseIntArray.get(rssi); |
| sparseIntArray.put(rssi, count + 1); |
| maybeIncrementRssiDeltaCount(rssi - mScanResultRssi); |
| } |
| } |
| |
| /** |
| * Increment occurence count of difference between scan result RSSI and the first RSSI poll. |
| * Ignores rssi values outside the bounds of [MIN_RSSI_DELTA, MAX_RSSI_DELTA] |
| * mLock must be held when calling this method. |
| */ |
| private void maybeIncrementRssiDeltaCount(int rssi) { |
| // Check if this RSSI poll is close enough to a scan result RSSI to log a delta value |
| if (mScanResultRssiTimestampMillis >= 0) { |
| long timeDelta = mClock.getElapsedSinceBootMillis() - mScanResultRssiTimestampMillis; |
| if (timeDelta <= TIMEOUT_RSSI_DELTA_MILLIS) { |
| if (rssi >= MIN_RSSI_DELTA && rssi <= MAX_RSSI_DELTA) { |
| int count = mRssiDeltaCounts.get(rssi); |
| mRssiDeltaCounts.put(rssi, count + 1); |
| } |
| } |
| mScanResultRssiTimestampMillis = -1; |
| } |
| } |
| |
| /** |
| * Increment occurrence count of link speed. |
| * Ignores link speed values that are lower than MIN_LINK_SPEED_MBPS |
| * and rssi values outside the bounds of [MIN_RSSI_POLL, MAX_RSSI_POLL] |
| */ |
| @VisibleForTesting |
| public void incrementLinkSpeedCount(int linkSpeed, int rssi) { |
| if (!(mContext.getResources().getBoolean(R.bool.config_wifiLinkSpeedMetricsEnabled) |
| && linkSpeed >= MIN_LINK_SPEED_MBPS |
| && rssi >= MIN_RSSI_POLL |
| && rssi <= MAX_RSSI_POLL)) { |
| return; |
| } |
| synchronized (mLock) { |
| LinkSpeedCount linkSpeedCount = mLinkSpeedCounts.get(linkSpeed); |
| if (linkSpeedCount == null) { |
| linkSpeedCount = new LinkSpeedCount(); |
| linkSpeedCount.linkSpeedMbps = linkSpeed; |
| mLinkSpeedCounts.put(linkSpeed, linkSpeedCount); |
| } |
| linkSpeedCount.count++; |
| linkSpeedCount.rssiSumDbm += Math.abs(rssi); |
| linkSpeedCount.rssiSumOfSquaresDbmSq += rssi * rssi; |
| } |
| } |
| |
| /** |
| * Increment occurrence count of Tx link speed for operating sub-band |
| * Ignores link speed values that are lower than MIN_LINK_SPEED_MBPS |
| * @param txLinkSpeed PHY layer Tx link speed in Mbps |
| * @param frequency Channel frequency of beacon frames in MHz |
| */ |
| @VisibleForTesting |
| public void incrementTxLinkSpeedBandCount(int txLinkSpeed, int frequency) { |
| if (!(mContext.getResources().getBoolean(R.bool.config_wifiLinkSpeedMetricsEnabled) |
| && txLinkSpeed >= MIN_LINK_SPEED_MBPS)) { |
| return; |
| } |
| synchronized (mLock) { |
| if (ScanResult.is24GHz(frequency)) { |
| mTxLinkSpeedCount2g.increment(txLinkSpeed); |
| } else if (frequency <= KnownBandsChannelHelper.BAND_5_GHZ_LOW_END_FREQ) { |
| mTxLinkSpeedCount5gLow.increment(txLinkSpeed); |
| } else if (frequency <= KnownBandsChannelHelper.BAND_5_GHZ_MID_END_FREQ) { |
| mTxLinkSpeedCount5gMid.increment(txLinkSpeed); |
| } else if (frequency <= KnownBandsChannelHelper.BAND_5_GHZ_HIGH_END_FREQ) { |
| mTxLinkSpeedCount5gHigh.increment(txLinkSpeed); |
| } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_LOW_END_FREQ) { |
| mTxLinkSpeedCount6gLow.increment(txLinkSpeed); |
| } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_MID_END_FREQ) { |
| mTxLinkSpeedCount6gMid.increment(txLinkSpeed); |
| } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_HIGH_END_FREQ) { |
| mTxLinkSpeedCount6gHigh.increment(txLinkSpeed); |
| } |
| } |
| } |
| |
| /** |
| * Increment occurrence count of Rx link speed for operating sub-band |
| * Ignores link speed values that are lower than MIN_LINK_SPEED_MBPS |
| * @param rxLinkSpeed PHY layer Tx link speed in Mbps |
| * @param frequency Channel frequency of beacon frames in MHz |
| */ |
| @VisibleForTesting |
| public void incrementRxLinkSpeedBandCount(int rxLinkSpeed, int frequency) { |
| if (!(mContext.getResources().getBoolean(R.bool.config_wifiLinkSpeedMetricsEnabled) |
| && rxLinkSpeed >= MIN_LINK_SPEED_MBPS)) { |
| return; |
| } |
| synchronized (mLock) { |
| if (ScanResult.is24GHz(frequency)) { |
| mRxLinkSpeedCount2g.increment(rxLinkSpeed); |
| } else if (frequency <= KnownBandsChannelHelper.BAND_5_GHZ_LOW_END_FREQ) { |
| mRxLinkSpeedCount5gLow.increment(rxLinkSpeed); |
| } else if (frequency <= KnownBandsChannelHelper.BAND_5_GHZ_MID_END_FREQ) { |
| mRxLinkSpeedCount5gMid.increment(rxLinkSpeed); |
| } else if (frequency <= KnownBandsChannelHelper.BAND_5_GHZ_HIGH_END_FREQ) { |
| mRxLinkSpeedCount5gHigh.increment(rxLinkSpeed); |
| } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_LOW_END_FREQ) { |
| mRxLinkSpeedCount6gLow.increment(rxLinkSpeed); |
| } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_MID_END_FREQ) { |
| mRxLinkSpeedCount6gMid.increment(rxLinkSpeed); |
| } else if (frequency <= KnownBandsChannelHelper.BAND_6_GHZ_HIGH_END_FREQ) { |
| mRxLinkSpeedCount6gHigh.increment(rxLinkSpeed); |
| } |
| } |
| } |
| |
| /** |
| * Increment occurrence count of channel utilization |
| * @param channelUtilization Channel utilization of current network |
| * @param frequency Channel frequency of current network |
| */ |
| @VisibleForTesting |
| public void incrementChannelUtilizationCount(int channelUtilization, int frequency) { |
| if (channelUtilization < InformationElementUtil.BssLoad.MIN_CHANNEL_UTILIZATION |
| || channelUtilization > InformationElementUtil.BssLoad.MAX_CHANNEL_UTILIZATION) { |
| return; |
| } |
| synchronized (mLock) { |
| if (ScanResult.is24GHz(frequency)) { |
| mChannelUtilizationHistogram2G.increment(channelUtilization); |
| } else { |
| mChannelUtilizationHistogramAbove2G.increment(channelUtilization); |
| } |
| } |
| } |
| |
| /** |
| * Increment occurrence count of Tx and Rx throughput |
| * @param txThroughputKbps Tx throughput of current network in Kbps |
| * @param rxThroughputKbps Rx throughput of current network in Kbps |
| * @param frequency Channel frequency of current network in MHz |
| */ |
| @VisibleForTesting |
| public void incrementThroughputKbpsCount(int txThroughputKbps, int rxThroughputKbps, |
| int frequency) { |
| synchronized (mLock) { |
| if (ScanResult.is24GHz(frequency)) { |
| if (txThroughputKbps >= 0) { |
| mTxThroughputMbpsHistogram2G.increment(txThroughputKbps / 1000); |
| } |
| if (rxThroughputKbps >= 0) { |
| mRxThroughputMbpsHistogram2G.increment(rxThroughputKbps / 1000); |
| } |
| } else { |
| if (txThroughputKbps >= 0) { |
| mTxThroughputMbpsHistogramAbove2G.increment(txThroughputKbps / 1000); |
| } |
| if (rxThroughputKbps >= 0) { |
| mRxThroughputMbpsHistogramAbove2G.increment(rxThroughputKbps / 1000); |
| } |
| } |
| mWifiStatusBuilder.setEstimatedTxKbps(txThroughputKbps); |
| mWifiStatusBuilder.setEstimatedRxKbps(rxThroughputKbps); |
| } |
| } |
| |
| /** |
| * Increment count of Watchdog successes. |
| */ |
| public void incrementNumLastResortWatchdogSuccesses() { |
| synchronized (mLock) { |
| mWifiLogProto.numLastResortWatchdogSuccesses++; |
| } |
| } |
| |
| /** |
| * Increment the count of network connection failures that happened after watchdog has been |
| * triggered. |
| */ |
| public void incrementWatchdogTotalConnectionFailureCountAfterTrigger() { |
| synchronized (mLock) { |
| mWifiLogProto.watchdogTotalConnectionFailureCountAfterTrigger++; |
| } |
| } |
| |
| /** |
| * Sets the time taken for wifi to connect after a watchdog triggers a restart. |
| * @param milliseconds |
| */ |
| public void setWatchdogSuccessTimeDurationMs(long ms) { |
| synchronized (mLock) { |
| mWifiLogProto.watchdogTriggerToConnectionSuccessDurationMs = ms; |
| } |
| } |
| |
| /** |
| * Increments the count of alerts by alert reason. |
| * |
| * @param reason The cause of the alert. The reason values are driver-specific. |
| */ |
| private void incrementAlertReasonCount(int reason) { |
| if (reason > WifiLoggerHal.WIFI_ALERT_REASON_MAX |
| || reason < WifiLoggerHal.WIFI_ALERT_REASON_MIN) { |
| reason = WifiLoggerHal.WIFI_ALERT_REASON_RESERVED; |
| } |
| synchronized (mLock) { |
| int alertCount = mWifiAlertReasonCounts.get(reason); |
| mWifiAlertReasonCounts.put(reason, alertCount + 1); |
| } |
| } |
| |
| /** |
| * Counts all the different types of networks seen in a set of scan results |
| */ |
| public void countScanResults(List<ScanDetail> scanDetails) { |
| if (scanDetails == null) { |
| return; |
| } |
| int totalResults = 0; |
| int openNetworks = 0; |
| int personalNetworks = 0; |
| int enterpriseNetworks = 0; |
| int hiddenNetworks = 0; |
| int hotspot2r1Networks = 0; |
| int hotspot2r2Networks = 0; |
| int hotspot2r3Networks = 0; |
| int enhacedOpenNetworks = 0; |
| int wpa3PersonalNetworks = 0; |
| int wpa3EnterpriseNetworks = 0; |
| int wapiPersonalNetworks = 0; |
| int wapiEnterpriseNetworks = 0; |
| int mboSupportedNetworks = 0; |
| int mboCellularDataAwareNetworks = 0; |
| int oceSupportedNetworks = 0; |
| int filsSupportedNetworks = 0; |
| int band6gNetworks = 0; |
| int band6gPscNetworks = 0; |
| int standard11axNetworks = 0; |
| |
| for (ScanDetail scanDetail : scanDetails) { |
| NetworkDetail networkDetail = scanDetail.getNetworkDetail(); |
| ScanResult scanResult = scanDetail.getScanResult(); |
| totalResults++; |
| if (networkDetail != null) { |
| if (networkDetail.isHiddenBeaconFrame()) { |
| hiddenNetworks++; |
| } |
| if (networkDetail.getHSRelease() != null) { |
| if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) { |
| hotspot2r1Networks++; |
| } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) { |
| hotspot2r2Networks++; |
| } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R3) { |
| hotspot2r3Networks++; |
| } |
| } |
| if (networkDetail.isMboSupported()) { |
| mboSupportedNetworks++; |
| if (networkDetail.isMboCellularDataAware()) { |
| mboCellularDataAwareNetworks++; |
| } |
| if (networkDetail.isOceSupported()) { |
| oceSupportedNetworks++; |
| } |
| } |
| if (networkDetail.getWifiMode() == InformationElementUtil.WifiMode.MODE_11AX) { |
| standard11axNetworks++; |
| } |
| } |
| if (scanResult != null && scanResult.capabilities != null) { |
| if (ScanResultUtil.isScanResultForFilsSha256Network(scanResult) |
| || ScanResultUtil.isScanResultForFilsSha384Network(scanResult)) { |
| filsSupportedNetworks++; |
| } |
| if (scanResult.is6GHz()) { |
| band6gNetworks++; |
| if (scanResult.is6GhzPsc()) { |
| band6gPscNetworks++; |
| } |
| } |
| if (ScanResultUtil.isScanResultForEapSuiteBNetwork(scanResult) |
| || ScanResultUtil.isScanResultForWpa3EnterpriseTransitionNetwork(scanResult) |
| || ScanResultUtil.isScanResultForWpa3EnterpriseOnlyNetwork(scanResult)) { |
| wpa3EnterpriseNetworks++; |
| } else if (ScanResultUtil.isScanResultForWapiPskNetwork(scanResult)) { |
| wapiPersonalNetworks++; |
| } else if (ScanResultUtil.isScanResultForWapiCertNetwork(scanResult)) { |
| wapiEnterpriseNetworks++; |
| } else if (ScanResultUtil.isScanResultForEapNetwork(scanResult)) { |
| enterpriseNetworks++; |
| } else if (ScanResultUtil.isScanResultForSaeNetwork(scanResult)) { |
| wpa3PersonalNetworks++; |
| } else if (ScanResultUtil.isScanResultForPskNetwork(scanResult) |
| || ScanResultUtil.isScanResultForWepNetwork(scanResult)) { |
| personalNetworks++; |
| } else if (ScanResultUtil.isScanResultForOweNetwork(scanResult)) { |
| enhacedOpenNetworks++; |
| } else { |
| openNetworks++; |
| } |
| } |
| } |
| synchronized (mLock) { |
| mWifiLogProto.numTotalScanResults += totalResults; |
| mWifiLogProto.numOpenNetworkScanResults += openNetworks; |
| mWifiLogProto.numLegacyPersonalNetworkScanResults += personalNetworks; |
| mWifiLogProto.numLegacyEnterpriseNetworkScanResults += enterpriseNetworks; |
| mWifiLogProto.numEnhancedOpenNetworkScanResults += enhacedOpenNetworks; |
| mWifiLogProto.numWpa3PersonalNetworkScanResults += wpa3PersonalNetworks; |
| mWifiLogProto.numWpa3EnterpriseNetworkScanResults += wpa3EnterpriseNetworks; |
| mWifiLogProto.numWapiPersonalNetworkScanResults += wapiPersonalNetworks; |
| mWifiLogProto.numWapiEnterpriseNetworkScanResults += wapiEnterpriseNetworks; |
| mWifiLogProto.numHiddenNetworkScanResults += hiddenNetworks; |
| mWifiLogProto.numHotspot2R1NetworkScanResults += hotspot2r1Networks; |
| mWifiLogProto.numHotspot2R2NetworkScanResults += hotspot2r2Networks; |
| mWifiLogProto.numHotspot2R3NetworkScanResults += hotspot2r3Networks; |
| mWifiLogProto.numMboSupportedNetworkScanResults += mboSupportedNetworks; |
| mWifiLogProto.numMboCellularDataAwareNetworkScanResults += mboCellularDataAwareNetworks; |
| mWifiLogProto.numOceSupportedNetworkScanResults += oceSupportedNetworks; |
| mWifiLogProto.numFilsSupportedNetworkScanResults += filsSupportedNetworks; |
| mWifiLogProto.num11AxNetworkScanResults += standard11axNetworks; |
| mWifiLogProto.num6GNetworkScanResults += band6gNetworks; |
| mWifiLogProto.num6GPscNetworkScanResults += band6gPscNetworks; |
| mWifiLogProto.numScans++; |
| } |
| } |
| |
| private boolean mWifiWins = false; // Based on scores, use wifi instead of mobile data? |
| // Based on Wifi usability scores. use wifi instead of mobile data? |
| private boolean mWifiWinsUsabilityScore = false; |
| |
| /** |
| * Increments occurence of a particular wifi score calculated |
| * in WifiScoreReport by current connected network. Scores are bounded |
| * within [MIN_WIFI_SCORE, MAX_WIFI_SCORE] to limit size of SparseArray. |
| * |
| * Also records events when the current score breaches significant thresholds. |
| */ |
| public void incrementWifiScoreCount(String ifaceName, int score) { |
| if (score < MIN_WIFI_SCORE || score > MAX_WIFI_SCORE) { |
| return; |
| } |
| synchronized (mLock) { |
| int count = mWifiScoreCounts.get(score); |
| mWifiScoreCounts.put(score, count + 1); |
| |
| boolean wifiWins = mWifiWins; |
| if (mWifiWins && score < LOW_WIFI_SCORE) { |
| wifiWins = false; |
| } else if (!mWifiWins && score > LOW_WIFI_SCORE) { |
| wifiWins = true; |
| } |
| mLastScore = score; |
| mLastScoreNoReset = score; |
| if (wifiWins != mWifiWins) { |
| mWifiWins = wifiWins; |
| StaEvent event = new StaEvent(); |
| event.type = StaEvent.TYPE_SCORE_BREACH; |
| addStaEvent(ifaceName, event); |
| // Only record the first score breach by checking whether mScoreBreachLowTimeMillis |
| // has been set to -1 |
| if (!wifiWins && mScoreBreachLowTimeMillis == -1) { |
| mScoreBreachLowTimeMillis = mClock.getElapsedSinceBootMillis(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Increments occurence of the results from attempting to start SoftAp. |
| * Maps the |result| and WifiManager |failureCode| constant to proto defined SoftApStartResult |
| * codes. |
| */ |
| public void incrementSoftApStartResult(boolean result, int failureCode) { |
| synchronized (mLock) { |
| if (result) { |
| int count = mSoftApManagerReturnCodeCounts.get( |
| WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY); |
| mSoftApManagerReturnCodeCounts.put( |
| WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY, |
| count + 1); |
| return; |
| } |
| |
| // now increment failure modes - if not explicitly handled, dump into the general |
| // error bucket. |
| if (failureCode == WifiManager.SAP_START_FAILURE_NO_CHANNEL) { |
| int count = mSoftApManagerReturnCodeCounts.get( |
| WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL); |
| mSoftApManagerReturnCodeCounts.put( |
| WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL, |
| count + 1); |
| } else if (failureCode == WifiManager.SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION) { |
| int count = mSoftApManagerReturnCodeCounts.get( |
| WifiMetricsProto.SoftApReturnCodeCount |
| .SOFT_AP_FAILED_UNSUPPORTED_CONFIGURATION); |
| mSoftApManagerReturnCodeCounts.put( |
| WifiMetricsProto.SoftApReturnCodeCount |
| .SOFT_AP_FAILED_UNSUPPORTED_CONFIGURATION, |
| count + 1); |
| } else { |
| // failure mode not tracked at this time... count as a general error for now. |
| int count = mSoftApManagerReturnCodeCounts.get( |
| WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR); |
| mSoftApManagerReturnCodeCounts.put( |
| WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR, |
| count + 1); |
| } |
| } |
| } |
| |
| /** |
| * Adds a record indicating the current up state of soft AP |
| */ |
| public void addSoftApUpChangedEvent(boolean isUp, int mode, long defaultShutdownTimeoutMillis, |
| boolean isBridged) { |
| int numOfEventNeedToAdd = isBridged && isUp ? 2 : 1; |
| for (int i = 0; i < numOfEventNeedToAdd; i++) { |
| SoftApConnectedClientsEvent event = new SoftApConnectedClientsEvent(); |
| if (isUp) { |
| event.eventType = isBridged ? SoftApConnectedClientsEvent.DUAL_AP_BOTH_INSTANCES_UP |
| : SoftApConnectedClientsEvent.SOFT_AP_UP; |
| } else { |
| event.eventType = SoftApConnectedClientsEvent.SOFT_AP_DOWN; |
| } |
| event.numConnectedClients = 0; |
| event.defaultShutdownTimeoutSetting = defaultShutdownTimeoutMillis; |
| addSoftApConnectedClientsEvent(event, mode); |
| } |
| } |
| |
| /** |
| * Adds a record indicating the one of the dual AP instances is down. |
| */ |
| public void addSoftApInstanceDownEventInDualMode(int mode, @NonNull SoftApInfo info) { |
| SoftApConnectedClientsEvent event = new SoftApConnectedClientsEvent(); |
| event.eventType = SoftApConnectedClientsEvent.DUAL_AP_ONE_INSTANCE_DOWN; |
| event.channelFrequency = info.getFrequency(); |
| event.channelBandwidth = info.getBandwidth(); |
| event.generation = info.getWifiStandardInternal(); |
| addSoftApConnectedClientsEvent(event, mode); |
| } |
| |
| /** |
| * Adds a record for current number of associated stations to soft AP |
| */ |
| public void addSoftApNumAssociatedStationsChangedEvent(int numTotalStations, |
| int numStationsOnCurrentFrequency, int mode, @Nullable SoftApInfo info) { |
| SoftApConnectedClientsEvent event = new SoftApConnectedClientsEvent(); |
| event.eventType = SoftApConnectedClientsEvent.NUM_CLIENTS_CHANGED; |
| if (info != null) { |
| event.channelFrequency = info.getFrequency(); |
| event.channelBandwidth = info.getBandwidth(); |
| event.generation = info.getWifiStandardInternal(); |
| } |
| event.numConnectedClients = numTotalStations; |
| event.numConnectedClientsOnCurrentFrequency = numStationsOnCurrentFrequency; |
| addSoftApConnectedClientsEvent(event, mode); |
| } |
| |
| /** |
| * Adds a record to the corresponding event list based on mode param |
| */ |
| private void addSoftApConnectedClientsEvent(SoftApConnectedClientsEvent event, int mode) { |
| synchronized (mLock) { |
| List<SoftApConnectedClientsEvent> softApEventList; |
| switch (mode) { |
| case WifiManager.IFACE_IP_MODE_TETHERED: |
| softApEventList = mSoftApEventListTethered; |
| break; |
| case WifiManager.IFACE_IP_MODE_LOCAL_ONLY: |
| softApEventList = mSoftApEventListLocalOnly; |
| break; |
| default: |
| return; |
| } |
| |
| if (softApEventList.size() > MAX_NUM_SOFT_AP_EVENTS) { |
| return; |
| } |
| |
| event.timeStampMillis = mClock.getElapsedSinceBootMillis(); |
| softApEventList.add(event); |
| } |
| } |
| |
| /** |
| * Updates current soft AP events with channel info |
| */ |
| public void addSoftApChannelSwitchedEvent(List<SoftApInfo> infos, int mode, boolean isBridged) { |
| synchronized (mLock) { |
| int numOfEventNeededToUpdate = infos.size(); |
| if (isBridged && numOfEventNeededToUpdate == 1) { |
| // Ignore the channel info update when only 1 info in bridged mode because it means |
| // that one of the instance was been shutdown. |
| return; |
| } |
| int apUpEvent = isBridged ? SoftApConnectedClientsEvent.DUAL_AP_BOTH_INSTANCES_UP |
| : SoftApConnectedClientsEvent.SOFT_AP_UP; |
| List<SoftApConnectedClientsEvent> softApEventList; |
| switch (mode) { |
| case WifiManager.IFACE_IP_MODE_TETHERED: |
| softApEventList = mSoftApEventListTethered; |
| break; |
| case WifiManager.IFACE_IP_MODE_LOCAL_ONLY: |
| softApEventList = mSoftApEventListLocalOnly; |
| break; |
| default: |
| return; |
| } |
| |
| for (int index = softApEventList.size() - 1; |
| index >= 0 && numOfEventNeededToUpdate != 0; index--) { |
| SoftApConnectedClientsEvent event = softApEventList.get(index); |
| if (event != null && event.eventType == apUpEvent) { |
| int infoIndex = numOfEventNeededToUpdate - 1; |
| event.channelFrequency = infos.get(infoIndex).getFrequency(); |
| event.channelBandwidth = infos.get(infoIndex).getBandwidth(); |
| event.generation = infos.get(infoIndex).getWifiStandardInternal(); |
| numOfEventNeededToUpdate--; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Updates current soft AP events with softap configuration |
| */ |
| public void updateSoftApConfiguration(SoftApConfiguration config, int mode, boolean isBridged) { |
| synchronized (mLock) { |
| List<SoftApConnectedClientsEvent> softApEventList; |
| switch (mode) { |
| case WifiManager.IFACE_IP_MODE_TETHERED: |
| softApEventList = mSoftApEventListTethered; |
| break; |
| case WifiManager.IFACE_IP_MODE_LOCAL_ONLY: |
| softApEventList = mSoftApEventListLocalOnly; |
| break; |
| default: |
| return; |
| } |
| |
| int numOfEventNeededToUpdate = isBridged ? 2 : 1; |
| int apUpEvent = isBridged ? SoftApConnectedClientsEvent.DUAL_AP_BOTH_INSTANCES_UP |
| : SoftApConnectedClientsEvent.SOFT_AP_UP; |
| |
| for (int index = softApEventList.size() - 1; |
| index >= 0 && numOfEventNeededToUpdate != 0; index--) { |
| SoftApConnectedClientsEvent event = softApEventList.get(index); |
| if (event != null && event.eventType == apUpEvent) { |
| event.maxNumClientsSettingInSoftapConfiguration = |
| config.getMaxNumberOfClients(); |
| event.shutdownTimeoutSettingInSoftapConfiguration = |
| config.getShutdownTimeoutMillis(); |
| event.clientControlIsEnabled = config.isClientControlByUserEnabled(); |
| numOfEventNeededToUpdate--; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Updates current soft AP events with softap capability |
| */ |
| public void updateSoftApCapability(SoftApCapability capability, int mode, boolean isBridged) { |
| synchronized (mLock) { |
| List<SoftApConnectedClientsEvent> softApEventList; |
| switch (mode) { |
| case WifiManager.IFACE_IP_MODE_TETHERED: |
| softApEventList = mSoftApEventListTethered; |
| break; |
| case WifiManager.IFACE_IP_MODE_LOCAL_ONLY: |
| softApEventList = mSoftApEventListLocalOnly; |
| break; |
| default: |
| return; |
| } |
| |
| int numOfEventNeededToUpdate = isBridged ? 2 : 1; |
| int apUpEvent = isBridged ? SoftApConnectedClientsEvent.DUAL_AP_BOTH_INSTANCES_UP |
| : SoftApConnectedClientsEvent.SOFT_AP_UP; |
| |
| for (int index = softApEventList.size() - 1; |
| index >= 0 && numOfEventNeededToUpdate != 0; index--) { |
| SoftApConnectedClientsEvent event = softApEventList.get(index); |
| if (event != null && event.eventType == apUpEvent) { |
| event.maxNumClientsSettingInSoftapCapability = |
| capability.getMaxSupportedClients(); |
| numOfEventNeededToUpdate--; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Increment number of times the HAL crashed. |
| */ |
| public void incrementNumHalCrashes() { |
| synchronized (mLock) { |
| mWifiLogProto.numHalCrashes++; |
| } |
| } |
| |
| /** |
| * Increment number of times the Wificond crashed. |
| */ |
| public void incrementNumWificondCrashes() { |
| synchronized (mLock) { |
| mWifiLogProto.numWificondCrashes++; |
| } |
| } |
| |
| /** |
| * Increment number of times the supplicant crashed. |
| */ |
| public void incrementNumSupplicantCrashes() { |
| synchronized (mLock) { |
| mWifiLogProto.numSupplicantCrashes++; |
| } |
| } |
| |
| /** |
| * Increment number of times the hostapd crashed. |
| */ |
| public void incrementNumHostapdCrashes() { |
| synchronized (mLock) { |
| mWifiLogProto.numHostapdCrashes++; |
| } |
| } |
| |
| /** |
| * Increment number of times the wifi on failed due to an error in HAL. |
| */ |
| public void incrementNumSetupClientInterfaceFailureDueToHal() { |
| synchronized (mLock) { |
| mWifiLogProto.numSetupClientInterfaceFailureDueToHal++; |
| } |
| } |
| |
| /** |
| * Increment number of times the wifi on failed due to an error in wificond. |
| */ |
| public void incrementNumSetupClientInterfaceFailureDueToWificond() { |
| synchronized (mLock) { |
| mWifiLogProto.numSetupClientInterfaceFailureDueToWificond++; |
| } |
| } |
| |
| /** |
| * Increment number of times the wifi on failed due to an error in supplicant. |
| */ |
| public void incrementNumSetupClientInterfaceFailureDueToSupplicant() { |
| synchronized (mLock) { |
| mWifiLogProto.numSetupClientInterfaceFailureDueToSupplicant++; |
| } |
| } |
| |
| /** |
| * Increment number of times the SoftAp on failed due to an error in HAL. |
| */ |
| public void incrementNumSetupSoftApInterfaceFailureDueToHal() { |
| synchronized (mLock) { |
| mWifiLogProto.numSetupSoftApInterfaceFailureDueToHal++; |
| } |
| } |
| |
| /** |
| * Increment number of times the SoftAp on failed due to an error in wificond. |
| */ |
| public void incrementNumSetupSoftApInterfaceFailureDueToWificond() { |
| synchronized (mLock) { |
| mWifiLogProto.numSetupSoftApInterfaceFailureDueToWificond++; |
| } |
| } |
| |
| /** |
| * Increment number of times the SoftAp on failed due to an error in hostapd. |
| */ |
| public void incrementNumSetupSoftApInterfaceFailureDueToHostapd() { |
| synchronized (mLock) { |
| mWifiLogProto.numSetupSoftApInterfaceFailureDueToHostapd++; |
| } |
| } |
| |
| /** |
| * Increment number of times we got client interface down. |
| */ |
| public void incrementNumClientInterfaceDown() { |
| synchronized (mLock) { |
| mWifiLogProto.numClientInterfaceDown++; |
| } |
| } |
| |
| /** |
| * Increment number of times we got client interface down. |
| */ |
| public void incrementNumSoftApInterfaceDown() { |
| synchronized (mLock) { |
| mWifiLogProto.numSoftApInterfaceDown++; |
| } |
| } |
| |
| /** |
| * Increment number of times Passpoint provider being installed. |
| */ |
| public void incrementNumPasspointProviderInstallation() { |
| synchronized (mLock) { |
| mWifiLogProto.numPasspointProviderInstallation++; |
| } |
| } |
| |
| /** |
| * Increment number of times Passpoint provider is installed successfully. |
| */ |
| public void incrementNumPasspointProviderInstallSuccess() { |
| synchronized (mLock) { |
| mWifiLogProto.numPasspointProviderInstallSuccess++; |
| } |
| } |
| |
| /** |
| * Increment number of times Passpoint provider being uninstalled. |
| */ |
| public void incrementNumPasspointProviderUninstallation() { |
| synchronized (mLock) { |
| mWifiLogProto.numPasspointProviderUninstallation++; |
| } |
| } |
| |
| /** |
| * Increment number of times Passpoint provider is uninstalled successfully. |
| */ |
| public void incrementNumPasspointProviderUninstallSuccess() { |
| synchronized (mLock) { |
| mWifiLogProto.numPasspointProviderUninstallSuccess++; |
| } |
| } |
| |
| /** |
| * Increment number of Passpoint providers with no Root CA in their profile. |
| */ |
| public void incrementNumPasspointProviderWithNoRootCa() { |
| synchronized (mLock) { |
| mWifiLogProto.numPasspointProviderWithNoRootCa++; |
| } |
| } |
| |
| /** |
| * Increment number of Passpoint providers with a self-signed Root CA in their profile. |
| */ |
| public void incrementNumPasspointProviderWithSelfSignedRootCa() { |
| synchronized (mLock) { |
| mWifiLogProto.numPasspointProviderWithSelfSignedRootCa++; |
| } |
| } |
| |
| /** |
| * Increment number of Passpoint providers with subscription expiration date in their profile. |
| */ |
| public void incrementNumPasspointProviderWithSubscriptionExpiration() { |
| synchronized (mLock) { |
| mWifiLogProto.numPasspointProviderWithSubscriptionExpiration++; |
| } |
| } |
| |
| /** |
| * Increment number of times we detected a radio mode change to MCC. |
| */ |
| public void incrementNumRadioModeChangeToMcc() { |
| synchronized (mLock) { |
| mWifiLogProto.numRadioModeChangeToMcc++; |
| } |
| } |
| |
| /** |
| * Increment number of times we detected a radio mode change to SCC. |
| */ |
| public void incrementNumRadioModeChangeToScc() { |
| synchronized (mLock) { |
| mWifiLogProto.numRadioModeChangeToScc++; |
| } |
| } |
| |
| /** |
| * Increment number of times we detected a radio mode change to SBS. |
| */ |
| public void incrementNumRadioModeChangeToSbs() { |
| synchronized (mLock) { |
| mWifiLogProto.numRadioModeChangeToSbs++; |
| } |
| } |
| |
| /** |
| * Increment number of times we detected a radio mode change to DBS. |
| */ |
| public void incrementNumRadioModeChangeToDbs() { |
| synchronized (mLock) { |
| mWifiLogProto.numRadioModeChangeToDbs++; |
| } |
| } |
| |
| /** |
| * Increment number of times we detected a channel did not satisfy user band preference. |
| */ |
| public void incrementNumSoftApUserBandPreferenceUnsatisfied() { |
| synchronized (mLock) { |
| mWifiLogProto.numSoftApUserBandPreferenceUnsatisfied++; |
| } |
| } |
| |
| /** |
| * Increment N-Way network selection decision histograms: |
| * Counts the size of various sets of scanDetails within a scan, and increment the occurrence |
| * of that size for the associated histogram. There are ten histograms generated for each |
| * combination of: {SSID, BSSID} *{Total, Saved, Open, Saved_or_Open, Passpoint} |
| * Only performs this count if isFullBand is true, otherwise, increments the partial scan count |
| */ |
| public void incrementAvailableNetworksHistograms(List<ScanDetail> scanDetails, |
| boolean isFullBand) { |
| synchronized (mLock) { |
| if (mWifiConfigManager == null || mWifiNetworkSelector == null |
| || mPasspointManager == null) { |
| return; |
| } |
| if (!isFullBand) { |
| mWifiLogProto.partialAllSingleScanListenerResults++; |
| return; |
| } |
| Set<ScanResultMatchInfo> ssids = new HashSet<ScanResultMatchInfo>(); |
| int bssids = 0; |
| Set<ScanResultMatchInfo> openSsids = new HashSet<ScanResultMatchInfo>(); |
| int openBssids = 0; |
| Set<ScanResultMatchInfo> savedSsids = new HashSet<ScanResultMatchInfo>(); |
| int savedBssids = 0; |
| // openOrSavedSsids calculated from union of savedSsids & openSsids |
| int openOrSavedBssids = 0; |
| Set<PasspointProvider> savedPasspointProviderProfiles = |
| new HashSet<PasspointProvider>(); |
| int savedPasspointProviderBssids = 0; |
| int passpointR1Aps = 0; |
| int passpointR2Aps = 0; |
| int passpointR3Aps = 0; |
| Map<ANQPNetworkKey, Integer> passpointR1UniqueEss = new HashMap<>(); |
| Map<ANQPNetworkKey, Integer> passpointR2UniqueEss = new HashMap<>(); |
| Map<ANQPNetworkKey, Integer> passpointR3UniqueEss = new HashMap<>(); |
| int supporting80211mcAps = 0; |
| for (ScanDetail scanDetail : scanDetails) { |
| NetworkDetail networkDetail = scanDetail.getNetworkDetail(); |
| ScanResult scanResult = scanDetail.getScanResult(); |
| |
| // statistics to be collected for ALL APs (irrespective of signal power) |
| if (networkDetail.is80211McResponderSupport()) { |
| supporting80211mcAps++; |
| } |
| |
| ScanResultMatchInfo matchInfo = ScanResultMatchInfo.fromScanResult(scanResult); |
| List<Pair<PasspointProvider, PasspointMatch>> matchedProviders = null; |
| if (networkDetail.isInterworking()) { |
| // Try to match provider, but do not allow new ANQP messages. Use cached data. |
| matchedProviders = mPasspointManager.matchProvider(scanResult, false); |
| if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) { |
| passpointR1Aps++; |
| } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) { |
| passpointR2Aps++; |
| } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R3) { |
| passpointR3Aps++; |
| } |
| |
| long bssid = 0; |
| boolean validBssid = false; |
| try { |
| bssid = Utils.parseMac(scanResult.BSSID); |
| validBssid = true; |
| } catch (IllegalArgumentException e) { |
| Log.e(TAG, |
| "Invalid BSSID provided in the scan result: " + scanResult.BSSID); |
| } |
| if (validBssid) { |
| ANQPNetworkKey uniqueEss = ANQPNetworkKey.buildKey(scanResult.SSID, bssid, |
| scanResult.hessid, networkDetail.getAnqpDomainID()); |
| if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R1) { |
| Integer countObj = passpointR1UniqueEss.get(uniqueEss); |
| int count = countObj == null ? 0 : countObj; |
| passpointR1UniqueEss.put(uniqueEss, count + 1); |
| } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R2) { |
| Integer countObj = passpointR2UniqueEss.get(uniqueEss); |
| int count = countObj == null ? 0 : countObj; |
| passpointR2UniqueEss.put(uniqueEss, count + 1); |
| } else if (networkDetail.getHSRelease() == NetworkDetail.HSRelease.R3) { |
| Integer countObj = passpointR3UniqueEss.get(uniqueEss); |
| int count = countObj == null ? 0 : countObj; |
| passpointR3UniqueEss.put(uniqueEss, count + 1); |
| } |
| } |
| } |
| |
| if (mWifiNetworkSelector.isSignalTooWeak(scanResult)) { |
| continue; |
| } |
| |
| // statistics to be collected ONLY for those APs with sufficient signal power |
| |
| ssids.add(matchInfo); |
| bssids++; |
| boolean isOpen = ScanResultUtil.isScanResultForOpenNetwork(scanResult) |
| || ScanResultUtil.isScanResultForOweNetwork(scanResult); |
| WifiConfiguration config = |
| mWifiConfigManager.getSavedNetworkForScanDetail(scanDetail); |
| boolean isSaved = (config != null) && !config.isEphemeral() |
| && !config.isPasspoint(); |
| if (isOpen) { |
| openSsids.add(matchInfo); |
| openBssids++; |
| } |
| if (isSaved) { |
| savedSsids.add(matchInfo); |
| savedBssids++; |
| } |
| if (isOpen || isSaved) { |
| openOrSavedBssids++; |
| // Calculate openOrSavedSsids union later |
| } |
| if (matchedProviders != null && !matchedProviders.isEmpty()) { |
| for (Pair<PasspointProvider, PasspointMatch> passpointProvider : |
| matchedProviders) { |
| savedPasspointProviderProfiles.add(passpointProvider.first); |
| } |
| savedPasspointProviderBssids++; |
| } |
| } |
| mWifiLogProto.fullBandAllSingleScanListenerResults++; |
| incrementTotalScanSsids(mTotalSsidsInScanHistogram, ssids.size()); |
| incrementTotalScanResults(mTotalBssidsInScanHistogram, bssids); |
| incrementSsid(mAvailableOpenSsidsInScanHistogram, openSsids.size()); |
| incrementBssid(mAvailableOpenBssidsInScanHistogram, openBssids); |
| incrementSsid(mAvailableSavedSsidsInScanHistogram, savedSsids.size()); |
| incrementBssid(mAvailableSavedBssidsInScanHistogram, savedBssids); |
| openSsids.addAll(savedSsids); // openSsids = Union(openSsids, savedSsids) |
| incrementSsid(mAvailableOpenOrSavedSsidsInScanHistogram, openSsids.size()); |
| incrementBssid(mAvailableOpenOrSavedBssidsInScanHistogram, openOrSavedBssids); |
| incrementSsid(mAvailableSavedPasspointProviderProfilesInScanHistogram, |
| savedPasspointProviderProfiles.size()); |
| incrementBssid(mAvailableSavedPasspointProviderBssidsInScanHistogram, |
| savedPasspointProviderBssids); |
| incrementTotalPasspointAps(mObservedHotspotR1ApInScanHistogram, passpointR1Aps); |
| incrementTotalPasspointAps(mObservedHotspotR2ApInScanHistogram, passpointR2Aps); |
| incrementTotalPasspointAps(mObservedHotspotR3ApInScanHistogram, passpointR3Aps); |
| incrementTotalUniquePasspointEss(mObservedHotspotR1EssInScanHistogram, |
| passpointR1UniqueEss.size()); |
| incrementTotalUniquePasspointEss(mObservedHotspotR2EssInScanHistogram, |
| passpointR2UniqueEss.size()); |
| incrementTotalUniquePasspointEss(mObservedHotspotR3EssInScanHistogram, |
| passpointR3UniqueEss.size()); |
| for (Integer count : passpointR1UniqueEss.values()) { |
| incrementPasspointPerUniqueEss(mObservedHotspotR1ApsPerEssInScanHistogram, count); |
| } |
| for (Integer count : passpointR2UniqueEss.values()) { |
| incrementPasspointPerUniqueEss(mObservedHotspotR2ApsPerEssInScanHistogram, count); |
| } |
| for (Integer count : passpointR3UniqueEss.values()) { |
| incrementPasspointPerUniqueEss(mObservedHotspotR3ApsPerEssInScanHistogram, count); |
| } |
| increment80211mcAps(mObserved80211mcApInScanHistogram, supporting80211mcAps); |
| } |
| } |
| |
| /** Increments the occurence of a "Connect to Network" notification. */ |
| public void incrementConnectToNetworkNotification(String notifierTag, int notificationType) { |
| synchronized (mLock) { |
| int count = mConnectToNetworkNotificationCount.get(notificationType); |
| mConnectToNetworkNotificationCount.put(notificationType, count + 1); |
| } |
| } |
| |
| /** Increments the occurence of an "Connect to Network" notification user action. */ |
| public void incrementConnectToNetworkNotificationAction(String notifierTag, |
| int notificationType, int actionType) { |
| synchronized (mLock) { |
| int key = notificationType * CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER |
| + actionType; |
| int count = mConnectToNetworkNotificationActionCount.get(key); |
| mConnectToNetworkNotificationActionCount.put(key, count + 1); |
| } |
| } |
| |
| /** |
| * Sets the number of SSIDs blocklisted from recommendation by the open network notification |
| * recommender. |
| */ |
| public void setNetworkRecommenderBlocklistSize(String notifierTag, int size) { |
| synchronized (mLock) { |
| mOpenNetworkRecommenderBlocklistSize = size; |
| } |
| } |
| |
| /** Sets if the available network notification feature is enabled. */ |
| public void setIsWifiNetworksAvailableNotificationEnabled(String notifierTag, boolean enabled) { |
| synchronized (mLock) { |
| mIsWifiNetworksAvailableNotificationOn = enabled; |
| } |
| } |
| |
| /** Increments the occurence of connection attempts that were initiated unsuccessfully */ |
| public void incrementNumNetworkRecommendationUpdates(String notifierTag) { |
| synchronized (mLock) { |
| mNumOpenNetworkRecommendationUpdates++; |
| } |
| } |
| |
| /** Increments the occurence of connection attempts that were initiated unsuccessfully */ |
| public void incrementNumNetworkConnectMessageFailedToSend(String notifierTag) { |
| synchronized (mLock) { |
| mNumOpenNetworkConnectMessageFailedToSend++; |
| } |
| } |
| |
| /** Log firmware alert related metrics */ |
| public void logFirmwareAlert(String ifaceName, int errorCode) { |
| incrementAlertReasonCount(errorCode); |
| logWifiIsUnusableEvent(ifaceName, WifiIsUnusableEvent.TYPE_FIRMWARE_ALERT, errorCode); |
| addToWifiUsabilityStatsList(ifaceName, WifiUsabilityStats.LABEL_BAD, |
| WifiUsabilityStats.TYPE_FIRMWARE_ALERT, errorCode); |
| } |
| |
| public static final String PROTO_DUMP_ARG = "wifiMetricsProto"; |
| public static final String CLEAN_DUMP_ARG = "clean"; |
| |
| /** |
| * Dump all WifiMetrics. Collects some metrics from ConfigStore, Settings and WifiManager |
| * at this time. |
| * |
| * @param fd unused |
| * @param pw PrintWriter for writing dump to |
| * @param args [wifiMetricsProto [clean]] |
| */ |
| public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { |
| synchronized (mLock) { |
| consolidateScoringParams(); |
| if (args != null && args.length > 0 && PROTO_DUMP_ARG.equals(args[0])) { |
| // Dump serialized WifiLog proto |
| consolidateProto(); |
| |
| byte[] wifiMetricsProto = WifiMetricsProto.WifiLog.toByteArray(mWifiLogProto); |
| String metricsProtoDump = Base64.encodeToString(wifiMetricsProto, Base64.DEFAULT); |
| if (args.length > 1 && CLEAN_DUMP_ARG.equals(args[1])) { |
| // Output metrics proto bytes (base64) and nothing else |
| pw.print(metricsProtoDump); |
| } else { |
| // Tag the start and end of the metrics proto bytes |
| pw.println("WifiMetrics:"); |
| pw.println(metricsProtoDump); |
| pw.println("EndWifiMetrics"); |
| } |
| clear(); |
| } else { |
| pw.println("WifiMetrics:"); |
| pw.println("mConnectionEvents:"); |
| for (ConnectionEvent event : mConnectionEventList) { |
| String eventLine = event.toString(); |
| if (mCurrentConnectionEventPerIface.containsValue(event)) { |
| eventLine += " CURRENTLY OPEN EVENT"; |
| } |
| pw.println(eventLine); |
| } |
| pw.println("mWifiLogProto.numSavedNetworks=" + mWifiLogProto.numSavedNetworks); |
| pw.println("mWifiLogProto.numSavedNetworksWithMacRandomization=" |
| + mWifiLogProto.numSavedNetworksWithMacRandomization); |
| pw.println("mWifiLogProto.numOpenNetworks=" + mWifiLogProto.numOpenNetworks); |
| pw.println("mWifiLogProto.numLegacyPersonalNetworks=" |
| + mWifiLogProto.numLegacyPersonalNetworks); |
| pw.println("mWifiLogProto.numLegacyEnterpriseNetworks=" |
| + mWifiLogProto.numLegacyEnterpriseNetworks); |
| pw.println("mWifiLogProto.numEnhancedOpenNetworks=" |
| + mWifiLogProto.numEnhancedOpenNetworks); |
| pw.println("mWifiLogProto.numWpa3PersonalNetworks=" |
| + mWifiLogProto.numWpa3PersonalNetworks); |
| pw.println("mWifiLogProto.numWpa3EnterpriseNetworks=" |
| + mWifiLogProto.numWpa3EnterpriseNetworks); |
| pw.println("mWifiLogProto.numWapiPersonalNetworks=" |
| + mWifiLogProto.numWapiPersonalNetworks); |
| pw.println("mWifiLogProto.numWapiEnterpriseNetworks=" |
| + mWifiLogProto.numWapiEnterpriseNetworks); |
| pw.println("mWifiLogProto.numHiddenNetworks=" + mWifiLogProto.numHiddenNetworks); |
| pw.println("mWifiLogProto.numPasspointNetworks=" |
| + mWifiLogProto.numPasspointNetworks); |
| pw.println("mWifiLogProto.isLocationEnabled=" + mWifiLogProto.isLocationEnabled); |
| pw.println("mWifiLogProto.isScanningAlwaysEnabled=" |
| + mWifiLogProto.isScanningAlwaysEnabled); |
| pw.println("mWifiLogProto.isVerboseLoggingEnabled=" |
| + mWifiLogProto.isVerboseLoggingEnabled); |
| pw.println("mWifiLogProto.isEnhancedMacRandomizationForceEnabled=" |
| + mWifiLogProto.isEnhancedMacRandomizationForceEnabled); |
| pw.println("mWifiLogProto.isWifiWakeEnabled=" + mWifiLogProto.isWifiWakeEnabled); |
| pw.println("mWifiLogProto.numNetworksAddedByUser=" |
| + mWifiLogProto.numNetworksAddedByUser); |
| pw.println("mWifiLogProto.numNetworksAddedByApps=" |
| + mWifiLogProto.numNetworksAddedByApps); |
| pw.println("mWifiLogProto.numNonEmptyScanResults=" |
| + mWifiLogProto.numNonEmptyScanResults); |
| pw.println("mWifiLogProto.numEmptyScanResults=" |
| + mWifiLogProto.numEmptyScanResults); |
| pw.println("mWifiLogProto.numConnecitvityOneshotScans=" |
| + mWifiLogProto.numConnectivityOneshotScans); |
| pw.println("mWifiLogProto.numOneshotScans=" |
| + mWifiLogProto.numOneshotScans); |
| pw.println("mWifiLogProto.numOneshotHasDfsChannelScans=" |
| + mWifiLogProto.numOneshotHasDfsChannelScans); |
| pw.println("mWifiLogProto.numBackgroundScans=" |
| + mWifiLogProto.numBackgroundScans); |
| pw.println("mWifiLogProto.numExternalAppOneshotScanRequests=" |
| + mWifiLogProto.numExternalAppOneshotScanRequests); |
| pw.println("mWifiLogProto.numExternalForegroundAppOneshotScanRequestsThrottled=" |
| + mWifiLogProto.numExternalForegroundAppOneshotScanRequestsThrottled); |
| pw.println("mWifiLogProto.numExternalBackgroundAppOneshotScanRequestsThrottled=" |
| + mWifiLogProto.numExternalBackgroundAppOneshotScanRequestsThrottled); |
| pw.println("mWifiLogProto.meteredNetworkStatsSaved="); |
| pw.println(mMeteredNetworkStatsBuilder.toProto(false)); |
| pw.println("mWifiLogProto.meteredNetworkStatsSuggestion="); |
| pw.println(mMeteredNetworkStatsBuilder.toProto(true)); |
| pw.println("mScanReturnEntries:"); |
| pw.println(" SCAN_UNKNOWN: " + getScanReturnEntry( |
| WifiMetricsProto.WifiLog.SCAN_UNKNOWN)); |
| pw.println(" SCAN_SUCCESS: " + getScanReturnEntry( |
| WifiMetricsProto.WifiLog.SCAN_SUCCESS)); |
| pw.println(" SCAN_FAILURE_INTERRUPTED: " + getScanReturnEntry( |
| WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED)); |
| pw.println(" SCAN_FAILURE_INVALID_CONFIGURATION: " + getScanReturnEntry( |
| WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION)); |
| pw.println(" FAILURE_WIFI_DISABLED: " + getScanReturnEntry( |
| WifiMetricsProto.WifiLog.FAILURE_WIFI_DISABLED)); |
| |
| pw.println("mSystemStateEntries: <state><screenOn> : <scansInitiated>"); |
| pw.println(" WIFI_UNKNOWN ON: " |
| + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, true)); |
| pw.println(" WIFI_DISABLED ON: " |
| + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, true)); |
| pw.println(" WIFI_DISCONNECTED ON: " |
| + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, true)); |
| pw.println(" WIFI_ASSOCIATED ON: " |
| + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, true)); |
| pw.println(" WIFI_UNKNOWN OFF: " |
| + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_UNKNOWN, false)); |
| pw.println(" WIFI_DISABLED OFF: " |
| + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISABLED, false)); |
| pw.println(" WIFI_DISCONNECTED OFF: " |
| + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_DISCONNECTED, false)); |
| pw.println(" WIFI_ASSOCIATED OFF: " |
| + getSystemStateCount(WifiMetricsProto.WifiLog.WIFI_ASSOCIATED, false)); |
| pw.println("mWifiLogProto.numConnectivityWatchdogPnoGood=" |
| + mWifiLogProto.numConnectivityWatchdogPnoGood); |
| pw.println("mWifiLogProto.numConnectivityWatchdogPnoBad=" |
| + mWifiLogProto.numConnectivityWatchdogPnoBad); |
| pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundGood=" |
| + mWifiLogProto.numConnectivityWatchdogBackgroundGood); |
| pw.println("mWifiLogProto.numConnectivityWatchdogBackgroundBad=" |
| + mWifiLogProto.numConnectivityWatchdogBackgroundBad); |
| pw.println("mWifiLogProto.numLastResortWatchdogTriggers=" |
| + mWifiLogProto.numLastResortWatchdogTriggers); |
| pw.println("mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal=" |
| + mWifiLogProto.numLastResortWatchdogBadAssociationNetworksTotal); |
| pw.println("mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal=" |
| + mWifiLogProto.numLastResortWatchdogBadAuthenticationNetworksTotal); |
| pw.println("mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal=" |
| + mWifiLogProto.numLastResortWatchdogBadDhcpNetworksTotal); |
| pw.println("mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal=" |
| + mWifiLogProto.numLastResortWatchdogBadOtherNetworksTotal); |
| pw.println("mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal=" |
| + mWifiLogProto.numLastResortWatchdogAvailableNetworksTotal); |
| pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation=" |
| + mWifiLogProto.numLastResortWatchdogTriggersWithBadAssociation); |
| pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication=" |
| + mWifiLogProto.numLastResortWatchdogTriggersWithBadAuthentication); |
| pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp=" |
| + mWifiLogProto.numLastResortWatchdogTriggersWithBadDhcp); |
| pw.println("mWifiLogProto.numLastResortWatchdogTriggersWithBadOther=" |
| + mWifiLogProto.numLastResortWatchdogTriggersWithBadOther); |
| pw.println("mWifiLogProto.numLastResortWatchdogSuccesses=" |
| + mWifiLogProto.numLastResortWatchdogSuccesses); |
| pw.println("mWifiLogProto.watchdogTotalConnectionFailureCountAfterTrigger=" |
| + mWifiLogProto.watchdogTotalConnectionFailureCountAfterTrigger); |
| pw.println("mWifiLogProto.watchdogTriggerToConnectionSuccessDurationMs=" |
| + mWifiLogProto.watchdogTriggerToConnectionSuccessDurationMs); |
| pw.println("mWifiLogProto.recordDurationSec=" |
| + ((mClock.getElapsedSinceBootMillis() / 1000) - mRecordStartTimeSec)); |
| |
| try { |
| JSONObject rssiMap = new JSONObject(); |
| for (Map.Entry<Integer, SparseIntArray> entry : mRssiPollCountsMap.entrySet()) { |
| int frequency = entry.getKey(); |
| final SparseIntArray histogram = entry.getValue(); |
| JSONArray histogramElements = new JSONArray(); |
| for (int i = MIN_RSSI_POLL; i <= MAX_RSSI_POLL; i++) { |
| int count = histogram.get(i); |
| if (count == 0) { |
| continue; |
| } |
| JSONObject histogramElement = new JSONObject(); |
| histogramElement.put(Integer.toString(i), count); |
| histogramElements.put(histogramElement); |
| } |
| rssiMap.put(Integer.toString(frequency), histogramElements); |
| } |
| pw.println("mWifiLogProto.rssiPollCount: " + rssiMap.toString()); |
| } catch (JSONException e) { |
| pw.println("JSONException occurred: " + e.getMessage()); |
| } |
| |
| pw.println("mWifiLogProto.rssiPollDeltaCount: Printing counts for [" |
| + MIN_RSSI_DELTA + ", " + MAX_RSSI_DELTA + "]"); |
| StringBuilder sb = new StringBuilder(); |
| for (int i = MIN_RSSI_DELTA; i <= MAX_RSSI_DELTA; i++) { |
| sb.append(mRssiDeltaCounts.get(i) + " "); |
| } |
| pw.println(" " + sb.toString()); |
| pw.println("mWifiLogProto.linkSpeedCounts: "); |
| sb.setLength(0); |
| for (int i = 0; i < mLinkSpeedCounts.size(); i++) { |
| LinkSpeedCount linkSpeedCount = mLinkSpeedCounts.valueAt(i); |
| sb.append(linkSpeedCount.linkSpeedMbps).append(":{") |
| .append(linkSpeedCount.count).append(", ") |
| .append(linkSpeedCount.rssiSumDbm).append(", ") |
| .append(linkSpeedCount.rssiSumOfSquaresDbmSq).append("} "); |
| } |
| if (sb.length() > 0) { |
| pw.println(sb.toString()); |
| } |
| pw.print("mWifiLogProto.alertReasonCounts="); |
| sb.setLength(0); |
| for (int i = WifiLoggerHal.WIFI_ALERT_REASON_MIN; |
| i <= WifiLoggerHal.WIFI_ALERT_REASON_MAX; i++) { |
| int count = mWifiAlertReasonCounts.get(i); |
| if (count > 0) { |
| sb.append("(" + i + "," + count + "),"); |
| } |
| } |
| if (sb.length() > 1) { |
| sb.setLength(sb.length() - 1); // strip trailing comma |
| pw.println(sb.toString()); |
| } else { |
| pw.println("()"); |
| } |
| pw.println("mWifiLogProto.numTotalScanResults=" |
| + mWifiLogProto.numTotalScanResults); |
| pw.println("mWifiLogProto.numOpenNetworkScanResults=" |
| + mWifiLogProto.numOpenNetworkScanResults); |
| pw.println("mWifiLogProto.numLegacyPersonalNetworkScanResults=" |
| + mWifiLogProto.numLegacyPersonalNetworkScanResults); |
| pw.println("mWifiLogProto.numLegacyEnterpriseNetworkScanResults=" |
| + mWifiLogProto.numLegacyEnterpriseNetworkScanResults); |
| pw.println("mWifiLogProto.numEnhancedOpenNetworkScanResults=" |
| + mWifiLogProto.numEnhancedOpenNetworkScanResults); |
| pw.println("mWifiLogProto.numWpa3PersonalNetworkScanResults=" |
| + mWifiLogProto.numWpa3PersonalNetworkScanResults); |
| pw.println("mWifiLogProto.numWpa3EnterpriseNetworkScanResults=" |
| + mWifiLogProto.numWpa3EnterpriseNetworkScanResults); |
| pw.println("mWifiLogProto.numWapiPersonalNetworkScanResults=" |
| + mWifiLogProto.numWapiPersonalNetworkScanResults); |
| pw.println("mWifiLogProto.numWapiEnterpriseNetworkScanResults=" |
| + mWifiLogProto.numWapiEnterpriseNetworkScanResults); |
| pw.println("mWifiLogProto.numHiddenNetworkScanResults=" |
| + mWifiLogProto.numHiddenNetworkScanResults); |
| pw.println("mWifiLogProto.numHotspot2R1NetworkScanResults=" |
| + mWifiLogProto.numHotspot2R1NetworkScanResults); |
| pw.println("mWifiLogProto.numHotspot2R2NetworkScanResults=" |
| + mWifiLogProto.numHotspot2R2NetworkScanResults); |
| pw.println("mWifiLogProto.numHotspot2R3NetworkScanResults=" |
| + mWifiLogProto.numHotspot2R3NetworkScanResults); |
| pw.println("mWifiLogProto.numMboSupportedNetworkScanResults=" |
| + mWifiLogProto.numMboSupportedNetworkScanResults); |
| pw.println("mWifiLogProto.numMboCellularDataAwareNetworkScanResults=" |
| + mWifiLogProto.numMboCellularDataAwareNetworkScanResults); |
| pw.println("mWifiLogProto.numOceSupportedNetworkScanResults=" |
| + mWifiLogProto.numOceSupportedNetworkScanResults); |
| pw.println("mWifiLogProto.numFilsSupportedNetworkScanResults=" |
| + mWifiLogProto.numFilsSupportedNetworkScanResults); |
| pw.println("mWifiLogProto.num11AxNetworkScanResults=" |
| + mWifiLogProto.num11AxNetworkScanResults); |
| pw.println("mWifiLogProto.num6GNetworkScanResults" |
| + mWifiLogProto.num6GNetworkScanResults); |
| pw.println("mWifiLogProto.num6GPscNetworkScanResults" |
| + mWifiLogProto.num6GPscNetworkScanResults); |
| pw.println("mWifiLogProto.numBssidFilteredDueToMboAssocDisallowInd=" |
| + mWifiLogProto.numBssidFilteredDueToMboAssocDisallowInd); |
| pw.println("mWifiLogProto.numConnectToNetworkSupportingMbo=" |
| + mWifiLogProto.numConnectToNetworkSupportingMbo); |
| pw.println("mWifiLogProto.numConnectToNetworkSupportingOce=" |
| + mWifiLogProto.numConnectToNetworkSupportingOce); |
| pw.println("mWifiLogProto.numSteeringRequest=" |
| + mWifiLogProto.numSteeringRequest); |
| pw.println("mWifiLogProto.numForceScanDueToSteeringRequest=" |
| + mWifiLogProto.numForceScanDueToSteeringRequest); |
| pw.println("mWifiLogProto.numMboCellularSwitchRequest=" |
| + mWifiLogProto.numMboCellularSwitchRequest); |
| pw.println("mWifiLogProto.numSteeringRequestIncludingMboAssocRetryDelay=" |
| + mWifiLogProto.numSteeringRequestIncludingMboAssocRetryDelay); |
| pw.println("mWifiLogProto.numConnectRequestWithFilsAkm=" |
| + mWifiLogProto.numConnectRequestWithFilsAkm); |
| pw.println("mWifiLogProto.numL2ConnectionThroughFilsAuthentication=" |
| + mWifiLogProto.numL2ConnectionThroughFilsAuthentication); |
| pw.println("mWifiLogProto.recentFailureAssociationStatus=" |
| + mRecentFailureAssociationStatus.toString()); |
| |
| pw.println("mWifiLogProto.numScans=" + mWifiLogProto.numScans); |
| pw.println("mWifiLogProto.WifiScoreCount: [" + MIN_WIFI_SCORE + ", " |
| + MAX_WIFI_SCORE + "]"); |
| for (int i = 0; i <= MAX_WIFI_SCORE; i++) { |
| pw.print(mWifiScoreCounts.get(i) + " "); |
| } |
| pw.println(); // add a line after wifi scores |
| pw.println("mWifiLogProto.WifiUsabilityScoreCount: [" + MIN_WIFI_USABILITY_SCORE |
| + ", " + MAX_WIFI_USABILITY_SCORE + "]"); |
| for (int i = MIN_WIFI_USABILITY_SCORE; i <= MAX_WIFI_USABILITY_SCORE; i++) { |
| pw.print(mWifiUsabilityScoreCounts.get(i) + " "); |
| } |
| pw.println(); // add a line after wifi usability scores |
| pw.println("mWifiLogProto.SoftApManagerReturnCodeCounts:"); |
| pw.println(" SUCCESS: " + mSoftApManagerReturnCodeCounts.get( |
| WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_STARTED_SUCCESSFULLY)); |
| pw.println(" FAILED_GENERAL_ERROR: " + mSoftApManagerReturnCodeCounts.get( |
| WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_GENERAL_ERROR)); |
| pw.println(" FAILED_NO_CHANNEL: " + mSoftApManagerReturnCodeCounts.get( |
| WifiMetricsProto.SoftApReturnCodeCount.SOFT_AP_FAILED_NO_CHANNEL)); |
| pw.println(" FAILED_UNSUPPORTED_CONFIGURATION: " |
| + mSoftApManagerReturnCodeCounts.get( |
| WifiMetricsProto.SoftApReturnCodeCount |
| .SOFT_AP_FAILED_UNSUPPORTED_CONFIGURATION)); |
| pw.print("\n"); |
| pw.println("mWifiLogProto.numHalCrashes=" |
| + mWifiLogProto.numHalCrashes); |
| pw.println("mWifiLogProto.numWificondCrashes=" |
| + mWifiLogProto.numWificondCrashes); |
| pw.println("mWifiLogProto.numSupplicantCrashes=" |
| + mWifiLogProto.numSupplicantCrashes); |
| pw.println("mWifiLogProto.numHostapdCrashes=" |
| + mWifiLogProto.numHostapdCrashes); |
| pw.println("mWifiLogProto.numSetupClientInterfaceFailureDueToHal=" |
| + mWifiLogProto.numSetupClientInterfaceFailureDueToHal); |
| pw.println("mWifiLogProto.numSetupClientInterfaceFailureDueToWificond=" |
| + mWifiLogProto.numSetupClientInterfaceFailureDueToWificond); |
| pw.println("mWifiLogProto.numSetupClientInterfaceFailureDueToSupplicant=" |
| + mWifiLogProto.numSetupClientInterfaceFailureDueToSupplicant); |
| pw.println("mWifiLogProto.numSetupSoftApInterfaceFailureDueToHal=" |
| + mWifiLogProto.numSetupSoftApInterfaceFailureDueToHal); |
| pw.println("mWifiLogProto.numSetupSoftApInterfaceFailureDueToWificond=" |
| + mWifiLogProto.numSetupSoftApInterfaceFailureDueToWificond); |
| pw.println("mWifiLogProto.numSetupSoftApInterfaceFailureDueToHostapd=" |
| + mWifiLogProto.numSetupSoftApInterfaceFailureDueToHostapd); |
| pw.println("StaEventList:"); |
| for (StaEventWithTime event : mStaEventList) { |
| pw.println(event); |
| } |
| pw.println("UserActionEvents:"); |
| for (UserActionEventWithTime event : mUserActionEventList) { |
| pw.println(event); |
| } |
| |
| pw.println("mWifiLogProto.numPasspointProviders=" |
| + mWifiLogProto.numPasspointProviders); |
| pw.println("mWifiLogProto.numPasspointProviderInstallation=" |
| + mWifiLogProto.numPasspointProviderInstallation); |
| pw.println("mWifiLogProto.numPasspointProviderInstallSuccess=" |
| + mWifiLogProto.numPasspointProviderInstallSuccess); |
| pw.println("mWifiLogProto.numPasspointProviderUninstallation=" |
| + mWifiLogProto.numPasspointProviderUninstallation); |
| pw.println("mWifiLogProto.numPasspointProviderUninstallSuccess=" |
| + mWifiLogProto.numPasspointProviderUninstallSuccess); |
| pw.println("mWifiLogProto.numPasspointProvidersSuccessfullyConnected=" |
| + mWifiLogProto.numPasspointProvidersSuccessfullyConnected); |
| |
| pw.println("mWifiLogProto.installedPasspointProfileTypeForR1:" |
| + mInstalledPasspointProfileTypeForR1); |
| pw.println("mWifiLogProto.installedPasspointProfileTypeForR2:" |
| + mInstalledPasspointProfileTypeForR2); |
| |
| pw.println("mWifiLogProto.passpointProvisionStats.numProvisionSuccess=" |
| + mNumProvisionSuccess); |
| pw.println("mWifiLogProto.passpointProvisionStats.provisionFailureCount:" |
| + mPasspointProvisionFailureCounts); |
| pw.println("mWifiLogProto.totalNumberOfPasspointConnectionsWithVenueUrl=" |
| + mWifiLogProto.totalNumberOfPasspointConnectionsWithVenueUrl); |
| pw.println( |
| "mWifiLogProto.totalNumberOfPasspointConnectionsWithTermsAndConditionsUrl=" |
| + mWifiLogProto |
| .totalNumberOfPasspointConnectionsWithTermsAndConditionsUrl); |
| pw.println( |
| "mWifiLogProto" |
| + ".totalNumberOfPasspointAcceptanceOfTermsAndConditions=" |
| + mWifiLogProto |
| .totalNumberOfPasspointAcceptanceOfTermsAndConditions); |
| pw.println("mWifiLogProto.totalNumberOfPasspointProfilesWithDecoratedIdentity=" |
| + mWifiLogProto.totalNumberOfPasspointProfilesWithDecoratedIdentity); |
| pw.println("mWifiLogProto.passpointDeauthImminentScope=" |
| + mPasspointDeauthImminentScope.toString()); |
| |
| pw.println("mWifiLogProto.numRadioModeChangeToMcc=" |
| + mWifiLogProto.numRadioModeChangeToMcc); |
| pw.println("mWifiLogProto.numRadioModeChangeToScc=" |
| + mWifiLogProto.numRadioModeChangeToScc); |
| pw.println("mWifiLogProto.numRadioModeChangeToSbs=" |
| + mWifiLogProto.numRadioModeChangeToSbs); |
| pw.println("mWifiLogProto.numRadioModeChangeToDbs=" |
| + mWifiLogProto.numRadioModeChangeToDbs); |
| pw.println("mWifiLogProto.numSoftApUserBandPreferenceUnsatisfied=" |
| + mWifiLogProto.numSoftApUserBandPreferenceUnsatisfied); |
| pw.println("mTotalSsidsInScanHistogram:" |
| + mTotalSsidsInScanHistogram.toString()); |
| pw.println("mTotalBssidsInScanHistogram:" |
| + mTotalBssidsInScanHistogram.toString()); |
| pw.println("mAvailableOpenSsidsInScanHistogram:" |
| + mAvailableOpenSsidsInScanHistogram.toString()); |
| pw.println("mAvailableOpenBssidsInScanHistogram:" |
| + mAvailableOpenBssidsInScanHistogram.toString()); |
| pw.println("mAvailableSavedSsidsInScanHistogram:" |
| + mAvailableSavedSsidsInScanHistogram.toString()); |
| pw.println("mAvailableSavedBssidsInScanHistogram:" |
| + mAvailableSavedBssidsInScanHistogram.toString()); |
| pw.println("mAvailableOpenOrSavedSsidsInScanHistogram:" |
| + mAvailableOpenOrSavedSsidsInScanHistogram.toString()); |
| pw.println("mAvailableOpenOrSavedBssidsInScanHistogram:" |
| + mAvailableOpenOrSavedBssidsInScanHistogram.toString()); |
| pw.println("mAvailableSavedPasspointProviderProfilesInScanHistogram:" |
| + mAvailableSavedPasspointProviderProfilesInScanHistogram.toString()); |
| pw.println("mAvailableSavedPasspointProviderBssidsInScanHistogram:" |
| + mAvailableSavedPasspointProviderBssidsInScanHistogram.toString()); |
| pw.println("mWifiLogProto.partialAllSingleScanListenerResults=" |
| + mWifiLogProto.partialAllSingleScanListenerResults); |
| pw.println("mWifiLogProto.fullBandAllSingleScanListenerResults=" |
| + mWifiLogProto.fullBandAllSingleScanListenerResults); |
| pw.println("mWifiAwareMetrics:"); |
| mWifiAwareMetrics.dump(fd, pw, args); |
| pw.println("mRttMetrics:"); |
| mRttMetrics.dump(fd, pw, args); |
| |
| pw.println("mPnoScanMetrics.numPnoScanAttempts=" |
| + mPnoScanMetrics.numPnoScanAttempts); |
| pw.println("mPnoScanMetrics.numPnoScanFailed=" |
| + mPnoScanMetrics.numPnoScanFailed); |
| pw.println("mPnoScanMetrics.numPnoScanStartedOverOffload=" |
| + mPnoScanMetrics.numPnoScanStartedOverOffload); |
| pw.println("mPnoScanMetrics.numPnoScanFailedOverOffload=" |
| + mPnoScanMetrics.numPnoScanFailedOverOffload); |
| pw.println("mPnoScanMetrics.numPnoFoundNetworkEvents=" |
| + mPnoScanMetrics.numPnoFoundNetworkEvents); |
| |
| pw.println("mWifiLinkLayerUsageStats.loggingDurationMs=" |
| + mWifiLinkLayerUsageStats.loggingDurationMs); |
| pw.println("mWifiLinkLayerUsageStats.radioOnTimeMs=" |
| + mWifiLinkLayerUsageStats.radioOnTimeMs); |
| pw.println("mWifiLinkLayerUsageStats.radioTxTimeMs=" |
| + mWifiLinkLayerUsageStats.radioTxTimeMs); |
| pw.println("mWifiLinkLayerUsageStats.radioRxTimeMs=" |
| + mWifiLinkLayerUsageStats.radioRxTimeMs); |
| pw.println("mWifiLinkLayerUsageStats.radioScanTimeMs=" |
| + mWifiLinkLayerUsageStats.radioScanTimeMs); |
| pw.println("mWifiLinkLayerUsageStats.radioNanScanTimeMs=" |
| + mWifiLinkLayerUsageStats.radioNanScanTimeMs); |
| pw.println("mWifiLinkLayerUsageStats.radioBackgroundScanTimeMs=" |
| + mWifiLinkLayerUsageStats.radioBackgroundScanTimeMs); |
| pw.println("mWifiLinkLayerUsageStats.radioRoamScanTimeMs=" |
| + mWifiLinkLayerUsageStats.radioRoamScanTimeMs); |
| pw.println("mWifiLinkLayerUsageStats.radioPnoScanTimeMs=" |
| + mWifiLinkLayerUsageStats.radioPnoScanTimeMs); |
| pw.println("mWifiLinkLayerUsageStats.radioHs20ScanTimeMs=" |
| + mWifiLinkLayerUsageStats.radioHs20ScanTimeMs); |
| pw.println("mWifiLinkLayerUsageStats per Radio Stats: "); |
| for (int i = 0; i < mRadioStats.size(); i++) { |
| RadioStats radioStat = mRadioStats.valueAt(i); |
| pw.println("radioId=" + radioStat.radioId); |
| pw.println("totalRadioOnTimeMs=" + radioStat.totalRadioOnTimeMs); |
| pw.println("totalRadioTxTimeMs=" + radioStat.totalRadioTxTimeMs); |
| pw.println("totalRadioRxTimeMs=" + radioStat.totalRadioRxTimeMs); |
| pw.println("totalScanTimeMs=" + radioStat.totalScanTimeMs); |
| pw.println("totalNanScanTimeMs=" + radioStat.totalNanScanTimeMs); |
| pw.println("totalBackgroundScanTimeMs=" + radioStat.totalBackgroundScanTimeMs); |
| pw.println("totalRoamScanTimeMs=" + radioStat.totalRoamScanTimeMs); |
| pw.println("totalPnoScanTimeMs=" + radioStat.totalPnoScanTimeMs); |
| pw.println("totalHotspot2ScanTimeMs=" + radioStat.totalHotspot2ScanTimeMs); |
| } |
| |
| pw.println("mWifiLogProto.connectToNetworkNotificationCount=" |
| + mConnectToNetworkNotificationCount.toString()); |
| pw.println("mWifiLogProto.connectToNetworkNotificationActionCount=" |
| + mConnectToNetworkNotificationActionCount.toString()); |
| pw.println("mWifiLogProto.openNetworkRecommenderBlocklistSize=" |
| + mOpenNetworkRecommenderBlocklistSize); |
| pw.println("mWifiLogProto.isWifiNetworksAvailableNotificationOn=" |
| + mIsWifiNetworksAvailableNotificationOn); |
| pw.println("mWifiLogProto.numOpenNetworkRecommendationUpdates=" |
| + mNumOpenNetworkRecommendationUpdates); |
| pw.println("mWifiLogProto.numOpenNetworkConnectMessageFailedToSend=" |
| + mNumOpenNetworkConnectMessageFailedToSend); |
| |
| pw.println("mWifiLogProto.observedHotspotR1ApInScanHistogram=" |
| + mObservedHotspotR1ApInScanHistogram); |
| pw.println("mWifiLogProto.observedHotspotR2ApInScanHistogram=" |
| + mObservedHotspotR2ApInScanHistogram); |
| pw.println("mWifiLogProto.observedHotspotR3ApInScanHistogram=" |
| + mObservedHotspotR3ApInScanHistogram); |
| pw.println("mWifiLogProto.observedHotspotR1EssInScanHistogram=" |
| + mObservedHotspotR1EssInScanHistogram); |
| pw.println("mWifiLogProto.observedHotspotR2EssInScanHistogram=" |
| + mObservedHotspotR2EssInScanHistogram); |
| pw.println("mWifiLogProto.observedHotspotR3EssInScanHistogram=" |
| + mObservedHotspotR3EssInScanHistogram); |
| pw.println("mWifiLogProto.observedHotspotR1ApsPerEssInScanHistogram=" |
| + mObservedHotspotR1ApsPerEssInScanHistogram); |
| pw.println("mWifiLogProto.observedHotspotR2ApsPerEssInScanHistogram=" |
| + mObservedHotspotR2ApsPerEssInScanHistogram); |
| pw.println("mWifiLogProto.observedHotspotR3ApsPerEssInScanHistogram=" |
| + mObservedHotspotR3ApsPerEssInScanHistogram); |
| |
| pw.println("mWifiLogProto.observed80211mcSupportingApsInScanHistogram" |
| + mObserved80211mcApInScanHistogram); |
| pw.println("mWifiLogProto.bssidBlocklistStats:"); |
| pw.println(mBssidBlocklistStats.toString()); |
| |
| pw.println("mSoftApTetheredEvents:"); |
| for (SoftApConnectedClientsEvent event : mSoftApEventListTethered) { |
| StringBuilder eventLine = new StringBuilder(); |
| eventLine.append("event_type=" + event.eventType); |
| eventLine.append(",time_stamp_millis=" + event.timeStampMillis); |
| eventLine.append(",num_connected_clients=" + event.numConnectedClients); |
| eventLine.append(",num_connected_clients_on_current_frequency=" |
| + event.numConnectedClientsOnCurrentFrequency); |
| eventLine.append(",channel_frequency=" + event.channelFrequency); |
| eventLine.append(",channel_bandwidth=" + event.channelBandwidth); |
| eventLine.append(",generation=" + event.generation); |
| eventLine.append(",max_num_clients_setting_in_softap_configuration=" |
| + event.maxNumClientsSettingInSoftapConfiguration); |
| eventLine.append(",max_num_clients_setting_in_softap_capability=" |
| + event.maxNumClientsSettingInSoftapCapability); |
| eventLine.append(",shutdown_timeout_setting_in_softap_configuration=" |
| + event.shutdownTimeoutSettingInSoftapConfiguration); |
| eventLine.append(",default_shutdown_timeout_setting=" |
| + event.defaultShutdownTimeoutSetting); |
| eventLine.append(",client_control_is_enabled=" + event.clientControlIsEnabled); |
| pw.println(eventLine.toString()); |
| } |
| pw.println("mSoftApLocalOnlyEvents:"); |
| for (SoftApConnectedClientsEvent event : mSoftApEventListLocalOnly) { |
| StringBuilder eventLine = new StringBuilder(); |
| eventLine.append("event_type=" + event.eventType); |
| eventLine.append(",time_stamp_millis=" + event.timeStampMillis); |
| eventLine.append(",num_connected_clients=" + event.numConnectedClients); |
| eventLine.append(",num_connected_clients_on_current_frequency=" |
| + event.numConnectedClientsOnCurrentFrequency); |
| eventLine.append(",channel_frequency=" + event.channelFrequency); |
| eventLine.append(",channel_bandwidth=" + event.channelBandwidth); |
| eventLine.append(",generation=" + event.generation); |
| eventLine.append(",max_num_clients_setting_in_softap_configuration=" |
| + event.maxNumClientsSettingInSoftapConfiguration); |
| eventLine.append(",max_num_clients_setting_in_softap_capability=" |
| + event.maxNumClientsSettingInSoftapCapability); |
| eventLine.append(",shutdown_timeout_setting_in_softap_configuration=" |
| + event.shutdownTimeoutSettingInSoftapConfiguration); |
| eventLine.append(",default_shutdown_timeout_setting=" |
| + event.defaultShutdownTimeoutSetting); |
| eventLine.append(",client_control_is_enabled=" + event.clientControlIsEnabled); |
| pw.println(eventLine.toString()); |
| } |
| |
| mWifiPowerMetrics.dump(pw); |
| mWifiWakeMetrics.dump(pw); |
| |
| pw.println("mWifiLogProto.isMacRandomizationOn=" |
| + mContext.getResources().getBoolean( |
| R.bool.config_wifi_connected_mac_randomization_supported)); |
| pw.println("mWifiLogProto.scoreExperimentId=" + mWifiLogProto.scoreExperimentId); |
| pw.println("mExperimentValues.wifiIsUnusableLoggingEnabled=" |
| + mContext.getResources().getBoolean( |
| R.bool.config_wifiIsUnusableEventMetricsEnabled)); |
| pw.println("mExperimentValues.wifiDataStallMinTxBad=" |
| + mContext.getResources().getInteger( |
| R.integer.config_wifiDataStallMinTxBad)); |
| pw.println("mExperimentValues.wifiDataStallMinTxSuccessWithoutRx=" |
| + mContext.getResources().getInteger( |
| R.integer.config_wifiDataStallMinTxSuccessWithoutRx)); |
| pw.println("mExperimentValues.linkSpeedCountsLoggingEnabled=" |
| + mContext.getResources().getBoolean( |
| R.bool.config_wifiLinkSpeedMetricsEnabled)); |
| pw.println("mExperimentValues.dataStallDurationMs=" |
| + mExperimentValues.dataStallDurationMs); |
| pw.println("mExperimentValues.dataStallTxTputThrKbps=" |
| + mExperimentValues.dataStallTxTputThrKbps); |
| pw.println("mExperimentValues.dataStallRxTputThrKbps=" |
| + mExperimentValues.dataStallRxTputThrKbps); |
| pw.println("mExperimentValues.dataStallTxPerThr=" |
| + mExperimentValues.dataStallTxPerThr); |
| pw.println("mExperimentValues.dataStallCcaLevelThr=" |
| + mExperimentValues.dataStallCcaLevelThr); |
| pw.println("WifiIsUnusableEventList: "); |
| for (WifiIsUnusableWithTime event : mWifiIsUnusableList) { |
| pw.println(event); |
| } |
| pw.println("Hardware Version: " + SystemProperties.get("ro.boot.revision", "")); |
| |
| pw.println("mWifiUsabilityStatsEntriesList:"); |
| for (WifiUsabilityStatsEntry stats : mWifiUsabilityStatsEntriesList) { |
| printWifiUsabilityStatsEntry(pw, stats); |
| } |
| pw.println("mWifiUsabilityStatsList:"); |
| for (WifiUsabilityStats stats : mWifiUsabilityStatsListGood) { |
| pw.println("\nlabel=" + stats.label); |
| pw.println("\ntrigger_type=" + stats.triggerType); |
| pw.println("\ntime_stamp_ms=" + stats.timeStampMs); |
| for (WifiUsabilityStatsEntry entry : stats.stats) { |
| printWifiUsabilityStatsEntry(pw, entry); |
| } |
| } |
| for (WifiUsabilityStats stats : mWifiUsabilityStatsListBad) { |
| pw.println("\nlabel=" + stats.label); |
| pw.println("\ntrigger_type=" + stats.triggerType); |
| pw.println("\ntime_stamp_ms=" + stats.timeStampMs); |
| for (WifiUsabilityStatsEntry entry : stats.stats) { |
| printWifiUsabilityStatsEntry(pw, entry); |
| } |
| } |
| |
| pw.println("mMobilityStatePnoStatsMap:"); |
| for (int i = 0; i < mMobilityStatePnoStatsMap.size(); i++) { |
| printDeviceMobilityStatePnoScanStats(pw, mMobilityStatePnoStatsMap.valueAt(i)); |
| } |
| |
| mWifiP2pMetrics.dump(pw); |
| pw.println("mDppMetrics:"); |
| mDppMetrics.dump(pw); |
| |
| pw.println("mWifiConfigStoreReadDurationHistogram:" |
| + mWifiConfigStoreReadDurationHistogram.toString()); |
| pw.println("mWifiConfigStoreWriteDurationHistogram:" |
| + mWifiConfigStoreWriteDurationHistogram.toString()); |
| |
| pw.println("mLinkProbeSuccessRssiCounts:" + mLinkProbeSuccessRssiCounts); |
| pw.println("mLinkProbeFailureRssiCounts:" + mLinkProbeFailureRssiCounts); |
| pw.println("mLinkProbeSuccessLinkSpeedCounts:" + mLinkProbeSuccessLinkSpeedCounts); |
| pw.println("mLinkProbeFailureLinkSpeedCounts:" + mLinkProbeFailureLinkSpeedCounts); |
| pw.println("mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram:" |
| + mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram); |
| pw.println("mLinkProbeFailureSecondsSinceLastTxSuccessHistogram:" |
| + mLinkProbeFailureSecondsSinceLastTxSuccessHistogram); |
| pw.println("mLinkProbeSuccessElapsedTimeMsHistogram:" |
| + mLinkProbeSuccessElapsedTimeMsHistogram); |
| pw.println("mLinkProbeFailureReasonCounts:" + mLinkProbeFailureReasonCounts); |
| pw.println("mLinkProbeExperimentProbeCounts:" + mLinkProbeExperimentProbeCounts); |
| |
| pw.println("mNetworkSelectionExperimentPairNumChoicesCounts:" |
| + mNetworkSelectionExperimentPairNumChoicesCounts); |
| pw.println("mLinkProbeStaEventCount:" + mLinkProbeStaEventCount); |
| |
| pw.println("mWifiNetworkRequestApiLog:\n" + mWifiNetworkRequestApiLog); |
| pw.println("mWifiNetworkRequestApiMatchSizeHistogram:\n" |
| + mWifiNetworkRequestApiMatchSizeHistogram); |
| pw.println("mWifiNetworkRequestApiConnectionDurationSecOnPrimaryIfaceHistogram:\n" |
| + mWifiNetworkRequestApiConnectionDurationSecOnPrimaryIfaceHistogram); |
| pw.println("mWifiNetworkRequestApiConnectionDurationSecOnSecondaryIfaceHistogram:\n" |
| + mWifiNetworkRequestApiConnectionDurationSecOnSecondaryIfaceHistogram); |
| pw.println("mWifiNetworkRequestApiConcurrentConnectionDurationSecHistogram:\n" |
| + mWifiNetworkRequestApiConcurrentConnectionDurationSecHistogram); |
| pw.println("mWifiNetworkSuggestionApiLog:\n" + mWifiNetworkSuggestionApiLog); |
| pw.println("mWifiNetworkSuggestionApiMatchSizeHistogram:\n" |
| + mWifiNetworkSuggestionApiListSizeHistogram); |
| pw.println("mWifiNetworkSuggestionApiAppTypeCounter:\n" |
| + mWifiNetworkSuggestionApiAppTypeCounter); |
| pw.println("mWifiNetworkSuggestionPriorityGroups:\n" |
| + mWifiNetworkSuggestionPriorityGroups.toString()); |
| pw.println("mWifiNetworkSuggestionCoexistSavedNetworks:\n" |
| + mWifiNetworkSuggestionCoexistSavedNetworks.toString()); |
| printUserApprovalSuggestionAppReaction(pw); |
| printUserApprovalCarrierReaction(pw); |
| pw.println("mNetworkIdToNominatorId:\n" + mNetworkIdToNominatorId); |
| pw.println("mWifiLockStats:\n" + mWifiLockStats); |
| pw.println("mWifiLockHighPerfAcqDurationSecHistogram:\n" |
| + mWifiLockHighPerfAcqDurationSecHistogram); |
| pw.println("mWifiLockLowLatencyAcqDurationSecHistogram:\n" |
| + mWifiLockLowLatencyAcqDurationSecHistogram); |
| pw.println("mWifiLockHighPerfActiveSessionDurationSecHistogram:\n" |
| + mWifiLockHighPerfActiveSessionDurationSecHistogram); |
| pw.println("mWifiLockLowLatencyActiveSessionDurationSecHistogram:\n" |
| + mWifiLockLowLatencyActiveSessionDurationSecHistogram); |
| pw.println("mWifiToggleStats:\n" + mWifiToggleStats); |
| pw.println("mWifiLogProto.numAddOrUpdateNetworkCalls=" |
| + mWifiLogProto.numAddOrUpdateNetworkCalls); |
| pw.println("mWifiLogProto.numEnableNetworkCalls=" |
| + mWifiLogProto.numEnableNetworkCalls); |
| |
| pw.println("mWifiLogProto.txLinkSpeedCount2g=" + mTxLinkSpeedCount2g); |
| pw.println("mWifiLogProto.txLinkSpeedCount5gLow=" + mTxLinkSpeedCount5gLow); |
| pw.println("mWifiLogProto.txLinkSpeedCount5gMid=" + mTxLinkSpeedCount5gMid); |
| pw.println("mWifiLogProto.txLinkSpeedCount5gHigh=" + mTxLinkSpeedCount5gHigh); |
| pw.println("mWifiLogProto.txLinkSpeedCount6gLow=" + mTxLinkSpeedCount6gLow); |
| pw.println("mWifiLogProto.txLinkSpeedCount6gMid=" + mTxLinkSpeedCount6gMid); |
| pw.println("mWifiLogProto.txLinkSpeedCount6gHigh=" + mTxLinkSpeedCount6gHigh); |
| |
| pw.println("mWifiLogProto.rxLinkSpeedCount2g=" + mRxLinkSpeedCount2g); |
| pw.println("mWifiLogProto.rxLinkSpeedCount5gLow=" + mRxLinkSpeedCount5gLow); |
| pw.println("mWifiLogProto.rxLinkSpeedCount5gMid=" + mRxLinkSpeedCount5gMid); |
| pw.println("mWifiLogProto.rxLinkSpeedCount5gHigh=" + mRxLinkSpeedCount5gHigh); |
| pw.println("mWifiLogProto.rxLinkSpeedCount6gLow=" + mRxLinkSpeedCount6gLow); |
| pw.println("mWifiLogProto.rxLinkSpeedCount6gMid=" + mRxLinkSpeedCount6gMid); |
| pw.println("mWifiLogProto.rxLinkSpeedCount6gHigh=" + mRxLinkSpeedCount6gHigh); |
| |
| pw.println("mWifiLogProto.numIpRenewalFailure=" |
| + mWifiLogProto.numIpRenewalFailure); |
| pw.println("mWifiLogProto.connectionDurationStats=" |
| + mConnectionDurationStats.toString()); |
| pw.println("mWifiLogProto.isExternalWifiScorerOn=" |
| + mWifiLogProto.isExternalWifiScorerOn); |
| pw.println("mWifiLogProto.wifiOffMetrics=" |
| + mWifiOffMetrics.toString()); |
| pw.println("mWifiLogProto.softApConfigLimitationMetrics=" |
| + mSoftApConfigLimitationMetrics.toString()); |
| pw.println("mChannelUtilizationHistogram2G:\n" |
| + mChannelUtilizationHistogram2G); |
| pw.println("mChannelUtilizationHistogramAbove2G:\n" |
| + mChannelUtilizationHistogramAbove2G); |
| pw.println("mTxThroughputMbpsHistogram2G:\n" |
| + mTxThroughputMbpsHistogram2G); |
| pw.println("mRxThroughputMbpsHistogram2G:\n" |
| + mRxThroughputMbpsHistogram2G); |
| pw.println("mTxThroughputMbpsHistogramAbove2G:\n" |
| + mTxThroughputMbpsHistogramAbove2G); |
| pw.println("mRxThroughputMbpsHistogramAbove2G:\n" |
| + mRxThroughputMbpsHistogramAbove2G); |
| pw.println("mCarrierWifiMetrics:\n" |
| + mCarrierWifiMetrics); |
| pw.println(firstConnectAfterBootStatsToString(mFirstConnectAfterBootStats)); |
| pw.println(wifiToWifiSwitchStatsToString(mWifiToWifiSwitchStats)); |
| |
| dumpInitPartialScanMetrics(pw); |
| } |
| } |
| } |
| |
| private void dumpInitPartialScanMetrics(PrintWriter pw) { |
| pw.println("mInitPartialScanTotalCount:\n" + mInitPartialScanTotalCount); |
| pw.println("mInitPartialScanSuccessCount:\n" + mInitPartialScanSuccessCount); |
| pw.println("mInitPartialScanFailureCount:\n" + mInitPartialScanFailureCount); |
| pw.println("mInitPartialScanSuccessHistogram:\n" + mInitPartialScanSuccessHistogram); |
| pw.println("mInitPartialScanFailureHistogram:\n" + mInitPartialScanFailureHistogram); |
| } |
| |
| private void printWifiUsabilityStatsEntry(PrintWriter pw, WifiUsabilityStatsEntry entry) { |
| StringBuilder line = new StringBuilder(); |
| line.append("timestamp_ms=" + entry.timeStampMs); |
| line.append(",rssi=" + entry.rssi); |
| line.append(",link_speed_mbps=" + entry.linkSpeedMbps); |
| line.append(",total_tx_success=" + entry.totalTxSuccess); |
| line.append(",total_tx_retries=" + entry.totalTxRetries); |
| line.append(",total_tx_bad=" + entry.totalTxBad); |
| line.append(",total_rx_success=" + entry.totalRxSuccess); |
| if (entry.radioStats != null) { |
| for (RadioStats radioStat : entry.radioStats) { |
| line.append(",Radio Stats from radio_id=" + radioStat.radioId); |
| line.append(",radio_on_time_ms=" + radioStat.totalRadioOnTimeMs); |
| line.append(",radio_tx_time_ms=" + radioStat.totalRadioTxTimeMs); |
| line.append(",radio_rx_time_ms=" + radioStat.totalRadioRxTimeMs); |
| line.append(",scan_time_ms=" + radioStat.totalScanTimeMs); |
| line.append(",nan_scan_time_ms=" + radioStat.totalNanScanTimeMs); |
| line.append(",background_scan_time_ms=" + radioStat.totalBackgroundScanTimeMs); |
| line.append(",roam_scan_time_ms=" + radioStat.totalRoamScanTimeMs); |
| line.append(",pno_scan_time_ms=" + radioStat.totalPnoScanTimeMs); |
| line.append(",hotspot_2_scan_time_ms=" + radioStat.totalHotspot2ScanTimeMs); |
| } |
| } |
| line.append(",total_radio_on_time_ms=" + entry.totalRadioOnTimeMs); |
| line.append(",total_radio_tx_time_ms=" + entry.totalRadioTxTimeMs); |
| line.append(",total_radio_rx_time_ms=" + entry.totalRadioRxTimeMs); |
| line.append(",total_scan_time_ms=" + entry.totalScanTimeMs); |
| line.append(",total_nan_scan_time_ms=" + entry.totalNanScanTimeMs); |
| line.append(",total_background_scan_time_ms=" + entry.totalBackgroundScanTimeMs); |
| line.append(",total_roam_scan_time_ms=" + entry.totalRoamScanTimeMs); |
| line.append(",total_pno_scan_time_ms=" + entry.totalPnoScanTimeMs); |
| line.append(",total_hotspot_2_scan_time_ms=" + entry.totalHotspot2ScanTimeMs); |
| line.append(",wifi_score=" + entry.wifiScore); |
| line.append(",wifi_usability_score=" + entry.wifiUsabilityScore); |
| line.append(",seq_num_to_framework=" + entry.seqNumToFramework); |
| line.append(",prediction_horizon_sec=" + entry.predictionHorizonSec); |
| line.append(",total_cca_busy_freq_time_ms=" + entry.totalCcaBusyFreqTimeMs); |
| line.append(",total_radio_on_freq_time_ms=" + entry.totalRadioOnFreqTimeMs); |
| line.append(",total_beacon_rx=" + entry.totalBeaconRx); |
| line.append(",probe_status_since_last_update=" + entry.probeStatusSinceLastUpdate); |
| line.append(",probe_elapsed_time_ms_since_last_update=" |
| + entry.probeElapsedTimeSinceLastUpdateMs); |
| line.append(",probe_mcs_rate_since_last_update=" + entry.probeMcsRateSinceLastUpdate); |
| line.append(",rx_link_speed_mbps=" + entry.rxLinkSpeedMbps); |
| line.append(",seq_num_inside_framework=" + entry.seqNumInsideFramework); |
| line.append(",is_same_bssid_and_freq=" + entry.isSameBssidAndFreq); |
| line.append(",device_mobility_state=" + entry.deviceMobilityState); |
| line.append(",time_slice_duty_cycle_in_percent=" + entry.timeSliceDutyCycleInPercent); |
| if (entry.contentionTimeStats != null) { |
| for (ContentionTimeStats stat : entry.contentionTimeStats) { |
| line.append(",access_category=" + stat.accessCategory); |
| line.append(",contention_time_min_micros=" + stat.contentionTimeMinMicros); |
| line.append(",contention_time_max_micros=" + stat.contentionTimeMaxMicros); |
| line.append(",contention_time_avg_micros=" + stat.contentionTimeAvgMicros); |
| line.append(",contention_num_samples=" + stat.contentionNumSamples); |
| } |
| } |
| line.append(",channel_utilization_ratio=" + entry.channelUtilizationRatio); |
| line.append(",is_throughput_sufficient=" + entry.isThroughputSufficient); |
| line.append(",is_wifi_scoring_enabled=" + entry.isWifiScoringEnabled); |
| line.append(",is_cellular_data_available=" + entry.isCellularDataAvailable); |
| line.append(",sta_count=" + entry.staCount); |
| line.append(",channel_utilization=" + entry.channelUtilization); |
| if (entry.rateStats != null) { |
| for (RateStats rateStat : entry.rateStats) { |
| line.append(",preamble=" + rateStat.preamble); |
| line.append(",nss=" + rateStat.nss); |
| line.append(",bw=" + rateStat.bw); |
| line.append(",rate_mcs_idx=" + rateStat.rateMcsIdx); |
| line.append(",bit_rate_in_kbps=" + rateStat.bitRateInKbps); |
| line.append(",tx_mpdu=" + rateStat.txMpdu); |
| line.append(",rx_mpdu=" + rateStat.rxMpdu); |
| line.append(",mpdu_lost=" + rateStat.mpduLost); |
| line.append(",retries=" + rateStat.retries); |
| } |
| } |
| pw.println(line.toString()); |
| } |
| |
| private void printDeviceMobilityStatePnoScanStats(PrintWriter pw, |
| DeviceMobilityStatePnoScanStats stats) { |
| StringBuilder line = new StringBuilder(); |
| line.append("device_mobility_state=" + stats.deviceMobilityState); |
| line.append(",num_times_entered_state=" + stats.numTimesEnteredState); |
| line.append(",total_duration_ms=" + stats.totalDurationMs); |
| line.append(",pno_duration_ms=" + stats.pnoDurationMs); |
| pw.println(line.toString()); |
| } |
| |
| private void printUserApprovalSuggestionAppReaction(PrintWriter pw) { |
| pw.println("mUserApprovalSuggestionAppUiUserReaction:"); |
| for (UserReaction event : mUserApprovalSuggestionAppUiReactionList) { |
| pw.println(event); |
| } |
| } |
| |
| private void printUserApprovalCarrierReaction(PrintWriter pw) { |
| pw.println("mUserApprovalCarrierUiUserReaction:"); |
| for (UserReaction event : mUserApprovalCarrierUiReactionList) { |
| pw.println(event); |
| } |
| } |
| |
| /** |
| * Update various counts of saved network types |
| * @param networks List of WifiConfigurations representing all saved networks, must not be null |
| */ |
| public void updateSavedNetworks(List<WifiConfiguration> networks) { |
| synchronized (mLock) { |
| mWifiLogProto.numSavedNetworks = networks.size(); |
| mWifiLogProto.numSavedNetworksWithMacRandomization = 0; |
| mWifiLogProto.numOpenNetworks = 0; |
| mWifiLogProto.numLegacyPersonalNetworks = 0; |
| mWifiLogProto.numLegacyEnterpriseNetworks = 0; |
| mWifiLogProto.numEnhancedOpenNetworks = 0; |
| mWifiLogProto.numWpa3PersonalNetworks = 0; |
| mWifiLogProto.numWpa3EnterpriseNetworks = 0; |
| mWifiLogProto.numWapiPersonalNetworks = 0; |
| mWifiLogProto.numWapiEnterpriseNetworks = 0; |
| mWifiLogProto.numNetworksAddedByUser = 0; |
| mWifiLogProto.numNetworksAddedByApps = 0; |
| mWifiLogProto.numHiddenNetworks = 0; |
| mWifiLogProto.numPasspointNetworks = 0; |
| |
| for (WifiConfiguration config : networks) { |
| if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_OPEN)) { |
| mWifiLogProto.numOpenNetworks++; |
| } else if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_OWE)) { |
| mWifiLogProto.numEnhancedOpenNetworks++; |
| } else if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_WAPI_PSK)) { |
| mWifiLogProto.numWapiPersonalNetworks++; |
| } else if (config.isEnterprise()) { |
| if (config.isSecurityType( |
| WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT)) { |
| mWifiLogProto.numWpa3EnterpriseNetworks++; |
| } else if (config.isSecurityType( |
| WifiConfiguration.SECURITY_TYPE_WAPI_CERT)) { |
| mWifiLogProto.numWapiEnterpriseNetworks++; |
| } else { |
| mWifiLogProto.numLegacyEnterpriseNetworks++; |
| } |
| } else { |
| if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_PSK)) { |
| mWifiLogProto.numLegacyPersonalNetworks++; |
| } |
| else if (config.isSecurityType(WifiConfiguration.SECURITY_TYPE_SAE)) { |
| mWifiLogProto.numWpa3PersonalNetworks++; |
| } |
| } |
| mWifiLogProto.numNetworksAddedByApps++; |
| if (config.hiddenSSID) { |
| mWifiLogProto.numHiddenNetworks++; |
| } |
| if (config.isPasspoint()) { |
| mWifiLogProto.numPasspointNetworks++; |
| } |
| if (config.macRandomizationSetting != WifiConfiguration.RANDOMIZATION_NONE) { |
| mWifiLogProto.numSavedNetworksWithMacRandomization++; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Update metrics for saved Passpoint profiles. |
| * |
| * @param numSavedProfiles The number of saved Passpoint profiles |
| * @param numConnectedProfiles The number of saved Passpoint profiles that have ever resulted |
| * in a successful network connection |
| */ |
| public void updateSavedPasspointProfiles(int numSavedProfiles, int numConnectedProfiles) { |
| synchronized (mLock) { |
| mWifiLogProto.numPasspointProviders = numSavedProfiles; |
| mWifiLogProto.numPasspointProvidersSuccessfullyConnected = numConnectedProfiles; |
| } |
| } |
| |
| /** |
| * Update number of times for type of saved Passpoint profile. |
| * |
| * @param providers Passpoint providers installed on the device. |
| */ |
| public void updateSavedPasspointProfilesInfo( |
| Map<String, PasspointProvider> providers) { |
| int passpointType; |
| int eapType; |
| PasspointConfiguration config; |
| synchronized (mLock) { |
| mInstalledPasspointProfileTypeForR1.clear(); |
| mInstalledPasspointProfileTypeForR2.clear(); |
| for (Map.Entry<String, PasspointProvider> entry : providers.entrySet()) { |
| config = entry.getValue().getConfig(); |
| if (config.getCredential().getUserCredential() != null) { |
| eapType = EAPConstants.EAP_TTLS; |
| } else if (config.getCredential().getCertCredential() != null) { |
| eapType = EAPConstants.EAP_TLS; |
| } else if (config.getCredential().getSimCredential() != null) { |
| eapType = config.getCredential().getSimCredential().getEapType(); |
| } else { |
| eapType = -1; |
| } |
| switch (eapType) { |
| case EAPConstants.EAP_TLS: |
| passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_TLS; |
| break; |
| case EAPConstants.EAP_TTLS: |
| passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_TTLS; |
| break; |
| case EAPConstants.EAP_SIM: |
| passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_SIM; |
| break; |
| case EAPConstants.EAP_AKA: |
| passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_AKA; |
| break; |
| case EAPConstants.EAP_AKA_PRIME: |
| passpointType = |
| WifiMetricsProto.PasspointProfileTypeCount.TYPE_EAP_AKA_PRIME; |
| break; |
| default: |
| passpointType = WifiMetricsProto.PasspointProfileTypeCount.TYPE_UNKNOWN; |
| |
| } |
| if (config.validateForR2()) { |
| mInstalledPasspointProfileTypeForR2.increment(passpointType); |
| } else { |
| mInstalledPasspointProfileTypeForR1.increment(passpointType); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Increment initial partial scan count |
| */ |
| public void incrementInitialPartialScanCount() { |
| synchronized (mLock) { |
| mInitPartialScanTotalCount++; |
| } |
| } |
| |
| /** |
| * Report of initial partial scan |
| * @param channelCount number of channels used in this scan |
| * @param status true if scan resulted in a network connection attempt, false otherwise |
| */ |
| public void reportInitialPartialScan(int channelCount, boolean status) { |
| synchronized (mLock) { |
| if (status) { |
| mInitPartialScanSuccessCount++; |
| mInitPartialScanSuccessHistogram.increment(channelCount); |
| } else { |
| mInitPartialScanFailureCount++; |
| mInitPartialScanFailureHistogram.increment(channelCount); |
| } |
| } |
| } |
| |
| /** |
| * Put all metrics that were being tracked separately into mWifiLogProto |
| */ |
| private void consolidateProto() { |
| List<WifiMetricsProto.RssiPollCount> rssis = new ArrayList<>(); |
| synchronized (mLock) { |
| mWifiLogProto.connectionEvent = mConnectionEventList |
| .stream() |
| // Exclude active un-ended connection events |
| .filter(connectionEvent -> |
| !mCurrentConnectionEventPerIface.containsValue(connectionEvent)) |
| // unwrap WifiMetrics.ConnectionEvent to get WifiMetricsProto.ConnectionEvent |
| .map(connectionEvent -> connectionEvent.mConnectionEvent) |
| .toArray(WifiMetricsProto.ConnectionEvent[]::new); |
| |
| //Convert the SparseIntArray of scanReturnEntry integers into ScanReturnEntry proto list |
| mWifiLogProto.scanReturnEntries = |
| new WifiMetricsProto.WifiLog.ScanReturnEntry[mScanReturnEntries.size()]; |
| for (int i = 0; i < mScanReturnEntries.size(); i++) { |
| mWifiLogProto.scanReturnEntries[i] = new WifiMetricsProto.WifiLog.ScanReturnEntry(); |
| mWifiLogProto.scanReturnEntries[i].scanReturnCode = mScanReturnEntries.keyAt(i); |
| mWifiLogProto.scanReturnEntries[i].scanResultsCount = mScanReturnEntries.valueAt(i); |
| } |
| |
| // Convert the SparseIntArray of systemStateEntry into WifiSystemStateEntry proto list |
| // This one is slightly more complex, as the Sparse are indexed with: |
| // key: wifiState * 2 + isScreenOn, value: wifiStateCount |
| mWifiLogProto.wifiSystemStateEntries = |
| new WifiMetricsProto.WifiLog |
| .WifiSystemStateEntry[mWifiSystemStateEntries.size()]; |
| for (int i = 0; i < mWifiSystemStateEntries.size(); i++) { |
| mWifiLogProto.wifiSystemStateEntries[i] = |
| new WifiMetricsProto.WifiLog.WifiSystemStateEntry(); |
| mWifiLogProto.wifiSystemStateEntries[i].wifiState = |
| mWifiSystemStateEntries.keyAt(i) / 2; |
| mWifiLogProto.wifiSystemStateEntries[i].wifiStateCount = |
| mWifiSystemStateEntries.valueAt(i); |
| mWifiLogProto.wifiSystemStateEntries[i].isScreenOn = |
| (mWifiSystemStateEntries.keyAt(i) % 2) > 0; |
| } |
| mWifiLogProto.recordDurationSec = (int) ((mClock.getElapsedSinceBootMillis() / 1000) |
| - mRecordStartTimeSec); |
| |
| /** |
| * Convert the SparseIntArrays of RSSI poll rssi, counts, and frequency to the |
| * proto's repeated IntKeyVal array. |
| */ |
| for (Map.Entry<Integer, SparseIntArray> entry : mRssiPollCountsMap.entrySet()) { |
| int frequency = entry.getKey(); |
| SparseIntArray histogram = entry.getValue(); |
| for (int i = 0; i < histogram.size(); i++) { |
| WifiMetricsProto.RssiPollCount keyVal = new WifiMetricsProto.RssiPollCount(); |
| keyVal.rssi = histogram.keyAt(i); |
| keyVal.count = histogram.valueAt(i); |
| keyVal.frequency = frequency; |
| rssis.add(keyVal); |
| } |
| } |
| mWifiLogProto.rssiPollRssiCount = rssis.toArray(mWifiLogProto.rssiPollRssiCount); |
| |
| /** |
| * Convert the SparseIntArray of RSSI delta rssi's and counts to the proto's repeated |
| * IntKeyVal array. |
| */ |
| mWifiLogProto.rssiPollDeltaCount = |
| new WifiMetricsProto.RssiPollCount[mRssiDeltaCounts.size()]; |
| for (int i = 0; i < mRssiDeltaCounts.size(); i++) { |
| mWifiLogProto.rssiPollDeltaCount[i] = new WifiMetricsProto.RssiPollCount(); |
| mWifiLogProto.rssiPollDeltaCount[i].rssi = mRssiDeltaCounts.keyAt(i); |
| mWifiLogProto.rssiPollDeltaCount[i].count = mRssiDeltaCounts.valueAt(i); |
| } |
| |
| /** |
| * Add LinkSpeedCount objects from mLinkSpeedCounts to proto. |
| */ |
| mWifiLogProto.linkSpeedCounts = |
| new WifiMetricsProto.LinkSpeedCount[mLinkSpeedCounts.size()]; |
| for (int i = 0; i < mLinkSpeedCounts.size(); i++) { |
| mWifiLogProto.linkSpeedCounts[i] = mLinkSpeedCounts.valueAt(i); |
| } |
| |
| /** |
| * Convert the SparseIntArray of alert reasons and counts to the proto's repeated |
| * IntKeyVal array. |
| */ |
| mWifiLogProto.alertReasonCount = |
| new WifiMetricsProto.AlertReasonCount[mWifiAlertReasonCounts.size()]; |
| for (int i = 0; i < mWifiAlertReasonCounts.size(); i++) { |
| mWifiLogProto.alertReasonCount[i] = new WifiMetricsProto.AlertReasonCount(); |
| mWifiLogProto.alertReasonCount[i].reason = mWifiAlertReasonCounts.keyAt(i); |
| mWifiLogProto.alertReasonCount[i].count = mWifiAlertReasonCounts.valueAt(i); |
| } |
| |
| /** |
| * Convert the SparseIntArray of Wifi Score and counts to proto's repeated |
| * IntKeyVal array. |
| */ |
| mWifiLogProto.wifiScoreCount = |
| new WifiMetricsProto.WifiScoreCount[mWifiScoreCounts.size()]; |
| for (int score = 0; score < mWifiScoreCounts.size(); score++) { |
| mWifiLogProto.wifiScoreCount[score] = new WifiMetricsProto.WifiScoreCount(); |
| mWifiLogProto.wifiScoreCount[score].score = mWifiScoreCounts.keyAt(score); |
| mWifiLogProto.wifiScoreCount[score].count = mWifiScoreCounts.valueAt(score); |
| } |
| |
| /** |
| * Convert the SparseIntArray of Wifi Usability Score and counts to proto's repeated |
| * IntKeyVal array. |
| */ |
| mWifiLogProto.wifiUsabilityScoreCount = |
| new WifiMetricsProto.WifiUsabilityScoreCount[mWifiUsabilityScoreCounts.size()]; |
| for (int scoreIdx = 0; scoreIdx < mWifiUsabilityScoreCounts.size(); scoreIdx++) { |
| mWifiLogProto.wifiUsabilityScoreCount[scoreIdx] = |
| new WifiMetricsProto.WifiUsabilityScoreCount(); |
| mWifiLogProto.wifiUsabilityScoreCount[scoreIdx].score = |
| mWifiUsabilityScoreCounts.keyAt(scoreIdx); |
| mWifiLogProto.wifiUsabilityScoreCount[scoreIdx].count = |
| mWifiUsabilityScoreCounts.valueAt(scoreIdx); |
| } |
| |
| /** |
| * Convert the SparseIntArray of SoftAp Return codes and counts to proto's repeated |
| * IntKeyVal array. |
| */ |
| int codeCounts = mSoftApManagerReturnCodeCounts.size(); |
| mWifiLogProto.softApReturnCode = new WifiMetricsProto.SoftApReturnCodeCount[codeCounts]; |
| for (int sapCode = 0; sapCode < codeCounts; sapCode++) { |
| mWifiLogProto.softApReturnCode[sapCode] = |
| new WifiMetricsProto.SoftApReturnCodeCount(); |
| mWifiLogProto.softApReturnCode[sapCode].startResult = |
| mSoftApManagerReturnCodeCounts.keyAt(sapCode); |
| mWifiLogProto.softApReturnCode[sapCode].count = |
| mSoftApManagerReturnCodeCounts.valueAt(sapCode); |
| } |
| |
| /** |
| * Convert StaEventList to array of StaEvents |
| */ |
| mWifiLogProto.staEventList = new StaEvent[mStaEventList.size()]; |
| for (int i = 0; i < mStaEventList.size(); i++) { |
| mWifiLogProto.staEventList[i] = mStaEventList.get(i).staEvent; |
| } |
| mWifiLogProto.userActionEvents = new UserActionEvent[mUserActionEventList.size()]; |
| for (int i = 0; i < mUserActionEventList.size(); i++) { |
| mWifiLogProto.userActionEvents[i] = mUserActionEventList.get(i).toProto(); |
| } |
| mWifiLogProto.totalSsidsInScanHistogram = |
| makeNumConnectableNetworksBucketArray(mTotalSsidsInScanHistogram); |
| mWifiLogProto.totalBssidsInScanHistogram = |
| makeNumConnectableNetworksBucketArray(mTotalBssidsInScanHistogram); |
| mWifiLogProto.availableOpenSsidsInScanHistogram = |
| makeNumConnectableNetworksBucketArray(mAvailableOpenSsidsInScanHistogram); |
| mWifiLogProto.availableOpenBssidsInScanHistogram = |
| makeNumConnectableNetworksBucketArray(mAvailableOpenBssidsInScanHistogram); |
| mWifiLogProto.availableSavedSsidsInScanHistogram = |
| makeNumConnectableNetworksBucketArray(mAvailableSavedSsidsInScanHistogram); |
| mWifiLogProto.availableSavedBssidsInScanHistogram = |
| makeNumConnectableNetworksBucketArray(mAvailableSavedBssidsInScanHistogram); |
| mWifiLogProto.availableOpenOrSavedSsidsInScanHistogram = |
| makeNumConnectableNetworksBucketArray( |
| mAvailableOpenOrSavedSsidsInScanHistogram); |
| mWifiLogProto.availableOpenOrSavedBssidsInScanHistogram = |
| makeNumConnectableNetworksBucketArray( |
| mAvailableOpenOrSavedBssidsInScanHistogram); |
| mWifiLogProto.availableSavedPasspointProviderProfilesInScanHistogram = |
| makeNumConnectableNetworksBucketArray( |
| mAvailableSavedPasspointProviderProfilesInScanHistogram); |
| mWifiLogProto.availableSavedPasspointProviderBssidsInScanHistogram = |
| makeNumConnectableNetworksBucketArray( |
| mAvailableSavedPasspointProviderBssidsInScanHistogram); |
| mWifiLogProto.wifiAwareLog = mWifiAwareMetrics.consolidateProto(); |
| mWifiLogProto.wifiRttLog = mRttMetrics.consolidateProto(); |
| |
| mWifiLogProto.pnoScanMetrics = mPnoScanMetrics; |
| mWifiLogProto.wifiLinkLayerUsageStats = mWifiLinkLayerUsageStats; |
| mWifiLogProto.wifiLinkLayerUsageStats.radioStats = |
| new WifiMetricsProto.RadioStats[mRadioStats.size()]; |
| for (int i = 0; i < mRadioStats.size(); i++) { |
| mWifiLogProto.wifiLinkLayerUsageStats.radioStats[i] = mRadioStats.valueAt(i); |
| } |
| |
| /** |
| * Convert the SparseIntArray of "Connect to Network" notification types and counts to |
| * proto's repeated IntKeyVal array. |
| */ |
| ConnectToNetworkNotificationAndActionCount[] notificationCountArray = |
| new ConnectToNetworkNotificationAndActionCount[ |
| mConnectToNetworkNotificationCount.size()]; |
| for (int i = 0; i < mConnectToNetworkNotificationCount.size(); i++) { |
| ConnectToNetworkNotificationAndActionCount keyVal = |
| new ConnectToNetworkNotificationAndActionCount(); |
| keyVal.notification = mConnectToNetworkNotificationCount.keyAt(i); |
| keyVal.recommender = |
| ConnectToNetworkNotificationAndActionCount.RECOMMENDER_OPEN; |
| keyVal.count = mConnectToNetworkNotificationCount.valueAt(i); |
| notificationCountArray[i] = keyVal; |
| } |
| mWifiLogProto.connectToNetworkNotificationCount = notificationCountArray; |
| |
| /** |
| * Convert the SparseIntArray of "Connect to Network" notification types and counts to |
| * proto's repeated IntKeyVal array. |
| */ |
| ConnectToNetworkNotificationAndActionCount[] notificationActionCountArray = |
| new ConnectToNetworkNotificationAndActionCount[ |
| mConnectToNetworkNotificationActionCount.size()]; |
| for (int i = 0; i < mConnectToNetworkNotificationActionCount.size(); i++) { |
| ConnectToNetworkNotificationAndActionCount keyVal = |
| new ConnectToNetworkNotificationAndActionCount(); |
| int k = mConnectToNetworkNotificationActionCount.keyAt(i); |
| keyVal.notification = k / CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER; |
| keyVal.action = k % CONNECT_TO_NETWORK_NOTIFICATION_ACTION_KEY_MULTIPLIER; |
| keyVal.recommender = |
| ConnectToNetworkNotificationAndActionCount.RECOMMENDER_OPEN; |
| keyVal.count = mConnectToNetworkNotificationActionCount.valueAt(i); |
| notificationActionCountArray[i] = keyVal; |
| } |
| |
| mWifiLogProto.installedPasspointProfileTypeForR1 = |
| convertPasspointProfilesToProto(mInstalledPasspointProfileTypeForR1); |
| mWifiLogProto.installedPasspointProfileTypeForR2 = |
| convertPasspointProfilesToProto(mInstalledPasspointProfileTypeForR2); |
| |
| mWifiLogProto.connectToNetworkNotificationActionCount = notificationActionCountArray; |
| |
| mWifiLogProto.openNetworkRecommenderBlocklistSize = |
| mOpenNetworkRecommenderBlocklistSize; |
| mWifiLogProto.isWifiNetworksAvailableNotificationOn = |
| mIsWifiNetworksAvailableNotificationOn; |
| mWifiLogProto.numOpenNetworkRecommendationUpdates = |
| mNumOpenNetworkRecommendationUpdates; |
| mWifiLogProto.numOpenNetworkConnectMessageFailedToSend = |
| mNumOpenNetworkConnectMessageFailedToSend; |
| |
| mWifiLogProto.observedHotspotR1ApsInScanHistogram = |
| makeNumConnectableNetworksBucketArray(mObservedHotspotR1ApInScanHistogram); |
| mWifiLogProto.observedHotspotR2ApsInScanHistogram = |
| makeNumConnectableNetworksBucketArray(mObservedHotspotR2ApInScanHistogram); |
| mWifiLogProto.observedHotspotR3ApsInScanHistogram = |
| makeNumConnectableNetworksBucketArray(mObservedHotspotR3ApInScanHistogram); |
| mWifiLogProto.observedHotspotR1EssInScanHistogram = |
| makeNumConnectableNetworksBucketArray(mObservedHotspotR1EssInScanHistogram); |
| mWifiLogProto.observedHotspotR2EssInScanHistogram = |
| makeNumConnectableNetworksBucketArray(mObservedHotspotR2EssInScanHistogram); |
| mWifiLogProto.observedHotspotR3EssInScanHistogram = |
| makeNumConnectableNetworksBucketArray(mObservedHotspotR3EssInScanHistogram); |
| mWifiLogProto.observedHotspotR1ApsPerEssInScanHistogram = |
| makeNumConnectableNetworksBucketArray( |
| mObservedHotspotR1ApsPerEssInScanHistogram); |
| mWifiLogProto.observedHotspotR2ApsPerEssInScanHistogram = |
| makeNumConnectableNetworksBucketArray( |
| mObservedHotspotR2ApsPerEssInScanHistogram); |
| mWifiLogProto.observedHotspotR3ApsPerEssInScanHistogram = |
| makeNumConnectableNetworksBucketArray( |
| mObservedHotspotR3ApsPerEssInScanHistogram); |
| |
| mWifiLogProto.observed80211McSupportingApsInScanHistogram = |
| makeNumConnectableNetworksBucketArray(mObserved80211mcApInScanHistogram); |
| |
| if (mSoftApEventListTethered.size() > 0) { |
| mWifiLogProto.softApConnectedClientsEventsTethered = |
| mSoftApEventListTethered.toArray( |
| mWifiLogProto.softApConnectedClientsEventsTethered); |
| } |
| if (mSoftApEventListLocalOnly.size() > 0) { |
| mWifiLogProto.softApConnectedClientsEventsLocalOnly = |
| mSoftApEventListLocalOnly.toArray( |
| mWifiLogProto.softApConnectedClientsEventsLocalOnly); |
| } |
| |
| mWifiLogProto.wifiPowerStats = mWifiPowerMetrics.buildProto(); |
| mWifiLogProto.wifiRadioUsage = mWifiPowerMetrics.buildWifiRadioUsageProto(); |
| mWifiLogProto.wifiWakeStats = mWifiWakeMetrics.buildProto(); |
| mWifiLogProto.isMacRandomizationOn = mContext.getResources().getBoolean( |
| R.bool.config_wifi_connected_mac_randomization_supported); |
| mExperimentValues.wifiIsUnusableLoggingEnabled = mContext.getResources().getBoolean( |
| R.bool.config_wifiIsUnusableEventMetricsEnabled); |
| mExperimentValues.linkSpeedCountsLoggingEnabled = mContext.getResources().getBoolean( |
| R.bool.config_wifiLinkSpeedMetricsEnabled); |
| mExperimentValues.wifiDataStallMinTxBad = mContext.getResources().getInteger( |
| R.integer.config_wifiDataStallMinTxBad); |
| mExperimentValues.wifiDataStallMinTxSuccessWithoutRx = |
| mContext.getResources().getInteger( |
| R.integer.config_wifiDataStallMinTxSuccessWithoutRx); |
| mWifiLogProto.experimentValues = mExperimentValues; |
| mWifiLogProto.wifiIsUnusableEventList = |
| new WifiIsUnusableEvent[mWifiIsUnusableList.size()]; |
| for (int i = 0; i < mWifiIsUnusableList.size(); i++) { |
| mWifiLogProto.wifiIsUnusableEventList[i] = mWifiIsUnusableList.get(i).event; |
| } |
| mWifiLogProto.hardwareRevision = SystemProperties.get("ro.boot.revision", ""); |
| |
| // Postprocessing on WifiUsabilityStats to upload an equal number of LABEL_GOOD and |
| // LABEL_BAD WifiUsabilityStats |
| final int numUsabilityStats = Math.min( |
| Math.min(mWifiUsabilityStatsListBad.size(), |
| mWifiUsabilityStatsListGood.size()), |
| MAX_WIFI_USABILITY_STATS_PER_TYPE_TO_UPLOAD); |
| LinkedList<WifiUsabilityStats> usabilityStatsGoodCopy = |
| new LinkedList<>(mWifiUsabilityStatsListGood); |
| LinkedList<WifiUsabilityStats> usabilityStatsBadCopy = |
| new LinkedList<>(mWifiUsabilityStatsListBad); |
| mWifiLogProto.wifiUsabilityStatsList = new WifiUsabilityStats[numUsabilityStats * 2]; |
| for (int i = 0; i < numUsabilityStats; i++) { |
| mWifiLogProto.wifiUsabilityStatsList[2 * i] = usabilityStatsGoodCopy.remove( |
| mRand.nextInt(usabilityStatsGoodCopy.size())); |
| mWifiLogProto.wifiUsabilityStatsList[2 * i + 1] = usabilityStatsBadCopy.remove( |
| mRand.nextInt(usabilityStatsBadCopy.size())); |
| } |
| mWifiLogProto.mobilityStatePnoStatsList = |
| new DeviceMobilityStatePnoScanStats[mMobilityStatePnoStatsMap.size()]; |
| for (int i = 0; i < mMobilityStatePnoStatsMap.size(); i++) { |
| mWifiLogProto.mobilityStatePnoStatsList[i] = mMobilityStatePnoStatsMap.valueAt(i); |
| } |
| mWifiLogProto.wifiP2PStats = mWifiP2pMetrics.consolidateProto(); |
| mWifiLogProto.wifiDppLog = mDppMetrics.consolidateProto(); |
| mWifiLogProto.wifiConfigStoreIo = new WifiMetricsProto.WifiConfigStoreIO(); |
| mWifiLogProto.wifiConfigStoreIo.readDurations = |
| makeWifiConfigStoreIODurationBucketArray(mWifiConfigStoreReadDurationHistogram); |
| mWifiLogProto.wifiConfigStoreIo.writeDurations = |
| makeWifiConfigStoreIODurationBucketArray( |
| mWifiConfigStoreWriteDurationHistogram); |
| |
| LinkProbeStats linkProbeStats = new LinkProbeStats(); |
| linkProbeStats.successRssiCounts = mLinkProbeSuccessRssiCounts.toProto(); |
| linkProbeStats.failureRssiCounts = mLinkProbeFailureRssiCounts.toProto(); |
| linkProbeStats.successLinkSpeedCounts = mLinkProbeSuccessLinkSpeedCounts.toProto(); |
| linkProbeStats.failureLinkSpeedCounts = mLinkProbeFailureLinkSpeedCounts.toProto(); |
| linkProbeStats.successSecondsSinceLastTxSuccessHistogram = |
| mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram.toProto(); |
| linkProbeStats.failureSecondsSinceLastTxSuccessHistogram = |
| mLinkProbeFailureSecondsSinceLastTxSuccessHistogram.toProto(); |
| linkProbeStats.successElapsedTimeMsHistogram = |
| mLinkProbeSuccessElapsedTimeMsHistogram.toProto(); |
| linkProbeStats.failureReasonCounts = mLinkProbeFailureReasonCounts.toProto( |
| LinkProbeFailureReasonCount.class, |
| (reason, count) -> { |
| LinkProbeFailureReasonCount c = new LinkProbeFailureReasonCount(); |
| c.failureReason = linkProbeFailureReasonToProto(reason); |
| c.count = count; |
| return c; |
| }); |
| linkProbeStats.experimentProbeCounts = mLinkProbeExperimentProbeCounts.toProto( |
| ExperimentProbeCounts.class, |
| (experimentId, probeCount) -> { |
| ExperimentProbeCounts c = new ExperimentProbeCounts(); |
| c.experimentId = experimentId; |
| c.probeCount = probeCount; |
| return c; |
| }); |
| mWifiLogProto.linkProbeStats = linkProbeStats; |
| |
| mWifiLogProto.networkSelectionExperimentDecisionsList = |
| makeNetworkSelectionExperimentDecisionsList(); |
| |
| mWifiNetworkRequestApiLog.networkMatchSizeHistogram = |
| mWifiNetworkRequestApiMatchSizeHistogram.toProto(); |
| mWifiNetworkRequestApiLog.connectionDurationSecOnPrimaryIfaceHistogram = |
| mWifiNetworkRequestApiConnectionDurationSecOnPrimaryIfaceHistogram.toProto(); |
| mWifiNetworkRequestApiLog.connectionDurationSecOnSecondaryIfaceHistogram = |
| mWifiNetworkRequestApiConnectionDurationSecOnSecondaryIfaceHistogram.toProto(); |
| mWifiNetworkRequestApiLog.concurrentConnectionDurationSecHistogram = |
| mWifiNetworkRequestApiConcurrentConnectionDurationSecHistogram.toProto(); |
| mWifiLogProto.wifiNetworkRequestApiLog = mWifiNetworkRequestApiLog; |
| |
| mWifiNetworkSuggestionApiLog.networkListSizeHistogram = |
| mWifiNetworkSuggestionApiListSizeHistogram.toProto(); |
| mWifiNetworkSuggestionApiLog.appCountPerType = |
| mWifiNetworkSuggestionApiAppTypeCounter.toProto(SuggestionAppCount.class, |
| (key, count) -> { |
| SuggestionAppCount entry = new SuggestionAppCount(); |
| entry.appType = key; |
| entry.count = count; |
| return entry; |
| }); |
| mWifiNetworkSuggestionApiLog.numPriorityGroups = |
| mWifiNetworkSuggestionPriorityGroups.size(); |
| mWifiNetworkSuggestionApiLog.numSavedNetworksWithConfiguredSuggestion = |
| mWifiNetworkSuggestionCoexistSavedNetworks.size(); |
| mWifiLogProto.wifiNetworkSuggestionApiLog = mWifiNetworkSuggestionApiLog; |
| |
| UserReactionToApprovalUiEvent events = new UserReactionToApprovalUiEvent(); |
| events.userApprovalAppUiReaction = mUserApprovalSuggestionAppUiReactionList |
| .toArray(new UserReaction[0]); |
| events.userApprovalCarrierUiReaction = mUserApprovalCarrierUiReactionList |
| .toArray(new UserReaction[0]); |
| mWifiLogProto.userReactionToApprovalUiEvent = events; |
| |
| mWifiLockStats.highPerfLockAcqDurationSecHistogram = |
| mWifiLockHighPerfAcqDurationSecHistogram.toProto(); |
| |
| mWifiLockStats.lowLatencyLockAcqDurationSecHistogram = |
| mWifiLockLowLatencyAcqDurationSecHistogram.toProto(); |
| |
| mWifiLockStats.highPerfActiveSessionDurationSecHistogram = |
| mWifiLockHighPerfActiveSessionDurationSecHistogram.toProto(); |
| |
| mWifiLockStats.lowLatencyActiveSessionDurationSecHistogram = |
| mWifiLockLowLatencyActiveSessionDurationSecHistogram.toProto(); |
| |
| mWifiLogProto.wifiLockStats = mWifiLockStats; |
| mWifiLogProto.wifiToggleStats = mWifiToggleStats; |
| |
| /** |
| * Convert the SparseIntArray of passpoint provision failure code |
| * and counts to the proto's repeated IntKeyVal array. |
| */ |
| mWifiLogProto.passpointProvisionStats = new PasspointProvisionStats(); |
| mWifiLogProto.passpointProvisionStats.numProvisionSuccess = mNumProvisionSuccess; |
| mWifiLogProto.passpointProvisionStats.provisionFailureCount = |
| mPasspointProvisionFailureCounts.toProto(ProvisionFailureCount.class, |
| (key, count) -> { |
| ProvisionFailureCount entry = new ProvisionFailureCount(); |
| entry.failureCode = key; |
| entry.count = count; |
| return entry; |
| }); |
| // 'G' is due to that 1st Letter after _ becomes capital during protobuff compilation |
| mWifiLogProto.txLinkSpeedCount2G = mTxLinkSpeedCount2g.toProto(); |
| mWifiLogProto.txLinkSpeedCount5GLow = mTxLinkSpeedCount5gLow.toProto(); |
| mWifiLogProto.txLinkSpeedCount5GMid = mTxLinkSpeedCount5gMid.toProto(); |
| mWifiLogProto.txLinkSpeedCount5GHigh = mTxLinkSpeedCount5gHigh.toProto(); |
| mWifiLogProto.txLinkSpeedCount6GLow = mTxLinkSpeedCount6gLow.toProto(); |
| mWifiLogProto.txLinkSpeedCount6GMid = mTxLinkSpeedCount6gMid.toProto(); |
| mWifiLogProto.txLinkSpeedCount6GHigh = mTxLinkSpeedCount6gHigh.toProto(); |
| |
| mWifiLogProto.rxLinkSpeedCount2G = mRxLinkSpeedCount2g.toProto(); |
| mWifiLogProto.rxLinkSpeedCount5GLow = mRxLinkSpeedCount5gLow.toProto(); |
| mWifiLogProto.rxLinkSpeedCount5GMid = mRxLinkSpeedCount5gMid.toProto(); |
| mWifiLogProto.rxLinkSpeedCount5GHigh = mRxLinkSpeedCount5gHigh.toProto(); |
| mWifiLogProto.rxLinkSpeedCount6GLow = mRxLinkSpeedCount6gLow.toProto(); |
| mWifiLogProto.rxLinkSpeedCount6GMid = mRxLinkSpeedCount6gMid.toProto(); |
| mWifiLogProto.rxLinkSpeedCount6GHigh = mRxLinkSpeedCount6gHigh.toProto(); |
| |
| HealthMonitorMetrics healthMonitorMetrics = mWifiHealthMonitor.buildProto(); |
| if (healthMonitorMetrics != null) { |
| mWifiLogProto.healthMonitorMetrics = healthMonitorMetrics; |
| } |
| mWifiLogProto.bssidBlocklistStats = mBssidBlocklistStats.toProto(); |
| mWifiLogProto.connectionDurationStats = mConnectionDurationStats.toProto(); |
| mWifiLogProto.wifiOffMetrics = mWifiOffMetrics.toProto(); |
| mWifiLogProto.softApConfigLimitationMetrics = mSoftApConfigLimitationMetrics.toProto(); |
| mWifiLogProto.channelUtilizationHistogram = |
| new WifiMetricsProto.ChannelUtilizationHistogram(); |
| mWifiLogProto.channelUtilizationHistogram.utilization2G = |
| mChannelUtilizationHistogram2G.toProto(); |
| mWifiLogProto.channelUtilizationHistogram.utilizationAbove2G = |
| mChannelUtilizationHistogramAbove2G.toProto(); |
| mWifiLogProto.throughputMbpsHistogram = |
| new WifiMetricsProto.ThroughputMbpsHistogram(); |
| mWifiLogProto.throughputMbpsHistogram.tx2G = |
| mTxThroughputMbpsHistogram2G.toProto(); |
| mWifiLogProto.throughputMbpsHistogram.txAbove2G = |
| mTxThroughputMbpsHistogramAbove2G.toProto(); |
| mWifiLogProto.throughputMbpsHistogram.rx2G = |
| mRxThroughputMbpsHistogram2G.toProto(); |
| mWifiLogProto.throughputMbpsHistogram.rxAbove2G = |
| mRxThroughputMbpsHistogramAbove2G.toProto(); |
| mWifiLogProto.meteredNetworkStatsSaved = mMeteredNetworkStatsBuilder.toProto(false); |
| mWifiLogProto.meteredNetworkStatsSuggestion = mMeteredNetworkStatsBuilder.toProto(true); |
| |
| InitPartialScanStats initialPartialScanStats = new InitPartialScanStats(); |
| initialPartialScanStats.numScans = mInitPartialScanTotalCount; |
| initialPartialScanStats.numSuccessScans = mInitPartialScanSuccessCount; |
| initialPartialScanStats.numFailureScans = mInitPartialScanFailureCount; |
| initialPartialScanStats.successfulScanChannelCountHistogram = |
| mInitPartialScanSuccessHistogram.toProto(); |
| initialPartialScanStats.failedScanChannelCountHistogram = |
| mInitPartialScanFailureHistogram.toProto(); |
| mWifiLogProto.initPartialScanStats = initialPartialScanStats; |
| mWifiLogProto.carrierWifiMetrics = mCarrierWifiMetrics.toProto(); |
| mWifiLogProto.mainlineModuleVersion = mWifiHealthMonitor.getWifiStackVersion(); |
| mWifiLogProto.firstConnectAfterBootStats = mFirstConnectAfterBootStats; |
| mWifiLogProto.wifiToWifiSwitchStats = buildWifiToWifiSwitchStats(); |
| mWifiLogProto.bandwidthEstimatorStats = mWifiScoreCard.dumpBandwidthEstimatorStats(); |
| mWifiLogProto.passpointDeauthImminentScope = mPasspointDeauthImminentScope.toProto(); |
| mWifiLogProto.recentFailureAssociationStatus = |
| mRecentFailureAssociationStatus.toProto(); |
| } |
| } |
| |
| private WifiToWifiSwitchStats buildWifiToWifiSwitchStats() { |
| mWifiToWifiSwitchStats.makeBeforeBreakLingerDurationSeconds = |
| mMakeBeforeBreakLingeringDurationSeconds.toProto(); |
| return mWifiToWifiSwitchStats; |
| } |
| |
| private static int linkProbeFailureReasonToProto(int reason) { |
| switch (reason) { |
| case WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED: |
| return LinkProbeStats.LINK_PROBE_FAILURE_REASON_MCS_UNSUPPORTED; |
| case WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_NO_ACK: |
| return LinkProbeStats.LINK_PROBE_FAILURE_REASON_NO_ACK; |
| case WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_TIMEOUT: |
| return LinkProbeStats.LINK_PROBE_FAILURE_REASON_TIMEOUT; |
| case WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_ALREADY_STARTED: |
| return LinkProbeStats.LINK_PROBE_FAILURE_REASON_ALREADY_STARTED; |
| default: |
| return LinkProbeStats.LINK_PROBE_FAILURE_REASON_UNKNOWN; |
| } |
| } |
| |
| private NetworkSelectionExperimentDecisions[] makeNetworkSelectionExperimentDecisionsList() { |
| NetworkSelectionExperimentDecisions[] results = new NetworkSelectionExperimentDecisions[ |
| mNetworkSelectionExperimentPairNumChoicesCounts.size()]; |
| int i = 0; |
| for (Map.Entry<Pair<Integer, Integer>, NetworkSelectionExperimentResults> entry : |
| mNetworkSelectionExperimentPairNumChoicesCounts.entrySet()) { |
| NetworkSelectionExperimentDecisions result = new NetworkSelectionExperimentDecisions(); |
| result.experiment1Id = entry.getKey().first; |
| result.experiment2Id = entry.getKey().second; |
| result.sameSelectionNumChoicesCounter = |
| entry.getValue().sameSelectionNumChoicesCounter.toProto(); |
| result.differentSelectionNumChoicesCounter = |
| entry.getValue().differentSelectionNumChoicesCounter.toProto(); |
| results[i] = result; |
| i++; |
| } |
| return results; |
| } |
| |
| /** Sets the scoring experiment id to current value */ |
| private void consolidateScoringParams() { |
| synchronized (mLock) { |
| if (mScoringParams != null) { |
| int experimentIdentifier = mScoringParams.getExperimentIdentifier(); |
| if (experimentIdentifier == 0) { |
| mWifiLogProto.scoreExperimentId = ""; |
| } else { |
| mWifiLogProto.scoreExperimentId = "x" + experimentIdentifier; |
| } |
| } |
| } |
| } |
| |
| private WifiMetricsProto.NumConnectableNetworksBucket[] makeNumConnectableNetworksBucketArray( |
| SparseIntArray sia) { |
| WifiMetricsProto.NumConnectableNetworksBucket[] array = |
| new WifiMetricsProto.NumConnectableNetworksBucket[sia.size()]; |
| for (int i = 0; i < sia.size(); i++) { |
| WifiMetricsProto.NumConnectableNetworksBucket keyVal = |
| new WifiMetricsProto.NumConnectableNetworksBucket(); |
| keyVal.numConnectableNetworks = sia.keyAt(i); |
| keyVal.count = sia.valueAt(i); |
| array[i] = keyVal; |
| } |
| return array; |
| } |
| |
| private WifiMetricsProto.WifiConfigStoreIO.DurationBucket[] |
| makeWifiConfigStoreIODurationBucketArray(SparseIntArray sia) { |
| MetricsUtils.GenericBucket[] genericBuckets = |
| MetricsUtils.linearHistogramToGenericBuckets(sia, |
| WIFI_CONFIG_STORE_IO_DURATION_BUCKET_RANGES_MS); |
| WifiMetricsProto.WifiConfigStoreIO.DurationBucket[] array = |
| new WifiMetricsProto.WifiConfigStoreIO.DurationBucket[genericBuckets.length]; |
| try { |
| for (int i = 0; i < genericBuckets.length; i++) { |
| array[i] = new WifiMetricsProto.WifiConfigStoreIO.DurationBucket(); |
| array[i].rangeStartMs = toIntExact(genericBuckets[i].start); |
| array[i].rangeEndMs = toIntExact(genericBuckets[i].end); |
| array[i].count = genericBuckets[i].count; |
| } |
| } catch (ArithmeticException e) { |
| // Return empty array on any overflow errors. |
| array = new WifiMetricsProto.WifiConfigStoreIO.DurationBucket[0]; |
| } |
| return array; |
| } |
| |
| /** |
| * Clear all WifiMetrics, except for currentConnectionEvent and Open Network Notification |
| * feature enabled state, blocklist size. |
| */ |
| private void clear() { |
| synchronized (mLock) { |
| mConnectionEventList.clear(); |
| // Add in-progress events back |
| mConnectionEventList.addAll(mCurrentConnectionEventPerIface.values()); |
| |
| mScanReturnEntries.clear(); |
| mWifiSystemStateEntries.clear(); |
| mRecordStartTimeSec = mClock.getElapsedSinceBootMillis() / 1000; |
| mRssiPollCountsMap.clear(); |
| mRssiDeltaCounts.clear(); |
| mLinkSpeedCounts.clear(); |
| mTxLinkSpeedCount2g.clear(); |
| mTxLinkSpeedCount5gLow.clear(); |
| mTxLinkSpeedCount5gMid.clear(); |
| mTxLinkSpeedCount5gHigh.clear(); |
| mTxLinkSpeedCount6gLow.clear(); |
| mTxLinkSpeedCount6gMid.clear(); |
| mTxLinkSpeedCount6gHigh.clear(); |
| mRxLinkSpeedCount2g.clear(); |
| mRxLinkSpeedCount5gLow.clear(); |
| mRxLinkSpeedCount5gMid.clear(); |
| mRxLinkSpeedCount5gHigh.clear(); |
| mRxLinkSpeedCount6gLow.clear(); |
| mRxLinkSpeedCount6gMid.clear(); |
| mRxLinkSpeedCount6gHigh.clear(); |
| mWifiAlertReasonCounts.clear(); |
| mMakeBeforeBreakLingeringDurationSeconds.clear(); |
| mWifiScoreCounts.clear(); |
| mWifiUsabilityScoreCounts.clear(); |
| mWifiLogProto.clear(); |
| mScanResultRssiTimestampMillis = -1; |
| mSoftApManagerReturnCodeCounts.clear(); |
| mStaEventList.clear(); |
| mUserActionEventList.clear(); |
| mWifiAwareMetrics.clear(); |
| mRttMetrics.clear(); |
| mTotalSsidsInScanHistogram.clear(); |
| mTotalBssidsInScanHistogram.clear(); |
| mAvailableOpenSsidsInScanHistogram.clear(); |
| mAvailableOpenBssidsInScanHistogram.clear(); |
| mAvailableSavedSsidsInScanHistogram.clear(); |
| mAvailableSavedBssidsInScanHistogram.clear(); |
| mAvailableOpenOrSavedSsidsInScanHistogram.clear(); |
| mAvailableOpenOrSavedBssidsInScanHistogram.clear(); |
| mAvailableSavedPasspointProviderProfilesInScanHistogram.clear(); |
| mAvailableSavedPasspointProviderBssidsInScanHistogram.clear(); |
| mPnoScanMetrics.clear(); |
| mWifiLinkLayerUsageStats.clear(); |
| mRadioStats.clear(); |
| mConnectToNetworkNotificationCount.clear(); |
| mConnectToNetworkNotificationActionCount.clear(); |
| mNumOpenNetworkRecommendationUpdates = 0; |
| mNumOpenNetworkConnectMessageFailedToSend = 0; |
| mObservedHotspotR1ApInScanHistogram.clear(); |
| mObservedHotspotR2ApInScanHistogram.clear(); |
| mObservedHotspotR3ApInScanHistogram.clear(); |
| mObservedHotspotR1EssInScanHistogram.clear(); |
| mObservedHotspotR2EssInScanHistogram.clear(); |
| mObservedHotspotR3EssInScanHistogram.clear(); |
| mObservedHotspotR1ApsPerEssInScanHistogram.clear(); |
| mObservedHotspotR2ApsPerEssInScanHistogram.clear(); |
| mObservedHotspotR3ApsPerEssInScanHistogram.clear(); |
| mSoftApEventListTethered.clear(); |
| mSoftApEventListLocalOnly.clear(); |
| mWifiWakeMetrics.clear(); |
| mObserved80211mcApInScanHistogram.clear(); |
| mWifiIsUnusableList.clear(); |
| mInstalledPasspointProfileTypeForR1.clear(); |
| mInstalledPasspointProfileTypeForR2.clear(); |
| mWifiUsabilityStatsListGood.clear(); |
| mWifiUsabilityStatsListBad.clear(); |
| mWifiUsabilityStatsEntriesList.clear(); |
| mMobilityStatePnoStatsMap.clear(); |
| mWifiP2pMetrics.clear(); |
| mDppMetrics.clear(); |
| mWifiUsabilityStatsCounter = 0; |
| mLastBssid = null; |
| mLastFrequency = -1; |
| mSeqNumInsideFramework = 0; |
| mLastWifiUsabilityScore = -1; |
| mLastWifiUsabilityScoreNoReset = -1; |
| mLastPredictionHorizonSec = -1; |
| mLastPredictionHorizonSecNoReset = -1; |
| mSeqNumToFramework = -1; |
| mProbeStatusSinceLastUpdate = |
| android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE; |
| mProbeElapsedTimeSinceLastUpdateMs = -1; |
| mProbeMcsRateSinceLastUpdate = -1; |
| mScoreBreachLowTimeMillis = -1; |
| mMeteredNetworkStatsBuilder.clear(); |
| mWifiConfigStoreReadDurationHistogram.clear(); |
| mWifiConfigStoreWriteDurationHistogram.clear(); |
| mLinkProbeSuccessRssiCounts.clear(); |
| mLinkProbeFailureRssiCounts.clear(); |
| mLinkProbeSuccessLinkSpeedCounts.clear(); |
| mLinkProbeFailureLinkSpeedCounts.clear(); |
| mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram.clear(); |
| mLinkProbeFailureSecondsSinceLastTxSuccessHistogram.clear(); |
| mLinkProbeSuccessElapsedTimeMsHistogram.clear(); |
| mLinkProbeFailureReasonCounts.clear(); |
| mLinkProbeExperimentProbeCounts.clear(); |
| mLinkProbeStaEventCount = 0; |
| mNetworkSelectionExperimentPairNumChoicesCounts.clear(); |
| mWifiNetworkSuggestionApiLog.clear(); |
| mWifiNetworkRequestApiMatchSizeHistogram.clear(); |
| mWifiNetworkRequestApiConnectionDurationSecOnPrimaryIfaceHistogram.clear(); |
| mWifiNetworkRequestApiConnectionDurationSecOnSecondaryIfaceHistogram.clear(); |
| mWifiNetworkRequestApiConcurrentConnectionDurationSecHistogram.clear(); |
| mWifiNetworkSuggestionApiListSizeHistogram.clear(); |
| mWifiNetworkSuggestionApiAppTypeCounter.clear(); |
| mUserApprovalSuggestionAppUiReactionList.clear(); |
| mUserApprovalCarrierUiReactionList.clear(); |
| mWifiLockHighPerfAcqDurationSecHistogram.clear(); |
| mWifiLockLowLatencyAcqDurationSecHistogram.clear(); |
| mWifiLockHighPerfActiveSessionDurationSecHistogram.clear(); |
| mWifiLockLowLatencyActiveSessionDurationSecHistogram.clear(); |
| mWifiLockStats.clear(); |
| mWifiToggleStats.clear(); |
| mChannelUtilizationHistogram2G.clear(); |
| mChannelUtilizationHistogramAbove2G.clear(); |
| mTxThroughputMbpsHistogram2G.clear(); |
| mRxThroughputMbpsHistogram2G.clear(); |
| mTxThroughputMbpsHistogramAbove2G.clear(); |
| mRxThroughputMbpsHistogramAbove2G.clear(); |
| mPasspointProvisionFailureCounts.clear(); |
| mNumProvisionSuccess = 0; |
| mBssidBlocklistStats = new BssidBlocklistStats(); |
| mConnectionDurationStats.clear(); |
| mWifiLogProto.isExternalWifiScorerOn = false; |
| mWifiOffMetrics.clear(); |
| mSoftApConfigLimitationMetrics.clear(); |
| //Initial partial scan metrics |
| mInitPartialScanTotalCount = 0; |
| mInitPartialScanSuccessCount = 0; |
| mInitPartialScanFailureCount = 0; |
| mInitPartialScanSuccessHistogram.clear(); |
| mInitPartialScanFailureHistogram.clear(); |
| mCarrierWifiMetrics.clear(); |
| mFirstConnectAfterBootStats = null; |
| mWifiToWifiSwitchStats.clear(); |
| mPasspointDeauthImminentScope.clear(); |
| mRecentFailureAssociationStatus.clear(); |
| mWifiNetworkSuggestionPriorityGroups.clear(); |
| mWifiNetworkSuggestionCoexistSavedNetworks.clear(); |
| } |
| } |
| |
| /** |
| * Set screen state (On/Off) |
| */ |
| private void setScreenState(boolean screenOn) { |
| synchronized (mLock) { |
| mScreenOn = screenOn; |
| } |
| } |
| |
| private boolean isPrimary(String ifaceName) { |
| return mIfaceToRoleMap.get(ifaceName) == ActiveModeManager.ROLE_CLIENT_PRIMARY; |
| } |
| |
| /** |
| * Set wifi state (WIFI_UNKNOWN, WIFI_DISABLED, WIFI_DISCONNECTED, WIFI_ASSOCIATED) |
| */ |
| public void setWifiState(String ifaceName, int wifiState) { |
| synchronized (mLock) { |
| mWifiState = wifiState; |
| // set wifi priority over setting when any STA gets connected. |
| if (wifiState == WifiMetricsProto.WifiLog.WIFI_ASSOCIATED) { |
| mWifiWins = true; |
| mWifiWinsUsabilityScore = true; |
| } |
| if (isPrimary(ifaceName) && (wifiState == WifiMetricsProto.WifiLog.WIFI_DISCONNECTED |
| || wifiState == WifiMetricsProto.WifiLog.WIFI_DISABLED)) { |
| mWifiStatusBuilder = new WifiStatusBuilder(); |
| } |
| } |
| } |
| |
| /** |
| * Message handler for interesting WifiMonitor messages. Generates StaEvents |
| */ |
| private void processMessage(Message msg) { |
| String ifaceName = msg.getData().getString(WifiMonitor.KEY_IFACE); |
| |
| StaEvent event = new StaEvent(); |
| boolean logEvent = true; |
| switch (msg.what) { |
| case WifiMonitor.ASSOCIATION_REJECTION_EVENT: |
| event.type = StaEvent.TYPE_ASSOCIATION_REJECTION_EVENT; |
| AssocRejectEventInfo assocRejectEventInfo = (AssocRejectEventInfo) msg.obj; |
| event.associationTimedOut = assocRejectEventInfo.timedOut; |
| event.status = assocRejectEventInfo.statusCode; |
| break; |
| case WifiMonitor.AUTHENTICATION_FAILURE_EVENT: |
| event.type = StaEvent.TYPE_AUTHENTICATION_FAILURE_EVENT; |
| switch (msg.arg1) { |
| case WifiManager.ERROR_AUTH_FAILURE_NONE: |
| event.authFailureReason = StaEvent.AUTH_FAILURE_NONE; |
| break; |
| case WifiManager.ERROR_AUTH_FAILURE_TIMEOUT: |
| event.authFailureReason = StaEvent.AUTH_FAILURE_TIMEOUT; |
| break; |
| case WifiManager.ERROR_AUTH_FAILURE_WRONG_PSWD: |
| event.authFailureReason = StaEvent.AUTH_FAILURE_WRONG_PSWD; |
| break; |
| case WifiManager.ERROR_AUTH_FAILURE_EAP_FAILURE: |
| event.authFailureReason = StaEvent.AUTH_FAILURE_EAP_FAILURE; |
| break; |
| default: |
| break; |
| } |
| break; |
| case WifiMonitor.NETWORK_CONNECTION_EVENT: |
| event.type = StaEvent.TYPE_NETWORK_CONNECTION_EVENT; |
| break; |
| case WifiMonitor.NETWORK_DISCONNECTION_EVENT: |
| event.type = StaEvent.TYPE_NETWORK_DISCONNECTION_EVENT; |
| DisconnectEventInfo disconnectEventInfo = (DisconnectEventInfo) msg.obj; |
| event.reason = disconnectEventInfo.reasonCode; |
| event.localGen = disconnectEventInfo.locallyGenerated; |
| break; |
| case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: |
| logEvent = false; |
| StateChangeResult stateChangeResult = (StateChangeResult) msg.obj; |
| mSupplicantStateChangeBitmask |= supplicantStateToBit(stateChangeResult.state); |
| break; |
| case WifiMonitor.ASSOCIATED_BSSID_EVENT: |
| event.type = StaEvent.TYPE_CMD_ASSOCIATED_BSSID; |
| break; |
| case WifiMonitor.TARGET_BSSID_EVENT: |
| event.type = StaEvent.TYPE_CMD_TARGET_BSSID; |
| break; |
| default: |
| return; |
| } |
| if (logEvent) { |
| addStaEvent(ifaceName, event); |
| } |
| } |
| /** |
| * Log a StaEvent from ClientModeImpl. The StaEvent must not be one of the supplicant |
| * generated event types, which are logged through 'sendMessage' |
| * @param type StaEvent.EventType describing the event |
| */ |
| public void logStaEvent(String ifaceName, int type) { |
| logStaEvent(ifaceName, type, StaEvent.DISCONNECT_UNKNOWN, null); |
| } |
| /** |
| * Log a StaEvent from ClientModeImpl. The StaEvent must not be one of the supplicant |
| * generated event types, which are logged through 'sendMessage' |
| * @param type StaEvent.EventType describing the event |
| * @param config WifiConfiguration for a framework initiated connection attempt |
| */ |
| public void logStaEvent(String ifaceName, int type, WifiConfiguration config) { |
| logStaEvent(ifaceName, type, StaEvent.DISCONNECT_UNKNOWN, config); |
| } |
| /** |
| * Log a StaEvent from ClientModeImpl. The StaEvent must not be one of the supplicant |
| * generated event types, which are logged through 'sendMessage' |
| * @param type StaEvent.EventType describing the event |
| * @param frameworkDisconnectReason StaEvent.FrameworkDisconnectReason explaining why framework |
| * initiated a FRAMEWORK_DISCONNECT |
| */ |
| public void logStaEvent(String ifaceName, int type, int frameworkDisconnectReason) { |
| logStaEvent(ifaceName, type, frameworkDisconnectReason, null); |
| } |
| /** |
| * Log a StaEvent from ClientModeImpl. The StaEvent must not be one of the supplicant |
| * generated event types, which are logged through 'sendMessage' |
| * @param type StaEvent.EventType describing the event |
| * @param frameworkDisconnectReason StaEvent.FrameworkDisconnectReason explaining why framework |
| * initiated a FRAMEWORK_DISCONNECT |
| * @param config WifiConfiguration for a framework initiated connection attempt |
| */ |
| public void logStaEvent(String ifaceName, int type, int frameworkDisconnectReason, |
| WifiConfiguration config) { |
| switch (type) { |
| case StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL: |
| case StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST: |
| case StaEvent.TYPE_CMD_IP_REACHABILITY_LOST: |
| case StaEvent.TYPE_CMD_START_CONNECT: |
| case StaEvent.TYPE_CMD_START_ROAM: |
| case StaEvent.TYPE_CONNECT_NETWORK: |
| case StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK: |
| mWifiStatusBuilder.setValidated(true); |
| case StaEvent.TYPE_FRAMEWORK_DISCONNECT: |
| case StaEvent.TYPE_SCORE_BREACH: |
| case StaEvent.TYPE_MAC_CHANGE: |
| case StaEvent.TYPE_WIFI_ENABLED: |
| case StaEvent.TYPE_WIFI_DISABLED: |
| case StaEvent.TYPE_WIFI_USABILITY_SCORE_BREACH: |
| break; |
| default: |
| Log.e(TAG, "Unknown StaEvent:" + type); |
| return; |
| } |
| StaEvent event = new StaEvent(); |
| event.type = type; |
| if (frameworkDisconnectReason != StaEvent.DISCONNECT_UNKNOWN) { |
| event.frameworkDisconnectReason = frameworkDisconnectReason; |
| } |
| event.configInfo = createConfigInfo(config); |
| addStaEvent(ifaceName, event); |
| } |
| |
| private void addStaEvent(String ifaceName, StaEvent staEvent) { |
| // Nano proto runtime will throw a NPE during serialization if interfaceName is null |
| if (ifaceName == null) { |
| Log.wtf(TAG, "Null StaEvent.ifaceName: " + staEventToString(staEvent)); |
| return; |
| } |
| staEvent.interfaceName = ifaceName; |
| staEvent.interfaceRole = convertIfaceToEnum(ifaceName); |
| staEvent.startTimeMillis = mClock.getElapsedSinceBootMillis(); |
| staEvent.lastRssi = mLastPollRssi; |
| staEvent.lastFreq = mLastPollFreq; |
| staEvent.lastLinkSpeed = mLastPollLinkSpeed; |
| staEvent.supplicantStateChangesBitmask = mSupplicantStateChangeBitmask; |
| staEvent.lastScore = mLastScore; |
| staEvent.lastWifiUsabilityScore = mLastWifiUsabilityScore; |
| staEvent.lastPredictionHorizonSec = mLastPredictionHorizonSec; |
| staEvent.mobileTxBytes = mFacade.getMobileTxBytes(); |
| staEvent.mobileRxBytes = mFacade.getMobileRxBytes(); |
| staEvent.totalTxBytes = mFacade.getTotalTxBytes(); |
| staEvent.totalRxBytes = mFacade.getTotalRxBytes(); |
| staEvent.screenOn = mScreenOn; |
| if (mWifiDataStall != null) { |
| staEvent.isCellularDataAvailable = mWifiDataStall.isCellularDataAvailable(); |
| } |
| staEvent.isAdaptiveConnectivityEnabled = mAdaptiveConnectivityEnabled; |
| mSupplicantStateChangeBitmask = 0; |
| mLastPollRssi = -127; |
| mLastPollFreq = -1; |
| mLastPollLinkSpeed = -1; |
| mLastPollRxLinkSpeed = -1; |
| mLastScore = -1; |
| mLastWifiUsabilityScore = -1; |
| mLastPredictionHorizonSec = -1; |
| synchronized (mLock) { |
| mStaEventList.add(new StaEventWithTime(staEvent, mClock.getWallClockMillis())); |
| // Prune StaEventList if it gets too long |
| if (mStaEventList.size() > MAX_STA_EVENTS) mStaEventList.remove(); |
| } |
| } |
| |
| private ConfigInfo createConfigInfo(WifiConfiguration config) { |
| if (config == null) return null; |
| ConfigInfo info = new ConfigInfo(); |
| info.allowedKeyManagement = bitSetToInt(config.allowedKeyManagement); |
| info.allowedProtocols = bitSetToInt(config.allowedProtocols); |
| info.allowedAuthAlgorithms = bitSetToInt(config.allowedAuthAlgorithms); |
| info.allowedPairwiseCiphers = bitSetToInt(config.allowedPairwiseCiphers); |
| info.allowedGroupCiphers = bitSetToInt(config.allowedGroupCiphers); |
| info.hiddenSsid = config.hiddenSSID; |
| info.isPasspoint = config.isPasspoint(); |
| info.isEphemeral = config.isEphemeral(); |
| info.hasEverConnected = config.getNetworkSelectionStatus().hasEverConnected(); |
| ScanResult candidate = config.getNetworkSelectionStatus().getCandidate(); |
| if (candidate != null) { |
| info.scanRssi = candidate.level; |
| info.scanFreq = candidate.frequency; |
| } |
| return info; |
| } |
| |
| private static final int[] WIFI_MONITOR_EVENTS = { |
| WifiMonitor.ASSOCIATION_REJECTION_EVENT, |
| WifiMonitor.AUTHENTICATION_FAILURE_EVENT, |
| WifiMonitor.NETWORK_CONNECTION_EVENT, |
| WifiMonitor.NETWORK_DISCONNECTION_EVENT, |
| WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT, |
| WifiMonitor.ASSOCIATED_BSSID_EVENT, |
| WifiMonitor.TARGET_BSSID_EVENT, |
| }; |
| |
| public void registerForWifiMonitorEvents(String ifaceName) { |
| for (int event : WIFI_MONITOR_EVENTS) { |
| mWifiMonitor.registerHandler(ifaceName, event, mHandler); |
| } |
| } |
| |
| public void deregisterForWifiMonitorEvents(String ifaceName) { |
| for (int event : WIFI_MONITOR_EVENTS) { |
| mWifiMonitor.deregisterHandler(ifaceName, event, mHandler); |
| } |
| } |
| |
| public WifiAwareMetrics getWifiAwareMetrics() { |
| return mWifiAwareMetrics; |
| } |
| |
| public WifiWakeMetrics getWakeupMetrics() { |
| return mWifiWakeMetrics; |
| } |
| |
| public RttMetrics getRttMetrics() { |
| return mRttMetrics; |
| } |
| |
| // Rather than generate a StaEvent for each SUPPLICANT_STATE_CHANGE, cache these in a bitmask |
| // and attach it to the next event which is generated. |
| private int mSupplicantStateChangeBitmask = 0; |
| |
| /** |
| * Converts a SupplicantState value to a single bit, with position defined by |
| * {@code StaEvent.SupplicantState} |
| */ |
| public static int supplicantStateToBit(SupplicantState state) { |
| switch(state) { |
| case DISCONNECTED: |
| return 1 << StaEvent.STATE_DISCONNECTED; |
| case INTERFACE_DISABLED: |
| return 1 << StaEvent.STATE_INTERFACE_DISABLED; |
| case INACTIVE: |
| return 1 << StaEvent.STATE_INACTIVE; |
| case SCANNING: |
| return 1 << StaEvent.STATE_SCANNING; |
| case AUTHENTICATING: |
| return 1 << StaEvent.STATE_AUTHENTICATING; |
| case ASSOCIATING: |
| return 1 << StaEvent.STATE_ASSOCIATING; |
| case ASSOCIATED: |
| return 1 << StaEvent.STATE_ASSOCIATED; |
| case FOUR_WAY_HANDSHAKE: |
| return 1 << StaEvent.STATE_FOUR_WAY_HANDSHAKE; |
| case GROUP_HANDSHAKE: |
| return 1 << StaEvent.STATE_GROUP_HANDSHAKE; |
| case COMPLETED: |
| return 1 << StaEvent.STATE_COMPLETED; |
| case DORMANT: |
| return 1 << StaEvent.STATE_DORMANT; |
| case UNINITIALIZED: |
| return 1 << StaEvent.STATE_UNINITIALIZED; |
| case INVALID: |
| return 1 << StaEvent.STATE_INVALID; |
| default: |
| Log.wtf(TAG, "Got unknown supplicant state: " + state.ordinal()); |
| return 0; |
| } |
| } |
| |
| private static String supplicantStateChangesBitmaskToString(int mask) { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("supplicantStateChangeEvents: {"); |
| if ((mask & (1 << StaEvent.STATE_DISCONNECTED)) > 0) sb.append(" DISCONNECTED"); |
| if ((mask & (1 << StaEvent.STATE_INTERFACE_DISABLED)) > 0) sb.append(" INTERFACE_DISABLED"); |
| if ((mask & (1 << StaEvent.STATE_INACTIVE)) > 0) sb.append(" INACTIVE"); |
| if ((mask & (1 << StaEvent.STATE_SCANNING)) > 0) sb.append(" SCANNING"); |
| if ((mask & (1 << StaEvent.STATE_AUTHENTICATING)) > 0) sb.append(" AUTHENTICATING"); |
| if ((mask & (1 << StaEvent.STATE_ASSOCIATING)) > 0) sb.append(" ASSOCIATING"); |
| if ((mask & (1 << StaEvent.STATE_ASSOCIATED)) > 0) sb.append(" ASSOCIATED"); |
| if ((mask & (1 << StaEvent.STATE_FOUR_WAY_HANDSHAKE)) > 0) sb.append(" FOUR_WAY_HANDSHAKE"); |
| if ((mask & (1 << StaEvent.STATE_GROUP_HANDSHAKE)) > 0) sb.append(" GROUP_HANDSHAKE"); |
| if ((mask & (1 << StaEvent.STATE_COMPLETED)) > 0) sb.append(" COMPLETED"); |
| if ((mask & (1 << StaEvent.STATE_DORMANT)) > 0) sb.append(" DORMANT"); |
| if ((mask & (1 << StaEvent.STATE_UNINITIALIZED)) > 0) sb.append(" UNINITIALIZED"); |
| if ((mask & (1 << StaEvent.STATE_INVALID)) > 0) sb.append(" INVALID"); |
| sb.append(" }"); |
| return sb.toString(); |
| } |
| |
| /** |
| * Returns a human readable string from a Sta Event. Only adds information relevant to the event |
| * type. |
| */ |
| public static String staEventToString(StaEvent event) { |
| if (event == null) return "<NULL>"; |
| StringBuilder sb = new StringBuilder(); |
| switch (event.type) { |
| case StaEvent.TYPE_ASSOCIATION_REJECTION_EVENT: |
| sb.append("ASSOCIATION_REJECTION_EVENT") |
| .append(" timedOut=").append(event.associationTimedOut) |
| .append(" status=").append(event.status).append(":") |
| .append(ISupplicantStaIfaceCallback.StatusCode.toString(event.status)); |
| break; |
| case StaEvent.TYPE_AUTHENTICATION_FAILURE_EVENT: |
| sb.append("AUTHENTICATION_FAILURE_EVENT reason=").append(event.authFailureReason) |
| .append(":").append(authFailureReasonToString(event.authFailureReason)); |
| break; |
| case StaEvent.TYPE_NETWORK_CONNECTION_EVENT: |
| sb.append("NETWORK_CONNECTION_EVENT"); |
| break; |
| case StaEvent.TYPE_NETWORK_DISCONNECTION_EVENT: |
| sb.append("NETWORK_DISCONNECTION_EVENT") |
| .append(" local_gen=").append(event.localGen) |
| .append(" reason=").append(event.reason).append(":") |
| .append(ISupplicantStaIfaceCallback.ReasonCode.toString( |
| (event.reason >= 0 ? event.reason : -1 * event.reason))); |
| break; |
| case StaEvent.TYPE_CMD_ASSOCIATED_BSSID: |
| sb.append("CMD_ASSOCIATED_BSSID"); |
| break; |
| case StaEvent.TYPE_CMD_IP_CONFIGURATION_SUCCESSFUL: |
| sb.append("CMD_IP_CONFIGURATION_SUCCESSFUL"); |
| break; |
| case StaEvent.TYPE_CMD_IP_CONFIGURATION_LOST: |
| sb.append("CMD_IP_CONFIGURATION_LOST"); |
| break; |
| case StaEvent.TYPE_CMD_IP_REACHABILITY_LOST: |
| sb.append("CMD_IP_REACHABILITY_LOST"); |
| break; |
| case StaEvent.TYPE_CMD_TARGET_BSSID: |
| sb.append("CMD_TARGET_BSSID"); |
| break; |
| case StaEvent.TYPE_CMD_START_CONNECT: |
| sb.append("CMD_START_CONNECT"); |
| break; |
| case StaEvent.TYPE_CMD_START_ROAM: |
| sb.append("CMD_START_ROAM"); |
| break; |
| case StaEvent.TYPE_CONNECT_NETWORK: |
| sb.append("CONNECT_NETWORK"); |
| break; |
| case StaEvent.TYPE_NETWORK_AGENT_VALID_NETWORK: |
| sb.append("NETWORK_AGENT_VALID_NETWORK"); |
| break; |
| case StaEvent.TYPE_FRAMEWORK_DISCONNECT: |
| sb.append("FRAMEWORK_DISCONNECT") |
| .append(" reason=") |
| .append(frameworkDisconnectReasonToString(event.frameworkDisconnectReason)); |
| break; |
| case StaEvent.TYPE_SCORE_BREACH: |
| sb.append("SCORE_BREACH"); |
| break; |
| case StaEvent.TYPE_MAC_CHANGE: |
| sb.append("MAC_CHANGE"); |
| break; |
| case StaEvent.TYPE_WIFI_ENABLED: |
| sb.append("WIFI_ENABLED"); |
| break; |
| case StaEvent.TYPE_WIFI_DISABLED: |
| sb.append("WIFI_DISABLED"); |
| break; |
| case StaEvent.TYPE_WIFI_USABILITY_SCORE_BREACH: |
| sb.append("WIFI_USABILITY_SCORE_BREACH"); |
| break; |
| case StaEvent.TYPE_LINK_PROBE: |
| sb.append("LINK_PROBE"); |
| sb.append(" linkProbeWasSuccess=").append(event.linkProbeWasSuccess); |
| if (event.linkProbeWasSuccess) { |
| sb.append(" linkProbeSuccessElapsedTimeMs=") |
| .append(event.linkProbeSuccessElapsedTimeMs); |
| } else { |
| sb.append(" linkProbeFailureReason=").append(event.linkProbeFailureReason); |
| } |
| break; |
| default: |
| sb.append("UNKNOWN " + event.type + ":"); |
| break; |
| } |
| if (event.lastRssi != -127) sb.append(" lastRssi=").append(event.lastRssi); |
| if (event.lastFreq != -1) sb.append(" lastFreq=").append(event.lastFreq); |
| if (event.lastLinkSpeed != -1) sb.append(" lastLinkSpeed=").append(event.lastLinkSpeed); |
| if (event.lastScore != -1) sb.append(" lastScore=").append(event.lastScore); |
| if (event.lastWifiUsabilityScore != -1) { |
| sb.append(" lastWifiUsabilityScore=").append(event.lastWifiUsabilityScore); |
| sb.append(" lastPredictionHorizonSec=").append(event.lastPredictionHorizonSec); |
| } |
| sb.append(" screenOn=").append(event.screenOn); |
| sb.append(" cellularData=").append(event.isCellularDataAvailable); |
| sb.append(" adaptiveConnectivity=").append(event.isAdaptiveConnectivityEnabled); |
| if (event.supplicantStateChangesBitmask != 0) { |
| sb.append(", ").append(supplicantStateChangesBitmaskToString( |
| event.supplicantStateChangesBitmask)); |
| } |
| if (event.configInfo != null) { |
| sb.append(", ").append(configInfoToString(event.configInfo)); |
| } |
| if (event.mobileTxBytes > 0) sb.append(" mobileTxBytes=").append(event.mobileTxBytes); |
| if (event.mobileRxBytes > 0) sb.append(" mobileRxBytes=").append(event.mobileRxBytes); |
| if (event.totalTxBytes > 0) sb.append(" totalTxBytes=").append(event.totalTxBytes); |
| if (event.totalRxBytes > 0) sb.append(" totalRxBytes=").append(event.totalRxBytes); |
| sb.append(" interfaceName=").append(event.interfaceName); |
| sb.append(" interfaceRole=").append(clientRoleEnumToString(event.interfaceRole)); |
| return sb.toString(); |
| } |
| |
| private int convertIfaceToEnum(String ifaceName) { |
| ActiveModeManager.ClientRole role = mIfaceToRoleMap.get(ifaceName); |
| if (role == ActiveModeManager.ROLE_CLIENT_SCAN_ONLY) { |
| return WifiMetricsProto.ROLE_CLIENT_SCAN_ONLY; |
| } else if (role == ActiveModeManager.ROLE_CLIENT_SECONDARY_TRANSIENT) { |
| return WifiMetricsProto.ROLE_CLIENT_SECONDARY_TRANSIENT; |
| } else if (role == ActiveModeManager.ROLE_CLIENT_LOCAL_ONLY) { |
| return WifiMetricsProto.ROLE_CLIENT_LOCAL_ONLY; |
| } else if (role == ActiveModeManager.ROLE_CLIENT_PRIMARY) { |
| return WifiMetricsProto.ROLE_CLIENT_PRIMARY; |
| } else if (role == ActiveModeManager.ROLE_CLIENT_SECONDARY_LONG_LIVED) { |
| return WifiMetricsProto.ROLE_CLIENT_SECONDARY_LONG_LIVED; |
| } |
| return WifiMetricsProto.ROLE_UNKNOWN; |
| } |
| |
| private static String clientRoleEnumToString(int role) { |
| switch (role) { |
| case WifiMetricsProto.ROLE_CLIENT_SCAN_ONLY: |
| return "ROLE_CLIENT_SCAN_ONLY"; |
| case WifiMetricsProto.ROLE_CLIENT_SECONDARY_TRANSIENT: |
| return "ROLE_CLIENT_SECONDARY_TRANSIENT"; |
| case WifiMetricsProto.ROLE_CLIENT_LOCAL_ONLY: |
| return "ROLE_CLIENT_LOCAL_ONLY"; |
| case WifiMetricsProto.ROLE_CLIENT_PRIMARY: |
| return "ROLE_CLIENT_PRIMARY"; |
| case WifiMetricsProto.ROLE_CLIENT_SECONDARY_LONG_LIVED: |
| return "ROLE_CLIENT_SECONDARY_LONG_LIVED"; |
| default: |
| return "ROLE_UNKNOWN"; |
| } |
| } |
| |
| private static String authFailureReasonToString(int authFailureReason) { |
| switch (authFailureReason) { |
| case StaEvent.AUTH_FAILURE_NONE: |
| return "ERROR_AUTH_FAILURE_NONE"; |
| case StaEvent.AUTH_FAILURE_TIMEOUT: |
| return "ERROR_AUTH_FAILURE_TIMEOUT"; |
| case StaEvent.AUTH_FAILURE_WRONG_PSWD: |
| return "ERROR_AUTH_FAILURE_WRONG_PSWD"; |
| case StaEvent.AUTH_FAILURE_EAP_FAILURE: |
| return "ERROR_AUTH_FAILURE_EAP_FAILURE"; |
| default: |
| return ""; |
| } |
| } |
| |
| private static String frameworkDisconnectReasonToString(int frameworkDisconnectReason) { |
| switch (frameworkDisconnectReason) { |
| case StaEvent.DISCONNECT_API: |
| return "DISCONNECT_API"; |
| case StaEvent.DISCONNECT_GENERIC: |
| return "DISCONNECT_GENERIC"; |
| case StaEvent.DISCONNECT_UNWANTED: |
| return "DISCONNECT_UNWANTED"; |
| case StaEvent.DISCONNECT_ROAM_WATCHDOG_TIMER: |
| return "DISCONNECT_ROAM_WATCHDOG_TIMER"; |
| case StaEvent.DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST: |
| return "DISCONNECT_P2P_DISCONNECT_WIFI_REQUEST"; |
| case StaEvent.DISCONNECT_RESET_SIM_NETWORKS: |
| return "DISCONNECT_RESET_SIM_NETWORKS"; |
| case StaEvent.DISCONNECT_MBB_NO_INTERNET: |
| return "DISCONNECT_MBB_NO_INTERNET"; |
| case StaEvent.DISCONNECT_NETWORK_REMOVED: |
| return "DISCONNECT_NETWORK_REMOVED"; |
| case StaEvent.DISCONNECT_NETWORK_METERED: |
| return "DISCONNECT_NETWORK_METERED"; |
| case StaEvent.DISCONNECT_NETWORK_TEMPORARY_DISABLED: |
| return "DISCONNECT_NETWORK_TEMPORARY_DISABLED"; |
| case StaEvent.DISCONNECT_NETWORK_PERMANENT_DISABLED: |
| return "DISCONNECT_NETWORK_PERMANENT_DISABLED"; |
| case StaEvent.DISCONNECT_CARRIER_OFFLOAD_DISABLED: |
| return "DISCONNECT_CARRIER_OFFLOAD_DISABLED"; |
| case StaEvent.DISCONNECT_PASSPOINT_TAC: |
| return "DISCONNECT_PASSPOINT_TAC"; |
| case StaEvent.DISCONNECT_VCN_REQUEST: |
| return "DISCONNECT_VCN_REQUEST"; |
| case StaEvent.DISCONNECT_UNKNOWN_NETWORK: |
| return "DISCONNECT_UNKNOWN_NETWORK"; |
| default: |
| return "DISCONNECT_UNKNOWN=" + frameworkDisconnectReason; |
| } |
| } |
| |
| private static String configInfoToString(ConfigInfo info) { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("ConfigInfo:") |
| .append(" allowed_key_management=").append(info.allowedKeyManagement) |
| .append(" allowed_protocols=").append(info.allowedProtocols) |
| .append(" allowed_auth_algorithms=").append(info.allowedAuthAlgorithms) |
| .append(" allowed_pairwise_ciphers=").append(info.allowedPairwiseCiphers) |
| .append(" allowed_group_ciphers=").append(info.allowedGroupCiphers) |
| .append(" hidden_ssid=").append(info.hiddenSsid) |
| .append(" is_passpoint=").append(info.isPasspoint) |
| .append(" is_ephemeral=").append(info.isEphemeral) |
| .append(" has_ever_connected=").append(info.hasEverConnected) |
| .append(" scan_rssi=").append(info.scanRssi) |
| .append(" scan_freq=").append(info.scanFreq); |
| return sb.toString(); |
| } |
| |
| /** |
| * Converts the first 31 bits of a BitSet to a little endian int |
| */ |
| private static int bitSetToInt(BitSet bits) { |
| int value = 0; |
| int nBits = bits.length() < 31 ? bits.length() : 31; |
| for (int i = 0; i < nBits; i++) { |
| value += bits.get(i) ? (1 << i) : 0; |
| } |
| return value; |
| } |
| private void incrementSsid(SparseIntArray sia, int element) { |
| increment(sia, Math.min(element, MAX_CONNECTABLE_SSID_NETWORK_BUCKET)); |
| } |
| private void incrementBssid(SparseIntArray sia, int element) { |
| increment(sia, Math.min(element, MAX_CONNECTABLE_BSSID_NETWORK_BUCKET)); |
| } |
| private void incrementTotalScanResults(SparseIntArray sia, int element) { |
| increment(sia, Math.min(element, MAX_TOTAL_SCAN_RESULTS_BUCKET)); |
| } |
| private void incrementTotalScanSsids(SparseIntArray sia, int element) { |
| increment(sia, Math.min(element, MAX_TOTAL_SCAN_RESULT_SSIDS_BUCKET)); |
| } |
| private void incrementTotalPasspointAps(SparseIntArray sia, int element) { |
| increment(sia, Math.min(element, MAX_TOTAL_PASSPOINT_APS_BUCKET)); |
| } |
| private void incrementTotalUniquePasspointEss(SparseIntArray sia, int element) { |
| increment(sia, Math.min(element, MAX_TOTAL_PASSPOINT_UNIQUE_ESS_BUCKET)); |
| } |
| private void incrementPasspointPerUniqueEss(SparseIntArray sia, int element) { |
| increment(sia, Math.min(element, MAX_PASSPOINT_APS_PER_UNIQUE_ESS_BUCKET)); |
| } |
| private void increment80211mcAps(SparseIntArray sia, int element) { |
| increment(sia, Math.min(element, MAX_TOTAL_80211MC_APS_BUCKET)); |
| } |
| private void increment(SparseIntArray sia, int element) { |
| int count = sia.get(element); |
| sia.put(element, count + 1); |
| } |
| |
| private static class StaEventWithTime { |
| public StaEvent staEvent; |
| public long wallClockMillis; |
| |
| StaEventWithTime(StaEvent event, long wallClockMillis) { |
| staEvent = event; |
| this.wallClockMillis = wallClockMillis; |
| } |
| |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| Calendar c = Calendar.getInstance(); |
| c.setTimeInMillis(wallClockMillis); |
| if (wallClockMillis != 0) { |
| sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); |
| } else { |
| sb.append(" "); |
| } |
| sb.append(" ").append(staEventToString(staEvent)); |
| return sb.toString(); |
| } |
| } |
| |
| private LinkedList<WifiIsUnusableWithTime> mWifiIsUnusableList = |
| new LinkedList<WifiIsUnusableWithTime>(); |
| private long mTxScucessDelta = 0; |
| private long mTxRetriesDelta = 0; |
| private long mTxBadDelta = 0; |
| private long mRxSuccessDelta = 0; |
| private long mLlStatsUpdateTimeDelta = 0; |
| private long mLlStatsLastUpdateTime = 0; |
| private int mLastScoreNoReset = -1; |
| private long mLastDataStallTime = Long.MIN_VALUE; |
| |
| private static class WifiIsUnusableWithTime { |
| public WifiIsUnusableEvent event; |
| public long wallClockMillis; |
| |
| WifiIsUnusableWithTime(WifiIsUnusableEvent event, long wallClockMillis) { |
| this.event = event; |
| this.wallClockMillis = wallClockMillis; |
| } |
| |
| public String toString() { |
| if (event == null) return "<NULL>"; |
| StringBuilder sb = new StringBuilder(); |
| if (wallClockMillis != 0) { |
| Calendar c = Calendar.getInstance(); |
| c.setTimeInMillis(wallClockMillis); |
| sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)); |
| } else { |
| sb.append(" "); |
| } |
| sb.append(" "); |
| |
| switch(event.type) { |
| case WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX: |
| sb.append("DATA_STALL_BAD_TX"); |
| break; |
| case WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX: |
| sb.append("DATA_STALL_TX_WITHOUT_RX"); |
| break; |
| case WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH: |
| sb.append("DATA_STALL_BOTH"); |
| break; |
| case WifiIsUnusableEvent.TYPE_FIRMWARE_ALERT: |
| sb.append("FIRMWARE_ALERT"); |
| break; |
| case WifiIsUnusableEvent.TYPE_IP_REACHABILITY_LOST: |
| sb.append("IP_REACHABILITY_LOST"); |
| break; |
| default: |
| sb.append("UNKNOWN " + event.type); |
| break; |
| } |
| |
| sb.append(" lastScore=").append(event.lastScore); |
| sb.append(" txSuccessDelta=").append(event.txSuccessDelta); |
| sb.append(" txRetriesDelta=").append(event.txRetriesDelta); |
| sb.append(" txBadDelta=").append(event.txBadDelta); |
| sb.append(" rxSuccessDelta=").append(event.rxSuccessDelta); |
| sb.append(" packetUpdateTimeDelta=").append(event.packetUpdateTimeDelta) |
| .append("ms"); |
| if (event.firmwareAlertCode != -1) { |
| sb.append(" firmwareAlertCode=").append(event.firmwareAlertCode); |
| } |
| sb.append(" lastWifiUsabilityScore=").append(event.lastWifiUsabilityScore); |
| sb.append(" lastPredictionHorizonSec=").append(event.lastPredictionHorizonSec); |
| sb.append(" screenOn=").append(event.screenOn); |
| sb.append(" mobileTxBytes=").append(event.mobileTxBytes); |
| sb.append(" mobileRxBytes=").append(event.mobileRxBytes); |
| sb.append(" totalTxBytes=").append(event.totalTxBytes); |
| sb.append(" totalRxBytes=").append(event.totalRxBytes); |
| return sb.toString(); |
| } |
| } |
| |
| /** |
| * Converts MeteredOverride enum to UserActionEvent type. |
| * @param value |
| */ |
| public static int convertMeteredOverrideEnumToUserActionEventType(@MeteredOverride int value) { |
| int result = UserActionEvent.EVENT_UNKNOWN; |
| switch(value) { |
| case WifiConfiguration.METERED_OVERRIDE_NONE: |
| result = UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_AUTO; |
| break; |
| case WifiConfiguration.METERED_OVERRIDE_METERED: |
| result = UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_METERED; |
| break; |
| case WifiConfiguration.METERED_OVERRIDE_NOT_METERED: |
| result = UserActionEvent.EVENT_CONFIGURE_METERED_STATUS_UNMETERED; |
| break; |
| } |
| return result; |
| } |
| |
| /** |
| * Converts Adaptive Connectivity state to UserActionEvent type. |
| * @param value |
| */ |
| public static int convertAdaptiveConnectivityStateToUserActionEventType(boolean value) { |
| return value ? UserActionEvent.EVENT_CONFIGURE_ADAPTIVE_CONNECTIVITY_ON |
| : UserActionEvent.EVENT_CONFIGURE_ADAPTIVE_CONNECTIVITY_OFF; |
| } |
| |
| static class MeteredNetworkStatsBuilder { |
| // A map from network identifier to MeteredDetail |
| Map<String, MeteredDetail> mNetworkMap = new ArrayMap<>(); |
| |
| void put(WifiConfiguration config, boolean detectedAsMetered) { |
| MeteredDetail meteredDetail = new MeteredDetail(); |
| boolean isMetered = detectedAsMetered; |
| if (config.meteredOverride == WifiConfiguration.METERED_OVERRIDE_METERED) { |
| isMetered = true; |
| } else if (config.meteredOverride == WifiConfiguration.METERED_OVERRIDE_NOT_METERED) { |
| isMetered = false; |
| } |
| meteredDetail.isMetered = isMetered; |
| meteredDetail.isMeteredOverrideSet = config.meteredOverride |
| != WifiConfiguration.METERED_OVERRIDE_NONE; |
| meteredDetail.isFromSuggestion = config.fromWifiNetworkSuggestion; |
| mNetworkMap.put(config.getProfileKey(), meteredDetail); |
| } |
| |
| void clear() { |
| mNetworkMap.clear(); |
| } |
| |
| MeteredNetworkStats toProto(boolean isFromSuggestion) { |
| MeteredNetworkStats result = new MeteredNetworkStats(); |
| for (MeteredDetail meteredDetail : mNetworkMap.values()) { |
| if (meteredDetail.isFromSuggestion != isFromSuggestion) { |
| continue; |
| } |
| if (meteredDetail.isMetered) { |
| result.numMetered++; |
| } else { |
| result.numUnmetered++; |
| } |
| if (meteredDetail.isMeteredOverrideSet) { |
| if (meteredDetail.isMetered) { |
| result.numOverrideMetered++; |
| } else { |
| result.numOverrideUnmetered++; |
| } |
| } |
| } |
| return result; |
| } |
| |
| static class MeteredDetail { |
| public boolean isMetered; |
| public boolean isMeteredOverrideSet; |
| public boolean isFromSuggestion; |
| } |
| } |
| |
| /** |
| * Add metered information of this network. |
| * @param config WifiConfiguration representing the netework. |
| * @param detectedAsMetered is the network detected as metered. |
| */ |
| public void addMeteredStat(WifiConfiguration config, boolean detectedAsMetered) { |
| synchronized (mLock) { |
| if (config == null) { |
| return; |
| } |
| mMeteredNetworkStatsBuilder.put(config, detectedAsMetered); |
| } |
| } |
| /** |
| * Logs a UserActionEvent without a target network. |
| * @param eventType the type of user action (one of WifiMetricsProto.UserActionEvent.EventType) |
| */ |
| public void logUserActionEvent(int eventType) { |
| logUserActionEvent(eventType, -1); |
| } |
| |
| /** |
| * Logs a UserActionEvent which has a target network. |
| * @param eventType the type of user action (one of WifiMetricsProto.UserActionEvent.EventType) |
| * @param networkId networkId of the target network. |
| */ |
| public void logUserActionEvent(int eventType, int networkId) { |
| synchronized (mLock) { |
| mUserActionEventList.add(new UserActionEventWithTime(eventType, networkId)); |
| if (mUserActionEventList.size() > MAX_USER_ACTION_EVENTS) { |
| mUserActionEventList.remove(); |
| } |
| } |
| } |
| |
| /** |
| * Logs a UserActionEvent, directly specifying the target network's properties. |
| * @param eventType the type of user action (one of WifiMetricsProto.UserActionEvent.EventType) |
| * @param isEphemeral true if the target network is ephemeral. |
| * @param isPasspoint true if the target network is passpoint. |
| */ |
| public void logUserActionEvent(int eventType, boolean isEphemeral, boolean isPasspoint) { |
| synchronized (mLock) { |
| TargetNetworkInfo networkInfo = new TargetNetworkInfo(); |
| networkInfo.isEphemeral = isEphemeral; |
| networkInfo.isPasspoint = isPasspoint; |
| mUserActionEventList.add(new UserActionEventWithTime(eventType, networkInfo)); |
| if (mUserActionEventList.size() > MAX_USER_ACTION_EVENTS) { |
| mUserActionEventList.remove(); |
| } |
| } |
| } |
| |
| /** |
| * Update the difference between the last two WifiLinkLayerStats for WifiIsUnusableEvent |
| */ |
| public void updateWifiIsUnusableLinkLayerStats(long txSuccessDelta, long txRetriesDelta, |
| long txBadDelta, long rxSuccessDelta, long updateTimeDelta) { |
| mTxScucessDelta = txSuccessDelta; |
| mTxRetriesDelta = txRetriesDelta; |
| mTxBadDelta = txBadDelta; |
| mRxSuccessDelta = rxSuccessDelta; |
| mLlStatsUpdateTimeDelta = updateTimeDelta; |
| mLlStatsLastUpdateTime = mClock.getElapsedSinceBootMillis(); |
| } |
| |
| /** |
| * Clear the saved difference between the last two WifiLinkLayerStats |
| */ |
| public void resetWifiIsUnusableLinkLayerStats() { |
| mTxScucessDelta = 0; |
| mTxRetriesDelta = 0; |
| mTxBadDelta = 0; |
| mRxSuccessDelta = 0; |
| mLlStatsUpdateTimeDelta = 0; |
| mLlStatsLastUpdateTime = 0; |
| mLastDataStallTime = Long.MIN_VALUE; |
| } |
| |
| /** |
| * Log a WifiIsUnusableEvent |
| * @param triggerType WifiIsUnusableEvent.type describing the event |
| * @param ifaceName name of the interface. |
| */ |
| public void logWifiIsUnusableEvent(String ifaceName, int triggerType) { |
| logWifiIsUnusableEvent(ifaceName, triggerType, -1); |
| } |
| |
| /** |
| * Log a WifiIsUnusableEvent |
| * @param triggerType WifiIsUnusableEvent.type describing the event |
| * @param firmwareAlertCode WifiIsUnusableEvent.firmwareAlertCode for firmware alert code |
| * @param ifaceName name of the interface. |
| */ |
| public void logWifiIsUnusableEvent(String ifaceName, int triggerType, int firmwareAlertCode) { |
| if (!isPrimary(ifaceName)) { |
| return; |
| } |
| mScoreBreachLowTimeMillis = -1; |
| if (!mContext.getResources().getBoolean(R.bool.config_wifiIsUnusableEventMetricsEnabled)) { |
| return; |
| } |
| |
| long currentBootTime = mClock.getElapsedSinceBootMillis(); |
| switch (triggerType) { |
| case WifiIsUnusableEvent.TYPE_DATA_STALL_BAD_TX: |
| case WifiIsUnusableEvent.TYPE_DATA_STALL_TX_WITHOUT_RX: |
| case WifiIsUnusableEvent.TYPE_DATA_STALL_BOTH: |
| // Have a time-based throttle for generating WifiIsUnusableEvent from data stalls |
| if (currentBootTime < mLastDataStallTime + MIN_DATA_STALL_WAIT_MS) { |
| return; |
| } |
| mLastDataStallTime = currentBootTime; |
| break; |
| case WifiIsUnusableEvent.TYPE_FIRMWARE_ALERT: |
| break; |
| case WifiIsUnusableEvent.TYPE_IP_REACHABILITY_LOST: |
| break; |
| default: |
| Log.e(TAG, "Unknown WifiIsUnusableEvent: " + triggerType); |
| return; |
| } |
| |
| WifiIsUnusableEvent event = new WifiIsUnusableEvent(); |
| event.type = triggerType; |
| if (triggerType == WifiIsUnusableEvent.TYPE_FIRMWARE_ALERT) { |
| event.firmwareAlertCode = firmwareAlertCode; |
| } |
| event.startTimeMillis = currentBootTime; |
| event.lastScore = mLastScoreNoReset; |
| event.lastWifiUsabilityScore = mLastWifiUsabilityScoreNoReset; |
| event.lastPredictionHorizonSec = mLastPredictionHorizonSecNoReset; |
| event.txSuccessDelta = mTxScucessDelta; |
| event.txRetriesDelta = mTxRetriesDelta; |
| event.txBadDelta = mTxBadDelta; |
| event.rxSuccessDelta = mRxSuccessDelta; |
| event.packetUpdateTimeDelta = mLlStatsUpdateTimeDelta; |
| event.lastLinkLayerStatsUpdateTime = mLlStatsLastUpdateTime; |
| event.screenOn = mScreenOn; |
| event.mobileTxBytes = mFacade.getMobileTxBytes(); |
| event.mobileRxBytes = mFacade.getMobileRxBytes(); |
| event.totalTxBytes = mFacade.getTotalTxBytes(); |
| event.totalRxBytes = mFacade.getTotalRxBytes(); |
| |
| mWifiIsUnusableList.add(new WifiIsUnusableWithTime(event, mClock.getWallClockMillis())); |
| if (mWifiIsUnusableList.size() > MAX_UNUSABLE_EVENTS) { |
| mWifiIsUnusableList.removeFirst(); |
| } |
| } |
| |
| /** |
| * Extract data from |info| and |stats| to build a WifiUsabilityStatsEntry and then adds it |
| * into an internal ring buffer. |
| * @param info |
| * @param stats |
| * @param ifaceName |
| */ |
| public void updateWifiUsabilityStatsEntries(String ifaceName, WifiInfo info, |
| WifiLinkLayerStats stats) { |
| // This is only collected for primary STA currently because RSSI polling is disabled for |
| // non-primary STAs. |
| synchronized (mLock) { |
| if (info == null) { |
| return; |
| } |
| if (stats == null) { |
| // For devices lacking vendor hal, fill in the parts that we can |
| stats = new WifiLinkLayerStats(); |
| stats.timeStampInMs = mClock.getElapsedSinceBootMillis(); |
| stats.txmpdu_be = info.txSuccess; |
| stats.retries_be = info.txRetries; |
| stats.lostmpdu_be = info.txBad; |
| stats.rxmpdu_be = info.rxSuccess; |
| } |
| WifiUsabilityStatsEntry wifiUsabilityStatsEntry = |
| mWifiUsabilityStatsEntriesList.size() |
| < MAX_WIFI_USABILITY_STATS_ENTRIES_LIST_SIZE |
| ? new WifiUsabilityStatsEntry() : mWifiUsabilityStatsEntriesList.remove(); |
| wifiUsabilityStatsEntry.timeStampMs = stats.timeStampInMs; |
| wifiUsabilityStatsEntry.totalTxSuccess = stats.txmpdu_be + stats.txmpdu_bk |
| + stats.txmpdu_vi + stats.txmpdu_vo; |
| wifiUsabilityStatsEntry.totalTxRetries = stats.retries_be + stats.retries_bk |
| + stats.retries_vi + stats.retries_vo; |
| wifiUsabilityStatsEntry.totalTxBad = stats.lostmpdu_be + stats.lostmpdu_bk |
| + stats.lostmpdu_vi + stats.lostmpdu_vo; |
| wifiUsabilityStatsEntry.totalRxSuccess = stats.rxmpdu_be + stats.rxmpdu_bk |
| + stats.rxmpdu_vi + stats.rxmpdu_vo; |
| /* Update per radio stats */ |
| if (stats.radioStats != null && stats.radioStats.length > 0) { |
| int numRadios = stats.radioStats.length; |
| wifiUsabilityStatsEntry.radioStats = |
| new RadioStats[numRadios]; |
| for (int i = 0; i < numRadios; i++) { |
| RadioStats radioStats = new RadioStats(); |
| WifiLinkLayerStats.RadioStat radio = stats.radioStats[i]; |
| radioStats.radioId = radio.radio_id; |
| radioStats.totalRadioOnTimeMs = radio.on_time; |
| radioStats.totalRadioTxTimeMs = radio.tx_time; |
| radioStats.totalRadioRxTimeMs = radio.rx_time; |
| radioStats.totalScanTimeMs = radio.on_time_scan; |
| radioStats.totalNanScanTimeMs = radio.on_time_nan_scan; |
| radioStats.totalBackgroundScanTimeMs = radio.on_time_background_scan; |
| radioStats.totalRoamScanTimeMs = radio.on_time_roam_scan; |
| radioStats.totalPnoScanTimeMs = radio.on_time_pno_scan; |
| radioStats.totalHotspot2ScanTimeMs = radio.on_time_hs20_scan; |
| wifiUsabilityStatsEntry.radioStats[i] = radioStats; |
| } |
| } |
| wifiUsabilityStatsEntry.totalRadioOnTimeMs = stats.on_time; |
| wifiUsabilityStatsEntry.totalRadioTxTimeMs = stats.tx_time; |
| wifiUsabilityStatsEntry.totalRadioRxTimeMs = stats.rx_time; |
| wifiUsabilityStatsEntry.totalScanTimeMs = stats.on_time_scan; |
| wifiUsabilityStatsEntry.totalNanScanTimeMs = stats.on_time_nan_scan; |
| wifiUsabilityStatsEntry.totalBackgroundScanTimeMs = stats.on_time_background_scan; |
| wifiUsabilityStatsEntry.totalRoamScanTimeMs = stats.on_time_roam_scan; |
| wifiUsabilityStatsEntry.totalPnoScanTimeMs = stats.on_time_pno_scan; |
| wifiUsabilityStatsEntry.totalHotspot2ScanTimeMs = stats.on_time_hs20_scan; |
| wifiUsabilityStatsEntry.rssi = info.getRssi(); |
| wifiUsabilityStatsEntry.linkSpeedMbps = info.getLinkSpeed(); |
| WifiLinkLayerStats.ChannelStats statsMap = |
| stats.channelStatsMap.get(info.getFrequency()); |
| if (statsMap != null) { |
| wifiUsabilityStatsEntry.totalRadioOnFreqTimeMs = statsMap.radioOnTimeMs; |
| wifiUsabilityStatsEntry.totalCcaBusyFreqTimeMs = statsMap.ccaBusyTimeMs; |
| } |
| wifiUsabilityStatsEntry.totalBeaconRx = stats.beacon_rx; |
| wifiUsabilityStatsEntry.timeSliceDutyCycleInPercent = stats.timeSliceDutyCycleInPercent; |
| |
| boolean isSameBssidAndFreq = mLastBssid == null || mLastFrequency == -1 |
| || (mLastBssid.equals(info.getBSSID()) |
| && mLastFrequency == info.getFrequency()); |
| mLastBssid = info.getBSSID(); |
| mLastFrequency = info.getFrequency(); |
| wifiUsabilityStatsEntry.wifiScore = mLastScoreNoReset; |
| wifiUsabilityStatsEntry.wifiUsabilityScore = mLastWifiUsabilityScoreNoReset; |
| wifiUsabilityStatsEntry.seqNumToFramework = mSeqNumToFramework; |
| wifiUsabilityStatsEntry.predictionHorizonSec = mLastPredictionHorizonSecNoReset; |
| switch (mProbeStatusSinceLastUpdate) { |
| case android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE: |
| wifiUsabilityStatsEntry.probeStatusSinceLastUpdate = |
| WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE; |
| break; |
| case android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS: |
| wifiUsabilityStatsEntry.probeStatusSinceLastUpdate = |
| WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS; |
| break; |
| case android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE: |
| wifiUsabilityStatsEntry.probeStatusSinceLastUpdate = |
| WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE; |
| break; |
| default: |
| wifiUsabilityStatsEntry.probeStatusSinceLastUpdate = |
| WifiUsabilityStatsEntry.PROBE_STATUS_UNKNOWN; |
| Log.e(TAG, "Unknown link probe status: " + mProbeStatusSinceLastUpdate); |
| } |
| wifiUsabilityStatsEntry.probeElapsedTimeSinceLastUpdateMs = |
| mProbeElapsedTimeSinceLastUpdateMs; |
| wifiUsabilityStatsEntry.probeMcsRateSinceLastUpdate = mProbeMcsRateSinceLastUpdate; |
| wifiUsabilityStatsEntry.rxLinkSpeedMbps = info.getRxLinkSpeedMbps(); |
| wifiUsabilityStatsEntry.isSameBssidAndFreq = isSameBssidAndFreq; |
| wifiUsabilityStatsEntry.seqNumInsideFramework = mSeqNumInsideFramework; |
| wifiUsabilityStatsEntry.deviceMobilityState = mCurrentDeviceMobilityState; |
| wifiUsabilityStatsEntry.contentionTimeStats = |
| new ContentionTimeStats[NUM_WME_ACCESS_CATEGORIES]; |
| for (int ac = 0; ac < NUM_WME_ACCESS_CATEGORIES; ac++) { |
| ContentionTimeStats contentionTimeStats = new ContentionTimeStats(); |
| switch (ac) { |
| case ContentionTimeStats.WME_ACCESS_CATEGORY_BE: |
| contentionTimeStats.accessCategory = |
| ContentionTimeStats.WME_ACCESS_CATEGORY_BE; |
| contentionTimeStats.contentionTimeMinMicros = |
| stats.contentionTimeMinBeInUsec; |
| contentionTimeStats.contentionTimeMaxMicros = |
| stats.contentionTimeMaxBeInUsec; |
| contentionTimeStats.contentionTimeAvgMicros = |
| stats.contentionTimeAvgBeInUsec; |
| contentionTimeStats.contentionNumSamples = |
| stats.contentionNumSamplesBe; |
| break; |
| case ContentionTimeStats.WME_ACCESS_CATEGORY_BK: |
| contentionTimeStats.accessCategory = |
| ContentionTimeStats.WME_ACCESS_CATEGORY_BK; |
| contentionTimeStats.contentionTimeMinMicros = |
| stats.contentionTimeMinBkInUsec; |
| contentionTimeStats.contentionTimeMaxMicros = |
| stats.contentionTimeMaxBkInUsec; |
| contentionTimeStats.contentionTimeAvgMicros = |
| stats.contentionTimeAvgBkInUsec; |
| contentionTimeStats.contentionNumSamples = |
| stats.contentionNumSamplesBk; |
| break; |
| case ContentionTimeStats.WME_ACCESS_CATEGORY_VI: |
| contentionTimeStats.accessCategory = |
| ContentionTimeStats.WME_ACCESS_CATEGORY_VI; |
| contentionTimeStats.contentionTimeMinMicros = |
| stats.contentionTimeMinViInUsec; |
| contentionTimeStats.contentionTimeMaxMicros = |
| stats.contentionTimeMaxViInUsec; |
| contentionTimeStats.contentionTimeAvgMicros = |
| stats.contentionTimeAvgViInUsec; |
| contentionTimeStats.contentionNumSamples = |
| stats.contentionNumSamplesVi; |
| break; |
| case ContentionTimeStats.WME_ACCESS_CATEGORY_VO: |
| contentionTimeStats.accessCategory = |
| ContentionTimeStats.WME_ACCESS_CATEGORY_VO; |
| contentionTimeStats.contentionTimeMinMicros = |
| stats.contentionTimeMinVoInUsec; |
| contentionTimeStats.contentionTimeMaxMicros = |
| stats.contentionTimeMaxVoInUsec; |
| contentionTimeStats.contentionTimeAvgMicros = |
| stats.contentionTimeAvgVoInUsec; |
| contentionTimeStats.contentionNumSamples = |
| stats.contentionNumSamplesVo; |
| break; |
| default: |
| Log.e(TAG, "Unknown WME Access Category: " + ac); |
| } |
| wifiUsabilityStatsEntry.contentionTimeStats[ac] = contentionTimeStats; |
| } |
| if (mWifiChannelUtilization != null) { |
| wifiUsabilityStatsEntry.channelUtilizationRatio = |
| mWifiChannelUtilization.getUtilizationRatio(mLastFrequency); |
| } |
| if (mWifiDataStall != null) { |
| wifiUsabilityStatsEntry.isThroughputSufficient = |
| mWifiDataStall.isThroughputSufficient(); |
| wifiUsabilityStatsEntry.isCellularDataAvailable = |
| mWifiDataStall.isCellularDataAvailable(); |
| } |
| if (mWifiSettingsStore != null) { |
| wifiUsabilityStatsEntry.isWifiScoringEnabled = |
| mWifiSettingsStore.isWifiScoringEnabled(); |
| } |
| // Here it is assumed there is only one peer information from HAL and the peer is the |
| // AP that STA is associated with. |
| if (stats.peerInfo != null && stats.peerInfo.length > 0 |
| && stats.peerInfo[0].rateStats != null) { |
| wifiUsabilityStatsEntry.staCount = stats.peerInfo[0].staCount; |
| wifiUsabilityStatsEntry.channelUtilization = stats.peerInfo[0].chanUtil; |
| int numRates = stats.peerInfo[0].rateStats != null |
| ? stats.peerInfo[0].rateStats.length : 0; |
| wifiUsabilityStatsEntry.rateStats = new RateStats[numRates]; |
| for (int i = 0; i < numRates; i++) { |
| RateStats rate = new RateStats(); |
| WifiLinkLayerStats.RateStat curRate = stats.peerInfo[0].rateStats[i]; |
| rate.preamble = curRate.preamble; |
| rate.nss = curRate.nss; |
| rate.bw = curRate.bw; |
| rate.rateMcsIdx = curRate.rateMcsIdx; |
| rate.bitRateInKbps = curRate.bitRateInKbps; |
| rate.txMpdu = curRate.txMpdu; |
| rate.rxMpdu = curRate.rxMpdu; |
| rate.mpduLost = curRate.mpduLost; |
| rate.retries = curRate.retries; |
| wifiUsabilityStatsEntry.rateStats[i] = rate; |
| } |
| } |
| |
| mWifiUsabilityStatsEntriesList.add(wifiUsabilityStatsEntry); |
| mWifiUsabilityStatsCounter++; |
| if (mWifiUsabilityStatsCounter >= NUM_WIFI_USABILITY_STATS_ENTRIES_PER_WIFI_GOOD) { |
| addToWifiUsabilityStatsList(ifaceName, WifiUsabilityStats.LABEL_GOOD, |
| WifiUsabilityStats.TYPE_UNKNOWN, -1); |
| } |
| if (mScoreBreachLowTimeMillis != -1) { |
| long elapsedTime = mClock.getElapsedSinceBootMillis() - mScoreBreachLowTimeMillis; |
| if (elapsedTime >= MIN_SCORE_BREACH_TO_GOOD_STATS_WAIT_TIME_MS) { |
| mScoreBreachLowTimeMillis = -1; |
| if (elapsedTime <= VALIDITY_PERIOD_OF_SCORE_BREACH_LOW_MS) { |
| addToWifiUsabilityStatsList(ifaceName, WifiUsabilityStats.LABEL_GOOD, |
| WifiUsabilityStats.TYPE_UNKNOWN, -1); |
| } |
| } |
| } |
| |
| // Invoke Wifi usability stats listener. |
| // TODO(b/179518316): Enable this for secondary transient STA also if external scorer |
| // is in charge of MBB. |
| sendWifiUsabilityStats(mSeqNumInsideFramework, isSameBssidAndFreq, |
| createNewWifiUsabilityStatsEntryParcelable(wifiUsabilityStatsEntry)); |
| |
| mSeqNumInsideFramework++; |
| mProbeStatusSinceLastUpdate = |
| android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE; |
| mProbeElapsedTimeSinceLastUpdateMs = -1; |
| mProbeMcsRateSinceLastUpdate = -1; |
| } |
| } |
| |
| /** |
| * Send Wifi usability stats. |
| * @param seqNum |
| * @param isSameBssidAndFreq |
| * @param statsEntry |
| */ |
| private void sendWifiUsabilityStats(int seqNum, boolean isSameBssidAndFreq, |
| android.net.wifi.WifiUsabilityStatsEntry statsEntry) { |
| int itemCount = mOnWifiUsabilityListeners.beginBroadcast(); |
| for (int i = 0; i < itemCount; i++) { |
| try { |
| mOnWifiUsabilityListeners.getBroadcastItem(i).onWifiUsabilityStats(seqNum, |
| isSameBssidAndFreq, statsEntry); |
| } catch (RemoteException e) { |
| Log.e(TAG, "Unable to invoke Wifi usability stats entry listener ", e); |
| } |
| } |
| mOnWifiUsabilityListeners.finishBroadcast(); |
| } |
| |
| private android.net.wifi.WifiUsabilityStatsEntry createNewWifiUsabilityStatsEntryParcelable( |
| WifiUsabilityStatsEntry s) { |
| int probeStatus; |
| switch (s.probeStatusSinceLastUpdate) { |
| case WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE: |
| probeStatus = android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_NO_PROBE; |
| break; |
| case WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS: |
| probeStatus = android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS; |
| break; |
| case WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE: |
| probeStatus = android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE; |
| break; |
| default: |
| probeStatus = android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_UNKNOWN; |
| Log.e(TAG, "Unknown link probe status: " + s.probeStatusSinceLastUpdate); |
| } |
| android.net.wifi.WifiUsabilityStatsEntry.ContentionTimeStats[] contentionTimeStats = |
| new android.net.wifi.WifiUsabilityStatsEntry.ContentionTimeStats[ |
| android.net.wifi.WifiUsabilityStatsEntry.NUM_WME_ACCESS_CATEGORIES]; |
| createNewContentionTimeStatsParcelable(contentionTimeStats, s.contentionTimeStats); |
| int numRates = s.rateStats != null ? s.rateStats.length : 0; |
| android.net.wifi.WifiUsabilityStatsEntry.RateStats[] rateStats = |
| new android.net.wifi.WifiUsabilityStatsEntry.RateStats[numRates]; |
| createNewRateStatsParcelable(rateStats, s.rateStats); |
| int numRadios = s.radioStats != null ? s.radioStats.length : 0; |
| android.net.wifi.WifiUsabilityStatsEntry.RadioStats[] radioStats = |
| new android.net.wifi.WifiUsabilityStatsEntry.RadioStats[numRadios]; |
| createNewRadioStatsParcelable(radioStats, s.radioStats); |
| // TODO: remove the following hardcoded values once if they are removed from public API |
| return new android.net.wifi.WifiUsabilityStatsEntry(s.timeStampMs, s.rssi, |
| s.linkSpeedMbps, s.totalTxSuccess, s.totalTxRetries, |
| s.totalTxBad, s.totalRxSuccess, s.totalRadioOnTimeMs, |
| s.totalRadioTxTimeMs, s.totalRadioRxTimeMs, s.totalScanTimeMs, |
| s.totalNanScanTimeMs, s.totalBackgroundScanTimeMs, s.totalRoamScanTimeMs, |
| s.totalPnoScanTimeMs, s.totalHotspot2ScanTimeMs, s.totalCcaBusyFreqTimeMs, |
| s.totalRadioOnFreqTimeMs, s.totalBeaconRx, probeStatus, |
| s.probeElapsedTimeSinceLastUpdateMs, s.probeMcsRateSinceLastUpdate, |
| s.rxLinkSpeedMbps, s.timeSliceDutyCycleInPercent, contentionTimeStats, rateStats, |
| radioStats, s.channelUtilizationRatio, s.isThroughputSufficient, |
| s.isWifiScoringEnabled, s.isCellularDataAvailable, 0, 0, 0, false |
| ); |
| } |
| |
| private void createNewContentionTimeStatsParcelable( |
| android.net.wifi.WifiUsabilityStatsEntry.ContentionTimeStats[] statsParcelable, |
| ContentionTimeStats[] stats) { |
| if (statsParcelable.length != stats.length || stats.length != NUM_WME_ACCESS_CATEGORIES) { |
| Log.e(TAG, "The two ContentionTimeStats do not match in length: " |
| + " in proto: " + stats.length |
| + " in system API: " + statsParcelable.length); |
| return; |
| } |
| for (int ac = 0; ac < NUM_WME_ACCESS_CATEGORIES; ac++) { |
| android.net.wifi.WifiUsabilityStatsEntry.ContentionTimeStats stat = |
| new android.net.wifi.WifiUsabilityStatsEntry.ContentionTimeStats( |
| stats[ac].contentionTimeMinMicros, |
| stats[ac].contentionTimeMaxMicros, |
| stats[ac].contentionTimeAvgMicros, |
| stats[ac].contentionNumSamples); |
| switch (ac) { |
| case ContentionTimeStats.WME_ACCESS_CATEGORY_BE: |
| statsParcelable[ |
| android.net.wifi.WifiUsabilityStatsEntry.WME_ACCESS_CATEGORY_BE] = stat; |
| break; |
| case ContentionTimeStats.WME_ACCESS_CATEGORY_BK: |
| statsParcelable[ |
| android.net.wifi.WifiUsabilityStatsEntry.WME_ACCESS_CATEGORY_BK] = stat; |
| break; |
| case ContentionTimeStats.WME_ACCESS_CATEGORY_VI: |
| statsParcelable[ |
| android.net.wifi.WifiUsabilityStatsEntry.WME_ACCESS_CATEGORY_VI] = stat; |
| break; |
| case ContentionTimeStats.WME_ACCESS_CATEGORY_VO: |
| statsParcelable[ |
| android.net.wifi.WifiUsabilityStatsEntry.WME_ACCESS_CATEGORY_VO] = stat; |
| break; |
| default: |
| Log.e(TAG, "Unknown WME Access Category: " + ac); |
| } |
| } |
| } |
| |
| private void createNewRateStatsParcelable( |
| android.net.wifi.WifiUsabilityStatsEntry.RateStats[] statsParcelable, |
| RateStats[] stats) { |
| if (stats == null) { |
| return; |
| } |
| for (int i = 0; i < stats.length; i++) { |
| statsParcelable[i] = new android.net.wifi.WifiUsabilityStatsEntry.RateStats( |
| convertPreambleTypeEnumToUsabilityStatsType(stats[i].preamble), |
| convertSpatialStreamEnumToUsabilityStatsType(stats[i].nss), |
| convertBandwidthEnumToUsabilityStatsType(stats[i].bw), |
| stats[i].rateMcsIdx, stats[i].bitRateInKbps, stats[i].txMpdu, stats[i].rxMpdu, |
| stats[i].mpduLost, stats[i].retries |
| ); |
| } |
| } |
| |
| /** |
| * Converts bandwidth enum in proto to WifiUsabilityStatsEntry type. |
| * @param value |
| */ |
| private static int convertBandwidthEnumToUsabilityStatsType(int value) { |
| switch (value) { |
| case RateStats.WIFI_BANDWIDTH_20_MHZ: |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_BANDWIDTH_20_MHZ; |
| case RateStats.WIFI_BANDWIDTH_40_MHZ: |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_BANDWIDTH_40_MHZ; |
| case RateStats.WIFI_BANDWIDTH_80_MHZ: |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_BANDWIDTH_80_MHZ; |
| case RateStats.WIFI_BANDWIDTH_160_MHZ: |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_BANDWIDTH_160_MHZ; |
| case RateStats.WIFI_BANDWIDTH_80P80_MHZ: |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_BANDWIDTH_80P80_MHZ; |
| case RateStats.WIFI_BANDWIDTH_5_MHZ: |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_BANDWIDTH_5_MHZ; |
| case RateStats.WIFI_BANDWIDTH_10_MHZ: |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_BANDWIDTH_10_MHZ; |
| } |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_BANDWIDTH_INVALID; |
| } |
| |
| /** |
| * Converts spatial streams enum in proto to WifiUsabilityStatsEntry type. |
| * @param value |
| */ |
| private static int convertSpatialStreamEnumToUsabilityStatsType(int value) { |
| switch (value) { |
| case RateStats.WIFI_SPATIAL_STREAMS_ONE: |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_SPATIAL_STREAMS_ONE; |
| case RateStats.WIFI_SPATIAL_STREAMS_TWO: |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_SPATIAL_STREAMS_TWO; |
| case RateStats.WIFI_SPATIAL_STREAMS_THREE: |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_SPATIAL_STREAMS_THREE; |
| case RateStats.WIFI_SPATIAL_STREAMS_FOUR: |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_SPATIAL_STREAMS_FOUR; |
| } |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_SPATIAL_STREAMS_INVALID; |
| } |
| |
| /** |
| * Converts preamble type enum in proto to WifiUsabilityStatsEntry type. |
| * @param value |
| */ |
| private static int convertPreambleTypeEnumToUsabilityStatsType(int value) { |
| switch (value) { |
| case RateStats.WIFI_PREAMBLE_OFDM: |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_PREAMBLE_OFDM; |
| case RateStats.WIFI_PREAMBLE_CCK: |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_PREAMBLE_CCK; |
| case RateStats.WIFI_PREAMBLE_HT: |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_PREAMBLE_HT; |
| case RateStats.WIFI_PREAMBLE_VHT: |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_PREAMBLE_VHT; |
| case RateStats.WIFI_PREAMBLE_HE: |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_PREAMBLE_HE; |
| } |
| return android.net.wifi.WifiUsabilityStatsEntry.WIFI_PREAMBLE_INVALID; |
| } |
| |
| private void createNewRadioStatsParcelable( |
| android.net.wifi.WifiUsabilityStatsEntry.RadioStats[] statsParcelable, |
| RadioStats[] stats) { |
| if (stats == null) { |
| return; |
| } |
| for (int i = 0; i < stats.length; i++) { |
| statsParcelable[i] = |
| new android.net.wifi.WifiUsabilityStatsEntry.RadioStats( |
| stats[i].radioId, |
| stats[i].totalRadioOnTimeMs, |
| stats[i].totalRadioTxTimeMs, |
| stats[i].totalRadioRxTimeMs, |
| stats[i].totalScanTimeMs, |
| stats[i].totalNanScanTimeMs, |
| stats[i].totalBackgroundScanTimeMs, |
| stats[i].totalRoamScanTimeMs, |
| stats[i].totalPnoScanTimeMs, |
| stats[i].totalHotspot2ScanTimeMs); |
| } |
| } |
| |
| private WifiUsabilityStatsEntry createNewWifiUsabilityStatsEntry(WifiUsabilityStatsEntry s) { |
| WifiUsabilityStatsEntry out = new WifiUsabilityStatsEntry(); |
| out.timeStampMs = s.timeStampMs; |
| out.totalTxSuccess = s.totalTxSuccess; |
| out.totalTxRetries = s.totalTxRetries; |
| out.totalTxBad = s.totalTxBad; |
| out.totalRxSuccess = s.totalRxSuccess; |
| out.totalRadioOnTimeMs = s.totalRadioOnTimeMs; |
| out.totalRadioTxTimeMs = s.totalRadioTxTimeMs; |
| out.totalRadioRxTimeMs = s.totalRadioRxTimeMs; |
| out.totalScanTimeMs = s.totalScanTimeMs; |
| out.totalNanScanTimeMs = s.totalNanScanTimeMs; |
| out.totalBackgroundScanTimeMs = s.totalBackgroundScanTimeMs; |
| out.totalRoamScanTimeMs = s.totalRoamScanTimeMs; |
| out.totalPnoScanTimeMs = s.totalPnoScanTimeMs; |
| out.totalHotspot2ScanTimeMs = s.totalHotspot2ScanTimeMs; |
| out.rssi = s.rssi; |
| out.linkSpeedMbps = s.linkSpeedMbps; |
| out.totalCcaBusyFreqTimeMs = s.totalCcaBusyFreqTimeMs; |
| out.totalRadioOnFreqTimeMs = s.totalRadioOnFreqTimeMs; |
| out.totalBeaconRx = s.totalBeaconRx; |
| out.wifiScore = s.wifiScore; |
| out.wifiUsabilityScore = s.wifiUsabilityScore; |
| out.seqNumToFramework = s.seqNumToFramework; |
| out.predictionHorizonSec = s.predictionHorizonSec; |
| out.probeStatusSinceLastUpdate = s.probeStatusSinceLastUpdate; |
| out.probeElapsedTimeSinceLastUpdateMs = s.probeElapsedTimeSinceLastUpdateMs; |
| out.probeMcsRateSinceLastUpdate = s.probeMcsRateSinceLastUpdate; |
| out.rxLinkSpeedMbps = s.rxLinkSpeedMbps; |
| out.isSameBssidAndFreq = s.isSameBssidAndFreq; |
| out.seqNumInsideFramework = s.seqNumInsideFramework; |
| out.deviceMobilityState = s.deviceMobilityState; |
| out.timeSliceDutyCycleInPercent = s.timeSliceDutyCycleInPercent; |
| out.contentionTimeStats = s.contentionTimeStats; |
| out.channelUtilizationRatio = s.channelUtilizationRatio; |
| out.isThroughputSufficient = s.isThroughputSufficient; |
| out.isWifiScoringEnabled = s.isWifiScoringEnabled; |
| out.isCellularDataAvailable = s.isCellularDataAvailable; |
| out.rateStats = s.rateStats; |
| out.staCount = s.staCount; |
| out.channelUtilization = s.channelUtilization; |
| out.radioStats = s.radioStats; |
| return out; |
| } |
| |
| private WifiUsabilityStats createWifiUsabilityStatsWithLabel(int label, int triggerType, |
| int firmwareAlertCode) { |
| WifiUsabilityStats wifiUsabilityStats = new WifiUsabilityStats(); |
| wifiUsabilityStats.label = label; |
| wifiUsabilityStats.triggerType = triggerType; |
| wifiUsabilityStats.firmwareAlertCode = firmwareAlertCode; |
| wifiUsabilityStats.timeStampMs = mClock.getElapsedSinceBootMillis(); |
| wifiUsabilityStats.stats = |
| new WifiUsabilityStatsEntry[mWifiUsabilityStatsEntriesList.size()]; |
| for (int i = 0; i < mWifiUsabilityStatsEntriesList.size(); i++) { |
| wifiUsabilityStats.stats[i] = |
| createNewWifiUsabilityStatsEntry(mWifiUsabilityStatsEntriesList.get(i)); |
| } |
| return wifiUsabilityStats; |
| } |
| |
| /** |
| * Label the current snapshot of WifiUsabilityStatsEntrys and save the labeled data in memory. |
| * @param label WifiUsabilityStats.LABEL_GOOD or WifiUsabilityStats.LABEL_BAD |
| * @param triggerType what event triggers WifiUsabilityStats |
| * @param firmwareAlertCode the firmware alert code when the stats was triggered by a |
| * firmware alert |
| */ |
| public void addToWifiUsabilityStatsList(String ifaceName, int label, int triggerType, |
| int firmwareAlertCode) { |
| synchronized (mLock) { |
| if (!isPrimary(ifaceName)) { |
| return; |
| } |
| if (mWifiUsabilityStatsEntriesList.isEmpty() || !mScreenOn) { |
| return; |
| } |
| if (label == WifiUsabilityStats.LABEL_GOOD) { |
| // Only add a good event if at least |MIN_WIFI_GOOD_USABILITY_STATS_PERIOD_MS| |
| // has passed. |
| if (mWifiUsabilityStatsListGood.isEmpty() |
| || mWifiUsabilityStatsListGood.getLast().stats[mWifiUsabilityStatsListGood |
| .getLast().stats.length - 1].timeStampMs |
| + MIN_WIFI_GOOD_USABILITY_STATS_PERIOD_MS |
| < mWifiUsabilityStatsEntriesList.getLast().timeStampMs) { |
| while (mWifiUsabilityStatsListGood.size() |
| >= MAX_WIFI_USABILITY_STATS_LIST_SIZE_PER_TYPE) { |
| mWifiUsabilityStatsListGood.remove( |
| mRand.nextInt(mWifiUsabilityStatsListGood.size())); |
| } |
| mWifiUsabilityStatsListGood.add( |
| createWifiUsabilityStatsWithLabel(label, triggerType, |
| firmwareAlertCode)); |
| } |
| } else { |
| // Only add a bad event if at least |MIN_DATA_STALL_WAIT_MS| |
| // has passed. |
| mScoreBreachLowTimeMillis = -1; |
| if (mWifiUsabilityStatsListBad.isEmpty() |
| || (mWifiUsabilityStatsListBad.getLast().stats[mWifiUsabilityStatsListBad |
| .getLast().stats.length - 1].timeStampMs |
| + MIN_DATA_STALL_WAIT_MS |
| < mWifiUsabilityStatsEntriesList.getLast().timeStampMs)) { |
| while (mWifiUsabilityStatsListBad.size() |
| >= MAX_WIFI_USABILITY_STATS_LIST_SIZE_PER_TYPE) { |
| mWifiUsabilityStatsListBad.remove( |
| mRand.nextInt(mWifiUsabilityStatsListBad.size())); |
| } |
| mWifiUsabilityStatsListBad.add( |
| createWifiUsabilityStatsWithLabel(label, triggerType, |
| firmwareAlertCode)); |
| } |
| } |
| mWifiUsabilityStatsCounter = 0; |
| mWifiUsabilityStatsEntriesList.clear(); |
| } |
| } |
| |
| private DeviceMobilityStatePnoScanStats getOrCreateDeviceMobilityStatePnoScanStats( |
| @DeviceMobilityState int deviceMobilityState) { |
| DeviceMobilityStatePnoScanStats stats = mMobilityStatePnoStatsMap.get(deviceMobilityState); |
| if (stats == null) { |
| stats = new DeviceMobilityStatePnoScanStats(); |
| stats.deviceMobilityState = deviceMobilityState; |
| stats.numTimesEnteredState = 0; |
| stats.totalDurationMs = 0; |
| stats.pnoDurationMs = 0; |
| mMobilityStatePnoStatsMap.put(deviceMobilityState, stats); |
| } |
| return stats; |
| } |
| |
| /** |
| * Updates the current device mobility state's total duration. This method should be called |
| * before entering a new device mobility state. |
| */ |
| private void updateCurrentMobilityStateTotalDuration(long now) { |
| DeviceMobilityStatePnoScanStats stats = |
| getOrCreateDeviceMobilityStatePnoScanStats(mCurrentDeviceMobilityState); |
| stats.totalDurationMs += now - mCurrentDeviceMobilityStateStartMs; |
| mCurrentDeviceMobilityStateStartMs = now; |
| } |
| |
| /** |
| * Convert the IntCounter of passpoint profile types and counts to proto's |
| * repeated IntKeyVal array. |
| * |
| * @param passpointProfileTypes passpoint profile types and counts. |
| */ |
| private PasspointProfileTypeCount[] convertPasspointProfilesToProto( |
| IntCounter passpointProfileTypes) { |
| return passpointProfileTypes.toProto(PasspointProfileTypeCount.class, (key, count) -> { |
| PasspointProfileTypeCount entry = new PasspointProfileTypeCount(); |
| entry.eapMethodType = key; |
| entry.count = count; |
| return entry; |
| }); |
| } |
| |
| /** |
| * Reports that the device entered a new mobility state. |
| * |
| * @param newState the new device mobility state. |
| */ |
| public void enterDeviceMobilityState(@DeviceMobilityState int newState) { |
| synchronized (mLock) { |
| long now = mClock.getElapsedSinceBootMillis(); |
| updateCurrentMobilityStateTotalDuration(now); |
| |
| if (newState == mCurrentDeviceMobilityState) return; |
| |
| mCurrentDeviceMobilityState = newState; |
| DeviceMobilityStatePnoScanStats stats = |
| getOrCreateDeviceMobilityStatePnoScanStats(mCurrentDeviceMobilityState); |
| stats.numTimesEnteredState++; |
| } |
| } |
| |
| /** |
| * Logs the start of a PNO scan. |
| */ |
| public void logPnoScanStart() { |
| synchronized (mLock) { |
| long now = mClock.getElapsedSinceBootMillis(); |
| mCurrentDeviceMobilityStatePnoScanStartMs = now; |
| updateCurrentMobilityStateTotalDuration(now); |
| } |
| } |
| |
| /** |
| * Logs the end of a PNO scan. This is attributed to the current device mobility state, as |
| * logged by {@link #enterDeviceMobilityState(int)}. Thus, if the mobility state changes during |
| * a PNO scan, one should call {@link #logPnoScanStop()}, {@link #enterDeviceMobilityState(int)} |
| * , then {@link #logPnoScanStart()} so that the portion of PNO scan before the mobility state |
| * change can be correctly attributed to the previous mobility state. |
| */ |
| public void logPnoScanStop() { |
| synchronized (mLock) { |
| if (mCurrentDeviceMobilityStatePnoScanStartMs < 0) { |
| Log.e(TAG, "Called WifiMetrics#logPNoScanStop() without calling " |
| + "WifiMetrics#logPnoScanStart() first!"); |
| return; |
| } |
| DeviceMobilityStatePnoScanStats stats = |
| getOrCreateDeviceMobilityStatePnoScanStats(mCurrentDeviceMobilityState); |
| long now = mClock.getElapsedSinceBootMillis(); |
| stats.pnoDurationMs += now - mCurrentDeviceMobilityStatePnoScanStartMs; |
| mCurrentDeviceMobilityStatePnoScanStartMs = -1; |
| updateCurrentMobilityStateTotalDuration(now); |
| } |
| } |
| |
| /** |
| * Logs that wifi bug report is taken |
| */ |
| public void logBugReport() { |
| synchronized (mLock) { |
| for (ConnectionEvent connectionEvent : mCurrentConnectionEventPerIface.values()) { |
| if (connectionEvent != null) { |
| connectionEvent.mConnectionEvent.automaticBugReportTaken = true; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Add a new listener for Wi-Fi usability stats handling. |
| */ |
| public void addOnWifiUsabilityListener(IOnWifiUsabilityStatsListener listener) { |
| if (!mOnWifiUsabilityListeners.register(listener)) { |
| Log.e(TAG, "Failed to add listener"); |
| return; |
| } |
| if (DBG) { |
| Log.v(TAG, "Adding listener. Num listeners: " |
| + mOnWifiUsabilityListeners.getRegisteredCallbackCount()); |
| } |
| } |
| |
| /** |
| * Remove an existing listener for Wi-Fi usability stats handling. |
| */ |
| public void removeOnWifiUsabilityListener(IOnWifiUsabilityStatsListener listener) { |
| mOnWifiUsabilityListeners.unregister(listener); |
| if (DBG) { |
| Log.v(TAG, "Removing listener. Num listeners: " |
| + mOnWifiUsabilityListeners.getRegisteredCallbackCount()); |
| } |
| } |
| |
| /** |
| * Updates the Wi-Fi usability score and increments occurence of a particular Wifi usability |
| * score passed in from outside framework. Scores are bounded within |
| * [MIN_WIFI_USABILITY_SCORE, MAX_WIFI_USABILITY_SCORE]. |
| * |
| * Also records events when the Wifi usability score breaches significant thresholds. |
| * |
| * @param seqNum Sequence number of the Wi-Fi usability score. |
| * @param score The Wi-Fi usability score. |
| * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score. |
| */ |
| public void incrementWifiUsabilityScoreCount(String ifaceName, int seqNum, int score, |
| int predictionHorizonSec) { |
| if (score < MIN_WIFI_USABILITY_SCORE || score > MAX_WIFI_USABILITY_SCORE) { |
| return; |
| } |
| synchronized (mLock) { |
| mSeqNumToFramework = seqNum; |
| mLastWifiUsabilityScore = score; |
| mLastWifiUsabilityScoreNoReset = score; |
| mWifiUsabilityScoreCounts.put(score, mWifiUsabilityScoreCounts.get(score) + 1); |
| mLastPredictionHorizonSec = predictionHorizonSec; |
| mLastPredictionHorizonSecNoReset = predictionHorizonSec; |
| |
| boolean wifiWins = mWifiWinsUsabilityScore; |
| if (score > LOW_WIFI_USABILITY_SCORE) { |
| wifiWins = true; |
| } else if (score < LOW_WIFI_USABILITY_SCORE) { |
| wifiWins = false; |
| } |
| |
| if (wifiWins != mWifiWinsUsabilityScore) { |
| mWifiWinsUsabilityScore = wifiWins; |
| StaEvent event = new StaEvent(); |
| event.type = StaEvent.TYPE_WIFI_USABILITY_SCORE_BREACH; |
| addStaEvent(ifaceName, event); |
| // Only record the first score breach by checking whether mScoreBreachLowTimeMillis |
| // has been set to -1 |
| if (!wifiWins && mScoreBreachLowTimeMillis == -1) { |
| mScoreBreachLowTimeMillis = mClock.getElapsedSinceBootMillis(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Reports stats for a successful link probe. |
| * |
| * @param timeSinceLastTxSuccessMs At {@code startTimestampMs}, the number of milliseconds since |
| * the last Tx success (according to |
| * {@link WifiInfo#txSuccess}). |
| * @param rssi The Rx RSSI at {@code startTimestampMs}. |
| * @param linkSpeed The Tx link speed in Mbps at {@code startTimestampMs}. |
| * @param elapsedTimeMs The number of milliseconds between when the command to transmit the |
| * probe was sent to the driver and when the driver responded that the |
| * probe was ACKed. Note: this number should be correlated with the number |
| * of retries that the driver attempted before the probe was ACKed. |
| */ |
| public void logLinkProbeSuccess(String ifaceName, long timeSinceLastTxSuccessMs, |
| int rssi, int linkSpeed, int elapsedTimeMs) { |
| synchronized (mLock) { |
| mProbeStatusSinceLastUpdate = |
| android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_SUCCESS; |
| mProbeElapsedTimeSinceLastUpdateMs = elapsedTimeMs; |
| |
| mLinkProbeSuccessSecondsSinceLastTxSuccessHistogram.increment( |
| (int) (timeSinceLastTxSuccessMs / 1000)); |
| mLinkProbeSuccessRssiCounts.increment(rssi); |
| mLinkProbeSuccessLinkSpeedCounts.increment(linkSpeed); |
| mLinkProbeSuccessElapsedTimeMsHistogram.increment(elapsedTimeMs); |
| |
| if (mLinkProbeStaEventCount < MAX_LINK_PROBE_STA_EVENTS) { |
| StaEvent event = new StaEvent(); |
| event.type = StaEvent.TYPE_LINK_PROBE; |
| event.linkProbeWasSuccess = true; |
| event.linkProbeSuccessElapsedTimeMs = elapsedTimeMs; |
| addStaEvent(ifaceName, event); |
| } |
| mLinkProbeStaEventCount++; |
| } |
| } |
| |
| /** |
| * Reports stats for an unsuccessful link probe. |
| * |
| * @param timeSinceLastTxSuccessMs At {@code startTimestampMs}, the number of milliseconds since |
| * the last Tx success (according to |
| * {@link WifiInfo#txSuccess}). |
| * @param rssi The Rx RSSI at {@code startTimestampMs}. |
| * @param linkSpeed The Tx link speed in Mbps at {@code startTimestampMs}. |
| * @param reason The error code for the failure. See |
| * {@link WifiNl80211Manager.SendMgmtFrameError}. |
| */ |
| public void logLinkProbeFailure(String ifaceName, long timeSinceLastTxSuccessMs, |
| int rssi, int linkSpeed, int reason) { |
| synchronized (mLock) { |
| mProbeStatusSinceLastUpdate = |
| android.net.wifi.WifiUsabilityStatsEntry.PROBE_STATUS_FAILURE; |
| mProbeElapsedTimeSinceLastUpdateMs = Integer.MAX_VALUE; |
| |
| mLinkProbeFailureSecondsSinceLastTxSuccessHistogram.increment( |
| (int) (timeSinceLastTxSuccessMs / 1000)); |
| mLinkProbeFailureRssiCounts.increment(rssi); |
| mLinkProbeFailureLinkSpeedCounts.increment(linkSpeed); |
| mLinkProbeFailureReasonCounts.increment(reason); |
| |
| if (mLinkProbeStaEventCount < MAX_LINK_PROBE_STA_EVENTS) { |
| StaEvent event = new StaEvent(); |
| event.type = StaEvent.TYPE_LINK_PROBE; |
| event.linkProbeWasSuccess = false; |
| event.linkProbeFailureReason = linkProbeFailureReasonToProto(reason); |
| addStaEvent(ifaceName, event); |
| } |
| mLinkProbeStaEventCount++; |
| } |
| } |
| |
| /** |
| * Increments the number of probes triggered by the experiment `experimentId`. |
| */ |
| public void incrementLinkProbeExperimentProbeCount(String experimentId) { |
| synchronized (mLock) { |
| mLinkProbeExperimentProbeCounts.increment(experimentId); |
| } |
| } |
| |
| /** |
| * Update wifi config store read duration. |
| * |
| * @param timeMs Time it took to complete the operation, in milliseconds |
| */ |
| public void noteWifiConfigStoreReadDuration(int timeMs) { |
| synchronized (mLock) { |
| MetricsUtils.addValueToLinearHistogram(timeMs, mWifiConfigStoreReadDurationHistogram, |
| WIFI_CONFIG_STORE_IO_DURATION_BUCKET_RANGES_MS); |
| } |
| } |
| |
| /** |
| * Update wifi config store write duration. |
| * |
| * @param timeMs Time it took to complete the operation, in milliseconds |
| */ |
| public void noteWifiConfigStoreWriteDuration(int timeMs) { |
| synchronized (mLock) { |
| MetricsUtils.addValueToLinearHistogram(timeMs, mWifiConfigStoreWriteDurationHistogram, |
| WIFI_CONFIG_STORE_IO_DURATION_BUCKET_RANGES_MS); |
| } |
| } |
| |
| /** |
| * Logs the decision of a network selection algorithm when compared against another network |
| * selection algorithm. |
| * |
| * @param experiment1Id ID of one experiment |
| * @param experiment2Id ID of the other experiment |
| * @param isSameDecision did the 2 experiments make the same decision? |
| * @param numNetworkChoices the number of non-null network choices there were, where the null |
| * choice is not selecting any network |
| */ |
| public void logNetworkSelectionDecision(int experiment1Id, int experiment2Id, |
| boolean isSameDecision, int numNetworkChoices) { |
| if (numNetworkChoices < 0) { |
| Log.e(TAG, "numNetworkChoices cannot be negative!"); |
| return; |
| } |
| if (experiment1Id == experiment2Id) { |
| Log.e(TAG, "comparing the same experiment id: " + experiment1Id); |
| return; |
| } |
| |
| Pair<Integer, Integer> key = new Pair<>(experiment1Id, experiment2Id); |
| synchronized (mLock) { |
| NetworkSelectionExperimentResults results = |
| mNetworkSelectionExperimentPairNumChoicesCounts |
| .computeIfAbsent(key, k -> new NetworkSelectionExperimentResults()); |
| |
| IntCounter counter = isSameDecision |
| ? results.sameSelectionNumChoicesCounter |
| : results.differentSelectionNumChoicesCounter; |
| |
| counter.increment(numNetworkChoices); |
| } |
| } |
| |
| /** Increment number of network request API usage stats */ |
| public void incrementNetworkRequestApiNumRequest() { |
| synchronized (mLock) { |
| mWifiNetworkRequestApiLog.numRequest++; |
| } |
| } |
| |
| /** Add to the network request API match size histogram */ |
| public void incrementNetworkRequestApiMatchSizeHistogram(int matchSize) { |
| synchronized (mLock) { |
| mWifiNetworkRequestApiMatchSizeHistogram.increment(matchSize); |
| } |
| } |
| |
| /** Increment number of connection success on primary iface via network request API */ |
| public void incrementNetworkRequestApiNumConnectSuccessOnPrimaryIface() { |
| synchronized (mLock) { |
| mWifiNetworkRequestApiLog.numConnectSuccessOnPrimaryIface++; |
| } |
| } |
| |
| /** Increment number of requests that bypassed user approval via network request API */ |
| public void incrementNetworkRequestApiNumUserApprovalBypass() { |
| synchronized (mLock) { |
| mWifiNetworkRequestApiLog.numUserApprovalBypass++; |
| } |
| } |
| |
| /** Increment number of requests that user rejected via network request API */ |
| public void incrementNetworkRequestApiNumUserReject() { |
| synchronized (mLock) { |
| mWifiNetworkRequestApiLog.numUserReject++; |
| } |
| } |
| |
| /** Increment number of requests from unique apps via network request API */ |
| public void incrementNetworkRequestApiNumApps() { |
| synchronized (mLock) { |
| mWifiNetworkRequestApiLog.numApps++; |
| } |
| } |
| |
| /** Add to the network request API connection duration histogram */ |
| public void incrementNetworkRequestApiConnectionDurationSecOnPrimaryIfaceHistogram( |
| int durationSec) { |
| synchronized (mLock) { |
| mWifiNetworkRequestApiConnectionDurationSecOnPrimaryIfaceHistogram.increment( |
| durationSec); |
| } |
| } |
| |
| /** Add to the network request API connection duration on secondary iface histogram */ |
| public void incrementNetworkRequestApiConnectionDurationSecOnSecondaryIfaceHistogram( |
| int durationSec) { |
| synchronized (mLock) { |
| mWifiNetworkRequestApiConnectionDurationSecOnSecondaryIfaceHistogram.increment( |
| durationSec); |
| } |
| } |
| |
| /** Increment number of connection on primary iface via network request API */ |
| public void incrementNetworkRequestApiNumConnectOnPrimaryIface() { |
| synchronized (mLock) { |
| mWifiNetworkRequestApiLog.numConnectOnPrimaryIface++; |
| } |
| } |
| |
| /** Increment number of connection on secondary iface via network request API */ |
| public void incrementNetworkRequestApiNumConnectOnSecondaryIface() { |
| synchronized (mLock) { |
| mWifiNetworkRequestApiLog.numConnectOnSecondaryIface++; |
| } |
| } |
| |
| /** Increment number of connection success on secondary iface via network request API */ |
| public void incrementNetworkRequestApiNumConnectSuccessOnSecondaryIface() { |
| synchronized (mLock) { |
| mWifiNetworkRequestApiLog.numConnectSuccessOnSecondaryIface++; |
| } |
| } |
| |
| /** Increment number of concurrent connection via network request API */ |
| public void incrementNetworkRequestApiNumConcurrentConnection() { |
| synchronized (mLock) { |
| mWifiNetworkRequestApiLog.numConcurrentConnection++; |
| } |
| } |
| |
| /** Add to the network request API concurrent connection duration histogram */ |
| public void incrementNetworkRequestApiConcurrentConnectionDurationSecHistogram( |
| int durationSec) { |
| synchronized (mLock) { |
| mWifiNetworkRequestApiConcurrentConnectionDurationSecHistogram.increment( |
| durationSec); |
| } |
| } |
| |
| /** Increment number of network suggestion API modification by app stats */ |
| public void incrementNetworkSuggestionApiNumModification() { |
| synchronized (mLock) { |
| mWifiNetworkSuggestionApiLog.numModification++; |
| } |
| } |
| |
| /** Increment number of connection success via network suggestion API */ |
| public void incrementNetworkSuggestionApiNumConnectSuccess() { |
| synchronized (mLock) { |
| mWifiNetworkSuggestionApiLog.numConnectSuccess++; |
| } |
| } |
| |
| /** Increment number of connection failure via network suggestion API */ |
| public void incrementNetworkSuggestionApiNumConnectFailure() { |
| synchronized (mLock) { |
| mWifiNetworkSuggestionApiLog.numConnectFailure++; |
| } |
| } |
| |
| /** Increment number of user revoke suggestion permission. Including from settings or |
| * disallowed from UI. |
| */ |
| public void incrementNetworkSuggestionUserRevokePermission() { |
| synchronized (mLock) { |
| mWifiNetworkSuggestionApiLog.userRevokeAppSuggestionPermission++; |
| } |
| } |
| |
| /** |
| * Increment number of times a ScanResult matches more than one WifiNetworkSuggestion. |
| */ |
| public void incrementNetworkSuggestionMoreThanOneSuggestionForSingleScanResult() { |
| synchronized (mLock) { |
| mWifiNetworkSuggestionApiLog.numMultipleSuggestions++; |
| } |
| } |
| |
| /** |
| * Add a saved network which has at least has one suggestion for same network on the device. |
| */ |
| public void addSuggestionExistsForSavedNetwork(String key) { |
| synchronized (mLock) { |
| mWifiNetworkSuggestionCoexistSavedNetworks.add(key); |
| } |
| } |
| |
| /** |
| * Add a priority group which is using on the device.(Except default priority group). |
| */ |
| public void addNetworkSuggestionPriorityGroup(int priorityGroup) { |
| synchronized (mLock) { |
| // Ignore the default group |
| if (priorityGroup == 0) { |
| return; |
| } |
| mWifiNetworkSuggestionPriorityGroups.put(priorityGroup, true); |
| } |
| |
| } |
| |
| /** Clear and set the latest network suggestion API max list size histogram */ |
| public void noteNetworkSuggestionApiListSizeHistogram(List<Integer> listSizes) { |
| synchronized (mLock) { |
| mWifiNetworkSuggestionApiListSizeHistogram.clear(); |
| for (Integer listSize : listSizes) { |
| mWifiNetworkSuggestionApiListSizeHistogram.increment(listSize); |
| } |
| } |
| } |
| |
| /** Increment number of app add suggestion with different privilege */ |
| public void incrementNetworkSuggestionApiUsageNumOfAppInType(int appType) { |
| int typeCode; |
| synchronized (mLock) { |
| switch (appType) { |
| case WifiNetworkSuggestionsManager.APP_TYPE_CARRIER_PRIVILEGED: |
| typeCode = WifiNetworkSuggestionApiLog.TYPE_CARRIER_PRIVILEGED; |
| break; |
| case WifiNetworkSuggestionsManager.APP_TYPE_NETWORK_PROVISIONING: |
| typeCode = WifiNetworkSuggestionApiLog.TYPE_NETWORK_PROVISIONING; |
| break; |
| case WifiNetworkSuggestionsManager.APP_TYPE_NON_PRIVILEGED: |
| typeCode = WifiNetworkSuggestionApiLog.TYPE_NON_PRIVILEGED; |
| break; |
| default: |
| typeCode = WifiNetworkSuggestionApiLog.TYPE_UNKNOWN; |
| } |
| mWifiNetworkSuggestionApiAppTypeCounter.increment(typeCode); |
| } |
| } |
| |
| /** Add user action to the approval suggestion app UI */ |
| public void addUserApprovalSuggestionAppUiReaction(@WifiNetworkSuggestionsManager.UserActionCode |
| int actionType, boolean isDialog) { |
| int actionCode; |
| switch (actionType) { |
| case WifiNetworkSuggestionsManager.ACTION_USER_ALLOWED_APP: |
| actionCode = UserReactionToApprovalUiEvent.ACTION_ALLOWED; |
| break; |
| case WifiNetworkSuggestionsManager.ACTION_USER_DISALLOWED_APP: |
| actionCode = UserReactionToApprovalUiEvent.ACTION_DISALLOWED; |
| break; |
| case WifiNetworkSuggestionsManager.ACTION_USER_DISMISS: |
| actionCode = UserReactionToApprovalUiEvent.ACTION_DISMISS; |
| break; |
| default: |
| actionCode = UserReactionToApprovalUiEvent.ACTION_UNKNOWN; |
| } |
| UserReaction event = new UserReaction(); |
| event.userAction = actionCode; |
| event.isDialog = isDialog; |
| synchronized (mLock) { |
| mUserApprovalSuggestionAppUiReactionList.add(event); |
| } |
| } |
| |
| /** Add user action to the approval Carrier Imsi protection exemption UI */ |
| public void addUserApprovalCarrierUiReaction(@WifiCarrierInfoManager.UserActionCode |
| int actionType, boolean isDialog) { |
| int actionCode; |
| switch (actionType) { |
| case WifiCarrierInfoManager.ACTION_USER_ALLOWED_CARRIER: |
| actionCode = UserReactionToApprovalUiEvent.ACTION_ALLOWED; |
| break; |
| case WifiCarrierInfoManager.ACTION_USER_DISALLOWED_CARRIER: |
| actionCode = UserReactionToApprovalUiEvent.ACTION_DISALLOWED; |
| break; |
| case WifiCarrierInfoManager.ACTION_USER_DISMISS: |
| actionCode = UserReactionToApprovalUiEvent.ACTION_DISMISS; |
| break; |
| default: |
| actionCode = UserReactionToApprovalUiEvent.ACTION_UNKNOWN; |
| } |
| UserReaction event = new UserReaction(); |
| event.userAction = actionCode; |
| event.isDialog = isDialog; |
| |
| synchronized (mLock) { |
| mUserApprovalCarrierUiReactionList.add(event); |
| } |
| } |
| |
| /** |
| * Sets the nominator for a network (i.e. which entity made the suggestion to connect) |
| * @param networkId the ID of the network, from its {@link WifiConfiguration} |
| * @param nominatorId the entity that made the suggestion to connect to this network, |
| * from {@link WifiMetricsProto.ConnectionEvent.ConnectionNominator} |
| */ |
| public void setNominatorForNetwork(int networkId, int nominatorId) { |
| synchronized (mLock) { |
| if (networkId == WifiConfiguration.INVALID_NETWORK_ID) return; |
| mNetworkIdToNominatorId.put(networkId, nominatorId); |
| |
| // user connect choice is preventing switching off from the connected network |
| if (nominatorId |
| == WifiMetricsProto.ConnectionEvent.NOMINATOR_SAVED_USER_CONNECT_CHOICE |
| && mWifiStatusBuilder.getNetworkId() == networkId) { |
| mWifiStatusBuilder.setUserChoice(true); |
| } |
| } |
| } |
| |
| /** |
| * Sets the numeric CandidateScorer id. |
| */ |
| public void setNetworkSelectorExperimentId(int expId) { |
| synchronized (mLock) { |
| mNetworkSelectorExperimentId = expId; |
| } |
| } |
| |
| /** Add a WifiLock acqusition session */ |
| public void addWifiLockAcqSession(int lockType, long duration) { |
| switch (lockType) { |
| case WifiManager.WIFI_MODE_FULL_HIGH_PERF: |
| mWifiLockHighPerfAcqDurationSecHistogram.increment((int) (duration / 1000)); |
| break; |
| |
| case WifiManager.WIFI_MODE_FULL_LOW_LATENCY: |
| mWifiLockLowLatencyAcqDurationSecHistogram.increment((int) (duration / 1000)); |
| break; |
| |
| default: |
| Log.e(TAG, "addWifiLockAcqSession: Invalid lock type: " + lockType); |
| break; |
| } |
| } |
| |
| /** Add a WifiLock active session */ |
| public void addWifiLockActiveSession(int lockType, long duration) { |
| switch (lockType) { |
| case WifiManager.WIFI_MODE_FULL_HIGH_PERF: |
| mWifiLockStats.highPerfActiveTimeMs += duration; |
| mWifiLockHighPerfActiveSessionDurationSecHistogram.increment( |
| (int) (duration / 1000)); |
| break; |
| |
| case WifiManager.WIFI_MODE_FULL_LOW_LATENCY: |
| mWifiLockStats.lowLatencyActiveTimeMs += duration; |
| mWifiLockLowLatencyActiveSessionDurationSecHistogram.increment( |
| (int) (duration / 1000)); |
| break; |
| |
| default: |
| Log.e(TAG, "addWifiLockActiveSession: Invalid lock type: " + lockType); |
| break; |
| } |
| } |
| |
| /** Increments metrics counting number of addOrUpdateNetwork calls. **/ |
| public void incrementNumAddOrUpdateNetworkCalls() { |
| synchronized (mLock) { |
| mWifiLogProto.numAddOrUpdateNetworkCalls++; |
| } |
| } |
| |
| /** Increments metrics counting number of enableNetwork calls. **/ |
| public void incrementNumEnableNetworkCalls() { |
| synchronized (mLock) { |
| mWifiLogProto.numEnableNetworkCalls++; |
| } |
| } |
| |
| /** Add to WifiToggleStats **/ |
| public void incrementNumWifiToggles(boolean isPrivileged, boolean enable) { |
| synchronized (mLock) { |
| if (isPrivileged && enable) { |
| mWifiToggleStats.numToggleOnPrivileged++; |
| } else if (isPrivileged && !enable) { |
| mWifiToggleStats.numToggleOffPrivileged++; |
| } else if (!isPrivileged && enable) { |
| mWifiToggleStats.numToggleOnNormal++; |
| } else { |
| mWifiToggleStats.numToggleOffNormal++; |
| } |
| } |
| } |
| |
| /** |
| * Increment number of passpoint provision failure |
| * @param failureCode indicates error condition |
| */ |
| public void incrementPasspointProvisionFailure(@OsuFailure int failureCode) { |
| int provisionFailureCode; |
| synchronized (mLock) { |
| switch (failureCode) { |
| case ProvisioningCallback.OSU_FAILURE_AP_CONNECTION: |
| provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_AP_CONNECTION; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_SERVER_URL_INVALID: |
| provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_SERVER_URL_INVALID; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_SERVER_CONNECTION: |
| provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_SERVER_CONNECTION; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_SERVER_VALIDATION: |
| provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_SERVER_VALIDATION; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION: |
| provisionFailureCode = PasspointProvisionStats |
| .OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_PROVISIONING_ABORTED: |
| provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_PROVISIONING_ABORTED; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_PROVISIONING_NOT_AVAILABLE: |
| provisionFailureCode = PasspointProvisionStats |
| .OSU_FAILURE_PROVISIONING_NOT_AVAILABLE; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_INVALID_URL_FORMAT_FOR_OSU: |
| provisionFailureCode = PasspointProvisionStats |
| .OSU_FAILURE_INVALID_URL_FORMAT_FOR_OSU; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_UNEXPECTED_COMMAND_TYPE: |
| provisionFailureCode = PasspointProvisionStats |
| .OSU_FAILURE_UNEXPECTED_COMMAND_TYPE; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE: |
| provisionFailureCode = PasspointProvisionStats |
| .OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_SOAP_MESSAGE_EXCHANGE: |
| provisionFailureCode = PasspointProvisionStats |
| .OSU_FAILURE_SOAP_MESSAGE_EXCHANGE; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_START_REDIRECT_LISTENER: |
| provisionFailureCode = PasspointProvisionStats |
| .OSU_FAILURE_START_REDIRECT_LISTENER; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER: |
| provisionFailureCode = PasspointProvisionStats |
| .OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_NO_OSU_ACTIVITY_FOUND: |
| provisionFailureCode = PasspointProvisionStats |
| .OSU_FAILURE_NO_OSU_ACTIVITY_FOUND; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS: |
| provisionFailureCode = PasspointProvisionStats |
| .OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_NO_PPS_MO: |
| provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_NO_PPS_MO; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE: |
| provisionFailureCode = PasspointProvisionStats |
| .OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE: |
| provisionFailureCode = PasspointProvisionStats |
| .OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE: |
| provisionFailureCode = PasspointProvisionStats |
| .OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES: |
| provisionFailureCode = PasspointProvisionStats |
| .OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE: |
| provisionFailureCode = PasspointProvisionStats |
| .OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION: |
| provisionFailureCode = PasspointProvisionStats |
| .OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION; |
| break; |
| case ProvisioningCallback.OSU_FAILURE_OSU_PROVIDER_NOT_FOUND: |
| provisionFailureCode = PasspointProvisionStats |
| .OSU_FAILURE_OSU_PROVIDER_NOT_FOUND; |
| break; |
| default: |
| provisionFailureCode = PasspointProvisionStats.OSU_FAILURE_UNKNOWN; |
| } |
| mPasspointProvisionFailureCounts.increment(provisionFailureCode); |
| } |
| } |
| |
| /** |
| * Add to the histogram of number of BSSIDs filtered out from network selection. |
| */ |
| public void incrementNetworkSelectionFilteredBssidCount(int numBssid) { |
| mBssidBlocklistStats.networkSelectionFilteredBssidCount.increment(numBssid); |
| } |
| |
| /** |
| * Increment the number of network connections skipped due to the high movement feature. |
| */ |
| public void incrementNumHighMovementConnectionSkipped() { |
| mBssidBlocklistStats.numHighMovementConnectionSkipped++; |
| } |
| |
| /** |
| * Increment the number of network connections initiated while under the high movement |
| * feature. |
| */ |
| public void incrementNumHighMovementConnectionStarted() { |
| mBssidBlocklistStats.numHighMovementConnectionStarted++; |
| } |
| |
| /** |
| * Increment the number of times BSSIDs are blocked per reason. |
| * @param blockReason one of {@link WifiBlocklistMonitor.FailureReason} |
| */ |
| public void incrementBssidBlocklistCount(int blockReason) { |
| mBssidBlocklistStats.incrementBssidBlocklistCount(blockReason); |
| } |
| |
| /** |
| * Increment the number of times WifiConfigurations are blocked per reason. |
| * @param blockReason one of {@Link NetworkSelectionStatus.NetworkSelectionDisableReason} |
| */ |
| public void incrementWificonfigurationBlocklistCount(int blockReason) { |
| mBssidBlocklistStats.incrementWificonfigurationBlocklistCount(blockReason); |
| } |
| |
| /** |
| * Increment number of passpoint provision success |
| */ |
| public void incrementPasspointProvisionSuccess() { |
| synchronized (mLock) { |
| mNumProvisionSuccess++; |
| } |
| } |
| |
| /** |
| * Increment number of IP renewal failures. |
| */ |
| public void incrementIpRenewalFailure() { |
| synchronized (mLock) { |
| mWifiLogProto.numIpRenewalFailure++; |
| } |
| } |
| |
| /** |
| * Sets the duration for evaluating Wifi condition to trigger a data stall |
| */ |
| public void setDataStallDurationMs(int duration) { |
| synchronized (mLock) { |
| mExperimentValues.dataStallDurationMs = duration; |
| } |
| } |
| |
| /** |
| * Sets the threshold of Tx throughput below which to trigger a data stall |
| */ |
| public void setDataStallTxTputThrKbps(int txTputThr) { |
| synchronized (mLock) { |
| mExperimentValues.dataStallTxTputThrKbps = txTputThr; |
| } |
| } |
| |
| /** |
| * Sets the threshold of Rx throughput below which to trigger a data stall |
| */ |
| public void setDataStallRxTputThrKbps(int rxTputThr) { |
| synchronized (mLock) { |
| mExperimentValues.dataStallRxTputThrKbps = rxTputThr; |
| } |
| } |
| |
| /** |
| * Sets the threshold of Tx packet error rate above which to trigger a data stall |
| */ |
| public void setDataStallTxPerThr(int txPerThr) { |
| synchronized (mLock) { |
| mExperimentValues.dataStallTxPerThr = txPerThr; |
| } |
| } |
| |
| /** |
| * Sets the threshold of CCA level above which to trigger a data stall |
| */ |
| public void setDataStallCcaLevelThr(int ccaLevel) { |
| synchronized (mLock) { |
| mExperimentValues.dataStallCcaLevelThr = ccaLevel; |
| } |
| } |
| |
| /** |
| * Sets health monitor RSSI poll valid time in ms |
| */ |
| public void setHealthMonitorRssiPollValidTimeMs(int rssiPollValidTimeMs) { |
| synchronized (mLock) { |
| mExperimentValues.healthMonitorRssiPollValidTimeMs = rssiPollValidTimeMs; |
| } |
| } |
| |
| /** |
| * Increment connection duration while link layer stats report are on |
| */ |
| public void incrementConnectionDuration(int timeDeltaLastTwoPollsMs, |
| boolean isThroughputSufficient, boolean isCellularDataAvailable) { |
| synchronized (mLock) { |
| mConnectionDurationStats.incrementDurationCount(timeDeltaLastTwoPollsMs, |
| isThroughputSufficient, isCellularDataAvailable, mWifiWins); |
| |
| int band = KnownBandsChannelHelper.getBand(mLastPollFreq); |
| WifiStatsLog.write(WifiStatsLog.WIFI_HEALTH_STAT_REPORTED, timeDeltaLastTwoPollsMs, |
| isThroughputSufficient || !mWifiWins, isCellularDataAvailable, band); |
| } |
| } |
| |
| /** |
| * Sets the status to indicate whether external WiFi connected network scorer is present or not. |
| */ |
| public void setIsExternalWifiScorerOn(boolean value) { |
| synchronized (mLock) { |
| mWifiLogProto.isExternalWifiScorerOn = value; |
| } |
| } |
| |
| /** |
| * Note Wi-Fi off metrics |
| */ |
| public void noteWifiOff(boolean isDeferred, boolean isTimeout, int duration) { |
| synchronized (mLock) { |
| mWifiOffMetrics.numWifiOff++; |
| if (isDeferred) { |
| mWifiOffMetrics.numWifiOffDeferring++; |
| if (isTimeout) { |
| mWifiOffMetrics.numWifiOffDeferringTimeout++; |
| } |
| mWifiOffMetrics.wifiOffDeferringTimeHistogram.increment(duration); |
| } |
| } |
| } |
| |
| /** |
| * Increment number of BSSIDs filtered out from network selection due to MBO Association |
| * disallowed indication. |
| */ |
| public void incrementNetworkSelectionFilteredBssidCountDueToMboAssocDisallowInd() { |
| synchronized (mLock) { |
| mWifiLogProto.numBssidFilteredDueToMboAssocDisallowInd++; |
| } |
| } |
| |
| /** |
| * Increment number of times BSS transition management request frame is received from the AP. |
| */ |
| public void incrementSteeringRequestCount() { |
| synchronized (mLock) { |
| mWifiLogProto.numSteeringRequest++; |
| } |
| } |
| |
| /** |
| * Increment number of times force scan is triggered due to a |
| * BSS transition management request frame from AP. |
| */ |
| public void incrementForceScanCountDueToSteeringRequest() { |
| synchronized (mLock) { |
| mWifiLogProto.numForceScanDueToSteeringRequest++; |
| } |
| } |
| |
| /** |
| * Increment number of times STA received cellular switch |
| * request from MBO supported AP. |
| */ |
| public void incrementMboCellularSwitchRequestCount() { |
| synchronized (mLock) { |
| mWifiLogProto.numMboCellularSwitchRequest++; |
| } |
| } |
| |
| /** |
| * Increment number of times STA received steering request |
| * including MBO association retry delay. |
| */ |
| public void incrementSteeringRequestCountIncludingMboAssocRetryDelay() { |
| synchronized (mLock) { |
| mWifiLogProto.numSteeringRequestIncludingMboAssocRetryDelay++; |
| } |
| } |
| |
| /** |
| * Increment number of connect request to AP adding FILS AKM. |
| */ |
| public void incrementConnectRequestWithFilsAkmCount() { |
| synchronized (mLock) { |
| mWifiLogProto.numConnectRequestWithFilsAkm++; |
| } |
| } |
| |
| /** |
| * Increment number of times STA connected through FILS |
| * authentication. |
| */ |
| public void incrementL2ConnectionThroughFilsAuthCount() { |
| synchronized (mLock) { |
| mWifiLogProto.numL2ConnectionThroughFilsAuthentication++; |
| } |
| } |
| |
| /** |
| * Note SoftapConfig Reset Metrics |
| */ |
| public void noteSoftApConfigReset(SoftApConfiguration originalConfig, |
| SoftApConfiguration newConfig) { |
| synchronized (mLock) { |
| if (originalConfig.getSecurityType() != newConfig.getSecurityType()) { |
| mSoftApConfigLimitationMetrics.numSecurityTypeResetToDefault++; |
| } |
| if (originalConfig.getMaxNumberOfClients() != newConfig.getMaxNumberOfClients()) { |
| mSoftApConfigLimitationMetrics.numMaxClientSettingResetToDefault++; |
| } |
| if (originalConfig.isClientControlByUserEnabled() |
| != newConfig.isClientControlByUserEnabled()) { |
| mSoftApConfigLimitationMetrics.numClientControlByUserResetToDefault++; |
| } |
| } |
| } |
| |
| /** |
| * Note Softap client blocked due to max client limitation |
| */ |
| public void noteSoftApClientBlocked(int maxClient) { |
| mSoftApConfigLimitationMetrics.maxClientSettingWhenReachHistogram.increment(maxClient); |
| } |
| |
| /** |
| * Increment number of connection with different BSSID between framework and firmware selection. |
| */ |
| public void incrementNumBssidDifferentSelectionBetweenFrameworkAndFirmware() { |
| synchronized (mLock) { |
| mWifiLogProto.numBssidDifferentSelectionBetweenFrameworkAndFirmware++; |
| } |
| } |
| |
| /** |
| * Note the carrier wifi network connected successfully. |
| */ |
| public void incrementNumOfCarrierWifiConnectionSuccess() { |
| synchronized (mLock) { |
| mCarrierWifiMetrics.numConnectionSuccess++; |
| } |
| } |
| |
| /** |
| * Note the carrier wifi network connection authentication failure. |
| */ |
| public void incrementNumOfCarrierWifiConnectionAuthFailure() { |
| synchronized (mLock) { |
| mCarrierWifiMetrics.numConnectionAuthFailure++; |
| } |
| } |
| |
| /** |
| * Note the carrier wifi network connection non-authentication failure. |
| */ |
| public void incrementNumOfCarrierWifiConnectionNonAuthFailure() { |
| synchronized (mLock) { |
| mCarrierWifiMetrics.numConnectionNonAuthFailure++; |
| } |
| } |
| |
| /** |
| * Set Adaptive Connectivity state (On/Off) |
| */ |
| public void setAdaptiveConnectivityState(boolean adaptiveConnectivityEnabled) { |
| synchronized (mLock) { |
| mAdaptiveConnectivityEnabled = adaptiveConnectivityEnabled; |
| } |
| } |
| |
| /** |
| * Get total beacon receive count |
| */ |
| public long getTotalBeaconRxCount() { |
| if (mWifiUsabilityStatsEntriesList.isEmpty()) { |
| return -1; |
| } else { |
| return mWifiUsabilityStatsEntriesList.getLast().totalBeaconRx; |
| } |
| } |
| |
| /** Note whether Wifi was enabled at boot time. */ |
| public void noteWifiEnabledDuringBoot(boolean isWifiEnabled) { |
| synchronized (mLock) { |
| if (mIsFirstConnectionAttemptComplete |
| || mFirstConnectAfterBootStats == null |
| || mFirstConnectAfterBootStats.wifiEnabledAtBoot != null) { |
| return; |
| } |
| Attempt wifiEnabledAtBoot = new Attempt(); |
| wifiEnabledAtBoot.isSuccess = isWifiEnabled; |
| wifiEnabledAtBoot.timestampSinceBootMillis = mClock.getElapsedSinceBootMillis(); |
| mFirstConnectAfterBootStats.wifiEnabledAtBoot = wifiEnabledAtBoot; |
| if (!isWifiEnabled) { |
| mIsFirstConnectionAttemptComplete = true; |
| } |
| } |
| } |
| |
| /** Note the first network selection after boot. */ |
| public void noteFirstNetworkSelectionAfterBoot(boolean wasAnyCandidatesFound) { |
| synchronized (mLock) { |
| if (mIsFirstConnectionAttemptComplete |
| || mFirstConnectAfterBootStats == null |
| || mFirstConnectAfterBootStats.firstNetworkSelection != null) { |
| return; |
| } |
| Attempt firstNetworkSelection = new Attempt(); |
| firstNetworkSelection.isSuccess = wasAnyCandidatesFound; |
| firstNetworkSelection.timestampSinceBootMillis = mClock.getElapsedSinceBootMillis(); |
| mFirstConnectAfterBootStats.firstNetworkSelection = firstNetworkSelection; |
| if (!wasAnyCandidatesFound) { |
| mIsFirstConnectionAttemptComplete = true; |
| } |
| } |
| } |
| |
| /** Note the first L2 connection after boot. */ |
| public void noteFirstL2ConnectionAfterBoot(boolean wasConnectionSuccessful) { |
| synchronized (mLock) { |
| if (mIsFirstConnectionAttemptComplete |
| || mFirstConnectAfterBootStats == null |
| || mFirstConnectAfterBootStats.firstL2Connection != null) { |
| return; |
| } |
| Attempt firstL2Connection = new Attempt(); |
| firstL2Connection.isSuccess = wasConnectionSuccessful; |
| firstL2Connection.timestampSinceBootMillis = mClock.getElapsedSinceBootMillis(); |
| mFirstConnectAfterBootStats.firstL2Connection = firstL2Connection; |
| if (!wasConnectionSuccessful) { |
| mIsFirstConnectionAttemptComplete = true; |
| } |
| } |
| } |
| |
| /** Note the first L3 connection after boot. */ |
| public void noteFirstL3ConnectionAfterBoot(boolean wasConnectionSuccessful) { |
| synchronized (mLock) { |
| if (mIsFirstConnectionAttemptComplete |
| || mFirstConnectAfterBootStats == null |
| || mFirstConnectAfterBootStats.firstL3Connection != null) { |
| return; |
| } |
| Attempt firstL3Connection = new Attempt(); |
| firstL3Connection.isSuccess = wasConnectionSuccessful; |
| firstL3Connection.timestampSinceBootMillis = mClock.getElapsedSinceBootMillis(); |
| mFirstConnectAfterBootStats.firstL3Connection = firstL3Connection; |
| if (!wasConnectionSuccessful) { |
| mIsFirstConnectionAttemptComplete = true; |
| } |
| } |
| } |
| |
| private static String attemptToString(@Nullable Attempt attempt) { |
| if (attempt == null) return "Attempt=null"; |
| return "Attempt{" |
| + "timestampSinceBootMillis=" + attempt.timestampSinceBootMillis |
| + ",isSuccess=" + attempt.isSuccess |
| + "}"; |
| } |
| |
| private static String firstConnectAfterBootStatsToString( |
| @Nullable FirstConnectAfterBootStats stats) { |
| if (stats == null) return "FirstConnectAfterBootStats=null"; |
| return "FirstConnectAfterBootStats{" |
| + "wifiEnabledAtBoot=" + attemptToString(stats.wifiEnabledAtBoot) |
| + ",firstNetworkSelection" + attemptToString(stats.firstNetworkSelection) |
| + ",firstL2Connection" + attemptToString(stats.firstL2Connection) |
| + ",firstL3Connection" + attemptToString(stats.firstL3Connection) |
| + "}"; |
| } |
| |
| public ScanMetrics getScanMetrics() { |
| return mScanMetrics; |
| } |
| |
| public enum ScanType { SINGLE, BACKGROUND } |
| |
| public enum PnoScanState { STARTED, FAILED_TO_START, COMPLETED_NETWORK_FOUND, FAILED } |
| |
| /** |
| * This class reports Scan metrics to statsd and holds intermediate scan request state. |
| */ |
| public static class ScanMetrics { |
| private static final String TAG_SCANS = "ScanMetrics"; |
| private static final String GMS_PACKAGE = "com.google.android.gms"; |
| |
| // Scan types. |
| public static final int SCAN_TYPE_SINGLE = 0; |
| public static final int SCAN_TYPE_BACKGROUND = 1; |
| public static final int SCAN_TYPE_MAX_VALUE = SCAN_TYPE_BACKGROUND; |
| @IntDef(prefix = { "SCAN_TYPE_" }, value = { |
| SCAN_TYPE_SINGLE, |
| SCAN_TYPE_BACKGROUND, |
| }) |
| public @interface ScanType {} |
| |
| // PNO scan states. |
| public static final int PNO_SCAN_STATE_STARTED = 1; |
| public static final int PNO_SCAN_STATE_FAILED_TO_START = 2; |
| public static final int PNO_SCAN_STATE_COMPLETED_NETWORK_FOUND = 3; |
| public static final int PNO_SCAN_STATE_FAILED = 4; |
| @IntDef(prefix = { "PNO_SCAN_STATE_" }, value = { |
| PNO_SCAN_STATE_STARTED, |
| PNO_SCAN_STATE_FAILED_TO_START, |
| PNO_SCAN_STATE_COMPLETED_NETWORK_FOUND, |
| PNO_SCAN_STATE_FAILED |
| }) |
| public @interface PnoScanState {} |
| |
| private final Object mLock = new Object(); |
| private Clock mClock; |
| |
| private List<String> mSettingsPackages = new ArrayList<>(); |
| private int mGmsUid = -1; |
| |
| // mNextScanState collects metadata about the next scan that's about to happen. |
| // It is mutated by external callers via setX methods before the call to logScanStarted. |
| private State mNextScanState = new State(); |
| // mActiveScanState is an immutable copy of mNextScanState during the scan process, |
| // i.e. between logScanStarted and logScanSucceeded/Failed. Since the state is pushed to |
| // statsd only when a scan ends, it's important to keep the immutable copy |
| // for the duration of the scan. |
| private State[] mActiveScanStates = new State[SCAN_TYPE_MAX_VALUE + 1]; |
| |
| ScanMetrics(Context context, Clock clock) { |
| mClock = clock; |
| |
| PackageManager pm = context.getPackageManager(); |
| if (pm != null) { |
| Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS); |
| List<ResolveInfo> packages = pm.queryIntentActivities(settingsIntent, 0); |
| for (ResolveInfo res : packages) { |
| String packageName = res.activityInfo.packageName; |
| Log.d(TAG_SCANS, "Settings package: " + packageName); |
| mSettingsPackages.add(packageName); |
| } |
| } |
| |
| try { |
| mGmsUid = context.getPackageManager().getApplicationInfo(GMS_PACKAGE, 0).uid; |
| Log.d(TAG_SCANS, "GMS uid: " + mGmsUid); |
| } catch (Exception e) { |
| Log.e(TAG_SCANS, "Can't get GMS uid"); |
| } |
| } |
| |
| /** |
| * Set WorkSource for the upcoming scan request. |
| * |
| * @param workSource |
| */ |
| public void setWorkSource(WorkSource workSource) { |
| synchronized (mLock) { |
| if (mNextScanState.mWorkSource == null) { |
| mNextScanState.mWorkSource = workSource; |
| if (DBG) Log.d(TAG_SCANS, "setWorkSource: workSource = " + workSource); |
| } |
| } |
| } |
| |
| /** |
| * Set ClientUid for the upcoming scan request. |
| * |
| * @param uid |
| */ |
| public void setClientUid(int uid) { |
| synchronized (mLock) { |
| mNextScanState.mClientUid = uid; |
| |
| if (DBG) Log.d(TAG_SCANS, "setClientUid: uid = " + uid); |
| } |
| } |
| |
| /** |
| * Set Importance for the upcoming scan request. |
| * |
| * @param packageImportance See {@link ActivityManager.RunningAppProcessInfo.Importance} |
| */ |
| public void setImportance(int packageImportance) { |
| synchronized (mLock) { |
| mNextScanState.mPackageImportance = packageImportance; |
| |
| if (DBG) { |
| Log.d(TAG_SCANS, |
| "setRequestFromBackground: packageImportance = " + packageImportance); |
| } |
| } |
| } |
| |
| /** |
| * Indicate that a scan started. |
| * @param scanType See {@link ScanMetrics.ScanType} |
| */ |
| public void logScanStarted(@ScanType int scanType) { |
| synchronized (mLock) { |
| if (DBG) Log.d(TAG_SCANS, "logScanStarted"); |
| |
| mNextScanState.mTimeStartMillis = mClock.getElapsedSinceBootMillis(); |
| mActiveScanStates[scanType] = mNextScanState; |
| mNextScanState = new State(); |
| } |
| } |
| |
| /** |
| * Indicate that a scan failed to start. |
| * @param scanType See {@link ScanMetrics.ScanType} |
| */ |
| public void logScanFailedToStart(@ScanType int scanType) { |
| synchronized (mLock) { |
| Log.d(TAG_SCANS, "logScanFailedToStart"); |
| |
| mNextScanState.mTimeStartMillis = mClock.getElapsedSinceBootMillis(); |
| mActiveScanStates[scanType] = mNextScanState; |
| mNextScanState = new State(); |
| |
| log(scanType, WifiStatsLog.WIFI_SCAN_REPORTED__RESULT__RESULT_FAILED_TO_START, 0); |
| mActiveScanStates[scanType] = null; |
| } |
| } |
| |
| /** |
| * Indicate that a scan finished successfully. |
| * @param scanType See {@link ScanMetrics.ScanType} |
| * @param countOfNetworksFound How many networks were found. |
| */ |
| public void logScanSucceeded(@ScanType int scanType, int countOfNetworksFound) { |
| synchronized (mLock) { |
| if (DBG) Log.d(TAG_SCANS, "logScanSucceeded: found = " + countOfNetworksFound); |
| |
| log(scanType, WifiStatsLog.WIFI_SCAN_REPORTED__RESULT__RESULT_SUCCESS, |
| countOfNetworksFound); |
| mActiveScanStates[scanType] = null; |
| } |
| } |
| |
| /** |
| * Log a PNO scan event: start/finish/fail. |
| * @param pnoScanState See {@link PnoScanState} |
| */ |
| public void logPnoScanEvent(@PnoScanState int pnoScanState) { |
| synchronized (mLock) { |
| int state = 0; |
| |
| switch (pnoScanState) { |
| case PNO_SCAN_STATE_STARTED: |
| state = WifiStatsLog.WIFI_PNO_SCAN_REPORTED__STATE__STARTED; |
| break; |
| case PNO_SCAN_STATE_FAILED_TO_START: |
| state = WifiStatsLog.WIFI_PNO_SCAN_REPORTED__STATE__FAILED_TO_START; |
| break; |
| case PNO_SCAN_STATE_COMPLETED_NETWORK_FOUND: |
| state = WifiStatsLog.WIFI_PNO_SCAN_REPORTED__STATE__FINISHED_NETWORKS_FOUND; |
| break; |
| case PNO_SCAN_STATE_FAILED: |
| state = WifiStatsLog.WIFI_PNO_SCAN_REPORTED__STATE__FAILED; |
| break; |
| } |
| |
| WifiStatsLog.write(WifiStatsLog.WIFI_PNO_SCAN_REPORTED, state); |
| |
| if (DBG) Log.d(TAG_SCANS, "logPnoScanEvent: pnoScanState = " + pnoScanState); |
| } |
| } |
| |
| /** |
| * Indicate that a scan failed. |
| */ |
| public void logScanFailed(@ScanType int scanType) { |
| synchronized (mLock) { |
| if (DBG) Log.d(TAG_SCANS, "logScanFailed"); |
| |
| log(scanType, WifiStatsLog.WIFI_SCAN_REPORTED__RESULT__RESULT_FAILED_TO_SCAN, 0); |
| mActiveScanStates[scanType] = null; |
| } |
| } |
| |
| private void log(@ScanType int scanType, int result, int countNetworks) { |
| State state = mActiveScanStates[scanType]; |
| |
| if (state == null) { |
| if (DBG) Log.e(TAG_SCANS, "Wifi scan result log called with no prior start calls!"); |
| return; |
| } |
| |
| int type = WifiStatsLog.WIFI_SCAN_REPORTED__TYPE__TYPE_UNKNOWN; |
| if (scanType == SCAN_TYPE_SINGLE) { |
| type = WifiStatsLog.WIFI_SCAN_REPORTED__TYPE__TYPE_SINGLE; |
| } else if (scanType == SCAN_TYPE_BACKGROUND) { |
| type = WifiStatsLog.WIFI_SCAN_REPORTED__TYPE__TYPE_BACKGROUND; |
| } |
| |
| long duration = mClock.getElapsedSinceBootMillis() - state.mTimeStartMillis; |
| |
| int source = WifiStatsLog.WIFI_SCAN_REPORTED__SOURCE__SOURCE_NO_WORK_SOURCE; |
| if (state.mClientUid != -1 && state.mClientUid == mGmsUid) { |
| source = WifiStatsLog.WIFI_SCAN_REPORTED__SOURCE__SOURCE_GMS; |
| } else if (state.mWorkSource != null) { |
| if (state.mWorkSource.equals(ClientModeImpl.WIFI_WORK_SOURCE)) { |
| source = WifiStatsLog.WIFI_SCAN_REPORTED__SOURCE__SOURCE_WIFI_STACK; |
| } else { |
| source = WifiStatsLog.WIFI_SCAN_REPORTED__SOURCE__SOURCE_OTHER_APP; |
| |
| for (int i = 0; i < state.mWorkSource.size(); i++) { |
| if (mSettingsPackages.contains( |
| state.mWorkSource.getPackageName(i))) { |
| source = WifiStatsLog.WIFI_SCAN_REPORTED__SOURCE__SOURCE_SETTINGS_APP; |
| break; |
| } |
| } |
| } |
| } |
| |
| int importance = WifiStatsLog.WIFI_SCAN_REPORTED__IMPORTANCE__IMPORTANCE_UNKNOWN; |
| if (state.mPackageImportance != -1) { |
| if (state.mPackageImportance |
| <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { |
| importance = WifiStatsLog.WIFI_SCAN_REPORTED__IMPORTANCE__IMPORTANCE_FOREGROUND; |
| } else if (state.mPackageImportance |
| <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE) { |
| importance = |
| WifiStatsLog.WIFI_SCAN_REPORTED__IMPORTANCE__IMPORTANCE_FOREGROUND_SERVICE; |
| } else { |
| importance = WifiStatsLog.WIFI_SCAN_REPORTED__IMPORTANCE__IMPORTANCE_BACKGROUND; |
| } |
| } |
| |
| WifiStatsLog.write(WifiStatsLog.WIFI_SCAN_REPORTED, |
| type, |
| result, |
| source, |
| importance, |
| (int) duration, |
| countNetworks); |
| |
| if (DBG) { |
| Log.d(TAG_SCANS, |
| "WifiScanReported: type = " + type |
| + ", result = " + result |
| + ", source = " + source |
| + ", importance = " + importance |
| + ", networks = " + countNetworks); |
| } |
| } |
| |
| static class State { |
| WorkSource mWorkSource = null; |
| int mClientUid = -1; |
| // see @ActivityManager.RunningAppProcessInfo.Importance |
| int mPackageImportance = -1; |
| |
| long mTimeStartMillis; |
| } |
| } |
| |
| /** Set whether Make Before Break is supported by the hardware and enabled. */ |
| public void setIsMakeBeforeBreakSupported(boolean supported) { |
| synchronized (mLock) { |
| mWifiToWifiSwitchStats.isMakeBeforeBreakSupported = supported; |
| } |
| } |
| |
| /** |
| * Increment the number of times Wifi to Wifi switch was triggered. This includes Make Before |
| * Break and Break Before Make. |
| */ |
| public void incrementWifiToWifiSwitchTriggerCount() { |
| synchronized (mLock) { |
| mWifiToWifiSwitchStats.wifiToWifiSwitchTriggerCount++; |
| } |
| } |
| |
| /** |
| * Increment the Number of times Wifi to Wifi switch was triggered using Make Before Break |
| * (MBB). Note that MBB may not always be used for various reasons e.g. no additional iface |
| * available due to ongoing SoftAP, both old and new network have MAC randomization disabled, |
| * etc. |
| */ |
| public void incrementMakeBeforeBreakTriggerCount() { |
| synchronized (mLock) { |
| mWifiToWifiSwitchStats.makeBeforeBreakTriggerCount++; |
| } |
| } |
| |
| /** |
| * Increment the number of times Make Before Break was aborted due to the new network not having |
| * internet. |
| */ |
| public void incrementMakeBeforeBreakNoInternetCount() { |
| synchronized (mLock) { |
| mWifiToWifiSwitchStats.makeBeforeBreakNoInternetCount++; |
| } |
| } |
| |
| /** |
| * Increment the number of times where, for some reason, Make Before Break resulted in the |
| * loss of the primary ClientModeManager, and we needed to recover by making one of the |
| * SECONDARY_TRANSIENT ClientModeManagers primary. |
| */ |
| public void incrementMakeBeforeBreakRecoverPrimaryCount() { |
| synchronized (mLock) { |
| mWifiToWifiSwitchStats.makeBeforeBreakRecoverPrimaryCount++; |
| } |
| } |
| |
| /** |
| * Increment the number of times the new network in Make Before Break had its internet |
| * connection validated. |
| */ |
| public void incrementMakeBeforeBreakInternetValidatedCount() { |
| synchronized (mLock) { |
| mWifiToWifiSwitchStats.makeBeforeBreakInternetValidatedCount++; |
| } |
| } |
| |
| /** |
| * Increment the number of times the old network in Make Before Break was successfully |
| * transitioned from PRIMARY to SECONDARY_TRANSIENT role. |
| */ |
| public void incrementMakeBeforeBreakSuccessCount() { |
| synchronized (mLock) { |
| mWifiToWifiSwitchStats.makeBeforeBreakSuccessCount++; |
| } |
| } |
| |
| /** |
| * Increment the number of times the old network in Make Before Break completed lingering and |
| * was disconnected. |
| * @param duration the lingering duration in ms |
| */ |
| public void incrementMakeBeforeBreakLingerCompletedCount(long duration) { |
| synchronized (mLock) { |
| mWifiToWifiSwitchStats.makeBeforeBreakLingerCompletedCount++; |
| int lingeringDurationSeconds = Math.min(MBB_LINGERING_DURATION_MAX_SECONDS, |
| (int) duration / 1000); |
| mMakeBeforeBreakLingeringDurationSeconds.increment(lingeringDurationSeconds); |
| } |
| } |
| |
| private String wifiToWifiSwitchStatsToString(WifiToWifiSwitchStats stats) { |
| return "WifiToWifiSwitchStats{" |
| + "isMakeBeforeBreakSupported=" + stats.isMakeBeforeBreakSupported |
| + ",wifiToWifiSwitchTriggerCount=" + stats.wifiToWifiSwitchTriggerCount |
| + ",makeBeforeBreakTriggerCount=" + stats.makeBeforeBreakTriggerCount |
| + ",makeBeforeBreakNoInternetCount=" + stats.makeBeforeBreakNoInternetCount |
| + ",makeBeforeBreakRecoverPrimaryCount=" + stats.makeBeforeBreakRecoverPrimaryCount |
| + ",makeBeforeBreakInternetValidatedCount=" |
| + stats.makeBeforeBreakInternetValidatedCount |
| + ",makeBeforeBreakSuccessCount=" + stats.makeBeforeBreakSuccessCount |
| + ",makeBeforeBreakLingerCompletedCount=" |
| + stats.makeBeforeBreakLingerCompletedCount |
| + ",makeBeforeBreakLingeringDurationSeconds=" |
| + mMakeBeforeBreakLingeringDurationSeconds |
| + "}"; |
| } |
| |
| /** |
| * Increment number of number of Passpoint connections with a venue URL |
| */ |
| public void incrementTotalNumberOfPasspointConnectionsWithVenueUrl() { |
| synchronized (mLock) { |
| mWifiLogProto.totalNumberOfPasspointConnectionsWithVenueUrl++; |
| } |
| } |
| |
| /** |
| * Increment number of number of Passpoint connections with a T&C URL |
| */ |
| public void incrementTotalNumberOfPasspointConnectionsWithTermsAndConditionsUrl() { |
| synchronized (mLock) { |
| mWifiLogProto.totalNumberOfPasspointConnectionsWithTermsAndConditionsUrl++; |
| } |
| } |
| |
| /** |
| * Increment number of successful acceptance of Passpoint T&C |
| */ |
| public void incrementTotalNumberOfPasspointAcceptanceOfTermsAndConditions() { |
| synchronized (mLock) { |
| mWifiLogProto.totalNumberOfPasspointAcceptanceOfTermsAndConditions++; |
| } |
| } |
| |
| /** |
| * Increment number of Passpoint profiles with decorated identity prefix |
| */ |
| public void incrementTotalNumberOfPasspointProfilesWithDecoratedIdentity() { |
| synchronized (mLock) { |
| mWifiLogProto.totalNumberOfPasspointProfilesWithDecoratedIdentity++; |
| } |
| } |
| |
| /** |
| * Increment number of Passpoint Deauth-Imminent notification scope |
| */ |
| public void incrementPasspointDeauthImminentScope(boolean isEss) { |
| synchronized (mLock) { |
| mPasspointDeauthImminentScope.increment(isEss ? PASSPOINT_DEAUTH_IMMINENT_SCOPE_ESS |
| : PASSPOINT_DEAUTH_IMMINENT_SCOPE_BSS); |
| } |
| } |
| |
| /** |
| * Increment number of times connection failure status reported per |
| * WifiConfiguration.RecentFailureReason |
| */ |
| public void incrementRecentFailureAssociationStatusCount( |
| @WifiConfiguration.RecentFailureReason int reason) { |
| synchronized (mLock) { |
| mRecentFailureAssociationStatus.increment(reason); |
| } |
| } |
| } |