1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi; 18 19 import android.app.AlarmManager; 20 import android.content.Context; 21 import android.net.NetworkCapabilities; 22 import android.net.NetworkFactory; 23 import android.net.NetworkRequest; 24 import android.net.wifi.ScanResult; 25 import android.net.wifi.WifiNetworkSpecifier; 26 import android.os.Looper; 27 import android.os.WorkSource; 28 import android.util.LocalLog; 29 import android.util.Log; 30 import android.util.SparseArray; 31 32 import com.android.server.wifi.util.WifiPermissionsUtil; 33 34 import java.io.FileDescriptor; 35 import java.io.PrintWriter; 36 37 /** 38 * Network factory to handle multi internet wifi network requests. 39 */ 40 public class MultiInternetWifiNetworkFactory extends NetworkFactory { 41 private static final String TAG = "MultiInternetWifiNetworkFactory"; 42 private static final int SCORE_FILTER = Integer.MAX_VALUE; 43 44 private final WifiConnectivityManager mWifiConnectivityManager; 45 private final MultiInternetManager mMultiInternetManager; 46 private final WifiPermissionsUtil mWifiPermissionsUtil; 47 private final FrameworkFacade mFacade; 48 private final Context mContext; 49 private final AlarmManager mAlarmManager; 50 private final LocalLog mLocalLog; 51 52 // Verbose logging flag. 53 private boolean mVerboseLoggingEnabled = false; 54 // Connection request state per each band. 55 private SparseArray<NetworkRequestState> mNetworkRequestStates = new SparseArray<>(); 56 // Connection request count per each band. 57 private SparseArray<Integer> mConnectionReqCount = new SparseArray<>(); 58 59 // A helper to log debugging information in the local log buffer, which can 60 // be retrieved in bugreport. localLog(String log)61 private void localLog(String log) { 62 mLocalLog.log(log); 63 if (mVerboseLoggingEnabled) Log.v(TAG, log); 64 } 65 66 /** 67 * Internal network request state for multi internet networks 68 */ 69 public static class NetworkRequestState { 70 public final NetworkRequest networkRequest; 71 public final WifiNetworkSpecifier networkRequestSpecifier; 72 public final boolean isFromSetting; 73 public final boolean isFromForegroundApp; 74 public final boolean isFromForegroundAppOrService; 75 NetworkRequestState(NetworkRequest request, WifiNetworkSpecifier specifier, boolean setting, boolean foregroundApp, boolean foregroundAppOrService)76 NetworkRequestState(NetworkRequest request, 77 WifiNetworkSpecifier specifier, 78 boolean setting, 79 boolean foregroundApp, 80 boolean foregroundAppOrService) { 81 networkRequest = request; 82 networkRequestSpecifier = specifier; 83 isFromSetting = setting; 84 isFromForegroundApp = foregroundApp; 85 isFromForegroundAppOrService = foregroundAppOrService; 86 } 87 } 88 89 /** 90 * Check if the network request is for multi internet Wifi network. 91 * @param networkRequest the network requested by connectivity service 92 * @return true if the request if for multi internet Wifi network, false if not. 93 */ isWifiMultiInternetRequest(NetworkRequest networkRequest, boolean isFromSettings)94 public static boolean isWifiMultiInternetRequest(NetworkRequest networkRequest, 95 boolean isFromSettings) { 96 if (networkRequest.getNetworkSpecifier() == null 97 || !(networkRequest.getNetworkSpecifier() instanceof WifiNetworkSpecifier)) { 98 return false; 99 } 100 WifiNetworkSpecifier wns = (WifiNetworkSpecifier) networkRequest.getNetworkSpecifier(); 101 // Multi internet request must have internet capability, with specifier of band request. 102 // It must not have SSID/BSSID pattern matcher - except a request from Settings which can 103 // specify a BSSID (while an SSID specification is allowed here, it is dropped later on). 104 if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) 105 && wns.getBand() != ScanResult.UNSPECIFIED 106 && (isFromSettings || WifiConfigurationUtil.isMatchAllNetworkSpecifier(wns))) { 107 return true; 108 } 109 return false; 110 } 111 MultiInternetWifiNetworkFactory(Looper looper, Context context, NetworkCapabilities nc, FrameworkFacade facade, AlarmManager alarmManager, WifiPermissionsUtil wifiPermissionsUtil, MultiInternetManager multiInternetManager, WifiConnectivityManager connectivityManager, LocalLog localLog)112 public MultiInternetWifiNetworkFactory(Looper looper, Context context, NetworkCapabilities nc, 113 FrameworkFacade facade, AlarmManager alarmManager, 114 WifiPermissionsUtil wifiPermissionsUtil, 115 MultiInternetManager multiInternetManager, 116 WifiConnectivityManager connectivityManager, 117 LocalLog localLog) { 118 super(looper, context, TAG, nc); 119 mContext = context; 120 mFacade = facade; 121 mAlarmManager = alarmManager; 122 mWifiPermissionsUtil = wifiPermissionsUtil; 123 mMultiInternetManager = multiInternetManager; 124 mWifiConnectivityManager = connectivityManager; 125 mLocalLog = localLog; 126 setScoreFilter(SCORE_FILTER); 127 } 128 129 /** 130 * Enable verbose logging. 131 */ enableVerboseLogging(boolean verbose)132 public void enableVerboseLogging(boolean verbose) { 133 mVerboseLoggingEnabled = verbose; 134 } 135 136 /** 137 * Check whether to accept the new network connection request. Validate the incoming request 138 * and return true if valid. 139 */ 140 @Override acceptRequest(NetworkRequest networkRequest)141 public boolean acceptRequest(NetworkRequest networkRequest) { 142 final int uid = networkRequest.getRequestorUid(); 143 boolean isFromSetting = mWifiPermissionsUtil.checkNetworkSettingsPermission(uid) 144 || mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid); 145 if (!mMultiInternetManager.isStaConcurrencyForMultiInternetEnabled() 146 || !isWifiMultiInternetRequest(networkRequest, isFromSetting)) { 147 return false; 148 } 149 boolean isFromNetworkStack = mWifiPermissionsUtil.checkNetworkStackPermission(uid) 150 || mWifiPermissionsUtil.checkMainlineNetworkStackPermission(uid); 151 // Only allow specific wifi network request with band from apps or services with settings 152 // or network stack permission. 153 if (!isFromSetting && !isFromNetworkStack) { 154 // Do not release the network request. The app will not get onUnavailable right away, 155 // it can wait when another app with permission make the request and obtain the network. 156 Log.w(TAG, "Request is from app or service does not have the permission." 157 + " Rejecting request from " + networkRequest.getRequestorPackageName()); 158 return false; 159 } 160 WifiNetworkSpecifier wns = (WifiNetworkSpecifier) networkRequest.getNetworkSpecifier(); 161 final int band = wns.getBand(); 162 // TODO: b/181741503 Check if the band is supported. 163 localLog("Accepted network request with specifier for band " + band); 164 return true; 165 } 166 167 @Override needNetworkFor(NetworkRequest networkRequest)168 protected void needNetworkFor(NetworkRequest networkRequest) { 169 boolean isFromSetting = mWifiPermissionsUtil.checkNetworkSettingsPermission( 170 networkRequest.getRequestorUid()); 171 if (!mMultiInternetManager.isStaConcurrencyForMultiInternetEnabled() 172 || !isWifiMultiInternetRequest(networkRequest, isFromSetting)) { 173 return; 174 } 175 WifiNetworkSpecifier wns = (WifiNetworkSpecifier) networkRequest.getNetworkSpecifier(); 176 final int band = wns.getBand(); 177 boolean isFromForegroundApp = mFacade.isRequestFromForegroundApp(mContext, 178 networkRequest.getRequestorPackageName()); 179 boolean isFromForegroundAppOrService = 180 mFacade.isRequestFromForegroundAppOrService(mContext, 181 networkRequest.getRequestorPackageName()); 182 NetworkRequestState nrs = new NetworkRequestState(networkRequest, 183 new WifiNetworkSpecifier( 184 wns.ssidPatternMatcher, wns.bssidPatternMatcher, wns.getBand(), 185 wns.wifiConfiguration, wns.getPreferredChannelFrequenciesMhz(), 186 wns.isPreferSecondarySta()), 187 isFromSetting, 188 isFromForegroundApp, 189 isFromForegroundAppOrService); 190 mNetworkRequestStates.put(band, nrs); 191 // If multi internet is requested, without specifying SSID or BSSID, 192 // The WifiConnectivityManager will perform network selection to choose a candidate. 193 // Create a worksource using the caller's UID. 194 WorkSource workSource = new WorkSource(networkRequest.getRequestorUid()); 195 int reqCount = 0; 196 if (mConnectionReqCount.contains(band)) { 197 reqCount = mConnectionReqCount.get(band); 198 } 199 if (reqCount == 0 || isFromSetting) { 200 localLog("Need network : Uid " + networkRequest.getRequestorUid() + " PackageName " 201 + networkRequest.getRequestorPackageName() + " for band " + band 202 + " is rom Setting " + isFromSetting + " ForegroundApp " + isFromForegroundApp 203 + " ForegroundAppOrService " + isFromForegroundApp); 204 mMultiInternetManager.setMultiInternetConnectionWorksource( 205 band, wns.wifiConfiguration.BSSID, 206 new WorkSource(networkRequest.getRequestorUid(), 207 networkRequest.getRequestorPackageName())); 208 } 209 mConnectionReqCount.put(band, reqCount + 1); 210 } 211 212 @Override releaseNetworkFor(NetworkRequest networkRequest)213 protected void releaseNetworkFor(NetworkRequest networkRequest) { 214 boolean isFromSetting = mWifiPermissionsUtil.checkNetworkSettingsPermission( 215 networkRequest.getRequestorUid()); 216 if (!isWifiMultiInternetRequest(networkRequest, isFromSetting)) { 217 return; 218 } 219 localLog("releaseNetworkFor " + networkRequest); 220 final int band = ((WifiNetworkSpecifier) networkRequest.getNetworkSpecifier()).getBand(); 221 int reqCount = mConnectionReqCount.contains(band) 222 ? mConnectionReqCount.get(band) : 0; 223 if (reqCount == 0) { 224 Log.e(TAG, "No valid network request to release"); 225 return; 226 } 227 if (reqCount == 1) { 228 mMultiInternetManager.setMultiInternetConnectionWorksource(band, null, null); 229 } 230 mConnectionReqCount.put(band, reqCount - 1); 231 } 232 233 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)234 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 235 super.dump(fd, pw, args); 236 pw.println("Dump of MultiInternetWifiNetworkFactory"); 237 for (int i = 0; i < mConnectionReqCount.size(); i++) { 238 final int band = mConnectionReqCount.keyAt(i); 239 NetworkRequestState state = mNetworkRequestStates.get(band); 240 pw.println(" Band " + band + " Req count " + mConnectionReqCount.valueAt(i) 241 + " isFromSetting " + state.isFromSetting 242 + " isFromForegroundApp " + state.isFromForegroundApp 243 + " isFromForegroundAppOrService " + state.isFromForegroundAppOrService 244 + " Uid " + state.networkRequest.getRequestorUid() 245 + " PackageName " + state.networkRequest.getRequestorPackageName()); 246 } 247 mMultiInternetManager.dump(fd, pw, args); 248 } 249 } 250