Home | History | Annotate | Download | only in bluetooth
      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 
     17 package com.android.bluetooth;
     18 
     19 import android.app.ActivityManager;
     20 import android.app.ActivityThread;
     21 import android.bluetooth.BluetoothAdapter;
     22 import android.bluetooth.BluetoothDevice;
     23 import android.content.Context;
     24 import android.content.ContextWrapper;
     25 import android.content.pm.UserInfo;
     26 import android.os.Binder;
     27 import android.os.ParcelUuid;
     28 import android.os.Process;
     29 import android.os.UserHandle;
     30 import android.os.UserManager;
     31 import android.util.Log;
     32 
     33 import java.io.IOException;
     34 import java.io.InputStream;
     35 import java.io.OutputStream;
     36 import java.nio.ByteBuffer;
     37 import java.nio.ByteOrder;
     38 import java.util.UUID;
     39 import java.util.concurrent.TimeUnit;
     40 
     41 /**
     42  * @hide
     43  */
     44 
     45 final 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