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