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)94 public static boolean isWifiMultiInternetRequest(NetworkRequest networkRequest) { 95 if (networkRequest.getNetworkSpecifier() == null 96 || !(networkRequest.getNetworkSpecifier() instanceof WifiNetworkSpecifier)) { 97 return false; 98 } 99 WifiNetworkSpecifier wns = (WifiNetworkSpecifier) networkRequest.getNetworkSpecifier(); 100 // Multi internet request must have internet capability, with specifier of band request, 101 // and must not have SSID/BSSID pattern matcher. 102 if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) 103 && wns.getBand() != ScanResult.UNSPECIFIED 104 && WifiConfigurationUtil.isMatchAllNetworkSpecifier(wns)) { 105 return true; 106 } 107 return false; 108 } 109 MultiInternetWifiNetworkFactory(Looper looper, Context context, NetworkCapabilities nc, FrameworkFacade facade, AlarmManager alarmManager, WifiPermissionsUtil wifiPermissionsUtil, MultiInternetManager multiInternetManager, WifiConnectivityManager connectivityManager, LocalLog localLog)110 public MultiInternetWifiNetworkFactory(Looper looper, Context context, NetworkCapabilities nc, 111 FrameworkFacade facade, AlarmManager alarmManager, 112 WifiPermissionsUtil wifiPermissionsUtil, 113 MultiInternetManager multiInternetManager, 114 WifiConnectivityManager connectivityManager, 115 LocalLog localLog) { 116 super(looper, context, TAG, nc); 117 mContext = context; 118 mFacade = facade; 119 mAlarmManager = alarmManager; 120 mWifiPermissionsUtil = wifiPermissionsUtil; 121 mMultiInternetManager = multiInternetManager; 122 mWifiConnectivityManager = connectivityManager; 123 mLocalLog = localLog; 124 setScoreFilter(SCORE_FILTER); 125 } 126 127 /** 128 * Enable verbose logging. 129 */ enableVerboseLogging(boolean verbose)130 public void enableVerboseLogging(boolean verbose) { 131 mVerboseLoggingEnabled = verbose; 132 } 133 134 /** 135 * Check whether to accept the new network connection request. Validate the incoming request 136 * and return true if valid. 137 */ 138 @Override acceptRequest(NetworkRequest networkRequest)139 public boolean acceptRequest(NetworkRequest networkRequest) { 140 if (!mMultiInternetManager.isStaConcurrencyForMultiInternetEnabled() 141 || !isWifiMultiInternetRequest(networkRequest)) { 142 return false; 143 } 144 final int uid = networkRequest.getRequestorUid(); 145 boolean isFromSetting = mWifiPermissionsUtil.checkNetworkSettingsPermission(uid) 146 || mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid); 147 boolean isFromNetworkStack = mWifiPermissionsUtil.checkNetworkStackPermission(uid) 148 || mWifiPermissionsUtil.checkMainlineNetworkStackPermission(uid); 149 // Only allow specific wifi network request with band from apps or services with settings 150 // or network stack permission. 151 if (!isFromSetting && !isFromNetworkStack) { 152 // Do not release the network request. The app will not get onUnavailable right away, 153 // it can wait when another app with permission make the request and obtain the network. 154 Log.w(TAG, "Request is from app or service does not have the permission." 155 + " Rejecting request from " + networkRequest.getRequestorPackageName()); 156 return false; 157 } 158 WifiNetworkSpecifier wns = (WifiNetworkSpecifier) networkRequest.getNetworkSpecifier(); 159 final int band = wns.getBand(); 160 // TODO: b/181741503 Check if the band is supported. 161 localLog("Accepted network request with specifier for band " + band); 162 return true; 163 } 164 165 @Override needNetworkFor(NetworkRequest networkRequest)166 protected void needNetworkFor(NetworkRequest networkRequest) { 167 if (!mMultiInternetManager.isStaConcurrencyForMultiInternetEnabled() 168 || !isWifiMultiInternetRequest(networkRequest)) { 169 return; 170 } 171 WifiNetworkSpecifier wns = (WifiNetworkSpecifier) networkRequest.getNetworkSpecifier(); 172 final int band = wns.getBand(); 173 boolean isFromSetting = mWifiPermissionsUtil.checkNetworkSettingsPermission( 174 networkRequest.getRequestorUid()); 175 boolean isFromForegroundApp = mFacade.isRequestFromForegroundApp(mContext, 176 networkRequest.getRequestorPackageName()); 177 boolean isFromForegroundAppOrService = 178 mFacade.isRequestFromForegroundAppOrService(mContext, 179 networkRequest.getRequestorPackageName()); 180 NetworkRequestState nrs = new NetworkRequestState(networkRequest, 181 new WifiNetworkSpecifier( 182 wns.ssidPatternMatcher, wns.bssidPatternMatcher, wns.getBand(), 183 wns.wifiConfiguration), 184 isFromSetting, 185 isFromForegroundApp, 186 isFromForegroundAppOrService); 187 mNetworkRequestStates.put(band, nrs); 188 // If multi internet is requested, without specifying SSID or BSSID, 189 // The WifiConnectivityManager will perform network selection to choose a candidate. 190 // Create a worksource using the caller's UID. 191 WorkSource workSource = new WorkSource(networkRequest.getRequestorUid()); 192 int reqCount = 0; 193 if (mConnectionReqCount.contains(band)) { 194 reqCount = mConnectionReqCount.get(band); 195 } 196 if (reqCount == 0) { 197 localLog("Need network : Uid " + networkRequest.getRequestorUid() + " PackageName " 198 + networkRequest.getRequestorPackageName() + " for band " + band 199 + " is rom Setting " + isFromSetting + " ForegroundApp " + isFromForegroundApp 200 + " ForegroundAppOrService " + isFromForegroundApp); 201 mMultiInternetManager.setMultiInternetConnectionWorksource( 202 band, new WorkSource(networkRequest.getRequestorUid(), 203 networkRequest.getRequestorPackageName())); 204 } 205 mConnectionReqCount.put(band, reqCount + 1); 206 } 207 208 @Override releaseNetworkFor(NetworkRequest networkRequest)209 protected void releaseNetworkFor(NetworkRequest networkRequest) { 210 if (!isWifiMultiInternetRequest(networkRequest)) { 211 return; 212 } 213 localLog("releaseNetworkFor " + networkRequest); 214 final int band = ((WifiNetworkSpecifier) networkRequest.getNetworkSpecifier()).getBand(); 215 int reqCount = mConnectionReqCount.contains(band) 216 ? mConnectionReqCount.get(band) : 0; 217 if (reqCount == 0) { 218 Log.e(TAG, "No valid network request to release"); 219 return; 220 } 221 if (reqCount == 1) { 222 mMultiInternetManager.setMultiInternetConnectionWorksource(band, null); 223 } 224 mConnectionReqCount.put(band, reqCount - 1); 225 } 226 227 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)228 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 229 super.dump(fd, pw, args); 230 pw.println("Dump of MultiInternetWifiNetworkFactory"); 231 for (int i = 0; i < mConnectionReqCount.size(); i++) { 232 final int band = mConnectionReqCount.keyAt(i); 233 NetworkRequestState state = mNetworkRequestStates.get(band); 234 pw.println(" Band " + band + " Req count " + mConnectionReqCount.valueAt(i) 235 + " isFromSetting " + state.isFromSetting 236 + " isFromForegroundApp " + state.isFromForegroundApp 237 + " isFromForegroundAppOrService " + state.isFromForegroundAppOrService 238 + " Uid " + state.networkRequest.getRequestorUid() 239 + " PackageName " + state.networkRequest.getRequestorPackageName()); 240 } 241 mLocalLog.dump(fd, pw, args); 242 mMultiInternetManager.dump(fd, pw, args); 243 } 244 } 245