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