Utils.java revision 4a9f9b0253fde7341bf9e12c5bd0e6f29fced4fc
1/* 2 * Copyright (C) 2012 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.bluetooth; 18 19import android.app.ActivityManager; 20import android.app.ActivityThread; 21import android.app.AppOpsManager; 22import android.bluetooth.BluetoothAdapter; 23import android.bluetooth.BluetoothDevice; 24import android.content.Context; 25import android.content.ContextWrapper; 26import android.content.pm.PackageManager; 27import android.content.pm.UserInfo; 28import android.os.Binder; 29import android.os.Build; 30import android.os.ParcelUuid; 31import android.os.Process; 32import android.os.UserHandle; 33import android.os.UserManager; 34import android.util.Log; 35 36import java.io.IOException; 37import java.io.InputStream; 38import java.io.OutputStream; 39import java.nio.ByteBuffer; 40import java.nio.ByteOrder; 41import java.util.List; 42import java.util.UUID; 43import java.util.concurrent.TimeUnit; 44 45/** 46 * @hide 47 */ 48 49final public class Utils { 50 private static final String TAG = "BluetoothUtils"; 51 private static final int MICROS_PER_UNIT = 625; 52 53 static final int BD_ADDR_LEN = 6; // bytes 54 static final int BD_UUID_LEN = 16; // bytes 55 56 public static String getAddressStringFromByte(byte[] address) { 57 if (address == null || address.length != BD_ADDR_LEN) { 58 return null; 59 } 60 61 return String.format("%02X:%02X:%02X:%02X:%02X:%02X", 62 address[0], address[1], address[2], address[3], address[4], 63 address[5]); 64 } 65 66 public static byte[] getByteAddress(BluetoothDevice device) { 67 return getBytesFromAddress(device.getAddress()); 68 } 69 70 public static byte[] getBytesFromAddress(String address) { 71 int i, j = 0; 72 byte[] output = new byte[BD_ADDR_LEN]; 73 74 for (i = 0; i < address.length(); i++) { 75 if (address.charAt(i) != ':') { 76 output[j] = (byte) Integer.parseInt(address.substring(i, i + 2), BD_UUID_LEN); 77 j++; 78 i++; 79 } 80 } 81 82 return output; 83 } 84 85 public static int byteArrayToInt(byte[] valueBuf) { 86 return byteArrayToInt(valueBuf, 0); 87 } 88 89 public static short byteArrayToShort(byte[] valueBuf) { 90 ByteBuffer converter = ByteBuffer.wrap(valueBuf); 91 converter.order(ByteOrder.nativeOrder()); 92 return converter.getShort(); 93 } 94 95 public static int byteArrayToInt(byte[] valueBuf, int offset) { 96 ByteBuffer converter = ByteBuffer.wrap(valueBuf); 97 converter.order(ByteOrder.nativeOrder()); 98 return converter.getInt(offset); 99 } 100 101 public static byte[] intToByteArray(int value) { 102 ByteBuffer converter = ByteBuffer.allocate(4); 103 converter.order(ByteOrder.nativeOrder()); 104 converter.putInt(value); 105 return converter.array(); 106 } 107 108 public static byte[] uuidToByteArray(ParcelUuid pUuid) { 109 int length = BD_UUID_LEN; 110 ByteBuffer converter = ByteBuffer.allocate(length); 111 converter.order(ByteOrder.BIG_ENDIAN); 112 long msb, lsb; 113 UUID uuid = pUuid.getUuid(); 114 msb = uuid.getMostSignificantBits(); 115 lsb = uuid.getLeastSignificantBits(); 116 converter.putLong(msb); 117 converter.putLong(8, lsb); 118 return converter.array(); 119 } 120 121 public static byte[] uuidsToByteArray(ParcelUuid[] uuids) { 122 int length = uuids.length * BD_UUID_LEN; 123 ByteBuffer converter = ByteBuffer.allocate(length); 124 converter.order(ByteOrder.BIG_ENDIAN); 125 UUID uuid; 126 long msb, lsb; 127 for (int i = 0; i < uuids.length; i++) { 128 uuid = uuids[i].getUuid(); 129 msb = uuid.getMostSignificantBits(); 130 lsb = uuid.getLeastSignificantBits(); 131 converter.putLong(i * BD_UUID_LEN, msb); 132 converter.putLong(i * BD_UUID_LEN + 8, lsb); 133 } 134 return converter.array(); 135 } 136 137 public static ParcelUuid[] byteArrayToUuid(byte[] val) { 138 int numUuids = val.length / BD_UUID_LEN; 139 ParcelUuid[] puuids = new ParcelUuid[numUuids]; 140 UUID uuid; 141 int offset = 0; 142 143 ByteBuffer converter = ByteBuffer.wrap(val); 144 converter.order(ByteOrder.BIG_ENDIAN); 145 146 for (int i = 0; i < numUuids; i++) { 147 puuids[i] = new ParcelUuid(new UUID(converter.getLong(offset), 148 converter.getLong(offset + 8))); 149 offset += BD_UUID_LEN; 150 } 151 return puuids; 152 } 153 154 public static String debugGetAdapterStateString(int state) { 155 switch (state) { 156 case BluetoothAdapter.STATE_OFF: 157 return "STATE_OFF"; 158 case BluetoothAdapter.STATE_ON: 159 return "STATE_ON"; 160 case BluetoothAdapter.STATE_TURNING_ON: 161 return "STATE_TURNING_ON"; 162 case BluetoothAdapter.STATE_TURNING_OFF: 163 return "STATE_TURNING_OFF"; 164 default: 165 return "UNKNOWN"; 166 } 167 } 168 169 public static void copyStream(InputStream is, OutputStream os, int bufferSize) 170 throws IOException { 171 if (is != null && os != null) { 172 byte[] buffer = new byte[bufferSize]; 173 int bytesRead = 0; 174 while ((bytesRead = is.read(buffer)) >= 0) { 175 os.write(buffer, 0, bytesRead); 176 } 177 } 178 } 179 180 public static void safeCloseStream(InputStream is) { 181 if (is != null) { 182 try { 183 is.close(); 184 } catch (Throwable t) { 185 Log.d(TAG, "Error closing stream", t); 186 } 187 } 188 } 189 190 public static void safeCloseStream(OutputStream os) { 191 if (os != null) { 192 try { 193 os.close(); 194 } catch (Throwable t) { 195 Log.d(TAG, "Error closing stream", t); 196 } 197 } 198 } 199 200 public static boolean checkCaller() { 201 boolean ok; 202 // Get the caller's user id then clear the calling identity 203 // which will be restored in the finally clause. 204 int callingUser = UserHandle.getCallingUserId(); 205 int callingUid = Binder.getCallingUid(); 206 long ident = Binder.clearCallingIdentity(); 207 208 try { 209 // With calling identity cleared the current user is the foreground user. 210 int foregroundUser = ActivityManager.getCurrentUser(); 211 ok = (foregroundUser == callingUser); 212 if (!ok) { 213 // Always allow SystemUI/System access. 214 int systemUiUid = ActivityThread.getPackageManager().getPackageUid( 215 "com.android.systemui", UserHandle.USER_OWNER); 216 ok = (systemUiUid == callingUid) || (Process.SYSTEM_UID == callingUid); 217 } 218 } catch (Exception ex) { 219 Log.e(TAG, "checkIfCallerIsSelfOrForegroundUser: Exception ex=" + ex); 220 ok = false; 221 } finally { 222 Binder.restoreCallingIdentity(ident); 223 } 224 return ok; 225 } 226 227 public static boolean checkCallerAllowManagedProfiles(Context mContext) { 228 if (mContext == null) { 229 return checkCaller(); 230 } 231 boolean ok; 232 // Get the caller's user id and if it's a managed profile, get it's parents 233 // id, then clear the calling identity 234 // which will be restored in the finally clause. 235 int callingUser = UserHandle.getCallingUserId(); 236 int callingUid = Binder.getCallingUid(); 237 long ident = Binder.clearCallingIdentity(); 238 try { 239 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 240 UserInfo ui = um.getProfileParent(callingUser); 241 int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL; 242 // With calling identity cleared the current user is the foreground user. 243 int foregroundUser = ActivityManager.getCurrentUser(); 244 ok = (foregroundUser == callingUser) || 245 (foregroundUser == parentUser); 246 if (!ok) { 247 // Always allow SystemUI/System access. 248 int systemUiUid = ActivityThread.getPackageManager().getPackageUid( 249 "com.android.systemui", UserHandle.USER_OWNER); 250 ok = (systemUiUid == callingUid) || (Process.SYSTEM_UID == callingUid); 251 } 252 } catch (Exception ex) { 253 Log.e(TAG, "checkCallerAllowManagedProfiles: Exception ex=" + ex); 254 ok = false; 255 } finally { 256 Binder.restoreCallingIdentity(ident); 257 } 258 return ok; 259 } 260 261 /** 262 * Enforce the context has android.Manifest.permission.BLUETOOTH_ADMIN permission. A 263 * {@link SecurityException} would be thrown if neither the calling process or the application 264 * does not have BLUETOOTH_ADMIN permission. 265 * 266 * @param context Context for the permission check. 267 */ 268 public static void enforceAdminPermission(ContextWrapper context) { 269 context.enforceCallingOrSelfPermission(android.Manifest.permission.BLUETOOTH_ADMIN, 270 "Need BLUETOOTH_ADMIN permission"); 271 } 272 273 /** 274 * Checks that calling process has android.Manifest.permission.ACCESS_COARSE_LOCATION or 275 * android.Manifest.permission.ACCESS_FINE_LOCATION and a corresponding app op is allowed 276 */ 277 public static boolean checkCallerHasLocationPermission(Context context, AppOpsManager appOps, 278 String callingPackage) { 279 if (context.checkCallingOrSelfPermission(android.Manifest.permission. 280 ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED 281 && isAppOppAllowed(appOps, AppOpsManager.OP_FINE_LOCATION, callingPackage)) { 282 return true; 283 } 284 285 if (context.checkCallingOrSelfPermission(android.Manifest.permission. 286 ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED 287 && isAppOppAllowed(appOps, AppOpsManager.OP_COARSE_LOCATION, callingPackage)) { 288 return true; 289 } 290 // Enforce location permission for apps targeting M and later versions 291 if (isMApp(context, callingPackage)) { 292 throw new SecurityException("Need ACCESS_COARSE_LOCATION or " 293 + "ACCESS_FINE_LOCATION permission to get scan results"); 294 } else { 295 // Pre-M apps running in the foreground should continue getting scan results 296 if (isForegroundApp(context, callingPackage)) { 297 return true; 298 } 299 Log.e(TAG, "Permission denial: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION " 300 + "permission to get scan results"); 301 } 302 return false; 303 } 304 305 /** 306 * Returns true if the caller holds PEERS_MAC_ADDRESS. 307 */ 308 public static boolean checkCallerHasPeersMacAddressPermission(Context context) { 309 return context.checkCallingOrSelfPermission( 310 android.Manifest.permission.PEERS_MAC_ADDRESS) == PackageManager.PERMISSION_GRANTED; 311 } 312 313 public static boolean isLegacyForegroundApp(Context context, String pkgName) { 314 return !isMApp(context, pkgName) && isForegroundApp(context, pkgName); 315 } 316 317 private static boolean isMApp(Context context, String pkgName) { 318 try { 319 return context.getPackageManager().getApplicationInfo(pkgName, 0) 320 .targetSdkVersion >= Build.VERSION_CODES.M; 321 } catch (PackageManager.NameNotFoundException e) { 322 // In case of exception, assume M app 323 } 324 return true; 325 } 326 327 /** 328 * Return true if the specified package name is a foreground app. 329 * 330 * @param pkgName application package name. 331 */ 332 private static boolean isForegroundApp(Context context, String pkgName) { 333 ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE); 334 List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1); 335 return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName()); 336 } 337 338 private static boolean isAppOppAllowed(AppOpsManager appOps, int op, String callingPackage) { 339 return appOps.noteOp(op, Binder.getCallingUid(), callingPackage) 340 == AppOpsManager.MODE_ALLOWED; 341 } 342 343 /** 344 * Converts {@code millisecond} to unit. Each unit is 0.625 millisecond. 345 */ 346 public static int millsToUnit(int milliseconds) { 347 return (int) (TimeUnit.MILLISECONDS.toMicros(milliseconds) / MICROS_PER_UNIT); 348 } 349} 350