• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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