New Manager for Trusted device enrollment.

Adding a new Car Manager with APIs to facilitate trusted device
enrollment.  The service implementation doesn't do anything yet, will
add that in a follow up change.

Bug: 119826696
Test: Build and flash.
Change-Id: I4b7454c0c58ce76daadc1efebac4058ef7573b81
diff --git a/car-lib/api/system-current.txt b/car-lib/api/system-current.txt
index a0046eb..d7305a8 100644
--- a/car-lib/api/system-current.txt
+++ b/car-lib/api/system-current.txt
@@ -10,6 +10,7 @@
     field public static final java.lang.String PERMISSION_CAR_DRIVING_STATE = "android.car.permission.CAR_DRIVING_STATE";
     field public static final java.lang.String PERMISSION_CAR_DYNAMICS_STATE = "android.car.permission.CAR_DYNAMICS_STATE";
     field public static final java.lang.String PERMISSION_CAR_ENGINE_DETAILED = "android.car.permission.CAR_ENGINE_DETAILED";
+    field public static final java.lang.String PERMISSION_CAR_ENROLL_TRUST = "android.car.permission.CAR_ENROLL_TRUST";
     field public static final java.lang.String PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL = "android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL";
     field public static final java.lang.String PERMISSION_CAR_POWER = "android.car.permission.CAR_POWER";
     field public static final java.lang.String PERMISSION_CAR_PROJECTION = "android.car.permission.CAR_PROJECTION";
@@ -891,6 +892,38 @@
 
 }
 
+package android.car.trust {
+
+  public final class CarTrustAgentEnrollmentManager {
+    method public void activateToken(long) throws android.car.CarNotConnectedException;
+    method public void enrollmentHandshakeAccepted() throws android.car.CarNotConnectedException;
+    method public java.util.List<java.lang.Integer> getEnrollmentHandlesForUser(int) throws android.car.CarNotConnectedException;
+    method public void initiateEnrollmentHandshake(android.bluetooth.BluetoothDevice) throws android.car.CarNotConnectedException;
+    method public void revokeTrust(long) throws android.car.CarNotConnectedException;
+    method public void setBleCallback(android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentBleCallback) throws android.car.CarNotConnectedException;
+    method public void setEnrollmentCallback(android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentEnrollmentCallback) throws android.car.CarNotConnectedException;
+    method public void startEnrollmentAdvertising() throws android.car.CarNotConnectedException;
+    method public void stopEnrollmentAdvertising() throws android.car.CarNotConnectedException;
+    method public void terminateEnrollmentHandshake() throws android.car.CarNotConnectedException;
+  }
+
+  public static abstract interface CarTrustAgentEnrollmentManager.CarTrustAgentBleCallback {
+    method public abstract void onBleEnrollmentDeviceConnected(android.bluetooth.BluetoothDevice);
+    method public abstract void onBleEnrollmentDeviceDisconnected(android.bluetooth.BluetoothDevice);
+    method public abstract void onEnrollmentAdvertisingFailed(int);
+    method public abstract void onEnrollmentAdvertisingStarted();
+  }
+
+  public static abstract interface CarTrustAgentEnrollmentManager.CarTrustAgentEnrollmentCallback {
+    method public abstract void onAuthStringAvailable(android.bluetooth.BluetoothDevice, java.lang.String);
+    method public abstract void onEnrollmentHandshakeFailure(android.bluetooth.BluetoothDevice, int);
+    method public abstract void onEscrowTokenActiveStateChanged(long, boolean);
+    method public abstract void onEscrowTokenAdded(long);
+    method public abstract void onTrustRevoked(long, boolean);
+  }
+
+}
+
 package android.car.vms {
 
   public final class VmsAvailableLayers implements android.os.Parcelable {
diff --git a/car-lib/src/android/car/Car.java b/car-lib/src/android/car/Car.java
index b4c4509..940c518 100644
--- a/car-lib/src/android/car/Car.java
+++ b/car-lib/src/android/car/Car.java
@@ -426,6 +426,15 @@
     public static final String PERMISSION_STORAGE_MONITORING =
             "android.car.permission.STORAGE_MONITORING";
 
+    /**
+     * Permission necessary to enroll a device as a trusted authenticator device.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String PERMISSION_CAR_ENROLL_TRUST =
+            "android.car.permission.CAR_ENROLL_TRUST";
+
     /** Type of car connection: platform runs directly in car. */
     public static final int CONNECTION_TYPE_EMBEDDED = 5;
 
diff --git a/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java b/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java
new file mode 100644
index 0000000..48ee384
--- /dev/null
+++ b/car-lib/src/android/car/trust/CarTrustAgentEnrollmentManager.java
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.trust;
+
+import static android.car.Car.PERMISSION_CAR_ENROLL_TRUST;
+
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.bluetooth.BluetoothDevice;
+import android.car.CarManagerBase;
+import android.car.CarNotConnectedException;
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.lang.ref.WeakReference;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+
+/**
+ * APIs to help enroll a remote device as a trusted device that can be used to authenticate a user
+ * in the head unit.
+ * <p>
+ * The call sequence to add a new trusted device from the client should be as follows:
+ * <ol>
+ * <li> setEnrollmentCallback()
+ * <li> setBleCallback(bleCallback)
+ * <li> startEnrollmentAdvertising()
+ * <li> wait for onEnrollmentAdvertisingStarted() or
+ * <li> wait for onBleEnrollmentDeviceConnected() and check if the device connected is the right
+ *  one.
+ * <li> initiateEnrollmentHandhake()
+ * <li> wait for onAuthStringAvailable() to get the pairing code to display to the user
+ * <li> enrollmentHandshakeAccepted() after user confirms the pairing code
+ * <li> wait for onEscrowTokenAdded()
+ * <li> Authenticate user's credentials by showing the lock screen
+ * <li> activateToken()
+ * <li> wait for onEscrowTokenActiveStateChanged() to add the device as a trusted device and show
+ * in the list
+ * </ol>
+ *
+ * @hide
+ */
+@SystemApi
+public final class CarTrustAgentEnrollmentManager implements CarManagerBase {
+    private static final String TAG = "CarTrustEnrollMgr";
+    private final Context mContext;
+    private final ICarTrustAgentEnrollment mEnrollmentService;
+    private Object mListenerLock = new Object();
+    @GuardedBy("mListenerLock")
+    private CarTrustAgentEnrollmentCallback mEnrollmentCallback;
+    @GuardedBy("mListenerLock")
+    private CarTrustAgentBleCallback mBleCallback;
+    @GuardedBy("mListenerLock")
+    private final ListenerToEnrollmentService mListenerToEnrollmentService =
+            new ListenerToEnrollmentService(this);
+    private final ListenerToBleService mListenerToBleService = new ListenerToBleService(this);
+
+
+    /** @hide */
+    public CarTrustAgentEnrollmentManager(IBinder service, Context context, Handler handler) {
+        mContext = context;
+        mEnrollmentService = ICarTrustAgentEnrollment.Stub.asInterface(service);
+    }
+
+    /** @hide */
+    @Override
+    public synchronized void onCarDisconnected() {
+    }
+
+    /**
+     * Starts broadcasting enrollment UUID on BLE.
+     * Phones can scan and connect for the enrollment process to begin.
+     */
+    @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+    public void startEnrollmentAdvertising() throws CarNotConnectedException {
+        try {
+            mEnrollmentService.startEnrollmentAdvertising();
+        } catch (RemoteException e) {
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Stops Enrollment advertising.
+     */
+    @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+    public void stopEnrollmentAdvertising() throws CarNotConnectedException {
+        try {
+            mEnrollmentService.stopEnrollmentAdvertising();
+        } catch (RemoteException e) {
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Initiates the handshake with the phone for enrollment.  This should be called after the
+     * user has confirmed the phone that is requesting enrollment.
+     *
+     * @param device the remote Bluetooth device that is trying to enroll.
+     */
+    @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+    public void initiateEnrollmentHandshake(BluetoothDevice device)
+            throws CarNotConnectedException {
+        try {
+            mEnrollmentService.initiateEnrollmentHandshake(device);
+        } catch (RemoteException e) {
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Confirms that the enrollment handshake has been accepted by the user.  This should be called
+     * after the user has confirmed the verification code displayed on the UI.
+     */
+    @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+    public void enrollmentHandshakeAccepted() throws CarNotConnectedException {
+        try {
+            mEnrollmentService.enrollmentHandshakeAccepted();
+        } catch (RemoteException e) {
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Provides an option to quit enrollment if the pairing code doesn't match for example.
+     */
+    @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+    public void terminateEnrollmentHandshake() throws CarNotConnectedException {
+        try {
+            mEnrollmentService.terminateEnrollmentHandshake();
+        } catch (RemoteException e) {
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Activate the newly added escrow token.
+     *
+     * @param handle the handle corresponding to the escrow token
+     */
+    @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+    public void activateToken(long handle) throws CarNotConnectedException {
+        try {
+            mEnrollmentService.activateToken(handle);
+        } catch (RemoteException e) {
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Revoke trust for the remote device denoted by the handle.
+     *
+     * @param handle the handle associated with the escrow token
+     */
+    @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+    public void revokeTrust(long handle) throws CarNotConnectedException {
+        try {
+            mEnrollmentService.revokeTrust(handle);
+        } catch (RemoteException e) {
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Register for enrollment event callbacks.
+     *
+     * @param callback The callback methods to call, null to unregister
+     */
+    @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+    public void setEnrollmentCallback(@Nullable CarTrustAgentEnrollmentCallback callback)
+            throws CarNotConnectedException {
+        if (callback == null) {
+            unregisterEnrollmentCallback();
+        } else {
+            registerEnrollmentCallback(callback);
+        }
+    }
+
+    private void registerEnrollmentCallback(CarTrustAgentEnrollmentCallback callback)
+            throws CarNotConnectedException {
+        synchronized (mListenerLock) {
+            if (callback != null && mEnrollmentCallback == null) {
+                try {
+                    mEnrollmentService.registerEnrollmentCallback(mListenerToEnrollmentService);
+                    mEnrollmentCallback = callback;
+                } catch (RemoteException e) {
+                    throw new CarNotConnectedException(e);
+                }
+            }
+        }
+    }
+
+    private void unregisterEnrollmentCallback() throws CarNotConnectedException {
+        synchronized (mListenerLock) {
+            if (mEnrollmentCallback != null) {
+                try {
+                    mEnrollmentService.unregisterEnrollmentCallback(mListenerToEnrollmentService);
+                } catch (RemoteException e) {
+                    throw new CarNotConnectedException(e);
+                }
+                mEnrollmentCallback = null;
+            }
+        }
+    }
+
+    /**
+     * Register for general BLE callbacks
+     *
+     * @param callback The callback methods to call, null to unregister
+     */
+    @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+    public void setBleCallback(@Nullable CarTrustAgentBleCallback callback)
+            throws CarNotConnectedException {
+        if (callback == null) {
+            unregisterBleCallback();
+        } else {
+            registerBleCallback(callback);
+        }
+    }
+
+    private void registerBleCallback(CarTrustAgentBleCallback callback)
+            throws CarNotConnectedException {
+        synchronized (mListenerLock) {
+            if (callback != null && mBleCallback == null) {
+                try {
+                    mEnrollmentService.registerBleCallback(mListenerToBleService);
+                    mBleCallback = callback;
+                } catch (RemoteException e) {
+                    throw new CarNotConnectedException(e);
+                }
+            }
+        }
+    }
+
+    private void unregisterBleCallback() throws CarNotConnectedException {
+        synchronized (mListenerLock) {
+            if (mBleCallback != null) {
+                try {
+                    mEnrollmentService.unregisterBleCallback(mListenerToBleService);
+                } catch (RemoteException e) {
+                    throw new CarNotConnectedException(e);
+                }
+                mBleCallback = null;
+            }
+        }
+    }
+
+    /**
+     * Provides a list of enrollment handles for the given user id.
+     * Each enrollment handle corresponds to a trusted device for the given user.
+     *
+     * @param uid user id.
+     * @return list of the Enrollment handles for the user id.
+     */
+    @RequiresPermission(PERMISSION_CAR_ENROLL_TRUST)
+    public List<Integer> getEnrollmentHandlesForUser(int uid) throws CarNotConnectedException {
+        try {
+            return Arrays.stream(
+                    mEnrollmentService.getEnrollmentHandlesForUser(uid)).boxed().collect(
+                    Collectors.toList());
+        } catch (RemoteException e) {
+            throw new CarNotConnectedException(e);
+        }
+    }
+
+    /**
+     * Callback interface for Trusted device enrollment applications to implement.  The applications
+     * get notified on various enrollment state change events.
+     */
+    public interface CarTrustAgentEnrollmentCallback {
+        /**
+         * Communicate about failure/timeouts in the handshake process.
+         *
+         * @param device the remote device trying to enroll
+         * @param errorCode information on what failed.
+         */
+        void onEnrollmentHandshakeFailure(BluetoothDevice device, int errorCode);
+
+        /**
+         * Present the pairing/authentication string to the user.
+         *
+         * @param device the remote device trying to enroll
+         * @param authString the authentication string to show to the user to confirm across
+         *                   both devices
+         */
+        void onAuthStringAvailable(BluetoothDevice device, String authString);
+
+        /**
+         * Escrow token was received and the Trust Agent framework has generated a corresponding
+         * handle.
+         *
+         * @param handle the handle associated with the escrow token.
+         */
+        void onEscrowTokenAdded(long handle);
+
+        /**
+         * Escrow token corresponding to the given handle has been removed.
+         *
+         * @param handle  the handle associated with the escrow token.
+         * @param success status of the revoke operation.
+         */
+        void onTrustRevoked(long handle, boolean success);
+
+        /**
+         * Escrow token's active state changed.
+         *
+         * @param handle the handle associated with the escrow token
+         * @param active True if token has been activated, false if not.
+         */
+        void onEscrowTokenActiveStateChanged(long handle, boolean active);
+
+    }
+
+    /**
+     * Callback interface for Trusted device enrollment applications to implement.  The applications
+     * get notified on various BLE state change events that happen during trusted device enrollment.
+     */
+    public interface CarTrustAgentBleCallback {
+        /**
+         * Indicates a remote device connected on BLE.
+         */
+        void onBleEnrollmentDeviceConnected(BluetoothDevice device);
+
+        /**
+         * Indicates a remote device disconnected on BLE.
+         */
+        void onBleEnrollmentDeviceDisconnected(BluetoothDevice device);
+
+        /**
+         * Indicates that the device is broadcasting for trusted device enrollment on BLE.
+         */
+        void onEnrollmentAdvertisingStarted();
+
+        /**
+         * Indicates a failure in BLE broadcasting for enrollment.
+         */
+        void onEnrollmentAdvertisingFailed(int errorCode);
+    }
+
+    // TODO(ramperry) - call the client callbacks from the methods of this listener to the service
+    // callbacks.
+    private class ListenerToEnrollmentService extends ICarTrustAgentEnrollmentCallback.Stub {
+        private final WeakReference<CarTrustAgentEnrollmentManager> mMgr;
+
+        ListenerToEnrollmentService(CarTrustAgentEnrollmentManager mgr) {
+            mMgr = new WeakReference<>(mgr);
+        }
+
+        /**
+         * Communicate about failure/timeouts in the handshake process.
+         */
+        public void onEnrollmentHandshakeFailure(BluetoothDevice device, int errorCode) {
+        }
+
+        /**
+         * Present the pairing/authentication string to the user.
+         */
+        public void onAuthStringAvailable(BluetoothDevice device, byte[] authString) {
+        }
+
+        /**
+         * Escrow token was received and the Trust Agent framework has generated a corresponding
+         * handle.
+         */
+        public void onEscrowTokenAdded(long handle) {
+        }
+
+        /**
+         * Escrow token corresponding to the given handle has been removed.
+         */
+        public void onTrustRevoked(long handle, boolean success) {
+        }
+
+        /**
+         * Escrow token's active state changed.
+         */
+        public void onEscrowTokenActiveStateChanged(long handle, boolean active) {
+        }
+    }
+
+    // TODO(ramperry) - call the client callbacks from the methods of this listener to the service
+    // callbacks.
+    private class ListenerToBleService extends ICarTrustAgentBleCallback.Stub {
+        private final WeakReference<CarTrustAgentEnrollmentManager> mMgr;
+
+        ListenerToBleService(CarTrustAgentEnrollmentManager mgr) {
+            mMgr = new WeakReference<>(mgr);
+        }
+
+        /**
+         * Called when the GATT server is started and BLE is successfully advertising for
+         * enrollment.
+         */
+        public void onEnrollmentAdvertisingStarted() {
+        }
+
+        /**
+         * Called when the BLE enrollment advertisement fails to start.
+         * see AdvertiseCallback#ADVERTISE_FAILED_* for possible error codes.
+         */
+        public void onEnrollmentAdvertisingFailed(int errorCode) {
+        }
+
+        /**
+         * Called when a remote device is connected on BLE.
+         */
+        public void onBleEnrollmentDeviceConnected(BluetoothDevice device) {
+        }
+
+        /**
+         * Called when a remote device is disconnected on BLE.
+         */
+        public void onBleEnrollmentDeviceDisconnected(BluetoothDevice device) {
+        }
+    }
+}
diff --git a/car-lib/src/android/car/trust/ICarTrustAgentBleCallback.aidl b/car-lib/src/android/car/trust/ICarTrustAgentBleCallback.aidl
new file mode 100644
index 0000000..e2a972d
--- /dev/null
+++ b/car-lib/src/android/car/trust/ICarTrustAgentBleCallback.aidl
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.trust;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * Callback interface for BLE connection state changes during trusted device enrollment.
+ *
+ * @hide
+ */
+oneway interface ICarTrustAgentBleCallback {
+    /**
+     * Called when the GATT server is started and BLE is successfully advertising for enrollment.
+     */
+    void onEnrollmentAdvertisingStarted();
+
+    /**
+     * Called when the BLE enrollment advertisement fails to start.
+     * see AdvertiseCallback#ADVERTISE_FAILED_* for possible error codes.
+     */
+    void onEnrollmentAdvertisingFailed(int errorCode);
+
+    /**
+     * Called when a remote device is connected on BLE.
+     */
+    void onBleEnrollmentDeviceConnected(in BluetoothDevice device);
+
+    /**
+     * Called when a remote device is disconnected on BLE.
+     */
+    void onBleEnrollmentDeviceDisconnected(in BluetoothDevice device);
+}
diff --git a/car-lib/src/android/car/trust/ICarTrustAgentEnrollment.aidl b/car-lib/src/android/car/trust/ICarTrustAgentEnrollment.aidl
new file mode 100644
index 0000000..0476f70
--- /dev/null
+++ b/car-lib/src/android/car/trust/ICarTrustAgentEnrollment.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.trust;
+
+import android.bluetooth.BluetoothDevice;
+import android.car.trust.ICarTrustAgentBleCallback;
+import android.car.trust.ICarTrustAgentEnrollmentCallback;
+
+/**
+ * Binder interface for CarTrustAgentEnrollmentService. The service implements the functionality
+ * to communicate with the remote device securely to enroll the remote device as a trusted device.
+ *
+ * @hide
+ */
+interface ICarTrustAgentEnrollment {
+    void startEnrollmentAdvertising();
+    void stopEnrollmentAdvertising();
+    void initiateEnrollmentHandshake(in BluetoothDevice device);
+    void enrollmentHandshakeAccepted();
+    void terminateEnrollmentHandshake();
+    void activateToken(in long handle);
+    void revokeTrust(in long handle);
+    int[] getEnrollmentHandlesForUser(in int uid);
+    void registerEnrollmentCallback(in ICarTrustAgentEnrollmentCallback callback);
+    void unregisterEnrollmentCallback(in ICarTrustAgentEnrollmentCallback callback);
+    void registerBleCallback(in ICarTrustAgentBleCallback callback);
+    void unregisterBleCallback(in ICarTrustAgentBleCallback callback);
+}
diff --git a/car-lib/src/android/car/trust/ICarTrustAgentEnrollmentCallback.aidl b/car-lib/src/android/car/trust/ICarTrustAgentEnrollmentCallback.aidl
new file mode 100644
index 0000000..9457fec
--- /dev/null
+++ b/car-lib/src/android/car/trust/ICarTrustAgentEnrollmentCallback.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.car.trust;
+
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * Callback interface for state changes during Trusted device enrollment.
+ *
+ * @hide
+ */
+oneway interface ICarTrustAgentEnrollmentCallback {
+    /**
+     * Communicate about failure/timeouts in the handshake process.
+     */
+    void onEnrollmentHandshakeFailure(in BluetoothDevice device, in int errorCode);
+
+    /**
+     * Present the pairing/authentication string to the user.
+     */
+    void onAuthStringAvailable(in BluetoothDevice device, in byte[] authString);
+
+    /**
+     * Escrow token was received and the Trust Agent framework has generated a corresponding handle.
+     */
+    void onEscrowTokenAdded(in long handle);
+
+    /*
+     * Escrow token corresponding to the given handle has been removed.
+     */
+    void onTrustRevoked(in long handle, in boolean success);
+
+    /**
+     * Escrow token's active state changed.
+     */
+    void onEscrowTokenActiveStateChanged(in long handle, in boolean active);
+
+}
diff --git a/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java b/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java
new file mode 100644
index 0000000..e6aeeac
--- /dev/null
+++ b/service/src/com/android/car/trust/CarTrustAgentEnrollmentService.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.trust;
+
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothDevice;
+import android.car.trust.ICarTrustAgentBleCallback;
+import android.car.trust.ICarTrustAgentEnrollment;
+import android.car.trust.ICarTrustAgentEnrollmentCallback;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.car.CarServiceBase;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A service that enables enrolling a phone as a trusted device for authenticating a user on the
+ * IHU.  This implements the APIs that an enrollment app can call to conduct an enrollment.
+ */
+public class CarTrustAgentEnrollmentService extends ICarTrustAgentEnrollment.Stub implements
+        CarServiceBase {
+    private static final String TAG = "CarTrustAgentEnroll";
+    private final Context mContext;
+    // List of clients listening to Enrollment state change events.
+    private final List<EnrollmentStateClient> mEnrollmentStateClients = new ArrayList<>();
+    // List of clients listening to BLE state change events.
+    private final List<BleStateChangeClient> mBleStateChangeClients = new ArrayList<>();
+
+    public CarTrustAgentEnrollmentService(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public synchronized void init() {
+    }
+
+    @Override
+    public synchronized void release() {
+        for (EnrollmentStateClient client : mEnrollmentStateClients) {
+            client.mListenerBinder.unlinkToDeath(client, 0);
+        }
+        mEnrollmentStateClients.clear();
+    }
+
+
+    // Binder methods
+    // TODO(b/120911995) The methods don't do anything yet.  The implementation will be checked in
+    // a follow up CL.
+    @Override
+    public void startEnrollmentAdvertising() {
+    }
+
+    @Override
+    public void stopEnrollmentAdvertising() {
+    }
+
+    @Override
+    public void initiateEnrollmentHandshake(BluetoothDevice device) {
+    }
+
+    @Override
+    public void enrollmentHandshakeAccepted() {
+    }
+
+    @Override
+    public void terminateEnrollmentHandshake() {
+    }
+
+    @Override
+    public void activateToken(long handle) {
+    }
+
+    @Override
+    public void revokeTrust(long handle) {
+    }
+
+    @Override
+    public int[] getEnrollmentHandlesForUser(int uid) {
+        int[] handles = {};
+        return handles;
+    }
+
+    /**
+     * Registers a {@link ICarTrustAgentEnrollmentCallback} to be notified for changes to the
+     * enrollment state.
+     *
+     * @param listener {@link ICarTrustAgentEnrollmentCallback}
+     */
+    @Override
+    public synchronized void registerEnrollmentCallback(ICarTrustAgentEnrollmentCallback listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("Listener is null");
+        }
+        // If a new client is registering, create a new EnrollmentStateClient and add it to the list
+        // of listening clients.
+        EnrollmentStateClient client = findEnrollmentStateClientLocked(listener);
+        if (client == null) {
+            client = new EnrollmentStateClient(listener);
+            try {
+                listener.asBinder().linkToDeath(client, 0);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Cannot link death recipient to binder ", e);
+                return;
+            }
+            mEnrollmentStateClients.add(client);
+        }
+    }
+
+    /**
+     * Iterates through the list of registered Enrollment State Change clients -
+     * {@link EnrollmentStateClient} and finds if the given client is already registered.
+     *
+     * @param listener Listener to look for.
+     * @return the {@link EnrollmentStateClient} if found, null if not
+     */
+    @Nullable
+    private EnrollmentStateClient findEnrollmentStateClientLocked(
+            ICarTrustAgentEnrollmentCallback listener) {
+        IBinder binder = listener.asBinder();
+        // Find the listener by comparing the binder object they host.
+        for (EnrollmentStateClient client : mEnrollmentStateClients) {
+            if (client.isHoldingBinder(binder)) {
+                return client;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Unregister the given Enrollment State Change listener
+     *
+     * @param listener client to unregister
+     */
+    @Override
+    public synchronized void unregisterEnrollmentCallback(
+            ICarTrustAgentEnrollmentCallback listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("Listener is null");
+        }
+
+        EnrollmentStateClient client = findEnrollmentStateClientLocked(listener);
+        if (client == null) {
+            Log.e(TAG, "unregisterEnrollmentCallback(): listener was not previously "
+                    + "registered");
+            return;
+        }
+        listener.asBinder().unlinkToDeath(client, 0);
+        mEnrollmentStateClients.remove(client);
+    }
+
+    /**
+     * Registers a {@link ICarTrustAgentBleCallback} to be notified for changes to the BLE state
+     * changes.
+     *
+     * @param listener {@link ICarTrustAgentBleCallback}
+     */
+    @Override
+    public synchronized void registerBleCallback(ICarTrustAgentBleCallback listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("Listener is null");
+        }
+        // If a new client is registering, create a new EnrollmentStateClient and add it to the list
+        // of listening clients.
+        BleStateChangeClient client = findBleStateClientLocked(listener);
+        if (client == null) {
+            client = new BleStateChangeClient(listener);
+            try {
+                listener.asBinder().linkToDeath(client, 0);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Cannot link death recipient to binder " + e);
+                return;
+            }
+            mBleStateChangeClients.add(client);
+        }
+    }
+
+    /**
+     * Iterates through the list of registered BLE State Change clients -
+     * {@link BleStateChangeClient} and finds if the given client is already registered.
+     *
+     * @param listener Listener to look for.
+     * @return the {@link BleStateChangeClient} if found, null if not
+     */
+    @Nullable
+    private BleStateChangeClient findBleStateClientLocked(
+            ICarTrustAgentBleCallback listener) {
+        IBinder binder = listener.asBinder();
+        // Find the listener by comparing the binder object they host.
+        for (BleStateChangeClient client : mBleStateChangeClients) {
+            if (client.isHoldingBinder(binder)) {
+                return client;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Unregister the given BLE State Change listener
+     *
+     * @param listener client to unregister
+     */
+    @Override
+    public synchronized void unregisterBleCallback(ICarTrustAgentBleCallback listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("Listener is null");
+        }
+
+        BleStateChangeClient client = findBleStateClientLocked(listener);
+        if (client == null) {
+            Log.e(TAG, "unregisterBleCallback(): listener was not previously "
+                    + "registered");
+            return;
+        }
+        listener.asBinder().unlinkToDeath(client, 0);
+        mBleStateChangeClients.remove(client);
+    }
+
+    /**
+     * Class that holds onto client related information - listener interface, process that hosts the
+     * binder object etc.
+     * <p>
+     * It also registers for death notifications of the host.
+     */
+    private class EnrollmentStateClient implements IBinder.DeathRecipient {
+        private final IBinder mListenerBinder;
+        private final ICarTrustAgentEnrollmentCallback mListener;
+
+        EnrollmentStateClient(ICarTrustAgentEnrollmentCallback listener) {
+            mListener = listener;
+            mListenerBinder = listener.asBinder();
+        }
+
+        @Override
+        public void binderDied() {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Binder died " + mListenerBinder);
+            }
+            mListenerBinder.unlinkToDeath(this, 0);
+            synchronized (CarTrustAgentEnrollmentService.this) {
+                mEnrollmentStateClients.remove(this);
+            }
+        }
+
+        /**
+         * Returns if the given binder object matches to what this client info holds.
+         * Used to check if the listener asking to be registered is already registered.
+         *
+         * @return true if matches, false if not
+         */
+        public boolean isHoldingBinder(IBinder binder) {
+            return mListenerBinder == binder;
+        }
+    }
+
+    private class BleStateChangeClient implements IBinder.DeathRecipient {
+        private final IBinder mListenerBinder;
+        private final ICarTrustAgentBleCallback mListener;
+
+        BleStateChangeClient(ICarTrustAgentBleCallback listener) {
+            mListener = listener;
+            mListenerBinder = listener.asBinder();
+        }
+
+        @Override
+        public void binderDied() {
+            if (Log.isLoggable(TAG, Log.DEBUG)) {
+                Log.d(TAG, "Binder died " + mListenerBinder);
+            }
+            mListenerBinder.unlinkToDeath(this, 0);
+            synchronized (CarTrustAgentEnrollmentService.this) {
+                mBleStateChangeClients.remove(this);
+            }
+        }
+
+        /**
+         * Returns if the given binder object matches to what this client info holds.
+         * Used to check if the listener asking to be registered is already registered.
+         *
+         * @return true if matches, false if not
+         */
+        public boolean isHoldingBinder(IBinder binder) {
+            return mListenerBinder == binder;
+        }
+
+    }
+
+    @Override
+    public void dump(PrintWriter writer) {
+    }
+}