你现在是一名资深的蓝牙工程师,请你详细讲解下面的BtpermissionUtils.java的代码:
package com.android.server.bluetooth;
18
19 import static android.Manifest.permission.BLUETOOTH_CONNECT;
20 import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
21 import static android.content.pm.PackageManager.SIGNATURE_MATCH;
22 import static android.os.Process.SYSTEM_UID;
23 import static android.permission.PermissionManager.PERMISSION_GRANTED;
24 import static android.permission.PermissionManager.PERMISSION_HARD_DENIED;
25
26 import static com.android.server.bluetooth.ChangeIds.RESTRICT_ENABLE_DISABLE;
27
28 import android.annotation.RequiresPermission;
29 import android.annotation.SuppressLint;
30 import android.app.ActivityManager;
31 import android.app.AppOpsManager;
32 import android.app.admin.DevicePolicyManager;
33 import android.app.compat.CompatChanges;
34 import android.content.AttributionSource;
35 import android.content.ComponentName;
36 import android.content.Context;
37 import android.content.pm.ApplicationInfo;
38 import android.content.pm.PackageManager;
39 import android.os.Binder;
40 import android.os.Process;
41 import android.os.UserHandle;
42 import android.os.UserManager;
43 import android.permission.PermissionManager;
44
45 import java.util.Objects;
46
47 class BtPermissionUtils {
48 private static final String TAG = BtPermissionUtils.class.getSimpleName();
49
50 private static final int FLAGS_SYSTEM_APP =
51 ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
52
53 private final int mSystemUiUid;
54
55 BtPermissionUtils(Context ctx) {
56 // Check if device is configured with no home screen, which implies no SystemUI.
57 int systemUiUid = -1;
58 try {
59 systemUiUid =
60 ctx.createContextAsUser(UserHandle.SYSTEM, 0)
61 .getPackageManager()
62 .getPackageUid(
63 "com.android.systemui",
64 PackageManager.PackageInfoFlags.of(
65 PackageManager.MATCH_SYSTEM_ONLY));
66 Log.d(TAG, "Detected SystemUiUid: " + systemUiUid);
67 } catch (PackageManager.NameNotFoundException e) {
68 Log.w(TAG, "Unable to resolve SystemUI's UID.");
69 }
70 mSystemUiUid = systemUiUid;
71 }
72
73 /**
74 * Returns true if the BLUETOOTH_CONNECT permission is granted for the calling app. Returns
75 * false if the result is a soft denial. Throws SecurityException if the result is a hard
76 * denial.
77 *
78 * <p>Should be used in situations where the app op should not be noted.
79 */
80 @SuppressLint("AndroidFrameworkRequiresPermission")
81 @RequiresPermission(BLUETOOTH_CONNECT)
82 static boolean checkConnectPermissionForDataDelivery(
83 Context ctx,
84 PermissionManager permissionManager,
85 AttributionSource source,
86 String message) {
87 final String permission = BLUETOOTH_CONNECT;
88 AttributionSource currentSource =
89 new AttributionSource.Builder(ctx.getAttributionSource())
90 .setNext(Objects.requireNonNull(source))
91 .build();
92 final int result =
93 permissionManager.checkPermissionForDataDeliveryFromDataSource(
94 permission, currentSource, message);
95 if (result == PERMISSION_GRANTED) {
96 return true;
97 }
98
99 final String msg = "Need " + permission + " permission for " + source + ": " + message;
100 if (result == PERMISSION_HARD_DENIED) {
101 throw new SecurityException(msg);
102 }
103 Log.w(TAG, msg);
104 return false;
105 }
106
107 /**
108 * Return an empty string if the current call is allowed to toggle bluetooth state
109 *
110 * <p>Return the error description if this caller is not allowed to toggle Bluetooth
111 */
112 String callerCanToggle(
113 Context ctx,
114 AttributionSource source,
115 UserManager userManager,
116 AppOpsManager appOpsManager,
117 PermissionManager permissionManager,
118 String message,
119 boolean requireForeground) {
120 if (isBluetoothDisallowed(userManager)) {
121 return "Bluetooth is not allowed";
122 }
123
124 if (!checkBluetoothPermissions(
125 ctx,
126 source,
127 userManager,
128 appOpsManager,
129 permissionManager,
130 message,
131 requireForeground)) {
132 return "Missing Bluetooth permission";
133 }
134
135 if (requireForeground && !checkCompatChangeRestriction(source, ctx)) {
136 return "Caller does not match restriction criteria";
137 }
138
139 return "";
140 }
141
142 static void enforcePrivileged(Context ctx) {
143 ctx.enforceCallingOrSelfPermission(
144 BLUETOOTH_PRIVILEGED, "Need BLUETOOTH_PRIVILEGED permission");
145 }
146
147 static int getCallingAppId() {
148 return UserHandle.getAppId(Binder.getCallingUid());
149 }
150
151 static boolean isCallerSystem(int callingAppId) {
152 return callingAppId == Process.SYSTEM_UID;
153 }
154
155 static boolean isCallerNfc(int callingAppId) {
156 return callingAppId == Process.NFC_UID;
157 }
158
159 private static boolean isCallerShell(int callingAppId) {
160 return callingAppId == Process.SHELL_UID;
161 }
162
163 private static boolean isCallerRoot(int callingAppId) {
164 return callingAppId == Process.ROOT_UID;
165 }
166
167 private boolean isCallerSystemUi(int callingAppId) {
168 return callingAppId == mSystemUiUid;
169 }
170
171 private static boolean isPrivileged(Context ctx, int pid, int uid) {
172 return (ctx.checkPermission(BLUETOOTH_PRIVILEGED, pid, uid) == PERMISSION_GRANTED)
173 || (ctx.getPackageManager().checkSignatures(uid, SYSTEM_UID) == SIGNATURE_MATCH);
174 }
175
176 private static boolean isProfileOwner(Context ctx, int uid, String packageName) {
177 Context userContext;
178 try {
179 userContext =
180 ctx.createPackageContextAsUser(
181 ctx.getPackageName(), 0, UserHandle.getUserHandleForUid(uid));
182 } catch (PackageManager.NameNotFoundException e) {
183 Log.e(TAG, "Unknown package name");
184 return false;
185 }
186 if (userContext == null) {
187 Log.e(TAG, "Unable to retrieve user context for " + uid);
188 return false;
189 }
190 DevicePolicyManager devicePolicyManager =
191 userContext.getSystemService(DevicePolicyManager.class);
192 if (devicePolicyManager == null) {
193 Log.w(TAG, "isProfileOwner: Error retrieving DevicePolicyManager service");
194 return false;
195 }
196 return devicePolicyManager.isProfileOwnerApp(packageName);
197 }
198
199 private static boolean isDeviceOwner(Context ctx, int uid, String packageName) {
200 if (packageName == null) {
201 Log.e(TAG, "isDeviceOwner: packageName is null, returning false");
202 return false;
203 }
204
205 DevicePolicyManager devicePolicyManager = ctx.getSystemService(DevicePolicyManager.class);
206 if (devicePolicyManager == null) {
207 Log.w(TAG, "isDeviceOwner: Error retrieving DevicePolicyManager service");
208 return false;
209 }
210 UserHandle deviceOwnerUser = null;
211 ComponentName deviceOwnerComponent = null;
212 long ident = Binder.clearCallingIdentity();
213 try {
214 deviceOwnerUser = devicePolicyManager.getDeviceOwnerUser();
215 deviceOwnerComponent = devicePolicyManager.getDeviceOwnerComponentOnAnyUser();
216 } finally {
217 Binder.restoreCallingIdentity(ident);
218 }
219 if (deviceOwnerUser == null
220 || deviceOwnerComponent == null
221 || deviceOwnerComponent.getPackageName() == null) {
222 return false;
223 }
224
225 return deviceOwnerUser.equals(UserHandle.getUserHandleForUid(uid))
226 && deviceOwnerComponent.getPackageName().equals(packageName);
227 }
228
229 private static boolean isSystem(Context ctx, String packageName, int uid) {
230 long ident = Binder.clearCallingIdentity();
231 try {
232 ApplicationInfo info =
233 ctx.getPackageManager()
234 .getApplicationInfoAsUser(
235 packageName, 0, UserHandle.getUserHandleForUid(uid));
236 return (info.flags & FLAGS_SYSTEM_APP) != 0;
237 } catch (PackageManager.NameNotFoundException e) {
238 return false;
239 } finally {
240 Binder.restoreCallingIdentity(ident);
241 }
242 }
243
244 private static boolean isBluetoothDisallowed(UserManager userManager) {
245 final long callingIdentity = Binder.clearCallingIdentity();
246 try {
247 return userManager.hasUserRestrictionForUser(
248 UserManager.DISALLOW_BLUETOOTH, UserHandle.SYSTEM);
249 } finally {
250 Binder.restoreCallingIdentity(callingIdentity);
251 }
252 }
253
254 /**
255 * Check ifthe packageName belongs to calling uid
256 *
257 * <p>A null package belongs to any uid
258 */
259 private static void checkPackage(AppOpsManager appOpsManager, String packageName) {
260 final int callingUid = Binder.getCallingUid();
261 if (packageName == null) {
262 Log.w(TAG, "checkPackage(): called with null packageName from " + callingUid);
263 return;
264 }
265
266 try {
267 appOpsManager.checkPackage(callingUid, packageName);
268 } catch (SecurityException e) {
269 Log.w(TAG, "checkPackage(): " + packageName + " does not belong to uid " + callingUid);
270 throw new SecurityException(e.getMessage());
271 }
272 }
273
274 boolean checkIfCallerIsForegroundUser(UserManager userManager) {
275 final int callingUid = Binder.getCallingUid();
276 final UserHandle callingUser = UserHandle.getUserHandleForUid(callingUid);
277 final UserHandle foregroundUser;
278 final UserHandle parentUser;
279 final long callingIdentity = Binder.clearCallingIdentity();
280 try {
281 // `getCurrentUser` need to be call by system server because it require one of
282 // INTERACT_ACROSS_USERS | INTERACT_ACROSS_USERS_FULL
283 foregroundUser = UserHandle.of(ActivityManager.getCurrentUser());
284 // `getProfileParent` need to be call by system server because it require one of
285 // MANAGE_USERS | INTERACT_ACROSS_USER and
286 parentUser = userManager.getProfileParent(callingUser);
287 } finally {
288 Binder.restoreCallingIdentity(callingIdentity);
289 }
290 final int callingAppId = UserHandle.getAppId(callingUid);
291
292 // TODO(b/280890575): Remove isCallerX() to only check isForegroundUser
293
294 final boolean valid =
295 Objects.equals(callingUser, foregroundUser)
296 || Objects.equals(parentUser, foregroundUser)
297 || isCallerNfc(callingAppId)
298 || isCallerSystemUi(callingAppId)
299 || isCallerShell(callingAppId);
300
301 if (!valid) {
302 Log.d(
303 TAG,
304 "checkIfCallerIsForegroundUser: REJECTED:"
305 + " callingUser="
306 + callingUser
307 + " parentUser="
308 + parentUser
309 + " foregroundUser="
310 + foregroundUser
311 + " callingAppId="
312 + callingAppId);
313 }
314 return valid;
315 }
316
317 @RequiresPermission(BLUETOOTH_CONNECT)
318 private boolean checkBluetoothPermissions(
319 Context ctx,
320 AttributionSource source,
321 UserManager userManager,
322 AppOpsManager appOpsManager,
323 PermissionManager permissionManager,
324 String message,
325 boolean requireForeground) {
326 final int callingAppId = getCallingAppId();
327 if (isCallerSystem(callingAppId)) return true;
328 if (isCallerShell(callingAppId)) return true;
329 if (isCallerRoot(callingAppId)) return true;
330 checkPackage(appOpsManager, source.getPackageName());
331
332 if (requireForeground && !checkIfCallerIsForegroundUser(userManager)) {
333 Log.w(TAG, "Not allowed for non-active and non system user");
334 return false;
335 }
336
337 if (!checkConnectPermissionForDataDelivery(ctx, permissionManager, source, message)) {
338 return false;
339 }
340 return true;
341 }
342
343 /** Starting from T, enable/disable APIs are limited to system apps or device owners. */
344 private static boolean checkCompatChangeRestriction(AttributionSource source, Context ctx) {
345 final String packageName = source.getPackageName();
346
347 final int callingUid = Binder.getCallingUid();
348 final int callingPid = Binder.getCallingPid();
349 if (CompatChanges.isChangeEnabled(RESTRICT_ENABLE_DISABLE, callingUid)
350 && !isPrivileged(ctx, callingPid, callingUid)
351 && !isSystem(ctx, packageName, callingUid)
352 && !isDeviceOwner(ctx, callingUid, packageName)
353 && !isProfileOwner(ctx, callingUid, packageName)) {
354 Log.e(TAG, "Caller is not one of: privileged | system | deviceOwner | profileOwner");
355 return false;
356 }
357 return true;
358 }
359 }
最新发布