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 isFromSetting, 187 isFromForegroundApp, 188 isFromForegroundAppOrService); 189 mNetworkRequestStates.put(band, nrs); 190 // If multi internet is requested, without specifying SSID or BSSID, 191 // The WifiConnectivityManager will perform network selection to choose a candidate. 192 // Create a worksource using the caller's UID. 193 WorkSource workSource = new WorkSource(networkRequest.getRequestorUid()); 194 int reqCount = 0; 195 if (mConnectionReqCount.contains(band)) { 196 reqCount = mConnectionReqCount.get(band); 197 } 198 if (reqCount == 0 || isFromSetting) { 199 localLog("Need network : Uid " + networkRequest.getRequestorUid() + " PackageName " 200 + networkRequest.getRequestorPackageName() + " for band " + band 201 + " is rom Setting " + isFromSetting + " ForegroundApp " + isFromForegroundApp 202 + " ForegroundAppOrService " + isFromForegroundApp); 203 mMultiInternetManager.setMultiInternetConnectionWorksource( 204 band, wns.wifiConfiguration.BSSID, 205 new WorkSource(networkRequest.getRequestorUid(), 206 networkRequest.getRequestorPackageName())); 207 } 208 mConnectionReqCount.put(band, reqCount + 1); 209 } 210 211 @Override releaseNetworkFor(NetworkRequest networkRequest)212 protected void releaseNetworkFor(NetworkRequest networkRequest) { 213 boolean isFromSetting = mWifiPermissionsUtil.checkNetworkSettingsPermission( 214 networkRequest.getRequestorUid()); 215 if (!isWifiMultiInternetRequest(networkRequest, isFromSetting)) { 216 return; 217 } 218 localLog("releaseNetworkFor " + networkRequest); 219 final int band = ((WifiNetworkSpecifier) networkRequest.getNetworkSpecifier()).getBand(); 220 int reqCount = mConnectionReqCount.contains(band) 221 ? mConnectionReqCount.get(band) : 0; 222 if (reqCount == 0) { 223 Log.e(TAG, "No valid network request to release"); 224 return; 225 } 226 if (reqCount == 1) { 227 mMultiInternetManager.setMultiInternetConnectionWorksource(band, null, null); 228 } 229 mConnectionReqCount.put(band, reqCount - 1); 230 } 231 232 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)233 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 234 super.dump(fd, pw, args); 235 pw.println("Dump of MultiInternetWifiNetworkFactory"); 236 for (int i = 0; i < mConnectionReqCount.size(); i++) { 237 final int band = mConnectionReqCount.keyAt(i); 238 NetworkRequestState state = mNetworkRequestStates.get(band); 239 pw.println(" Band " + band + " Req count " + mConnectionReqCount.valueAt(i) 240 + " isFromSetting " + state.isFromSetting 241 + " isFromForegroundApp " + state.isFromForegroundApp 242 + " isFromForegroundAppOrService " + state.isFromForegroundAppOrService 243 + " Uid " + state.networkRequest.getRequestorUid() 244 + " PackageName " + state.networkRequest.getRequestorPackageName()); 245 } 246 mMultiInternetManager.dump(fd, pw, args); 247 } 248 } 249