CarBleTrustAgent.java revision 77e5e49cf9dcceb69b07510c380ae2a9285ebfee
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 17package com.android.car.trust; 18 19import android.bluetooth.BluetoothDevice; 20import android.bluetooth.BluetoothGattServer; 21import android.bluetooth.BluetoothGattServerCallback; 22import android.bluetooth.BluetoothManager; 23import android.content.BroadcastReceiver; 24import android.content.ComponentName; 25import android.content.Context; 26import android.content.Intent; 27import android.content.IntentFilter; 28import android.content.ServiceConnection; 29import android.os.Handler; 30import android.os.IBinder; 31import android.os.UserHandle; 32import android.os.UserManager; 33import android.service.trust.TrustAgentService; 34import android.support.v4.content.LocalBroadcastManager; 35import android.util.Log; 36import com.android.car.trust.comms.SimpleBleServer; 37 38import java.util.concurrent.TimeUnit; 39 40/** 41 * A sample trust agent that demonstrates how to use 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. 45 */ 46public class CarBleTrustAgent extends TrustAgentService { 47 public static final String ACTION_REVOKE_TRUST = "revoke-trust-action"; 48 public static final String ACTION_ADD_TOKEN = "add-token-action"; 49 public static final String ACTION_IS_TOKEN_ACTIVE = "is-token-active-action"; 50 public static final String ACTION_REMOVE_TOKEN = "remove-token-action"; 51 public static final String ACTION_UNLOCK_DEVICE = "unlock-device-action"; 52 53 public static final String ACTION_TOKEN_STATUS_RESULT = "token-status-result-action"; 54 public static final String ACTION_ADD_TOKEN_RESULT = "add-token-result-action"; 55 56 public static final String INTENT_EXTRA_ESCROW_TOKEN = "extra-escrow-token"; 57 public static final String INTENT_EXTRA_TOKEN_HANDLE = "extra-token-handle"; 58 public static final String INTENT_EXTRA_TOKEN_STATUS = "extra-token-status"; 59 60 61 private static final String TAG = "CarBleTrustAgent"; 62 63 private static final long TRUST_DURATION_MS = TimeUnit.MINUTES.toMicros(5); 64 private static final long BLE_RETRY_MS = TimeUnit.SECONDS.toMillis(1); 65 66 private CarUnlockService mCarUnlockService; 67 private LocalBroadcastManager mLocalBroadcastManager; 68 69 private boolean mBleServiceBound; 70 71 // We cannot directly bind to TrustAgentService since the onBind method is final. 72 // As a result, we communicate with the various UI components using a LocalBroadcastManager. 73 private final BroadcastReceiver mTrustEventReceiver = new BroadcastReceiver() { 74 @Override 75 public void onReceive(Context context, Intent intent) { 76 String action = intent.getAction(); 77 Log.d(TAG, "Received broadcast: " + action); 78 if (ACTION_REVOKE_TRUST.equals(action)) { 79 revokeTrust(); 80 } else if (ACTION_ADD_TOKEN.equals(action)) { 81 byte[] token = intent.getByteArrayExtra(INTENT_EXTRA_ESCROW_TOKEN); 82 addEscrowToken(token, getCurrentUserHandle()); 83 } else if (ACTION_IS_TOKEN_ACTIVE.equals(action)) { 84 long handle = intent.getLongExtra(INTENT_EXTRA_TOKEN_HANDLE, -1); 85 isEscrowTokenActive(handle, getCurrentUserHandle()); 86 } else if (ACTION_REMOVE_TOKEN.equals(action)) { 87 long handle = intent.getLongExtra(INTENT_EXTRA_TOKEN_HANDLE, -1); 88 removeEscrowToken(handle, getCurrentUserHandle()); 89 } 90 } 91 }; 92 93 @Override 94 public void onTrustTimeout() { 95 super.onTrustTimeout(); 96 Log.d(TAG, "onTrustTimeout(): timeout expired"); 97 } 98 99 @Override 100 public void onCreate() { 101 super.onCreate(); 102 103 Log.d(TAG, "Bluetooth trust agent starting up"); 104 IntentFilter filter = new IntentFilter(); 105 filter.addAction(ACTION_REVOKE_TRUST); 106 filter.addAction(ACTION_ADD_TOKEN); 107 filter.addAction(ACTION_IS_TOKEN_ACTIVE); 108 filter.addAction(ACTION_REMOVE_TOKEN); 109 110 mLocalBroadcastManager = LocalBroadcastManager.getInstance(this /* context */); 111 mLocalBroadcastManager.registerReceiver(mTrustEventReceiver, filter); 112 113 // If the user is already unlocked, don't bother starting the BLE service. 114 UserManager um = (UserManager) getSystemService(Context.USER_SERVICE); 115 if (!um.isUserUnlocked()) { 116 Log.d(TAG, "User locked, will now bind CarUnlockService"); 117 Intent intent = new Intent(this, CarUnlockService.class); 118 119 bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); 120 } else { 121 setManagingTrust(true); 122 } 123 } 124 125 @Override 126 public void onDestroy() { 127 Log.d(TAG, "Car Trust agent shutting down"); 128 mLocalBroadcastManager.unregisterReceiver(mTrustEventReceiver); 129 130 // Unbind the service to avoid leaks from BLE stack. 131 if (mBleServiceBound) { 132 unbindService(mServiceConnection); 133 } 134 super.onDestroy(); 135 } 136 137 private SimpleBleServer.ConnectionListener mConnectionListener 138 = new SimpleBleServer.ConnectionListener() { 139 @Override 140 public void onServerStarted() { 141 Log.d(TAG, "BLE server started"); 142 } 143 144 @Override 145 public void onServerStartFailed(int errorCode) { 146 Log.d(TAG, "BLE server failed to start. Error Code: " + errorCode); 147 } 148 149 @Override 150 public void onDeviceConnected(BluetoothDevice device) { 151 Log.d(TAG, "BLE device connected. Name: " + device.getName() 152 + " Address: " + device.getAddress()); 153 } 154 }; 155 156 private CarUnlockService.UnlockServiceCallback mUnlockCallback 157 = new CarUnlockService.UnlockServiceCallback() { 158 @Override 159 public void unlockDevice(byte[] token, long handle) { 160 unlock(token, handle); 161 } 162 }; 163 164 private ServiceConnection mServiceConnection = new ServiceConnection() { 165 166 public void onServiceConnected(ComponentName className, IBinder service) { 167 Log.d(TAG, "CarUnlockService connected"); 168 169 mBleServiceBound = true; 170 CarUnlockService.UnlockServiceBinder binder 171 = (CarUnlockService.UnlockServiceBinder) service; 172 mCarUnlockService = binder.getService(); 173 mCarUnlockService.addUnlockServiceCallback(mUnlockCallback); 174 mCarUnlockService.addConnectionListener(mConnectionListener); 175 maybeStartBleUnlockService(); 176 } 177 178 public void onServiceDisconnected(ComponentName arg0) { 179 mCarUnlockService = null; 180 mBleServiceBound = false; 181 } 182 183 }; 184 185 private void maybeStartBleUnlockService() { 186 Log.d(TAG, "Trying to open a Ble GATT server"); 187 188 BluetoothManager btManager = 189 (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); 190 BluetoothGattServer mGattServer 191 = btManager.openGattServer(this, new BluetoothGattServerCallback() { 192 @Override 193 public void onConnectionStateChange(BluetoothDevice device, int status, int newState) { 194 super.onConnectionStateChange(device, status, newState); 195 } 196 }); 197 198 // The BLE stack is started up before the trust agent service, however Gatt capabilities 199 // might not be ready just yet. Keep trying until a GattServer can open up before proceeding 200 // to start the rest of the BLE services. 201 if (mGattServer == null) { 202 Log.e(TAG, "Gatt not available, will try again...in " + BLE_RETRY_MS + "ms"); 203 204 Handler handler = new Handler(); 205 handler.postDelayed(new Runnable() { 206 @Override 207 public void run() { 208 maybeStartBleUnlockService(); 209 } 210 }, BLE_RETRY_MS); 211 } else { 212 mGattServer.close(); 213 Log.d(TAG, "GATT available, starting up UnlockService"); 214 mCarUnlockService.start(); 215 } 216 } 217 218 private void unlock(byte[] token, long handle) { 219 UserManager um = (UserManager) getSystemService(Context.USER_SERVICE); 220 221 Log.d(TAG, "About to unlock user. Current handle: " + handle 222 + " Time: " + System.currentTimeMillis()); 223 unlockUserWithToken(handle, token, getCurrentUserHandle()); 224 Log.d(TAG, "Attempted to unlock user, is user unlocked? " + um.isUserUnlocked() 225 + " Time: " + System.currentTimeMillis()); 226 setManagingTrust(true); 227 228 if (um.isUserUnlocked()) { 229 Log.d(TAG, getString(R.string.trust_granted_explanation)); 230 grantTrust("Granting trust from escrow token", 231 TRUST_DURATION_MS, FLAG_GRANT_TRUST_DISMISS_KEYGUARD); 232 // Trust has been granted, disable the BLE server. This trust agent service does 233 // not need to receive additional BLE data. 234 unbindService(mServiceConnection); 235 } 236 } 237 238 @Override 239 public void onEscrowTokenRemoved(long handle, boolean successful) { 240 Log.d(TAG, "onEscrowTokenRemoved. Handle: " + handle + " successful? " + successful); 241 } 242 243 @Override 244 public void onEscrowTokenStateReceived(long handle, int tokenState) { 245 boolean isActive = tokenState == TOKEN_STATE_ACTIVE; 246 Log.d(TAG, "Token handle: " + handle + " isActive: " + isActive); 247 248 Intent intent = new Intent(); 249 intent.setAction(ACTION_TOKEN_STATUS_RESULT); 250 intent.putExtra(INTENT_EXTRA_TOKEN_STATUS, isActive); 251 252 mLocalBroadcastManager.sendBroadcast(intent); 253 } 254 255 @Override 256 public void onEscrowTokenAdded(byte[] token, long handle, UserHandle user) { 257 Log.d(TAG, "onEscrowTokenAdded, handle: " + handle); 258 259 Intent intent = new Intent(); 260 intent.setAction(ACTION_ADD_TOKEN_RESULT); 261 intent.putExtra(INTENT_EXTRA_TOKEN_HANDLE, handle); 262 263 mLocalBroadcastManager.sendBroadcast(intent); 264 } 265 266 private UserHandle getCurrentUserHandle() { 267 return UserHandle.of(UserHandle.myUserId()); 268 } 269} 270