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