Home | History | Annotate | Download | only in trust
      1 /*
      2  * Copyright (C) 2016 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.car.trust;
     18 
     19 import android.bluetooth.BluetoothDevice;
     20 import android.bluetooth.BluetoothGattServer;
     21 import android.bluetooth.BluetoothGattServerCallback;
     22 import android.bluetooth.BluetoothManager;
     23 import android.car.trust.ICarTrustAgentBleService;
     24 import android.car.trust.ICarTrustAgentTokenRequestDelegate;
     25 import android.car.trust.ICarTrustAgentUnlockCallback;
     26 import android.content.ComponentName;
     27 import android.content.Context;
     28 import android.content.Intent;
     29 import android.content.ServiceConnection;
     30 import android.os.Handler;
     31 import android.os.IBinder;
     32 import android.os.RemoteException;
     33 import android.os.UserHandle;
     34 import android.os.UserManager;
     35 import android.service.trust.TrustAgentService;
     36 import android.util.Log;
     37 
     38 import java.util.concurrent.TimeUnit;
     39 
     40 /**
     41  * A BluetoothLE (BLE) based {@link TrustAgentService} that uses the escrow token unlock APIs. </p>
     42  *
     43  * This trust agent runs during direct boot and binds to a BLE service that listens for remote
     44  * devices to trigger an unlock. <p/>
     45  *
     46  * The permissions for this agent must be enabled as priv-app permissions for it to start.
     47  */
     48 public class CarBleTrustAgent extends TrustAgentService {
     49 
     50     private static final String TAG = CarBleTrustAgent.class.getSimpleName();
     51 
     52     private static final long TRUST_DURATION_MS = TimeUnit.MINUTES.toMicros(5);
     53     private static final long BLE_RETRY_MS = TimeUnit.SECONDS.toMillis(1);
     54 
     55     private Handler mHandler;
     56     private BluetoothManager mBluetoothManager;
     57     private ICarTrustAgentBleService mCarTrustAgentBleService;
     58     private boolean mCarTrustAgentBleServiceBound;
     59 
     60     private final ICarTrustAgentUnlockCallback mUnlockCallback =
     61             new ICarTrustAgentUnlockCallback.Stub() {
     62         @Override
     63         public void onUnlockDataReceived(byte[] token, long handle) {
     64             UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
     65             // TODO(b/77854782): get the actual user to unlock by token
     66             UserHandle userHandle = getForegroundUserHandle();
     67 
     68             Log.d(TAG, "About to unlock user. Handle: " + handle
     69                     + " Time: " + System.currentTimeMillis());
     70             unlockUserWithToken(handle, token, userHandle);
     71 
     72             Log.d(TAG, "Attempted to unlock user, is user unlocked: "
     73                     + um.isUserUnlocked(userHandle)
     74                     + " Time: " + System.currentTimeMillis());
     75             setManagingTrust(true);
     76 
     77             if (um.isUserUnlocked(userHandle)) {
     78                 Log.d(TAG, getString(R.string.trust_granted_explanation));
     79                 grantTrust("Granting trust from escrow token",
     80                         TRUST_DURATION_MS, FLAG_GRANT_TRUST_DISMISS_KEYGUARD);
     81             }
     82         }
     83     };
     84 
     85     private final ICarTrustAgentTokenRequestDelegate mTokenRequestDelegate =
     86             new ICarTrustAgentTokenRequestDelegate.Stub() {
     87         @Override
     88         public void revokeTrust() {
     89             CarBleTrustAgent.this.revokeTrust();
     90         }
     91 
     92         @Override
     93         public void addEscrowToken(byte[] token, int uid) {
     94             CarBleTrustAgent.this.addEscrowToken(token, UserHandle.of(uid));
     95         }
     96 
     97         @Override
     98         public void removeEscrowToken(long handle, int uid) {
     99             CarBleTrustAgent.this.removeEscrowToken(handle, UserHandle.of(uid));
    100         }
    101 
    102         @Override
    103         public void isEscrowTokenActive(long handle, int uid) {
    104             CarBleTrustAgent.this.isEscrowTokenActive(handle, UserHandle.of(uid));
    105         }
    106     };
    107 
    108     private final ServiceConnection mServiceConnection = new ServiceConnection() {
    109         @Override
    110         public void onServiceConnected(ComponentName name, IBinder service) {
    111             Log.d(TAG, "CarTrustAgentBleService connected");
    112             mCarTrustAgentBleServiceBound = true;
    113             mCarTrustAgentBleService = ICarTrustAgentBleService.Stub.asInterface(service);
    114             try {
    115                 mCarTrustAgentBleService.registerUnlockCallback(mUnlockCallback);
    116                 mCarTrustAgentBleService.setTokenRequestDelegate(mTokenRequestDelegate);
    117                 maybeStartBleUnlockService();
    118             } catch (RemoteException e) {
    119                 Log.e(TAG, "Error registerUnlockCallback", e);
    120             }
    121         }
    122 
    123         @Override
    124         public void onServiceDisconnected(ComponentName name) {
    125             if (mCarTrustAgentBleService != null) {
    126                 try {
    127                     mCarTrustAgentBleService.unregisterUnlockCallback(mUnlockCallback);
    128                     mCarTrustAgentBleService.setTokenRequestDelegate(null);
    129                 } catch (RemoteException e) {
    130                     Log.e(TAG, "Error unregisterUnlockCallback", e);
    131                 }
    132                 mCarTrustAgentBleService = null;
    133                 mCarTrustAgentBleServiceBound = false;
    134             }
    135         }
    136     };
    137 
    138     @Override
    139     public void onCreate() {
    140         super.onCreate();
    141 
    142         Log.d(TAG, "Bluetooth trust agent starting up");
    143         mHandler = new Handler();
    144         mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
    145 
    146         // If the user is already unlocked, don't bother starting the BLE service.
    147         UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
    148         if (!um.isUserUnlocked(getForegroundUserHandle())) {
    149             Log.d(TAG, "User locked, will now bind CarTrustAgentBleService");
    150             Intent intent = new Intent(this, CarTrustAgentBleService.class);
    151             bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    152         } else {
    153             setManagingTrust(true);
    154         }
    155     }
    156 
    157     @Override
    158     public void onDestroy() {
    159         Log.d(TAG, "Car Trust agent shutting down");
    160         mHandler.removeCallbacks(null);
    161 
    162         // Unbind the service to avoid leaks from BLE stack.
    163         if (mCarTrustAgentBleServiceBound) {
    164             unbindService(mServiceConnection);
    165         }
    166         super.onDestroy();
    167     }
    168 
    169     @Override
    170     public void onDeviceLocked() {
    171         super.onDeviceLocked();
    172         if (mCarTrustAgentBleServiceBound) {
    173             try {
    174                 // Only one BLE advertising is allowed, ensure enrolment advertising is stopped
    175                 // before start unlock advertising.
    176                 mCarTrustAgentBleService.stopEnrolmentAdvertising();
    177                 mCarTrustAgentBleService.startUnlockAdvertising();
    178             } catch (RemoteException e) {
    179                 Log.e(TAG, "Error startUnlockAdvertising", e);
    180             }
    181         }
    182     }
    183 
    184     @Override
    185     public void onDeviceUnlocked() {
    186         super.onDeviceUnlocked();
    187         if (mCarTrustAgentBleServiceBound) {
    188             try {
    189                 // Only one BLE advertising is allowed, ensure unlock advertising is stopped.
    190                 mCarTrustAgentBleService.stopUnlockAdvertising();
    191             } catch (RemoteException e) {
    192                 Log.e(TAG, "Error stopUnlockAdvertising", e);
    193             }
    194         }
    195     }
    196 
    197     private void maybeStartBleUnlockService() {
    198         Log.d(TAG, "Trying to open a Ble GATT server");
    199         BluetoothGattServer gattServer = mBluetoothManager.openGattServer(
    200                 this, new BluetoothGattServerCallback() {
    201             @Override
    202             public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
    203                 super.onConnectionStateChange(device, status, newState);
    204             }
    205         });
    206 
    207         // The BLE stack is started up before the trust agent service, however Gatt capabilities
    208         // might not be ready just yet. Keep trying until a GattServer can open up before proceeding
    209         // to start the rest of the BLE services.
    210         if (gattServer == null) {
    211             Log.e(TAG, "Gatt not available, will try again...in " + BLE_RETRY_MS + "ms");
    212             mHandler.postDelayed(this::maybeStartBleUnlockService, BLE_RETRY_MS);
    213         } else {
    214             mHandler.removeCallbacks(null);
    215             gattServer.close();
    216             Log.d(TAG, "GATT available, starting up UnlockService");
    217             try {
    218                 mCarTrustAgentBleService.startUnlockAdvertising();
    219             } catch (RemoteException e) {
    220                 Log.e(TAG, "Error startUnlockAdvertising", e);
    221             }
    222         }
    223     }
    224 
    225     @Override
    226     public void onEscrowTokenRemoved(long handle, boolean successful) {
    227         if (mCarTrustAgentBleServiceBound) {
    228             try {
    229                 mCarTrustAgentBleService.onEscrowTokenRemoved(handle, successful);
    230                 Log.v(TAG, "Callback onEscrowTokenRemoved");
    231             } catch (RemoteException e) {
    232                 Log.e(TAG, "Error callback onEscrowTokenRemoved", e);
    233             }
    234         }
    235     }
    236 
    237     @Override
    238     public void onEscrowTokenStateReceived(long handle, int tokenState) {
    239         boolean isActive = tokenState == TOKEN_STATE_ACTIVE;
    240         if (mCarTrustAgentBleServiceBound) {
    241             try {
    242                 mCarTrustAgentBleService.onEscrowTokenActiveStateChanged(handle, isActive);
    243                 Log.v(TAG, "Callback onEscrowTokenActiveStateChanged");
    244             } catch (RemoteException e) {
    245                 Log.e(TAG, "Error callback onEscrowTokenActiveStateChanged", e);
    246             }
    247         }
    248     }
    249 
    250     @Override
    251     public void onEscrowTokenAdded(byte[] token, long handle, UserHandle user) {
    252         if (mCarTrustAgentBleServiceBound) {
    253             try {
    254                 mCarTrustAgentBleService.onEscrowTokenAdded(token, handle, user.getIdentifier());
    255                 Log.v(TAG, "Callback onEscrowTokenAdded");
    256             } catch (RemoteException e) {
    257                 Log.e(TAG, "Error callback onEscrowTokenAdded", e);
    258             }
    259         }
    260     }
    261 
    262     /**
    263      * TODO(b/77854782): return the {@link UserHandle} of foreground user.
    264      * CarBleTrustAgent itself runs as user-0
    265      */
    266     private UserHandle getForegroundUserHandle() {
    267         Log.d(TAG, "getForegroundUserHandle for " + UserHandle.myUserId());
    268         return UserHandle.of(UserHandle.myUserId());
    269     }
    270 }
    271