Home | History | Annotate | Download | only in trust
      1 /*
      2  * Copyright (C) 2017 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 package com.android.car.trust;
     17 
     18 import android.bluetooth.BluetoothDevice;
     19 import android.bluetooth.BluetoothGattCharacteristic;
     20 import android.bluetooth.BluetoothGattService;
     21 import android.content.Intent;
     22 import android.os.Binder;
     23 import android.os.IBinder;
     24 import android.os.ParcelUuid;
     25 import android.util.Log;
     26 import com.android.car.trust.comms.SimpleBleServer;
     27 
     28 import java.util.UUID;
     29 
     30 /**
     31  * A service that receives unlock requests from remote devices.
     32  */
     33 public class CarUnlockService extends SimpleBleServer {
     34     /**
     35      * A callback to receives callback
     36      */
     37     public interface UnlockServiceCallback {
     38         void unlockDevice(byte[] token, long handle);
     39     }
     40 
     41     private static final String TAG = "CarUnlockService";
     42 
     43     private BluetoothGattService mUnlockService;
     44     private BluetoothGattCharacteristic mUnlockEscrowToken;
     45     private BluetoothGattCharacteristic mUnlockTokenHandle;
     46 
     47     private UnlockServiceCallback mCallback;
     48 
     49     private byte[] mCurrentToken;
     50     private Long mCurrentHandle;
     51 
     52     private final IBinder mBinder = new UnlockServiceBinder();
     53 
     54     public class UnlockServiceBinder extends Binder {
     55         public CarUnlockService getService() {
     56             return CarUnlockService.this;
     57         }
     58     }
     59 
     60     @Override
     61     public void onCreate() {
     62         super.onCreate();
     63         if (Log.isLoggable(TAG, Log.DEBUG)) {
     64             Log.d(TAG, "CarUnlockService starting up, creating BLE service");
     65         }
     66         setupUnlockService();
     67     }
     68 
     69     /**
     70      * Start advertising the BLE unlock service
     71      */
     72     public void start() {
     73         ParcelUuid uuid = new ParcelUuid(
     74                 UUID.fromString(getString(R.string.unlock_service_uuid)));
     75         start(uuid, mUnlockService);
     76     }
     77 
     78     public void addUnlockServiceCallback(UnlockServiceCallback callback) {
     79         mCallback = callback;
     80     }
     81 
     82     @Override
     83     public IBinder onBind(Intent intent) {
     84         return mBinder;
     85     }
     86 
     87     @Override
     88     public void onCharacteristicWrite(BluetoothDevice device,
     89             int requestId, BluetoothGattCharacteristic characteristic,
     90             boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
     91         UUID uuid = characteristic.getUuid();
     92 
     93         if (uuid.equals(mUnlockTokenHandle.getUuid())) {
     94             if (Log.isLoggable(TAG, Log.DEBUG)) {
     95                 Log.d(TAG, "Unlock handle received, value: " + Utils.getLong(value));
     96             }
     97             mCurrentHandle = Utils.getLong(value);
     98             unlockDataReceived();
     99         } else if (uuid.equals(mUnlockEscrowToken.getUuid())) {
    100             if (Log.isLoggable(TAG, Log.DEBUG)) {
    101                 Log.d(TAG, "Unlock escrow token received, value: " + Utils.getLong(value));
    102             }
    103             mCurrentToken = value;
    104             unlockDataReceived();
    105         }
    106     }
    107 
    108     @Override
    109     public void onCharacteristicRead(BluetoothDevice device,
    110             int requestId, int offset, BluetoothGattCharacteristic characteristic) {
    111         // The BLE unlock service should not receive any read requests.
    112     }
    113 
    114     private synchronized void unlockDataReceived() {
    115         // If any piece of the unlocking data is not received, then do not unlock.
    116         if (mCurrentHandle == null || mCurrentToken == null) {
    117             return;
    118         }
    119 
    120         if (Log.isLoggable(TAG, Log.DEBUG)) {
    121             Log.d(TAG, "Handle and token both received, requesting unlock. Time: "
    122                     + System.currentTimeMillis());
    123         }
    124         // Both the handle and token has been received, try to unlock the device.
    125 
    126 
    127         mCallback.unlockDevice(mCurrentToken, mCurrentHandle);
    128 
    129         // Once we've notified the client of the unlocking data, clear it out.
    130         mCurrentToken = null;
    131         mCurrentHandle = null;
    132     }
    133 
    134 
    135     // Create services and characteristics to receive tokens and handles for unlocking the device.
    136     private void setupUnlockService() {
    137         mUnlockService = new BluetoothGattService(
    138                 UUID.fromString(getString(R.string.unlock_service_uuid)),
    139                 BluetoothGattService.SERVICE_TYPE_PRIMARY);
    140 
    141         // Characteristic to describe the escrow token being used for unlock
    142         mUnlockEscrowToken = new BluetoothGattCharacteristic(
    143                 UUID.fromString(getString(R.string.unlock_escrow_token_uiid)),
    144                 BluetoothGattCharacteristic.PROPERTY_WRITE,
    145                 BluetoothGattCharacteristic.PERMISSION_WRITE);
    146 
    147         // Characteristic to describe the handle being used for this escrow token
    148         mUnlockTokenHandle = new BluetoothGattCharacteristic(
    149                 UUID.fromString(getString(R.string.unlock_handle_uiid)),
    150                 BluetoothGattCharacteristic.PROPERTY_WRITE,
    151                 BluetoothGattCharacteristic.PERMISSION_WRITE);
    152 
    153         mUnlockService.addCharacteristic(mUnlockEscrowToken);
    154         mUnlockService.addCharacteristic(mUnlockTokenHandle);
    155     }
    156 
    157 }
    158