• 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)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