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