1/* 2 * Copyright (C) 2015 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 17package com.android.server.net; 18 19import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; 20import static android.net.NetworkStats.UID_ALL; 21import static android.net.TrafficStats.UID_REMOVED; 22import static android.net.TrafficStats.UID_TETHERING; 23 24import android.Manifest; 25import android.annotation.IntDef; 26import android.app.AppOpsManager; 27import android.app.admin.DeviceAdminInfo; 28import android.app.admin.DevicePolicyManagerInternal; 29import android.content.Context; 30import android.content.pm.PackageManager; 31import android.os.UserHandle; 32import android.telephony.TelephonyManager; 33 34import com.android.server.LocalServices; 35 36import java.lang.annotation.Retention; 37import java.lang.annotation.RetentionPolicy; 38 39/** Utility methods for controlling access to network stats APIs. */ 40public final class NetworkStatsAccess { 41 private NetworkStatsAccess() {} 42 43 /** 44 * Represents an access level for the network usage history and statistics APIs. 45 * 46 * <p>Access levels are in increasing order; that is, it is reasonable to check access by 47 * verifying that the caller's access level is at least the minimum required level. 48 */ 49 @IntDef({ 50 Level.DEFAULT, 51 Level.USER, 52 Level.DEVICESUMMARY, 53 Level.DEVICE, 54 }) 55 @Retention(RetentionPolicy.SOURCE) 56 public @interface Level { 57 /** 58 * Default, unprivileged access level. 59 * 60 * <p>Can only access usage for one's own UID. 61 * 62 * <p>Every app will have at least this access level. 63 */ 64 int DEFAULT = 0; 65 66 /** 67 * Access level for apps which can access usage for any app running in the same user. 68 * 69 * <p>Granted to: 70 * <ul> 71 * <li>Profile owners. 72 * </ul> 73 */ 74 int USER = 1; 75 76 /** 77 * Access level for apps which can access usage summary of device. Device summary includes 78 * usage by apps running in any profiles/users, however this access level does not 79 * allow querying usage of individual apps running in other profiles/users. 80 * 81 * <p>Granted to: 82 * <ul> 83 * <li>Apps with the PACKAGE_USAGE_STATS permission granted. Note that this is an AppOps bit 84 * so it is not necessarily sufficient to declare this in the manifest. 85 * <li>Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission. 86 * </ul> 87 */ 88 int DEVICESUMMARY = 2; 89 90 /** 91 * Access level for apps which can access usage for any app on the device, including apps 92 * running on other users/profiles. 93 * 94 * <p>Granted to: 95 * <ul> 96 * <li>Device owners. 97 * <li>Carrier-privileged applications. 98 * <li>The system UID. 99 * </ul> 100 */ 101 int DEVICE = 3; 102 } 103 104 /** Returns the {@link NetworkStatsAccess.Level} for the given caller. */ 105 public static @NetworkStatsAccess.Level int checkAccessLevel( 106 Context context, int callingUid, String callingPackage) { 107 final DevicePolicyManagerInternal dpmi = LocalServices.getService( 108 DevicePolicyManagerInternal.class); 109 final TelephonyManager tm = (TelephonyManager) 110 context.getSystemService(Context.TELEPHONY_SERVICE); 111 boolean hasCarrierPrivileges = tm != null && 112 tm.checkCarrierPrivilegesForPackage(callingPackage) == 113 TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; 114 boolean isDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, 115 DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); 116 if (hasCarrierPrivileges || isDeviceOwner 117 || UserHandle.getAppId(callingUid) == android.os.Process.SYSTEM_UID) { 118 // Carrier-privileged apps and device owners, and the system can access data usage for 119 // all apps on the device. 120 return NetworkStatsAccess.Level.DEVICE; 121 } 122 123 boolean hasAppOpsPermission = hasAppOpsPermission(context, callingUid, callingPackage); 124 if (hasAppOpsPermission || context.checkCallingOrSelfPermission( 125 READ_NETWORK_USAGE_HISTORY) == PackageManager.PERMISSION_GRANTED) { 126 return NetworkStatsAccess.Level.DEVICESUMMARY; 127 } 128 129 boolean isProfileOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, 130 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); 131 if (isProfileOwner) { 132 // Apps with the AppOps permission, profile owners, and apps with the privileged 133 // permission can access data usage for all apps in this user/profile. 134 return NetworkStatsAccess.Level.USER; 135 } 136 137 // Everyone else gets default access (only to their own UID). 138 return NetworkStatsAccess.Level.DEFAULT; 139 } 140 141 /** 142 * Returns whether the given caller should be able to access the given UID when the caller has 143 * the given {@link NetworkStatsAccess.Level}. 144 */ 145 public static boolean isAccessibleToUser(int uid, int callerUid, 146 @NetworkStatsAccess.Level int accessLevel) { 147 switch (accessLevel) { 148 case NetworkStatsAccess.Level.DEVICE: 149 // Device-level access - can access usage for any uid. 150 return true; 151 case NetworkStatsAccess.Level.DEVICESUMMARY: 152 // Can access usage for any app running in the same user, along 153 // with some special uids (system, removed, or tethering) and 154 // anonymized uids 155 return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED 156 || uid == UID_TETHERING || uid == UID_ALL 157 || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid); 158 case NetworkStatsAccess.Level.USER: 159 // User-level access - can access usage for any app running in the same user, along 160 // with some special uids (system, removed, or tethering). 161 return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED 162 || uid == UID_TETHERING 163 || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid); 164 case NetworkStatsAccess.Level.DEFAULT: 165 default: 166 // Default access level - can only access one's own usage. 167 return uid == callerUid; 168 } 169 } 170 171 private static boolean hasAppOpsPermission( 172 Context context, int callingUid, String callingPackage) { 173 if (callingPackage != null) { 174 AppOpsManager appOps = (AppOpsManager) context.getSystemService( 175 Context.APP_OPS_SERVICE); 176 177 final int mode = appOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS, 178 callingUid, callingPackage); 179 if (mode == AppOpsManager.MODE_DEFAULT) { 180 // The default behavior here is to check if PackageManager has given the app 181 // permission. 182 final int permissionCheck = context.checkCallingPermission( 183 Manifest.permission.PACKAGE_USAGE_STATS); 184 return permissionCheck == PackageManager.PERMISSION_GRANTED; 185 } 186 return (mode == AppOpsManager.MODE_ALLOWED); 187 } 188 return false; 189 } 190} 191