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