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