1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi; 18 19 import android.app.StatsManager; 20 import android.content.Context; 21 import android.content.pm.PackageInfo; 22 import android.content.pm.PackageManager; 23 import android.net.wifi.WifiConfiguration; 24 import android.net.wifi.WifiManager; 25 import android.net.wifi.WifiNetworkSuggestion; 26 import android.net.wifi.WifiSsid; 27 import android.os.Handler; 28 import android.os.Process; 29 import android.text.TextUtils; 30 import android.util.Log; 31 import android.util.StatsEvent; 32 33 import com.android.server.wifi.proto.WifiStatsLog; 34 35 import java.util.List; 36 import java.util.Set; 37 38 /** 39 * This is used to log pulled atoms to StatsD via Callback. 40 */ 41 public class WifiPulledAtomLogger { 42 public static final String WIFI_BUILD_FROM_SOURCE_PACKAGE_NAME = "com.android.wifi"; 43 private static final String WIFI_PACKAGE_NAME_SUFFIX = ".android.wifi"; 44 private int mWifiBuildType = 0; 45 46 private static final String TAG = "WifiPulledAtomLogger"; 47 private final StatsManager mStatsManager; 48 private final Handler mWifiHandler; 49 private final Context mContext; 50 private final WifiInjector mWifiInjector; 51 private StatsManager.StatsPullAtomCallback mStatsPullAtomCallback; 52 53 private int mApexVersionNumber = -1; 54 WifiPulledAtomLogger(StatsManager statsManager, Handler handler, Context context, WifiInjector wifiInjector)55 public WifiPulledAtomLogger(StatsManager statsManager, Handler handler, Context context, 56 WifiInjector wifiInjector) { 57 mStatsManager = statsManager; 58 mWifiHandler = handler; 59 mStatsPullAtomCallback = new WifiPullAtomCallback(); 60 mContext = context; 61 mWifiInjector = wifiInjector; 62 } 63 64 /** 65 * Set up an atom to get pulled. 66 * @param atomTag 67 */ setPullAtomCallback(int atomTag)68 public void setPullAtomCallback(int atomTag) { 69 if (mStatsManager == null) { 70 Log.e(TAG, "StatsManager is null. Failed to set wifi pull atom callback for atomTag=" 71 + atomTag); 72 return; 73 } 74 mStatsManager.setPullAtomCallback( 75 atomTag, 76 null, // use default meta data values 77 command -> mWifiHandler.post(command), // Executor posting to wifi handler thread 78 mStatsPullAtomCallback 79 ); 80 } 81 82 /** 83 * Implementation of StatsPullAtomCallback. This will check the atom tag and log data 84 * correspondingly. 85 */ 86 public class WifiPullAtomCallback implements StatsManager.StatsPullAtomCallback { 87 @Override onPullAtom(int atomTag, List<StatsEvent> data)88 public int onPullAtom(int atomTag, List<StatsEvent> data) { 89 switch (atomTag) { 90 case WifiStatsLog.WIFI_MODULE_INFO: 91 return handleWifiVersionPull(atomTag, data); 92 case WifiStatsLog.WIFI_SETTING_INFO: 93 return handleWifiSettingsPull(atomTag, data); 94 case WifiStatsLog.WIFI_COMPLEX_SETTING_INFO: 95 return handleWifiComplexSettingsPull(atomTag, data); 96 case WifiStatsLog.WIFI_CONFIGURED_NETWORK_INFO: 97 return handleWifiConfiguredNetworkInfoPull(atomTag, data); 98 default: 99 return StatsManager.PULL_SKIP; 100 } 101 } 102 } 103 handleWifiVersionPull(int atomTag, List<StatsEvent> data)104 private int handleWifiVersionPull(int atomTag, List<StatsEvent> data) { 105 if (mWifiBuildType != 0) { 106 // build type already cached. No need to get it again. 107 data.add(WifiStatsLog.buildStatsEvent(atomTag, mApexVersionNumber, mWifiBuildType)); 108 return StatsManager.PULL_SUCCESS; 109 } 110 PackageManager pm = mContext.getPackageManager(); 111 if (pm == null) { 112 Log.e(TAG, "Failed to get package manager"); 113 return StatsManager.PULL_SKIP; 114 } 115 updateBuildTypeAndVersionCode(pm); 116 117 data.add(WifiStatsLog.buildStatsEvent(atomTag, mApexVersionNumber, mWifiBuildType)); 118 return StatsManager.PULL_SUCCESS; 119 } 120 handleWifiSettingsPull(int atomTag, List<StatsEvent> data)121 private int handleWifiSettingsPull(int atomTag, List<StatsEvent> data) { 122 WifiSettingsStore settingsStore = mWifiInjector.getWifiSettingsStore(); 123 data.add(WifiStatsLog.buildStatsEvent(atomTag, 124 WifiStatsLog.WIFI_SETTING_INFO__SETTING_NAME__WIFI_SCAN_ALWAYS_AVAILABLE, 125 settingsStore.isScanAlwaysAvailable())); 126 data.add(WifiStatsLog.buildStatsEvent(atomTag, 127 WifiStatsLog.WIFI_SETTING_INFO__SETTING_NAME__WIFI_SCAN_THROTTLE, 128 settingsStore.isWifiScanThrottleEnabled())); 129 data.add(WifiStatsLog.buildStatsEvent(atomTag, 130 WifiStatsLog.WIFI_SETTING_INFO__SETTING_NAME__WIFI_SCORING, 131 settingsStore.isWifiScoringEnabled())); 132 data.add(WifiStatsLog.buildStatsEvent(atomTag, 133 WifiStatsLog.WIFI_SETTING_INFO__SETTING_NAME__WIFI_PASSPOINT, 134 settingsStore.isWifiPasspointEnabled())); 135 136 boolean nonPersistentMacRandEnabled = mWifiInjector.getFrameworkFacade().getIntegerSetting( 137 mContext, 138 WifiConfigManager.NON_PERSISTENT_MAC_RANDOMIZATION_FEATURE_FORCE_ENABLE_FLAG, 0) 139 == 1 ? true : false; 140 data.add(WifiStatsLog.buildStatsEvent(atomTag, 141 WifiStatsLog.WIFI_SETTING_INFO__SETTING_NAME__WIFI_ENHANCED_MAC_RANDOMIZATION, 142 nonPersistentMacRandEnabled)); 143 144 data.add(WifiStatsLog.buildStatsEvent(atomTag, 145 WifiStatsLog.WIFI_SETTING_INFO__SETTING_NAME__WIFI_WAKE, 146 mWifiInjector.getWakeupController().isEnabled())); 147 data.add(WifiStatsLog.buildStatsEvent(atomTag, 148 WifiStatsLog.WIFI_SETTING_INFO__SETTING_NAME__WIFI_NETWORKS_AVAILABLE_NOTIFICATION, 149 mWifiInjector.getOpenNetworkNotifier().isSettingEnabled())); 150 data.add(WifiStatsLog.buildStatsEvent(atomTag, 151 WifiStatsLog.WIFI_SETTING_INFO__SETTING_NAME__LOCATION_MODE, 152 mWifiInjector.getWifiPermissionsUtil().isLocationModeEnabled())); 153 data.add(WifiStatsLog.buildStatsEvent(atomTag, 154 WifiStatsLog.WIFI_SETTING_INFO__SETTING_NAME__EXTERNAL_SCORER_DRY_RUN, 155 !TextUtils.isEmpty( 156 mWifiInjector.getDeviceConfigFacade().getDryRunScorerPkgName()))); 157 return StatsManager.PULL_SUCCESS; 158 } 159 frameworkToAtomMultiInternetMode( @ifiManager.WifiMultiInternetMode int mode)160 private static int frameworkToAtomMultiInternetMode( 161 @WifiManager.WifiMultiInternetMode int mode) { 162 switch (mode) { 163 case WifiManager.WIFI_MULTI_INTERNET_MODE_DISABLED: 164 return WifiStatsLog 165 .WIFI_COMPLEX_SETTING_INFO__MULTI_INTERNET_MODE__MULTI_INTERNET_MODE_DISABLED; 166 case WifiManager.WIFI_MULTI_INTERNET_MODE_DBS_AP: 167 return WifiStatsLog 168 .WIFI_COMPLEX_SETTING_INFO__MULTI_INTERNET_MODE__MULTI_INTERNET_MODE_DBS_AP; 169 case WifiManager.WIFI_MULTI_INTERNET_MODE_MULTI_AP: 170 return WifiStatsLog 171 .WIFI_COMPLEX_SETTING_INFO__MULTI_INTERNET_MODE__MULTI_INTERNET_MODE_MULTI_AP; 172 default: 173 Log.i(TAG, "Invalid multi-internet mode: " + mode); 174 return -1; 175 } 176 } 177 handleWifiComplexSettingsPull(int atomTag, List<StatsEvent> data)178 private int handleWifiComplexSettingsPull(int atomTag, List<StatsEvent> data) { 179 int multiInternetMode = frameworkToAtomMultiInternetMode( 180 mWifiInjector.getWifiSettingsStore().getWifiMultiInternetMode()); 181 if (multiInternetMode == -1) { 182 return StatsManager.PULL_SKIP; 183 } 184 data.add(WifiStatsLog.buildStatsEvent(atomTag, multiInternetMode)); 185 return StatsManager.PULL_SUCCESS; 186 } 187 updateBuildTypeAndVersionCode(PackageManager pm)188 private void updateBuildTypeAndVersionCode(PackageManager pm) { 189 // Query build type and cache if not already cached. 190 List<PackageInfo> packageInfos = pm.getInstalledPackages(PackageManager.MATCH_APEX); 191 boolean found = false; 192 String wifiPackageName = null; 193 for (PackageInfo packageInfo : packageInfos) { 194 if (packageInfo.packageName.endsWith(WIFI_PACKAGE_NAME_SUFFIX)) { 195 mApexVersionNumber = (int) packageInfo.getLongVersionCode(); 196 wifiPackageName = packageInfo.packageName; 197 if (packageInfo.packageName.equals(WIFI_BUILD_FROM_SOURCE_PACKAGE_NAME)) { 198 found = true; 199 } 200 break; 201 } 202 } 203 mWifiBuildType = found 204 ? WifiStatsLog.WIFI_MODULE_INFO__BUILD_TYPE__TYPE_BUILT_FROM_SOURCE 205 : WifiStatsLog.WIFI_MODULE_INFO__BUILD_TYPE__TYPE_PREBUILT; 206 Log.i(TAG, "Wifi Module package name is " + wifiPackageName 207 + ", version is " + mApexVersionNumber); 208 } 209 configHasUtf8Ssid(WifiConfiguration config)210 private static boolean configHasUtf8Ssid(WifiConfiguration config) { 211 return WifiSsid.fromString(config.SSID).getUtf8Text() != null; 212 } 213 wifiConfigToStatsEvent( int atomTag, WifiConfiguration config, boolean isSuggestion)214 private StatsEvent wifiConfigToStatsEvent( 215 int atomTag, WifiConfiguration config, boolean isSuggestion) { 216 return WifiStatsLog.buildStatsEvent( 217 atomTag, 218 0, // deprecated network ID field 219 config.isEnterprise(), 220 config.hiddenSSID, 221 config.isPasspoint(), 222 isSuggestion, 223 configHasUtf8Ssid(config), 224 mWifiInjector.getSsidTranslator().isSsidTranslationEnabled(), 225 false, // legacy TOFU field 226 !config.getNetworkSelectionStatus().hasNeverDetectedCaptivePortal(), 227 config.allowAutojoin, 228 WifiMetrics.convertSecurityModeToProto(config), 229 WifiMetrics.convertMacRandomizationToProto(config.getMacRandomizationSetting()), 230 WifiMetrics.convertMeteredOverrideToProto(config.meteredOverride), 231 WifiMetrics.convertEapMethodToProto(config), 232 WifiMetrics.convertEapInnerMethodToProto(config), 233 WifiMetrics.isFreeOpenRoaming(config), 234 WifiMetrics.isSettledOpenRoaming(config), 235 WifiMetrics.convertTofuConnectionStateToProto(config), 236 WifiMetrics.convertTofuDialogStateToProto(config)); 237 } 238 handleWifiConfiguredNetworkInfoPull(int atomTag, List<StatsEvent> data)239 private int handleWifiConfiguredNetworkInfoPull(int atomTag, List<StatsEvent> data) { 240 List<WifiConfiguration> savedConfigs = 241 mWifiInjector.getWifiConfigManager().getSavedNetworks(Process.WIFI_UID); 242 for (WifiConfiguration config : savedConfigs) { 243 if (!config.isPasspoint()) { 244 data.add(wifiConfigToStatsEvent(atomTag, config, false)); 245 } 246 } 247 248 Set<WifiNetworkSuggestion> approvedSuggestions = 249 mWifiInjector.getWifiNetworkSuggestionsManager().getAllApprovedNetworkSuggestions(); 250 for (WifiNetworkSuggestion suggestion : approvedSuggestions) { 251 WifiConfiguration config = suggestion.getWifiConfiguration(); 252 if (!config.isPasspoint()) { 253 data.add(wifiConfigToStatsEvent(atomTag, config, true)); 254 } 255 } 256 257 List<WifiConfiguration> passpointConfigs = 258 mWifiInjector.getPasspointManager().getWifiConfigsForPasspointProfiles(false); 259 for (WifiConfiguration config : passpointConfigs) { 260 data.add(wifiConfigToStatsEvent(atomTag, config, false)); 261 } 262 263 List<WifiConfiguration> passpointSuggestions = 264 mWifiInjector.getWifiNetworkSuggestionsManager() 265 .getAllPasspointScanOptimizationSuggestionNetworks(false); 266 for (WifiConfiguration config : passpointSuggestions) { 267 data.add(wifiConfigToStatsEvent(atomTag, config, true)); 268 } 269 270 return StatsManager.PULL_SUCCESS; 271 } 272 } 273