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.bluetooth.BluetoothAdapter; 22import android.bluetooth.BluetoothDevice; 23import android.content.Context; 24import android.content.ContextWrapper; 25import android.content.pm.UserInfo; 26import android.os.Binder; 27import android.os.ParcelUuid; 28import android.os.Process; 29import android.os.UserHandle; 30import android.os.UserManager; 31import android.util.Log; 32 33import java.io.IOException; 34import java.io.InputStream; 35import java.io.OutputStream; 36import java.nio.ByteBuffer; 37import java.nio.ByteOrder; 38import java.util.UUID; 39import java.util.concurrent.TimeUnit; 40 41/** 42 * @hide 43 */ 44 45final public class Utils { 46 private static final String TAG = "BluetoothUtils"; 47 private static final int MICROS_PER_UNIT = 625; 48 49 static final int BD_ADDR_LEN = 6; // bytes 50 static final int BD_UUID_LEN = 16; // bytes 51 52 public static String getAddressStringFromByte(byte[] address) { 53 if (address == null || address.length != BD_ADDR_LEN) { 54 return null; 55 } 56 57 return String.format("%02X:%02X:%02X:%02X:%02X:%02X", 58 address[0], address[1], address[2], address[3], address[4], 59 address[5]); 60 } 61 62 public static byte[] getByteAddress(BluetoothDevice device) { 63 return getBytesFromAddress(device.getAddress()); 64 } 65 66 public static byte[] getBytesFromAddress(String address) { 67 int i, j = 0; 68 byte[] output = new byte[BD_ADDR_LEN]; 69 70 for (i = 0; i < address.length(); i++) { 71 if (address.charAt(i) != ':') { 72 output[j] = (byte) Integer.parseInt(address.substring(i, i + 2), BD_UUID_LEN); 73 j++; 74 i++; 75 } 76 } 77 78 return output; 79 } 80 81 public static int byteArrayToInt(byte[] valueBuf) { 82 return byteArrayToInt(valueBuf, 0); 83 } 84 85 public static short byteArrayToShort(byte[] valueBuf) { 86 ByteBuffer converter = ByteBuffer.wrap(valueBuf); 87 converter.order(ByteOrder.nativeOrder()); 88 return converter.getShort(); 89 } 90 91 public static int byteArrayToInt(byte[] valueBuf, int offset) { 92 ByteBuffer converter = ByteBuffer.wrap(valueBuf); 93 converter.order(ByteOrder.nativeOrder()); 94 return converter.getInt(offset); 95 } 96 97 public static byte[] intToByteArray(int value) { 98 ByteBuffer converter = ByteBuffer.allocate(4); 99 converter.order(ByteOrder.nativeOrder()); 100 converter.putInt(value); 101 return converter.array(); 102 } 103 104 public static byte[] uuidToByteArray(ParcelUuid pUuid) { 105 int length = BD_UUID_LEN; 106 ByteBuffer converter = ByteBuffer.allocate(length); 107 converter.order(ByteOrder.BIG_ENDIAN); 108 long msb, lsb; 109 UUID uuid = pUuid.getUuid(); 110 msb = uuid.getMostSignificantBits(); 111 lsb = uuid.getLeastSignificantBits(); 112 converter.putLong(msb); 113 converter.putLong(8, lsb); 114 return converter.array(); 115 } 116 117 public static byte[] uuidsToByteArray(ParcelUuid[] uuids) { 118 int length = uuids.length * BD_UUID_LEN; 119 ByteBuffer converter = ByteBuffer.allocate(length); 120 converter.order(ByteOrder.BIG_ENDIAN); 121 UUID uuid; 122 long msb, lsb; 123 for (int i = 0; i < uuids.length; i++) { 124 uuid = uuids[i].getUuid(); 125 msb = uuid.getMostSignificantBits(); 126 lsb = uuid.getLeastSignificantBits(); 127 converter.putLong(i * BD_UUID_LEN, msb); 128 converter.putLong(i * BD_UUID_LEN + 8, lsb); 129 } 130 return converter.array(); 131 } 132 133 public static ParcelUuid[] byteArrayToUuid(byte[] val) { 134 int numUuids = val.length / BD_UUID_LEN; 135 ParcelUuid[] puuids = new ParcelUuid[numUuids]; 136 UUID uuid; 137 int offset = 0; 138 139 ByteBuffer converter = ByteBuffer.wrap(val); 140 converter.order(ByteOrder.BIG_ENDIAN); 141 142 for (int i = 0; i < numUuids; i++) { 143 puuids[i] = new ParcelUuid(new UUID(converter.getLong(offset), 144 converter.getLong(offset + 8))); 145 offset += BD_UUID_LEN; 146 } 147 return puuids; 148 } 149 150 public static String debugGetAdapterStateString(int state) { 151 switch (state) { 152 case BluetoothAdapter.STATE_OFF: 153 return "STATE_OFF"; 154 case BluetoothAdapter.STATE_ON: 155 return "STATE_ON"; 156 case BluetoothAdapter.STATE_TURNING_ON: 157 return "STATE_TURNING_ON"; 158 case BluetoothAdapter.STATE_TURNING_OFF: 159 return "STATE_TURNING_OFF"; 160 default: 161 return "UNKNOWN"; 162 } 163 } 164 165 public static void copyStream(InputStream is, OutputStream os, int bufferSize) 166 throws IOException { 167 if (is != null && os != null) { 168 byte[] buffer = new byte[bufferSize]; 169 int bytesRead = 0; 170 while ((bytesRead = is.read(buffer)) >= 0) { 171 os.write(buffer, 0, bytesRead); 172 } 173 } 174 } 175 176 public static void safeCloseStream(InputStream is) { 177 if (is != null) { 178 try { 179 is.close(); 180 } catch (Throwable t) { 181 Log.d(TAG, "Error closing stream", t); 182 } 183 } 184 } 185 186 public static void safeCloseStream(OutputStream os) { 187 if (os != null) { 188 try { 189 os.close(); 190 } catch (Throwable t) { 191 Log.d(TAG, "Error closing stream", t); 192 } 193 } 194 } 195 196 public static boolean checkCaller() { 197 boolean ok; 198 // Get the caller's user id then clear the calling identity 199 // which will be restored in the finally clause. 200 int callingUser = UserHandle.getCallingUserId(); 201 int callingUid = Binder.getCallingUid(); 202 long ident = Binder.clearCallingIdentity(); 203 204 try { 205 // With calling identity cleared the current user is the foreground user. 206 int foregroundUser = ActivityManager.getCurrentUser(); 207 ok = (foregroundUser == callingUser); 208 if (!ok) { 209 // Always allow SystemUI/System access. 210 int systemUiUid = ActivityThread.getPackageManager().getPackageUid( 211 "com.android.systemui", UserHandle.USER_OWNER); 212 ok = (systemUiUid == callingUid) || (Process.SYSTEM_UID == callingUid); 213 } 214 } catch (Exception ex) { 215 Log.e(TAG, "checkIfCallerIsSelfOrForegroundUser: Exception ex=" + ex); 216 ok = false; 217 } finally { 218 Binder.restoreCallingIdentity(ident); 219 } 220 return ok; 221 } 222 223 public static boolean checkCallerAllowManagedProfiles(Context mContext) { 224 if (mContext == null) { 225 return checkCaller(); 226 } 227 boolean ok; 228 // Get the caller's user id and if it's a managed profile, get it's parents 229 // id, then clear the calling identity 230 // which will be restored in the finally clause. 231 int callingUser = UserHandle.getCallingUserId(); 232 int callingUid = Binder.getCallingUid(); 233 long ident = Binder.clearCallingIdentity(); 234 try { 235 UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 236 UserInfo ui = um.getProfileParent(callingUser); 237 int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL; 238 // With calling identity cleared the current user is the foreground user. 239 int foregroundUser = ActivityManager.getCurrentUser(); 240 ok = (foregroundUser == callingUser) || 241 (foregroundUser == parentUser); 242 if (!ok) { 243 // Always allow SystemUI/System access. 244 int systemUiUid = ActivityThread.getPackageManager().getPackageUid( 245 "com.android.systemui", UserHandle.USER_OWNER); 246 ok = (systemUiUid == callingUid) || (Process.SYSTEM_UID == callingUid); 247 } 248 } catch (Exception ex) { 249 Log.e(TAG, "checkCallerAllowManagedProfiles: Exception ex=" + ex); 250 ok = false; 251 } finally { 252 Binder.restoreCallingIdentity(ident); 253 } 254 return ok; 255 } 256 257 /** 258 * Enforce the context has android.Manifest.permission.BLUETOOTH_ADMIN permission. A 259 * {@link SecurityException} would be thrown if neither the calling process or the application 260 * does not have BLUETOOTH_ADMIN permission. 261 * 262 * @param context Context for the permission check. 263 */ 264 public static void enforceAdminPermission(ContextWrapper context) { 265 context.enforceCallingOrSelfPermission(android.Manifest.permission.BLUETOOTH_ADMIN, 266 "Need BLUETOOTH_ADMIN permission"); 267 } 268 269 /** 270 * Converts {@code millisecond} to unit. Each unit is 0.625 millisecond. 271 */ 272 public static int millsToUnit(int milliseconds) { 273 return (int) (TimeUnit.MILLISECONDS.toMicros(milliseconds) / MICROS_PER_UNIT); 274 } 275} 276