• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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.util;
18 
19 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
20 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
21 
22 import android.annotation.NonNull;
23 import android.app.ActivityManager;
24 import android.content.pm.ApplicationInfo;
25 import android.content.pm.PackageManager;
26 import android.content.res.Resources;
27 import android.os.Process;
28 import android.os.UserHandle;
29 import android.os.WorkSource;
30 import android.text.TextUtils;
31 import android.util.Log;
32 
33 import com.android.wifi.resources.R;
34 
35 import java.util.Arrays;
36 
37 /**
38  * Class for wrapping a WorkSource object and providing some (wifi specific) utility methods.
39  *
40  * This is primarily used in {@link com.android.server.wifi.HalDeviceManager} class.
41  */
42 public class WorkSourceHelper {
43     private static final String TAG = "WorkSourceHelper";
44     private static final int APP_INFO_FLAGS_SYSTEM_APP =
45             ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
46     private final WorkSource mWorkSource;
47     private final WifiPermissionsUtil mWifiPermissionsUtil;
48     private final ActivityManager mActivityManager;
49     private final PackageManager mPackageManager;
50     private final Resources mResources;
51 
WorkSourceHelper( @onNull WorkSource workSource, @NonNull WifiPermissionsUtil wifiPermissionsUtil, @NonNull ActivityManager activityManager, @NonNull PackageManager packageManager, @NonNull Resources resources)52     public WorkSourceHelper(
53             @NonNull WorkSource workSource,
54             @NonNull WifiPermissionsUtil wifiPermissionsUtil,
55             @NonNull ActivityManager activityManager,
56             @NonNull PackageManager packageManager,
57             @NonNull Resources resources) {
58         mWorkSource = workSource;
59         mWifiPermissionsUtil = wifiPermissionsUtil;
60         mActivityManager = activityManager;
61         mPackageManager = packageManager;
62         mResources = resources;
63     }
64 
getWorkSource()65     public WorkSource getWorkSource() {
66         return mWorkSource;
67     }
68 
69     @Override
toString()70     public String toString() {
71         return mWorkSource.toString();
72     }
73 
isPrivileged(int uid)74     private boolean isPrivileged(int uid) {
75         return mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
76                 || mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid)
77                 || mWifiPermissionsUtil.checkNetworkStackPermission(uid)
78                 || mWifiPermissionsUtil.checkMainlineNetworkStackPermission(uid);
79     }
80 
81     /**
82      * Returns whether any of the one or more worksource objects contains a privileged app
83      * request.
84      *
85      * Privileged = Request from an app with NETWORK_SETTINGS, NETWORK_SETUP_WIZARD or
86      * NETWORK_STACK permissions.
87      */
hasAnyPrivilegedAppRequest()88     public boolean hasAnyPrivilegedAppRequest() {
89         for (int i = 0; i < mWorkSource.size(); i++) {
90             if (isPrivileged(mWorkSource.getUid(i))) return true;
91         }
92         return false;
93     }
94 
isSystem(String packageName, int uid)95     private boolean isSystem(String packageName, int uid) {
96         // when checking ActiveModeWarden#INTERNAL_REQUESTOR_WS
97         if (packageName == null) {
98             return false;
99         }
100         try {
101             ApplicationInfo info = mPackageManager.getApplicationInfoAsUser(
102                     packageName, 0, UserHandle.getUserHandleForUid(uid));
103             return (info.flags & APP_INFO_FLAGS_SYSTEM_APP) != 0;
104         } catch (PackageManager.NameNotFoundException e) {
105             Log.e(TAG, "Failed to retrieve app info for packageName=" + packageName + " uid=" + uid,
106                     e);
107             // In case of exception, assume unknown app (more strict checking)
108             // Note: This case will never happen since checkPackage is
109             // called to verify validity before checking App's version.
110             return false;
111         }
112     }
113 
114     /**
115      * Returns whether any of the one or more worksource objects contains a system app
116      * request.
117      */
hasAnySystemAppRequest()118     public boolean hasAnySystemAppRequest() {
119         for (int i = 0; i < mWorkSource.size(); i++) {
120             if (isSystem(mWorkSource.getPackageName(i), mWorkSource.getUid(i))) return true;
121         }
122         return false;
123     }
124 
125     /**
126      * Check if the request comes from foreground app.
127      */
isForegroundApp(@onNull String requestorPackageName, boolean allowOverlayBypass)128     private boolean isForegroundApp(@NonNull String requestorPackageName,
129             boolean allowOverlayBypass) {
130         if (allowOverlayBypass) {
131             String[] exceptionList = mResources.getStringArray(
132                     R.array.config_wifiInterfacePriorityTreatAsForegroundList);
133             if (exceptionList != null && Arrays.stream(exceptionList).anyMatch(
134                     s -> TextUtils.equals(requestorPackageName, s))) {
135                 return true;
136             }
137         }
138         try {
139             return mActivityManager.getPackageImportance(requestorPackageName)
140                     <= IMPORTANCE_FOREGROUND;
141         } catch (SecurityException e) {
142             Log.e(TAG, "Failed to check the app state", e);
143             return false;
144         }
145     }
146 
147     /**
148      * Returns whether any of the one or more worksource objects contains a foreground app
149      * request.
150      *
151      * @param allowOverlayBypass Use the `config_wifiInterfacePriorityTreatAsForegroundList` overlay
152      *                           to consider the specified packages are foreground.
153      */
hasAnyForegroundAppRequest(boolean allowOverlayBypass)154     public boolean hasAnyForegroundAppRequest(boolean allowOverlayBypass) {
155         for (int i = 0; i < mWorkSource.size(); i++) {
156             if (isForegroundApp(mWorkSource.getPackageName(i), allowOverlayBypass)) return true;
157         }
158         return false;
159     }
160 
161     /**
162      * Check if the request comes from foreground service.
163      */
isForegroundService(@onNull String requestorPackageName)164     private boolean isForegroundService(@NonNull String requestorPackageName) {
165         try {
166             int importance = mActivityManager.getPackageImportance(requestorPackageName);
167             return IMPORTANCE_FOREGROUND < importance
168                     && importance <= IMPORTANCE_FOREGROUND_SERVICE;
169         } catch (SecurityException e) {
170             Log.e(TAG, "Failed to check the app state", e);
171             return false;
172         }
173     }
174 
175     /**
176      * Returns whether any of the one or more worksource objects contains a foreground service
177      * request.
178      */
hasAnyForegroundServiceRequest()179     public boolean hasAnyForegroundServiceRequest() {
180         for (int i = 0; i < mWorkSource.size(); i++) {
181             if (isForegroundService(mWorkSource.getPackageName(i))) return true;
182         }
183         return false;
184     }
185 
186     /**
187      * Returns whether any of the one or more worksource objects contains an internal
188      * (i.e uid = Process.WIFI_UID) request.
189      */
hasAnyInternalRequest()190     public boolean hasAnyInternalRequest() {
191         for (int i = 0; i < mWorkSource.size(); i++) {
192             if (mWorkSource.getUid(i) == Process.WIFI_UID) return true;
193         }
194         return false;
195     }
196 }
197