[automerger skipped] Split vehicle client and server interface header am: 2f2b3bbef6 am: af57a4d60c am: ea6cdb8e21 am: b82291f6c2 -s ours
am skip reason: Change-Id I550034b071ca6a7ca322fb26b61d76ed4a7307ee with SHA-1 2f2b3bbef6 is in history

Change-Id: I1ed11150c74cd34f25f79dfe62b9e0fce90ff5fb
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 8e57901..e529675 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -63,6 +63,8 @@
         "impl/vhal_v2_0/CommConn.cpp",
         "impl/vhal_v2_0/EmulatedVehicleConnector.cpp",
         "impl/vhal_v2_0/EmulatedVehicleHal.cpp",
+        "impl/vhal_v2_0/VehicleHalClient.cpp",
+        "impl/vhal_v2_0/VehicleHalServer.cpp",
         "impl/vhal_v2_0/VehicleEmulator.cpp",
         "impl/vhal_v2_0/PipeComm.cpp",
         "impl/vhal_v2_0/ProtoMessageConverter.cpp",
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h
index 1e2f3ad..5e4bf27 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleClient.h
@@ -20,11 +20,7 @@
 
 #include <android/hardware/automotive/vehicle/2.0/types.h>
 
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace vehicle {
-namespace V2_0 {
+namespace android::hardware::automotive::vehicle::V2_0 {
 
 /**
  *  Vehicle HAL talks to the vehicle through a client, instead of accessing
@@ -66,8 +62,4 @@
     }
 };
 
-}  // namespace V2_0
-}  // namespace vehicle
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::automotive::vehicle::V2_0
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h
index 27ebbee..ba9799a 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleServer.h
@@ -20,11 +20,7 @@
 
 #include <android/hardware/automotive/vehicle/2.0/types.h>
 
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace vehicle {
-namespace V2_0 {
+namespace android::hardware::automotive::vehicle::V2_0 {
 
 /**
  *  Server lives on the vehicle side to talk to Android HAL.
@@ -69,8 +65,4 @@
 #endif  // __ANDROID__
 };
 
-}  // namespace V2_0
-}  // namespace vehicle
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
+}  // namespace android::hardware::automotive::vehicle::V2_0
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
index 7f90914..9c3c95f 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.cpp
@@ -35,346 +35,16 @@
 
 namespace impl {
 
-void EmulatedVehicleClient::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
-    if (!mPropCallback) {
-        LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!";
-        return;
-    }
-    return mPropCallback(value, updateStatus);
-}
+class EmulatedPassthroughConnector : public PassthroughConnector {
+  public:
+    bool onDump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
 
-void EmulatedVehicleClient::registerPropertyValueCallback(PropertyCallBackType&& callback) {
-    if (mPropCallback) {
-        LOG(ERROR) << __func__ << ": Cannot register multiple callbacks!";
-        return;
-    }
-    mPropCallback = std::move(callback);
-}
+  private:
+    void dumpUserHal(int fd, std::string indent);
+};
 
-GeneratorHub* EmulatedVehicleServer::getGenerator() {
-    return &mGeneratorHub;
-}
-
-VehiclePropValuePool* EmulatedVehicleServer::getValuePool() const {
-    if (!mValuePool) {
-        LOG(WARNING) << __func__ << ": Value pool not set!";
-    }
-    return mValuePool;
-}
-
-void EmulatedVehicleServer::setValuePool(VehiclePropValuePool* valuePool) {
-    if (!valuePool) {
-        LOG(WARNING) <<  __func__ << ": Setting value pool to nullptr!";
-    }
-    mValuePool = valuePool;
-}
-
-void EmulatedVehicleServer::onFakeValueGenerated(const VehiclePropValue& value) {
-    constexpr bool updateStatus = true;
-    LOG(DEBUG) << __func__ << ": " << toString(value);
-    auto updatedPropValue = getValuePool()->obtain(value);
-    if (updatedPropValue) {
-        updatedPropValue->timestamp = value.timestamp;
-        updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
-        onPropertyValueFromCar(*updatedPropValue, updateStatus);
-    }
-}
-
-std::vector<VehiclePropConfig> EmulatedVehicleServer::onGetAllPropertyConfig() const {
-    std::vector<VehiclePropConfig> vehiclePropConfigs;
-    constexpr size_t numOfVehiclePropConfigs =
-            sizeof(kVehicleProperties) / sizeof(kVehicleProperties[0]);
-    vehiclePropConfigs.reserve(numOfVehiclePropConfigs);
-    for (auto& it : kVehicleProperties) {
-        vehiclePropConfigs.emplace_back(it.config);
-    }
-    return vehiclePropConfigs;
-}
-
-StatusCode EmulatedVehicleServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
-    constexpr bool updateStatus = true;
-
-    LOG(INFO) << __func__;
-    const auto& v = request.value;
-    if (!v.int32Values.size()) {
-        LOG(ERROR) << __func__ << ": expected at least \"command\" field in int32Values";
-        return StatusCode::INVALID_ARG;
-    }
-
-    FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);
-
-    switch (command) {
-        case FakeDataCommand::StartLinear: {
-            LOG(INFO) << __func__ << ", FakeDataCommand::StartLinear";
-            if (v.int32Values.size() < 2) {
-                LOG(ERROR) << __func__ << ": expected property ID in int32Values";
-                return StatusCode::INVALID_ARG;
-            }
-            if (!v.int64Values.size()) {
-                LOG(ERROR) << __func__ << ": interval is not provided in int64Values";
-                return StatusCode::INVALID_ARG;
-            }
-            if (v.floatValues.size() < 3) {
-                LOG(ERROR) << __func__ << ": expected at least 3 elements in floatValues, got: "
-                      << v.floatValues.size();
-                return StatusCode::INVALID_ARG;
-            }
-            int32_t cookie = v.int32Values[1];
-            getGenerator()->registerGenerator(cookie,
-                                              std::make_unique<LinearFakeValueGenerator>(request));
-            break;
-        }
-        case FakeDataCommand::StartJson: {
-            LOG(INFO) << __func__ << ", FakeDataCommand::StartJson";
-            if (v.stringValue.empty()) {
-                LOG(ERROR) << __func__ << ": path to JSON file is missing";
-                return StatusCode::INVALID_ARG;
-            }
-            int32_t cookie = std::hash<std::string>()(v.stringValue);
-            getGenerator()->registerGenerator(cookie,
-                                              std::make_unique<JsonFakeValueGenerator>(request));
-            break;
-        }
-        case FakeDataCommand::StopLinear: {
-            LOG(INFO) << __func__ << ", FakeDataCommand::StopLinear";
-            if (v.int32Values.size() < 2) {
-                LOG(ERROR) << __func__ << ": expected property ID in int32Values";
-                return StatusCode::INVALID_ARG;
-            }
-            int32_t cookie = v.int32Values[1];
-            getGenerator()->unregisterGenerator(cookie);
-            break;
-        }
-        case FakeDataCommand::StopJson: {
-            LOG(INFO) << __func__ << ", FakeDataCommand::StopJson";
-            if (v.stringValue.empty()) {
-                LOG(ERROR) << __func__ << ": path to JSON file is missing";
-                return StatusCode::INVALID_ARG;
-            }
-            int32_t cookie = std::hash<std::string>()(v.stringValue);
-            getGenerator()->unregisterGenerator(cookie);
-            break;
-        }
-        case FakeDataCommand::KeyPress: {
-            LOG(INFO) << __func__ << ", FakeDataCommand::KeyPress";
-            int32_t keyCode = request.value.int32Values[2];
-            int32_t display = request.value.int32Values[3];
-            // Send back to HAL
-            onPropertyValueFromCar(
-                    *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display),
-                    updateStatus);
-            onPropertyValueFromCar(
-                    *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display),
-                    updateStatus);
-            break;
-        }
-        default: {
-            LOG(ERROR) << __func__ << ": unexpected command: " << toInt(command);
-            return StatusCode::INVALID_ARG;
-        }
-    }
-    return StatusCode::OK;
-}
-
-VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::createApPowerStateReq(
-    VehicleApPowerStateReq state, int32_t param) {
-    auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2);
-    req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
-    req->areaId = 0;
-    req->timestamp = elapsedRealtimeNano();
-    req->status = VehiclePropertyStatus::AVAILABLE;
-    req->value.int32Values[0] = toInt(state);
-    req->value.int32Values[1] = param;
-    return req;
-}
-
-VehicleHal::VehiclePropValuePtr EmulatedVehicleServer::createHwInputKeyProp(
-        VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
-    auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
-    keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT);
-    keyEvent->areaId = 0;
-    keyEvent->timestamp = elapsedRealtimeNano();
-    keyEvent->status = VehiclePropertyStatus::AVAILABLE;
-    keyEvent->value.int32Values[0] = toInt(action);
-    keyEvent->value.int32Values[1] = keyCode;
-    keyEvent->value.int32Values[2] = targetDisplay;
-    return keyEvent;
-}
-
-StatusCode EmulatedVehicleServer::onSetProperty(const VehiclePropValue& value, bool updateStatus) {
-    // Some properties need to be treated non-trivially
-    switch (value.prop) {
-        case kGenerateFakeDataControllingProperty:
-            return handleGenerateFakeDataRequest(value);
-
-        // set the value from vehicle side, used in end to end test.
-        case kSetIntPropertyFromVehicleForTest: {
-            auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
-            updatedPropValue->prop = value.value.int32Values[0];
-            updatedPropValue->value.int32Values[0] = value.value.int32Values[1];
-            updatedPropValue->timestamp = value.value.int64Values[0];
-            updatedPropValue->areaId = value.areaId;
-            onPropertyValueFromCar(*updatedPropValue, updateStatus);
-            return StatusCode::OK;
-        }
-        case kSetFloatPropertyFromVehicleForTest: {
-            auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
-            updatedPropValue->prop = value.value.int32Values[0];
-            updatedPropValue->value.floatValues[0] = value.value.floatValues[0];
-            updatedPropValue->timestamp = value.value.int64Values[0];
-            updatedPropValue->areaId = value.areaId;
-            onPropertyValueFromCar(*updatedPropValue, updateStatus);
-            return StatusCode::OK;
-        }
-        case kSetBooleanPropertyFromVehicleForTest: {
-            auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
-            updatedPropValue->prop = value.value.int32Values[1];
-            updatedPropValue->value.int32Values[0] = value.value.int32Values[0];
-            updatedPropValue->timestamp = value.value.int64Values[0];
-            updatedPropValue->areaId = value.areaId;
-            onPropertyValueFromCar(*updatedPropValue, updateStatus);
-            return StatusCode::OK;
-        }
-
-        case AP_POWER_STATE_REPORT:
-            switch (value.value.int32Values[0]) {
-                case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
-                case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
-                case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
-                    // CPMS is in WAIT_FOR_VHAL state, simply move to ON
-                    // Send back to HAL
-                    // ALWAYS update status for generated property value
-                    onPropertyValueFromCar(*createApPowerStateReq(VehicleApPowerStateReq::ON, 0),
-                                           true /* updateStatus */);
-                    break;
-                case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
-                case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
-                    // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
-                    // Send back to HAL
-                    // ALWAYS update status for generated property value
-                    onPropertyValueFromCar(
-                            *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0),
-                            true /* updateStatus */);
-                    break;
-                case toInt(VehicleApPowerStateReport::ON):
-                case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
-                case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
-                    // Do nothing
-                    break;
-                default:
-                    // Unknown state
-                    break;
-            }
-            break;
-        case INITIAL_USER_INFO:
-            return onSetInitialUserInfo(value, updateStatus);
-        default:
-            break;
-    }
-
-    // In the real vhal, the value will be sent to Car ECU.
-    // We just pretend it is done here and send back to HAL
-    auto updatedPropValue = getValuePool()->obtain(value);
-    updatedPropValue->timestamp = elapsedRealtimeNano();
-
-    onPropertyValueFromCar(*updatedPropValue, updateStatus);
-    return StatusCode::OK;
-}
-
-/**
- * INITIAL_USER_INFO is called by Android when it starts, and it's expecting a property change
- * indicating what the initial user should be.
- *
- * During normal circumstances, the emulator will reply right away, passing a response if
- * InitialUserInfoResponseAction::DEFAULT (so Android could use its own logic to decide which user
- * to boot).
- *
- * But during development / testing, the behavior can be changed using lshal dump, which must use
- * the areaId to indicate what should happen next.
- *
- * So, the behavior of set(INITIAL_USER_INFO) is:
- *
- * - if it has an areaId, store the property into mInitialUserResponseFromCmd (as it was called by
- *   lshal).
- * - else if mInitialUserResponseFromCmd is not set, return a response with the same request id and
- *   InitialUserInfoResponseAction::DEFAULT
- * - else the behavior is defined by the areaId on mInitialUserResponseFromCmd:
- * - if it's 1, reply with mInitialUserResponseFromCmd and the right request id
- * - if it's 2, reply with mInitialUserResponseFromCmd but a wrong request id (so Android can test
- *   this error scenario)
- * - if it's 3, then don't send a property change (so Android can emulate a timeout)
- *
- */
-StatusCode EmulatedVehicleServer::onSetInitialUserInfo(const VehiclePropValue& value,
-                                                       bool updateStatus) {
-    // TODO: LOG calls below might be more suited to be DEBUG, but those are not being logged
-    // (even when explicitly calling setprop log.tag. As this class should be using ALOG instead of
-    // LOG, it's not worth investigating why...
-
-    if (value.value.int32Values.size() == 0) {
-        LOG(ERROR) << "set(INITIAL_USER_INFO): no int32values, ignoring it: " << toString(value);
-        return StatusCode::INVALID_ARG;
-    }
-
-    if (value.areaId != 0) {
-        LOG(INFO) << "set(INITIAL_USER_INFO) called from lshal; storing it: " << toString(value);
-        mInitialUserResponseFromCmd.reset(new VehiclePropValue(value));
-        return StatusCode::OK;
-    }
-    LOG(INFO) << "set(INITIAL_USER_INFO) called from Android: " << toString(value);
-
-    int32_t requestId = value.value.int32Values[0];
-
-    // Create the update property and set common values
-    auto updatedValue = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
-    updatedValue->prop = INITIAL_USER_INFO;
-    updatedValue->timestamp = elapsedRealtimeNano();
-
-    if (mInitialUserResponseFromCmd == nullptr) {
-        updatedValue->value.int32Values.resize(2);
-        updatedValue->value.int32Values[0] = requestId;
-        updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT;
-        LOG(INFO) << "no lshal response; returning InitialUserInfoResponseAction::DEFAULT: "
-                  << toString(*updatedValue);
-        onPropertyValueFromCar(*updatedValue, updateStatus);
-        return StatusCode::OK;
-    }
-
-    // mInitialUserResponseFromCmd is used for just one request
-    std::unique_ptr<VehiclePropValue> response = std::move(mInitialUserResponseFromCmd);
-
-    // TODO(b/138709788): rather than populate the raw values directly, it should use the
-    // libraries that convert a InitialUserInfoResponse into a VehiclePropValue)
-
-    switch (response->areaId) {
-        case 1:
-            LOG(INFO) << "returning response with right request id";
-            *updatedValue = *response;
-            updatedValue->areaId = 0;
-            updatedValue->value.int32Values[0] = requestId;
-            break;
-        case 2:
-            LOG(INFO) << "returning response with wrong request id";
-            *updatedValue = *response;
-            updatedValue->areaId = 0;
-            updatedValue->value.int32Values[0] = -requestId;
-            break;
-        case 3:
-            LOG(INFO) << "not generating a property change event because of lshal prop: "
-                      << toString(*response);
-            return StatusCode::OK;
-        default:
-            LOG(ERROR) << "invalid action on lshal response: " << toString(*response);
-            return StatusCode::INTERNAL_ERROR;
-    }
-
-    LOG(INFO) << "updating property to: " << toString(*updatedValue);
-    onPropertyValueFromCar(*updatedValue, updateStatus);
-    return StatusCode::OK;
-}
-
-bool EmulatedVehicleServer::onDump(const hidl_handle& handle,
-                                   const hidl_vec<hidl_string>& options) {
+bool EmulatedPassthroughConnector::onDump(const hidl_handle& handle,
+                                          const hidl_vec<hidl_string>& options) {
     int fd = handle->data[0];
 
     if (options.size() > 0) {
@@ -401,7 +71,7 @@
     return true;
 }
 
-void EmulatedVehicleServer::dumpUserHal(int fd, std::string indent) {
+void EmulatedPassthroughConnector::dumpUserHal(int fd, std::string indent) {
     if (mInitialUserResponseFromCmd != nullptr) {
         dprintf(fd, "%sInitial User Info: %s\n", indent.c_str(),
                 toString(*mInitialUserResponseFromCmd).c_str());
@@ -410,7 +80,7 @@
     }
 }
 
-EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector() {
+PassthroughConnectorPtr makeEmulatedPassthroughConnector() {
     return std::make_unique<EmulatedPassthroughConnector>();
 }
 
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
index 4850d32..57cbb8b 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleConnector.h
@@ -18,9 +18,9 @@
 #define android_hardware_automotive_vehicle_V2_0_impl_EmulatedVehicleConnector_H_
 
 #include <vhal_v2_0/VehicleConnector.h>
-#include <vhal_v2_0/VehicleHal.h>
 
-#include "GeneratorHub.h"
+#include "VehicleHalClient.h"
+#include "VehicleHalServer.h"
 
 namespace android {
 namespace hardware {
@@ -30,69 +30,10 @@
 
 namespace impl {
 
-// Extension of the client/server interfaces for emulated vehicle
+using PassthroughConnector = IPassThroughConnector<VehicleHalClient, VehicleHalServer>;
+using PassthroughConnectorPtr = std::unique_ptr<PassthroughConnector>;
 
-class EmulatedVehicleClient : public IVehicleClient {
-  public:
-    // Type of callback function for handling the new property values
-    using PropertyCallBackType = std::function<void(const VehiclePropValue&, bool updateStatus)>;
-
-    // Method from IVehicleClient
-    void onPropertyValue(const VehiclePropValue& value, bool updateStatus) override;
-
-    void registerPropertyValueCallback(PropertyCallBackType&& callback);
-
-  private:
-    PropertyCallBackType mPropCallback;
-};
-
-class EmulatedVehicleServer : public IVehicleServer {
-  public:
-    // Methods from IVehicleServer
-
-    std::vector<VehiclePropConfig> onGetAllPropertyConfig() const override;
-
-    StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override;
-
-    bool onDump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
-
-    // Set the Property Value Pool used in this server
-    void setValuePool(VehiclePropValuePool* valuePool);
-
-  private:
-    GeneratorHub* getGenerator();
-
-    VehiclePropValuePool* getValuePool() const;
-
-    void onFakeValueGenerated(const VehiclePropValue& value);
-
-    StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
-
-    VehicleHal::VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param);
-
-    VehicleHal::VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action,
-                                                         int32_t keyCode, int32_t targetDisplay);
-
-    // private data members
-
-    GeneratorHub mGeneratorHub{
-            std::bind(&EmulatedVehicleServer::onFakeValueGenerated, this, std::placeholders::_1)};
-
-    VehiclePropValuePool* mValuePool{nullptr};
-
-    // TODO(b/146207078): it might be clearer to move members below to an EmulatedUserHal class
-    std::unique_ptr<VehiclePropValue> mInitialUserResponseFromCmd;
-    StatusCode onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus);
-    void dumpUserHal(int fd, std::string indent);
-};
-
-// Helper functions
-
-using EmulatedPassthroughConnector =
-        IPassThroughConnector<EmulatedVehicleClient, EmulatedVehicleServer>;
-using EmulatedPassthroughConnectorPtr = std::unique_ptr<EmulatedPassthroughConnector>;
-
-EmulatedPassthroughConnectorPtr makeEmulatedPassthroughConnector();
+PassthroughConnectorPtr makeEmulatedPassthroughConnector();
 
 }  // namespace impl
 
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index 692c7f7..6d5f23f 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -87,12 +87,11 @@
     return sensorStore;
 }
 
-EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore,
-                                       EmulatedVehicleClient* client)
+EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client)
     : mPropStore(propStore),
       mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
-      mRecurrentTimer(
-          std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)),
+      mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this,
+                                std::placeholders::_1)),
       mVehicleClient(client) {
     initStaticConfig();
     for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index ebc405e..ebf1995 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -46,7 +46,7 @@
 class EmulatedVehicleHal : public EmulatedVehicleHalIface {
 public:
     EmulatedVehicleHal(VehiclePropertyStore* propStore,
-                       EmulatedVehicleClient* client);
+                       VehicleHalClient* client);
     ~EmulatedVehicleHal() = default;
 
     //  Methods from VehicleHal
@@ -85,7 +85,7 @@
     VehiclePropertyStore* mPropStore;
     std::unordered_set<int32_t> mHvacPowerProps;
     RecurrentTimer mRecurrentTimer;
-    EmulatedVehicleClient* mVehicleClient;
+    VehicleHalClient* mVehicleClient;
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp
new file mode 100644
index 0000000..25ffc6d
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "VehicleHalClient.h"
+
+#include <android-base/logging.h>
+
+namespace android::hardware::automotive::vehicle::V2_0::impl {
+
+void VehicleHalClient::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
+    if (!mPropCallback) {
+        LOG(ERROR) << __func__ << ": PropertyCallBackType is not registered!";
+        return;
+    }
+    return mPropCallback(value, updateStatus);
+}
+
+void VehicleHalClient::registerPropertyValueCallback(PropertyCallBackType&& callback) {
+    if (mPropCallback) {
+        LOG(ERROR) << __func__ << ": Cannot register multiple callbacks!";
+        return;
+    }
+    mPropCallback = std::move(callback);
+}
+
+}  // namespace android::hardware::automotive::vehicle::V2_0::impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.h
new file mode 100644
index 0000000..6559e2a
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalClient.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <vhal_v2_0/VehicleClient.h>
+
+namespace android::hardware::automotive::vehicle::V2_0::impl {
+
+// The common client operations that may be used by both native and
+// virtualized VHAL clients.
+class VehicleHalClient : public IVehicleClient {
+  public:
+    // Type of callback function for handling the new property values
+    using PropertyCallBackType = std::function<void(const VehiclePropValue&, bool updateStatus)>;
+
+    // Method from IVehicleClient
+    void onPropertyValue(const VehiclePropValue& value, bool updateStatus) override;
+
+    void registerPropertyValueCallback(PropertyCallBackType&& callback);
+
+  private:
+    PropertyCallBackType mPropCallback;
+};
+
+}  // namespace android::hardware::automotive::vehicle::V2_0::impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp
new file mode 100644
index 0000000..a91ca8e
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.cpp
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "VehicleHalServer.h"
+
+#include <fstream>
+
+#include <android-base/logging.h>
+#include <utils/SystemClock.h>
+
+#include "DefaultConfig.h"
+#include "JsonFakeValueGenerator.h"
+#include "LinearFakeValueGenerator.h"
+#include "Obd2SensorStore.h"
+
+namespace android::hardware::automotive::vehicle::V2_0::impl {
+
+GeneratorHub* VehicleHalServer::getGenerator() {
+    return &mGeneratorHub;
+}
+
+VehiclePropValuePool* VehicleHalServer::getValuePool() const {
+    if (!mValuePool) {
+        LOG(WARNING) << __func__ << ": Value pool not set!";
+    }
+    return mValuePool;
+}
+
+void VehicleHalServer::setValuePool(VehiclePropValuePool* valuePool) {
+    if (!valuePool) {
+        LOG(WARNING) << __func__ << ": Setting value pool to nullptr!";
+    }
+    mValuePool = valuePool;
+}
+
+void VehicleHalServer::onFakeValueGenerated(const VehiclePropValue& value) {
+    constexpr bool updateStatus = true;
+    LOG(DEBUG) << __func__ << ": " << toString(value);
+    auto updatedPropValue = getValuePool()->obtain(value);
+    if (updatedPropValue) {
+        updatedPropValue->timestamp = value.timestamp;
+        updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
+        onPropertyValueFromCar(*updatedPropValue, updateStatus);
+    }
+}
+
+std::vector<VehiclePropConfig> VehicleHalServer::onGetAllPropertyConfig() const {
+    std::vector<VehiclePropConfig> vehiclePropConfigs;
+    constexpr size_t numOfVehiclePropConfigs =
+            sizeof(kVehicleProperties) / sizeof(kVehicleProperties[0]);
+    vehiclePropConfigs.reserve(numOfVehiclePropConfigs);
+    for (auto& it : kVehicleProperties) {
+        vehiclePropConfigs.emplace_back(it.config);
+    }
+    return vehiclePropConfigs;
+}
+
+StatusCode VehicleHalServer::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
+    constexpr bool updateStatus = true;
+
+    LOG(INFO) << __func__;
+    const auto& v = request.value;
+    if (!v.int32Values.size()) {
+        LOG(ERROR) << __func__ << ": expected at least \"command\" field in int32Values";
+        return StatusCode::INVALID_ARG;
+    }
+
+    FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);
+
+    switch (command) {
+        case FakeDataCommand::StartLinear: {
+            LOG(INFO) << __func__ << ", FakeDataCommand::StartLinear";
+            if (v.int32Values.size() < 2) {
+                LOG(ERROR) << __func__ << ": expected property ID in int32Values";
+                return StatusCode::INVALID_ARG;
+            }
+            if (!v.int64Values.size()) {
+                LOG(ERROR) << __func__ << ": interval is not provided in int64Values";
+                return StatusCode::INVALID_ARG;
+            }
+            if (v.floatValues.size() < 3) {
+                LOG(ERROR) << __func__ << ": expected at least 3 elements in floatValues, got: "
+                           << v.floatValues.size();
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = v.int32Values[1];
+            getGenerator()->registerGenerator(cookie,
+                                              std::make_unique<LinearFakeValueGenerator>(request));
+            break;
+        }
+        case FakeDataCommand::StartJson: {
+            LOG(INFO) << __func__ << ", FakeDataCommand::StartJson";
+            if (v.stringValue.empty()) {
+                LOG(ERROR) << __func__ << ": path to JSON file is missing";
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = std::hash<std::string>()(v.stringValue);
+            getGenerator()->registerGenerator(cookie,
+                                              std::make_unique<JsonFakeValueGenerator>(request));
+            break;
+        }
+        case FakeDataCommand::StopLinear: {
+            LOG(INFO) << __func__ << ", FakeDataCommand::StopLinear";
+            if (v.int32Values.size() < 2) {
+                LOG(ERROR) << __func__ << ": expected property ID in int32Values";
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = v.int32Values[1];
+            getGenerator()->unregisterGenerator(cookie);
+            break;
+        }
+        case FakeDataCommand::StopJson: {
+            LOG(INFO) << __func__ << ", FakeDataCommand::StopJson";
+            if (v.stringValue.empty()) {
+                LOG(ERROR) << __func__ << ": path to JSON file is missing";
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = std::hash<std::string>()(v.stringValue);
+            getGenerator()->unregisterGenerator(cookie);
+            break;
+        }
+        case FakeDataCommand::KeyPress: {
+            LOG(INFO) << __func__ << ", FakeDataCommand::KeyPress";
+            int32_t keyCode = request.value.int32Values[2];
+            int32_t display = request.value.int32Values[3];
+            // Send back to HAL
+            onPropertyValueFromCar(
+                    *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display),
+                    updateStatus);
+            onPropertyValueFromCar(
+                    *createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display),
+                    updateStatus);
+            break;
+        }
+        default: {
+            LOG(ERROR) << __func__ << ": unexpected command: " << toInt(command);
+            return StatusCode::INVALID_ARG;
+        }
+    }
+    return StatusCode::OK;
+}
+
+VehicleHalServer::VehiclePropValuePtr VehicleHalServer::createApPowerStateReq(
+        VehicleApPowerStateReq state, int32_t param) {
+    auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2);
+    req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
+    req->areaId = 0;
+    req->timestamp = elapsedRealtimeNano();
+    req->status = VehiclePropertyStatus::AVAILABLE;
+    req->value.int32Values[0] = toInt(state);
+    req->value.int32Values[1] = param;
+    return req;
+}
+
+VehicleHalServer::VehiclePropValuePtr VehicleHalServer::createHwInputKeyProp(
+        VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
+    auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
+    keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT);
+    keyEvent->areaId = 0;
+    keyEvent->timestamp = elapsedRealtimeNano();
+    keyEvent->status = VehiclePropertyStatus::AVAILABLE;
+    keyEvent->value.int32Values[0] = toInt(action);
+    keyEvent->value.int32Values[1] = keyCode;
+    keyEvent->value.int32Values[2] = targetDisplay;
+    return keyEvent;
+}
+
+StatusCode VehicleHalServer::onSetProperty(const VehiclePropValue& value, bool updateStatus) {
+    // Some properties need to be treated non-trivially
+    switch (value.prop) {
+        case kGenerateFakeDataControllingProperty:
+            return handleGenerateFakeDataRequest(value);
+
+        // set the value from vehicle side, used in end to end test.
+        case kSetIntPropertyFromVehicleForTest: {
+            auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
+            updatedPropValue->prop = value.value.int32Values[0];
+            updatedPropValue->value.int32Values[0] = value.value.int32Values[1];
+            updatedPropValue->timestamp = value.value.int64Values[0];
+            updatedPropValue->areaId = value.areaId;
+            onPropertyValueFromCar(*updatedPropValue, updateStatus);
+            return StatusCode::OK;
+        }
+        case kSetFloatPropertyFromVehicleForTest: {
+            auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
+            updatedPropValue->prop = value.value.int32Values[0];
+            updatedPropValue->value.floatValues[0] = value.value.floatValues[0];
+            updatedPropValue->timestamp = value.value.int64Values[0];
+            updatedPropValue->areaId = value.areaId;
+            onPropertyValueFromCar(*updatedPropValue, updateStatus);
+            return StatusCode::OK;
+        }
+        case kSetBooleanPropertyFromVehicleForTest: {
+            auto updatedPropValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
+            updatedPropValue->prop = value.value.int32Values[1];
+            updatedPropValue->value.int32Values[0] = value.value.int32Values[0];
+            updatedPropValue->timestamp = value.value.int64Values[0];
+            updatedPropValue->areaId = value.areaId;
+            onPropertyValueFromCar(*updatedPropValue, updateStatus);
+            return StatusCode::OK;
+        }
+
+        case AP_POWER_STATE_REPORT:
+            switch (value.value.int32Values[0]) {
+                case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
+                case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
+                case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
+                    // CPMS is in WAIT_FOR_VHAL state, simply move to ON
+                    // Send back to HAL
+                    // ALWAYS update status for generated property value
+                    onPropertyValueFromCar(*createApPowerStateReq(VehicleApPowerStateReq::ON, 0),
+                                           true /* updateStatus */);
+                    break;
+                case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
+                case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
+                    // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
+                    // Send back to HAL
+                    // ALWAYS update status for generated property value
+                    onPropertyValueFromCar(
+                            *createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0),
+                            true /* updateStatus */);
+                    break;
+                case toInt(VehicleApPowerStateReport::ON):
+                case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
+                case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
+                    // Do nothing
+                    break;
+                default:
+                    // Unknown state
+                    break;
+            }
+            break;
+        case INITIAL_USER_INFO:
+            return onSetInitialUserInfo(value, updateStatus);
+        default:
+            break;
+    }
+
+    // In the real vhal, the value will be sent to Car ECU.
+    // We just pretend it is done here and send back to HAL
+    auto updatedPropValue = getValuePool()->obtain(value);
+    updatedPropValue->timestamp = elapsedRealtimeNano();
+
+    onPropertyValueFromCar(*updatedPropValue, updateStatus);
+    return StatusCode::OK;
+}
+
+/**
+ * INITIAL_USER_INFO is called by Android when it starts, and it's expecting a property change
+ * indicating what the initial user should be.
+ *
+ * During normal circumstances, the emulator will reply right away, passing a response if
+ * InitialUserInfoResponseAction::DEFAULT (so Android could use its own logic to decide which user
+ * to boot).
+ *
+ * But during development / testing, the behavior can be changed using lshal dump, which must use
+ * the areaId to indicate what should happen next.
+ *
+ * So, the behavior of set(INITIAL_USER_INFO) is:
+ *
+ * - if it has an areaId, store the property into mInitialUserResponseFromCmd (as it was called by
+ *   lshal).
+ * - else if mInitialUserResponseFromCmd is not set, return a response with the same request id and
+ *   InitialUserInfoResponseAction::DEFAULT
+ * - else the behavior is defined by the areaId on mInitialUserResponseFromCmd:
+ * - if it's 1, reply with mInitialUserResponseFromCmd and the right request id
+ * - if it's 2, reply with mInitialUserResponseFromCmd but a wrong request id (so Android can test
+ *   this error scenario)
+ * - if it's 3, then don't send a property change (so Android can emulate a timeout)
+ *
+ */
+StatusCode VehicleHalServer::onSetInitialUserInfo(const VehiclePropValue& value,
+                                                  bool updateStatus) {
+    // TODO: LOG calls below might be more suited to be DEBUG, but those are not being logged
+    // (even when explicitly calling setprop log.tag. As this class should be using ALOG instead of
+    // LOG, it's not worth investigating why...
+
+    if (value.value.int32Values.size() == 0) {
+        LOG(ERROR) << "set(INITIAL_USER_INFO): no int32values, ignoring it: " << toString(value);
+        return StatusCode::INVALID_ARG;
+    }
+
+    if (value.areaId != 0) {
+        LOG(INFO) << "set(INITIAL_USER_INFO) called from lshal; storing it: " << toString(value);
+        mInitialUserResponseFromCmd.reset(new VehiclePropValue(value));
+        return StatusCode::OK;
+    }
+    LOG(INFO) << "set(INITIAL_USER_INFO) called from Android: " << toString(value);
+
+    int32_t requestId = value.value.int32Values[0];
+
+    // Create the update property and set common values
+    auto updatedValue = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
+    updatedValue->prop = INITIAL_USER_INFO;
+    updatedValue->timestamp = elapsedRealtimeNano();
+
+    if (mInitialUserResponseFromCmd == nullptr) {
+        updatedValue->value.int32Values.resize(2);
+        updatedValue->value.int32Values[0] = requestId;
+        updatedValue->value.int32Values[1] = (int32_t)InitialUserInfoResponseAction::DEFAULT;
+        LOG(INFO) << "no lshal response; returning InitialUserInfoResponseAction::DEFAULT: "
+                  << toString(*updatedValue);
+        onPropertyValueFromCar(*updatedValue, updateStatus);
+        return StatusCode::OK;
+    }
+
+    // mInitialUserResponseFromCmd is used for just one request
+    std::unique_ptr<VehiclePropValue> response = std::move(mInitialUserResponseFromCmd);
+
+    // TODO(b/138709788): rather than populate the raw values directly, it should use the
+    // libraries that convert a InitialUserInfoResponse into a VehiclePropValue)
+
+    switch (response->areaId) {
+        case 1:
+            LOG(INFO) << "returning response with right request id";
+            *updatedValue = *response;
+            updatedValue->areaId = 0;
+            updatedValue->value.int32Values[0] = requestId;
+            break;
+        case 2:
+            LOG(INFO) << "returning response with wrong request id";
+            *updatedValue = *response;
+            updatedValue->areaId = 0;
+            updatedValue->value.int32Values[0] = -requestId;
+            break;
+        case 3:
+            LOG(INFO) << "not generating a property change event because of lshal prop: "
+                      << toString(*response);
+            return StatusCode::OK;
+        default:
+            LOG(ERROR) << "invalid action on lshal response: " << toString(*response);
+            return StatusCode::INTERNAL_ERROR;
+    }
+
+    LOG(INFO) << "updating property to: " << toString(*updatedValue);
+    onPropertyValueFromCar(*updatedValue, updateStatus);
+    return StatusCode::OK;
+}
+
+}  // namespace android::hardware::automotive::vehicle::V2_0::impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h
new file mode 100644
index 0000000..b1ae106
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/VehicleHalServer.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <vhal_v2_0/VehicleObjectPool.h>
+#include <vhal_v2_0/VehicleServer.h>
+
+#include "GeneratorHub.h"
+
+namespace android::hardware::automotive::vehicle::V2_0::impl {
+
+// This contains the common server operations that will be used by
+// both native and virtualized VHAL server. Notice that in the virtualized
+// scenario, the server may be run on a different OS than Android.
+class VehicleHalServer : public IVehicleServer {
+  public:
+    // Methods from IVehicleServer
+
+    std::vector<VehiclePropConfig> onGetAllPropertyConfig() const override;
+
+    StatusCode onSetProperty(const VehiclePropValue& value, bool updateStatus) override;
+
+    // Set the Property Value Pool used in this server
+    void setValuePool(VehiclePropValuePool* valuePool);
+
+  private:
+    using VehiclePropValuePtr = recyclable_ptr<VehiclePropValue>;
+
+    GeneratorHub* getGenerator();
+
+    VehiclePropValuePool* getValuePool() const;
+
+    void onFakeValueGenerated(const VehiclePropValue& value);
+
+    StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
+
+    VehiclePropValuePtr createApPowerStateReq(VehicleApPowerStateReq req, int32_t param);
+
+    VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode,
+                                             int32_t targetDisplay);
+
+    StatusCode onSetInitialUserInfo(const VehiclePropValue& value, bool updateStatus);
+
+  // data members
+
+  protected:
+    // TODO(b/146207078): it might be clearer to move members below to an EmulatedUserHal class
+    std::unique_ptr<VehiclePropValue> mInitialUserResponseFromCmd;
+
+  private:
+    GeneratorHub mGeneratorHub{
+            std::bind(&VehicleHalServer::onFakeValueGenerated, this, std::placeholders::_1)};
+
+    VehiclePropValuePool* mValuePool{nullptr};
+};
+
+}  // namespace android::hardware::automotive::vehicle::V2_0::impl
diff --git a/drm/1.0/vts/functional/Android.bp b/drm/1.0/vts/functional/Android.bp
index 235bfb4..e4d3393 100644
--- a/drm/1.0/vts/functional/Android.bp
+++ b/drm/1.0/vts/functional/Android.bp
@@ -24,7 +24,7 @@
         "vendor_modules.cpp",
     ],
     static_libs: [
-       "android.hardware.drm@1.0-helper",
+        "android.hardware.drm@1.0-helper",
     ],
     export_include_dirs: ["include"],
 }
@@ -43,12 +43,12 @@
         "android.hardware.drm@1.0",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
+        "libcrypto",
         "libhidlmemory",
         "libnativehelper",
     ],
     static_libs: [
         "android.hardware.drm@1.0-helper",
-        "libcrypto_static",
         "libdrmvtshelper",
     ],
     export_shared_lib_headers: [
@@ -76,14 +76,28 @@
         "android.hardware.drm@1.0",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
+        "libcrypto",
         "libhidlmemory",
         "libnativehelper",
     ],
     static_libs: [
         "android.hardware.drm@1.0-helper",
-        "libcrypto_static",
         "libdrmvtshelper",
     ],
+    arch: {
+        arm: {
+            data: [":libvtswidevine-arm-prebuilts"],
+        },
+        arm64: {
+            data: [":libvtswidevine-arm64-prebuilts"],
+        },
+        x86: {
+            data: [":libvtswidevine-x86-prebuilts"],
+        },
+        x86_64: {
+            data: [":libvtswidevine-x86_64-prebuilts"],
+        },
+    },
     test_suites: [
         "general-tests",
         "vts-core",
diff --git a/drm/1.0/vts/functional/AndroidTest.xml b/drm/1.0/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..92ea7e4
--- /dev/null
+++ b/drm/1.0/vts/functional/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Runs VtsHalDrmV1_0TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push-file" key="VtsHalDrmV1_0TargetTest" value="/data/local/tmp/VtsHalDrmV1_0TargetTest" />
+        <option name="push-file" key="libvtswidevine64.so" value="/data/local/tmp/64/lib/libvtswidevine.so" />
+        <option name="push-file" key="libvtswidevine32.so" value="/data/local/tmp/32/lib/libvtswidevine.so" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalDrmV1_0TargetTest" />
+    </test>
+</configuration>
diff --git a/drm/1.1/vts/functional/Android.bp b/drm/1.1/vts/functional/Android.bp
index e08d760..c31aee0 100644
--- a/drm/1.1/vts/functional/Android.bp
+++ b/drm/1.1/vts/functional/Android.bp
@@ -60,11 +60,25 @@
         "drm_hal_test_main.cpp",
     ],
     whole_static_libs: [
-        "android.hardware.drm@1.1-vts"
+        "android.hardware.drm@1.1-vts",
     ],
     shared_libs: [
         "android.hardware.drm@1.1",
     ],
+    arch: {
+        arm: {
+            data: [":libvtswidevine-arm-prebuilts"],
+        },
+        arm64: {
+            data: [":libvtswidevine-arm64-prebuilts"],
+        },
+        x86: {
+            data: [":libvtswidevine-x86-prebuilts"],
+        },
+        x86_64: {
+            data: [":libvtswidevine-x86_64-prebuilts"],
+        },
+    },
     test_suites: [
         "general-tests",
         "vts-core",
diff --git a/drm/1.1/vts/functional/AndroidTest.xml b/drm/1.1/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..65c45ac
--- /dev/null
+++ b/drm/1.1/vts/functional/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Runs VtsHalDrmV1_1TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push-file" key="VtsHalDrmV1_1TargetTest" value="/data/local/tmp/VtsHalDrmV1_1TargetTest" />
+        <option name="push-file" key="libvtswidevine64.so" value="/data/local/tmp/64/lib/libvtswidevine.so" />
+        <option name="push-file" key="libvtswidevine32.so" value="/data/local/tmp/32/lib/libvtswidevine.so" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalDrmV1_1TargetTest" />
+    </test>
+</configuration>
diff --git a/drm/1.2/vts/functional/Android.bp b/drm/1.2/vts/functional/Android.bp
index ecc7d6c..793ef80 100644
--- a/drm/1.2/vts/functional/Android.bp
+++ b/drm/1.2/vts/functional/Android.bp
@@ -31,12 +31,12 @@
         "android.hardware.drm@1.2",
         "android.hidl.allocator@1.0",
         "android.hidl.memory@1.0",
+        "libcrypto",
         "libhidlmemory",
         "libnativehelper",
     ],
     static_libs: [
         "android.hardware.drm@1.0-helper",
-        "libcrypto_static",
         "libdrmvtshelper",
     ],
     export_shared_lib_headers: [
@@ -63,13 +63,27 @@
         "android.hardware.drm@1.0",
         "android.hardware.drm@1.2",
         "android.hidl.allocator@1.0",
+        "libcrypto",
         "libhidlmemory",
     ],
     static_libs: [
         "android.hardware.drm@1.0-helper",
-        "libcrypto_static",
         "libdrmvtshelper",
     ],
+    arch: {
+        arm: {
+            data: [":libvtswidevine-arm-prebuilts"],
+        },
+        arm64: {
+            data: [":libvtswidevine-arm64-prebuilts"],
+        },
+        x86: {
+            data: [":libvtswidevine-x86-prebuilts"],
+        },
+        x86_64: {
+            data: [":libvtswidevine-x86_64-prebuilts"],
+        },
+    },
     test_suites: [
         "general-tests",
         "vts-core",
diff --git a/drm/1.2/vts/functional/AndroidTest.xml b/drm/1.2/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..5da38ae
--- /dev/null
+++ b/drm/1.2/vts/functional/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Runs VtsHalDrmV1_2TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push-file" key="VtsHalDrmV1_2TargetTest" value="/data/local/tmp/VtsHalDrmV1_2TargetTest" />
+        <option name="push-file" key="libvtswidevine64.so" value="/data/local/tmp/64/lib/libvtswidevine.so" />
+        <option name="push-file" key="libvtswidevine32.so" value="/data/local/tmp/32/lib/libvtswidevine.so" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalDrmV1_2TargetTest" />
+    </test>
+</configuration>
diff --git a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
index cbdd87b..1bef663 100644
--- a/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
+++ b/dumpstate/1.1/vts/functional/VtsHalDumpstateV1_1TargetTest.cpp
@@ -20,6 +20,7 @@
 #include <unistd.h>
 
 #include <functional>
+#include <tuple>
 #include <vector>
 
 #include <android/hardware/dumpstate/1.1/IDumpstateDevice.h>
@@ -27,6 +28,7 @@
 #include <cutils/native_handle.h>
 #include <gtest/gtest.h>
 #include <hidl/GtestPrinter.h>
+#include <hidl/HidlSupport.h>
 #include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
@@ -39,13 +41,18 @@
 using ::android::hardware::dumpstate::V1_1::IDumpstateDevice;
 using ::android::hardware::dumpstate::V1_1::toString;
 
-class DumpstateHidl1_1Test : public ::testing::TestWithParam<std::string> {
+// Base class common to all dumpstate HAL v1.1 tests.
+template <typename T>
+class DumpstateHidl1_1TestBase : public ::testing::TestWithParam<T> {
   protected:
     virtual void SetUp() override { GetService(); }
 
+    virtual std::string GetInstanceName() = 0;
+
     void GetService() {
-        dumpstate = IDumpstateDevice::getService(GetParam());
-        ASSERT_NE(dumpstate, nullptr) << "Could not get HIDL instance";
+        const std::string instance_name = GetInstanceName();
+        dumpstate = IDumpstateDevice::getService(instance_name);
+        ASSERT_NE(dumpstate, nullptr) << "Could not get HIDL instance " << instance_name;
     }
 
     void ToggleVerboseLogging(bool enable) {
@@ -78,77 +85,76 @@
     sp<IDumpstateDevice> dumpstate;
 };
 
-#define TEST_FOR_DUMPSTATE_MODE(name, body, mode) \
-    TEST_P(DumpstateHidl1_1Test, name##_##mode) { body(DumpstateMode::mode); }
+// Tests that don't need to iterate every single DumpstateMode value for dumpstateBoard_1_1.
+class DumpstateHidl1_1GeneralTest : public DumpstateHidl1_1TestBase<std::string> {
+  protected:
+    virtual std::string GetInstanceName() override { return GetParam(); }
+};
 
-// We use a macro to define individual test cases instead of hidl_enum_range<> because some HAL
-// implementations are lazy and may call exit() at the end of dumpstateBoard(), which would cause
-// DEAD_OBJECT errors after the first iteration. Separate cases re-get the service each time as part
-// of SetUp(), and also provide better separation of concerns when specific modes are problematic.
-#define TEST_FOR_ALL_DUMPSTATE_MODES(name, body)       \
-    TEST_FOR_DUMPSTATE_MODE(name, body, FULL);         \
-    TEST_FOR_DUMPSTATE_MODE(name, body, INTERACTIVE);  \
-    TEST_FOR_DUMPSTATE_MODE(name, body, REMOTE);       \
-    TEST_FOR_DUMPSTATE_MODE(name, body, WEAR);         \
-    TEST_FOR_DUMPSTATE_MODE(name, body, CONNECTIVITY); \
-    TEST_FOR_DUMPSTATE_MODE(name, body, WIFI);         \
-    TEST_FOR_DUMPSTATE_MODE(name, body, DEFAULT);      \
-    TEST_FOR_DUMPSTATE_MODE(name, body, PROTO);
+// Tests that iterate every single DumpstateMode value for dumpstateBoard_1_1.
+class DumpstateHidl1_1PerModeTest
+    : public DumpstateHidl1_1TestBase<std::tuple<std::string, DumpstateMode>> {
+  protected:
+    virtual std::string GetInstanceName() override { return std::get<0>(GetParam()); }
+
+    DumpstateMode GetMode() { return std::get<1>(GetParam()); }
+
+    // Will only execute additional_assertions when status == expected.
+    void AssertStatusForMode(const Return<DumpstateStatus>& status, const DumpstateStatus expected,
+                             std::function<void()> additional_assertions = nullptr) {
+        ASSERT_TRUE(status.isOk())
+                << "Status should be ok and return a more specific DumpstateStatus: "
+                << status.description();
+        if (GetMode() == DumpstateMode::DEFAULT) {
+            ASSERT_EQ(expected, status)
+                    << "Required mode (DumpstateMode::" << toString(GetMode())
+                    << "): status should be DumpstateStatus::" << toString(expected)
+                    << ", but got DumpstateStatus::" << toString(status);
+        } else {
+            // The rest of the modes are optional to support, but they MUST return either the
+            // expected value or UNSUPPORTED_MODE.
+            ASSERT_TRUE(status == expected || status == DumpstateStatus::UNSUPPORTED_MODE)
+                    << "Optional mode (DumpstateMode::" << toString(GetMode())
+                    << "): status should be DumpstateStatus::" << toString(expected)
+                    << " or DumpstateStatus::UNSUPPORTED_MODE, but got DumpstateStatus::"
+                    << toString(status);
+        }
+        if (status == expected && additional_assertions != nullptr) {
+            additional_assertions();
+        }
+    }
+};
 
 constexpr uint64_t kDefaultTimeoutMillis = 30 * 1000;  // 30 seconds
 
-// Will only execute additional_assertions when status == expected.
-void AssertStatusForMode(const DumpstateMode mode, const Return<DumpstateStatus>& status,
-                         const DumpstateStatus expected,
-                         std::function<void()> additional_assertions = nullptr) {
-    ASSERT_TRUE(status.isOk()) << "Status should be ok and return a more specific DumpstateStatus: "
-                               << status.description();
-    if (mode == DumpstateMode::DEFAULT) {
-        ASSERT_EQ(expected, status) << "Required mode (DumpstateMode::" << toString(mode)
-                                    << "): status should be DumpstateStatus::" << toString(expected)
-                                    << ", but got DumpstateStatus::" << toString(status);
-    } else {
-        // The rest of the modes are optional to support, but they MUST return either the expected
-        // value or UNSUPPORTED_MODE.
-        ASSERT_TRUE(status == expected || status == DumpstateStatus::UNSUPPORTED_MODE)
-                << "Optional mode (DumpstateMode::" << toString(mode)
-                << "): status should be DumpstateStatus::" << toString(expected)
-                << " or DumpstateStatus::UNSUPPORTED_MODE, but got DumpstateStatus::"
-                << toString(status);
-    }
-    if (status == expected && additional_assertions != nullptr) {
-        additional_assertions();
-    }
-}
-
 // Negative test: make sure dumpstateBoard() doesn't crash when passed a null pointer.
-TEST_FOR_ALL_DUMPSTATE_MODES(TestNullHandle, [this](DumpstateMode mode) {
+TEST_P(DumpstateHidl1_1PerModeTest, TestNullHandle) {
     EnableVerboseLogging();
 
     Return<DumpstateStatus> status =
-            dumpstate->dumpstateBoard_1_1(nullptr, mode, kDefaultTimeoutMillis);
+            dumpstate->dumpstateBoard_1_1(nullptr, GetMode(), kDefaultTimeoutMillis);
 
-    AssertStatusForMode(mode, status, DumpstateStatus::ILLEGAL_ARGUMENT);
-});
+    AssertStatusForMode(status, DumpstateStatus::ILLEGAL_ARGUMENT);
+}
 
 // Negative test: make sure dumpstateBoard() ignores a handle with no FD.
-TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithNoFd, [this](DumpstateMode mode) {
+TEST_P(DumpstateHidl1_1PerModeTest, TestHandleWithNoFd) {
     EnableVerboseLogging();
 
     native_handle_t* handle = native_handle_create(0, 0);
     ASSERT_NE(handle, nullptr) << "Could not create native_handle";
 
     Return<DumpstateStatus> status =
-            dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
+            dumpstate->dumpstateBoard_1_1(handle, GetMode(), kDefaultTimeoutMillis);
 
-    AssertStatusForMode(mode, status, DumpstateStatus::ILLEGAL_ARGUMENT);
+    AssertStatusForMode(status, DumpstateStatus::ILLEGAL_ARGUMENT);
 
     native_handle_close(handle);
     native_handle_delete(handle);
-});
+}
 
 // Positive test: make sure dumpstateBoard() writes something to the FD.
-TEST_FOR_ALL_DUMPSTATE_MODES(TestOk, [this](DumpstateMode mode) {
+TEST_P(DumpstateHidl1_1PerModeTest, TestOk) {
     EnableVerboseLogging();
 
     // Index 0 corresponds to the read end of the pipe; 1 to the write end.
@@ -160,9 +166,9 @@
     handle->data[0] = fds[1];
 
     Return<DumpstateStatus> status =
-            dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
+            dumpstate->dumpstateBoard_1_1(handle, GetMode(), kDefaultTimeoutMillis);
 
-    AssertStatusForMode(mode, status, DumpstateStatus::OK, [&fds]() {
+    AssertStatusForMode(status, DumpstateStatus::OK, [&fds]() {
         // Check that at least one byte was written.
         char buff;
         ASSERT_EQ(1, read(fds[0], &buff, 1)) << "Dumped nothing";
@@ -170,10 +176,10 @@
 
     native_handle_close(handle);
     native_handle_delete(handle);
-});
+}
 
 // Positive test: make sure dumpstateBoard() doesn't crash with two FDs.
-TEST_FOR_ALL_DUMPSTATE_MODES(TestHandleWithTwoFds, [this](DumpstateMode mode) {
+TEST_P(DumpstateHidl1_1PerModeTest, TestHandleWithTwoFds) {
     EnableVerboseLogging();
 
     int fds1[2];
@@ -187,9 +193,9 @@
     handle->data[1] = fds2[1];
 
     Return<DumpstateStatus> status =
-            dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
+            dumpstate->dumpstateBoard_1_1(handle, GetMode(), kDefaultTimeoutMillis);
 
-    AssertStatusForMode(mode, status, DumpstateStatus::OK, [&fds1, &fds2]() {
+    AssertStatusForMode(status, DumpstateStatus::OK, [&fds1, &fds2]() {
         // Check that at least one byte was written to one of the FDs.
         char buff;
         size_t read1 = read(fds1[0], &buff, 1);
@@ -200,10 +206,10 @@
 
     native_handle_close(handle);
     native_handle_delete(handle);
-});
+}
 
 // Make sure dumpstateBoard_1_1 actually validates its arguments.
-TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Negative) {
+TEST_P(DumpstateHidl1_1GeneralTest, TestInvalidModeArgument_Negative) {
     EnableVerboseLogging();
 
     int fds[2];
@@ -225,7 +231,7 @@
     native_handle_delete(handle);
 }
 
-TEST_P(DumpstateHidl1_1Test, TestInvalidModeArgument_Undefined) {
+TEST_P(DumpstateHidl1_1GeneralTest, TestInvalidModeArgument_Undefined) {
     EnableVerboseLogging();
 
     int fds[2];
@@ -248,7 +254,7 @@
 }
 
 // Positive test: make sure dumpstateBoard() from 1.0 doesn't fail.
-TEST_P(DumpstateHidl1_1Test, Test1_0MethodOk) {
+TEST_P(DumpstateHidl1_1GeneralTest, Test1_0MethodOk) {
     EnableVerboseLogging();
 
     int fds[2];
@@ -272,7 +278,7 @@
 
 // Make sure disabling verbose logging behaves correctly. Some info is still allowed to be emitted,
 // but it can't have privacy/storage/battery impacts.
-TEST_FOR_ALL_DUMPSTATE_MODES(TestVerboseLoggingDisabled, [this](DumpstateMode mode) {
+TEST_P(DumpstateHidl1_1PerModeTest, TestDeviceLoggingDisabled) {
     DisableVerboseLogging();
 
     // Index 0 corresponds to the read end of the pipe; 1 to the write end.
@@ -284,31 +290,31 @@
     handle->data[0] = fds[1];
 
     Return<DumpstateStatus> status =
-            dumpstate->dumpstateBoard_1_1(handle, mode, kDefaultTimeoutMillis);
+            dumpstate->dumpstateBoard_1_1(handle, GetMode(), kDefaultTimeoutMillis);
 
     // We don't include additional assertions here about the file passed in. If verbose logging is
     // disabled, the OEM may choose to include nothing at all, but it is allowed to include some
     // essential information based on the mode as long as it isn't private user information.
-    AssertStatusForMode(mode, status, DumpstateStatus::OK);
+    AssertStatusForMode(status, DumpstateStatus::OK);
 
     native_handle_close(handle);
     native_handle_delete(handle);
-});
+}
 
 // Double-enable is perfectly valid, but the second call shouldn't do anything.
-TEST_P(DumpstateHidl1_1Test, TestRepeatedEnable) {
+TEST_P(DumpstateHidl1_1GeneralTest, TestRepeatedEnable) {
     EnableVerboseLogging();
     EnableVerboseLogging();
 }
 
 // Double-disable is perfectly valid, but the second call shouldn't do anything.
-TEST_P(DumpstateHidl1_1Test, TestRepeatedDisable) {
+TEST_P(DumpstateHidl1_1GeneralTest, TestRepeatedDisable) {
     DisableVerboseLogging();
     DisableVerboseLogging();
 }
 
 // Toggling in short order is perfectly valid.
-TEST_P(DumpstateHidl1_1Test, TestRepeatedToggle) {
+TEST_P(DumpstateHidl1_1GeneralTest, TestRepeatedToggle) {
     EnableVerboseLogging();
     DisableVerboseLogging();
     EnableVerboseLogging();
@@ -316,8 +322,23 @@
 }
 
 INSTANTIATE_TEST_SUITE_P(
-        PerInstance, DumpstateHidl1_1Test,
+        PerInstance, DumpstateHidl1_1GeneralTest,
         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IDumpstateDevice::descriptor)),
         android::hardware::PrintInstanceNameToString);
 
+// Includes the mode's name as part of the description string.
+static inline std::string PrintInstanceNameToStringWithMode(
+        const testing::TestParamInfo<std::tuple<std::string, DumpstateMode>>& info) {
+    return android::hardware::PrintInstanceNameToString(
+                   testing::TestParamInfo(std::get<0>(info.param), info.index)) +
+           "_" + toString(std::get<1>(info.param));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+        PerInstanceAndMode, DumpstateHidl1_1PerModeTest,
+        testing::Combine(testing::ValuesIn(android::hardware::getAllHalInstanceNames(
+                                 IDumpstateDevice::descriptor)),
+                         testing::ValuesIn(android::hardware::hidl_enum_range<DumpstateMode>())),
+        PrintInstanceNameToStringWithMode);
+
 }  // namespace
diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
index 10ce4c2..cc14271 100644
--- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
@@ -176,6 +176,10 @@
      * @param itemsRequest
      *   If non-empty, contains request data that is signed by the reader. See above.
      *
+     * @param signingKeyBlob is either empty or a signingKeyBlob (see generateSigningKeyPair(),
+     *    below) containing the signing key to use to sign the data retrieved. If this
+     *    is not in the right format the call fails with STATUS_INVALID_DATA.
+     *
      * @param sessionTranscript
      *   Either empty or the CBOR of the SessionTranscript. See above.
      *
@@ -195,8 +199,7 @@
      *   and remove the corresponding requests from the counts.
      */
     void startRetrieval(in SecureAccessControlProfile[] accessControlProfiles,
-        in HardwareAuthToken authToken,
-        in byte[] itemsRequest,
+        in HardwareAuthToken authToken, in byte[] itemsRequest, in byte[] signingKeyBlob,
         in byte[] sessionTranscript, in byte[] readerSignature, in int[] requestCounts);
 
     /**
@@ -254,10 +257,6 @@
      * If signingKeyBlob or the sessionTranscript parameter passed to startRetrieval() is
      * empty then the returned MAC will be empty.
      *
-     * @param signingKeyBlob is either empty or a signingKeyBlob (see generateSigningKeyPair(),
-     *    below) containing the signing key to use to sign the data retrieved. If this
-     *    is not in the right format the call fails with STATUS_INVALID_DATA.
-     *
      * @param out mac is empty if signingKeyBlob or the sessionTranscript passed to
      *    startRetrieval() is empty. Otherwise it is a COSE_Mac0 with empty payload
      *    and the detached content is set to DeviceAuthentication as defined below.
@@ -304,7 +303,7 @@
      *
      * @param out deviceNameSpaces the bytes of DeviceNameSpaces.
      */
-    void finishRetrieval(in byte[] signingKeyBlob, out byte[] mac, out byte[] deviceNameSpaces);
+    void finishRetrieval(out byte[] mac, out byte[] deviceNameSpaces);
 
     /**
      * Generate a key pair to be used for signing session data and retrieved data items.
diff --git a/identity/aidl/default/IdentityCredential.cpp b/identity/aidl/default/IdentityCredential.cpp
index d5b3a0f..341fae6 100644
--- a/identity/aidl/default/IdentityCredential.cpp
+++ b/identity/aidl/default/IdentityCredential.cpp
@@ -256,8 +256,8 @@
 ndk::ScopedAStatus IdentityCredential::startRetrieval(
         const vector<SecureAccessControlProfile>& accessControlProfiles,
         const HardwareAuthToken& authToken, const vector<int8_t>& itemsRequestS,
-        const vector<int8_t>& sessionTranscriptS, const vector<int8_t>& readerSignatureS,
-        const vector<int32_t>& requestCounts) {
+        const vector<int8_t>& signingKeyBlobS, const vector<int8_t>& sessionTranscriptS,
+        const vector<int8_t>& readerSignatureS, const vector<int32_t>& requestCounts) {
     auto sessionTranscript = byteStringToUnsigned(sessionTranscriptS);
     auto itemsRequest = byteStringToUnsigned(itemsRequestS);
     auto readerSignature = byteStringToUnsigned(readerSignatureS);
@@ -498,6 +498,7 @@
     currentNameSpace_ = "";
 
     itemsRequest_ = itemsRequest;
+    signingKeyBlob_ = byteStringToUnsigned(signingKeyBlobS);
 
     numStartRetrievalCalls_ += 1;
     return ndk::ScopedAStatus::ok();
@@ -650,11 +651,8 @@
     return ndk::ScopedAStatus::ok();
 }
 
-ndk::ScopedAStatus IdentityCredential::finishRetrieval(const vector<int8_t>& signingKeyBlobS,
-                                                       vector<int8_t>* outMac,
+ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector<int8_t>* outMac,
                                                        vector<int8_t>* outDeviceNameSpaces) {
-    auto signingKeyBlob = byteStringToUnsigned(signingKeyBlobS);
-
     if (currentNameSpaceDeviceNameSpacesMap_.size() > 0) {
         deviceNameSpacesMap_.add(currentNameSpace_,
                                  std::move(currentNameSpaceDeviceNameSpacesMap_));
@@ -664,7 +662,8 @@
     // If there's no signing key or no sessionTranscript or no reader ephemeral
     // public key, we return the empty MAC.
     optional<vector<uint8_t>> mac;
-    if (signingKeyBlob.size() > 0 && sessionTranscript_.size() > 0 && readerPublicKey_.size() > 0) {
+    if (signingKeyBlob_.size() > 0 && sessionTranscript_.size() > 0 &&
+        readerPublicKey_.size() > 0) {
         cppbor::Array array;
         array.add("DeviceAuthentication");
         array.add(sessionTranscriptItem_->clone());
@@ -674,7 +673,7 @@
 
         vector<uint8_t> docTypeAsBlob(docType_.begin(), docType_.end());
         optional<vector<uint8_t>> signingKey =
-                support::decryptAes128Gcm(storageKey_, signingKeyBlob, docTypeAsBlob);
+                support::decryptAes128Gcm(storageKey_, signingKeyBlob_, docTypeAsBlob);
         if (!signingKey) {
             return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                     IIdentityCredentialStore::STATUS_INVALID_DATA,
diff --git a/identity/aidl/default/IdentityCredential.h b/identity/aidl/default/IdentityCredential.h
index 49ed0d4..fc29254 100644
--- a/identity/aidl/default/IdentityCredential.h
+++ b/identity/aidl/default/IdentityCredential.h
@@ -54,14 +54,14 @@
     ndk::ScopedAStatus startRetrieval(
             const vector<SecureAccessControlProfile>& accessControlProfiles,
             const HardwareAuthToken& authToken, const vector<int8_t>& itemsRequest,
-            const vector<int8_t>& sessionTranscript, const vector<int8_t>& readerSignature,
-            const vector<int32_t>& requestCounts) override;
+            const vector<int8_t>& signingKeyBlob, const vector<int8_t>& sessionTranscript,
+            const vector<int8_t>& readerSignature, const vector<int32_t>& requestCounts) override;
     ndk::ScopedAStatus startRetrieveEntryValue(
             const string& nameSpace, const string& name, int32_t entrySize,
             const vector<int32_t>& accessControlProfileIds) override;
     ndk::ScopedAStatus retrieveEntryValue(const vector<int8_t>& encryptedContent,
                                           vector<int8_t>* outContent) override;
-    ndk::ScopedAStatus finishRetrieval(const vector<int8_t>& signingKeyBlob, vector<int8_t>* outMac,
+    ndk::ScopedAStatus finishRetrieval(vector<int8_t>* outMac,
                                        vector<int8_t>* outDeviceNameSpaces) override;
     ndk::ScopedAStatus generateSigningKeyPair(vector<int8_t>* outSigningKeyBlob,
                                               Certificate* outSigningKeyCertificate) override;
@@ -88,6 +88,7 @@
 
     // Set at startRetrieval() time.
     map<int32_t, int> profileIdToAccessCheckResult_;
+    vector<uint8_t> signingKeyBlob_;
     vector<uint8_t> sessionTranscript_;
     std::unique_ptr<cppbor::Item> sessionTranscriptItem_;
     vector<uint8_t> itemsRequest_;
diff --git a/identity/aidl/default/WritableIdentityCredential.cpp b/identity/aidl/default/WritableIdentityCredential.cpp
index ba2062d..89f7f35 100644
--- a/identity/aidl/default/WritableIdentityCredential.cpp
+++ b/identity/aidl/default/WritableIdentityCredential.cpp
@@ -16,6 +16,9 @@
 
 #define LOG_TAG "WritableIdentityCredential"
 
+#include "WritableIdentityCredential.h"
+#include "IdentityCredentialStore.h"
+
 #include <android/hardware/identity/support/IdentityCredentialSupport.h>
 
 #include <android-base/logging.h>
@@ -23,6 +26,8 @@
 #include <cppbor/cppbor.h>
 #include <cppbor/cppbor_parse.h>
 
+#include <utility>
+
 #include "IdentityCredentialStore.h"
 #include "Util.h"
 #include "WritableIdentityCredential.h"
@@ -33,26 +38,6 @@
 using namespace ::android::hardware::identity;
 
 bool WritableIdentityCredential::initialize() {
-    optional<vector<uint8_t>> keyPair = support::createEcKeyPair();
-    if (!keyPair) {
-        LOG(ERROR) << "Error creating credentialKey";
-        return false;
-    }
-
-    optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair.value());
-    if (!pubKey) {
-        LOG(ERROR) << "Error getting public part of credentialKey";
-        return false;
-    }
-    credentialPubKey_ = pubKey.value();
-
-    optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair.value());
-    if (!privKey) {
-        LOG(ERROR) << "Error getting private part of credentialKey";
-        return false;
-    }
-    credentialPrivKey_ = privKey.value();
-
     optional<vector<uint8_t>> random = support::getRandom(16);
     if (!random) {
         LOG(ERROR) << "Error creating storageKey";
@@ -63,88 +48,54 @@
     return true;
 }
 
-// TODO: use |attestationApplicationId| and |attestationChallenge| and also
-//       ensure the returned certificate chain satisfy the requirements listed in
-//       the docs for IWritableIdentityCredential::getAttestationCertificate()
-//
+// This function generates the attestation certificate using the passed in
+// |attestationApplicationId| and |attestationChallenge|.  It will generate an
+// attestation certificate with current time and expires one year from now.  The
+// certificate shall contain all values as specified in hal.
 ndk::ScopedAStatus WritableIdentityCredential::getAttestationCertificate(
-        const vector<int8_t>& /*attestationApplicationId*/,
-        const vector<int8_t>& /*attestationChallenge*/, vector<Certificate>* outCertificateChain) {
-    // For now, we dynamically generate an attestion key on each and every
-    // request and use that to sign CredentialKey. In a real implementation this
-    // would look very differently.
-    optional<vector<uint8_t>> attestationKeyPair = support::createEcKeyPair();
-    if (!attestationKeyPair) {
-        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
-                IIdentityCredentialStore::STATUS_FAILED, "Error creating attestationKey"));
-    }
-
-    optional<vector<uint8_t>> attestationPubKey =
-            support::ecKeyPairGetPublicKey(attestationKeyPair.value());
-    if (!attestationPubKey) {
+        const vector<int8_t>& attestationApplicationId,  //
+        const vector<int8_t>& attestationChallenge,      //
+        vector<Certificate>* outCertificateChain) {
+    if (!credentialPrivKey_.empty() || !credentialPubKey_.empty() || !certificateChain_.empty()) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                 IIdentityCredentialStore::STATUS_FAILED,
-                "Error getting public part of attestationKey"));
+                "Error attestation certificate previously generated"));
     }
 
-    optional<vector<uint8_t>> attestationPrivKey =
-            support::ecKeyPairGetPrivateKey(attestationKeyPair.value());
-    if (!attestationPrivKey) {
+    vector<uint8_t> challenge(attestationChallenge.begin(), attestationChallenge.end());
+    vector<uint8_t> appId(attestationApplicationId.begin(), attestationApplicationId.end());
+
+    optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> keyAttestationPair =
+            support::createEcKeyPairAndAttestation(challenge, appId);
+    if (!keyAttestationPair) {
+        LOG(ERROR) << "Error creating credentialKey and attestation";
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                 IIdentityCredentialStore::STATUS_FAILED,
-                "Error getting private part of attestationKey"));
+                "Error creating credentialKey and attestation"));
     }
 
-    string serialDecimal;
-    string issuer;
-    string subject;
-    time_t validityNotBefore = time(nullptr);
-    time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600;
+    vector<uint8_t> keyPair = keyAttestationPair.value().first;
+    certificateChain_ = keyAttestationPair.value().second;
 
-    // First create a certificate for |credentialPubKey| which is signed by
-    // |attestationPrivKey|.
-    //
-    serialDecimal = "0";  // TODO: set serial to |attestationChallenge|
-    issuer = "Android Open Source Project";
-    subject = "Android IdentityCredential CredentialKey";
-    optional<vector<uint8_t>> credentialPubKeyCertificate = support::ecPublicKeyGenerateCertificate(
-            credentialPubKey_, attestationPrivKey.value(), serialDecimal, issuer, subject,
-            validityNotBefore, validityNotAfter);
-    if (!credentialPubKeyCertificate) {
+    optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair);
+    if (!pubKey) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                 IIdentityCredentialStore::STATUS_FAILED,
-                "Error creating certificate for credentialPubKey"));
+                "Error getting public part of credentialKey"));
     }
+    credentialPubKey_ = pubKey.value();
 
-    // This is followed by a certificate for |attestationPubKey| self-signed by
-    // |attestationPrivKey|.
-    serialDecimal = "0";  // TODO: set serial
-    issuer = "Android Open Source Project";
-    subject = "Android IdentityCredential AttestationKey";
-    optional<vector<uint8_t>> attestationKeyCertificate = support::ecPublicKeyGenerateCertificate(
-            attestationPubKey.value(), attestationPrivKey.value(), serialDecimal, issuer, subject,
-            validityNotBefore, validityNotAfter);
-    if (!attestationKeyCertificate) {
+    optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair);
+    if (!privKey) {
         return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
                 IIdentityCredentialStore::STATUS_FAILED,
-                "Error creating certificate for attestationPubKey"));
+                "Error getting private part of credentialKey"));
     }
+    credentialPrivKey_ = privKey.value();
 
-    // Concatenate the certificates to form the chain.
-    vector<uint8_t> certificateChain;
-    certificateChain.insert(certificateChain.end(), credentialPubKeyCertificate.value().begin(),
-                            credentialPubKeyCertificate.value().end());
-    certificateChain.insert(certificateChain.end(), attestationKeyCertificate.value().begin(),
-                            attestationKeyCertificate.value().end());
-
-    optional<vector<vector<uint8_t>>> splitCertChain =
-            support::certificateChainSplit(certificateChain);
-    if (!splitCertChain) {
-        return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
-                IIdentityCredentialStore::STATUS_FAILED, "Error splitting certificate chain"));
-    }
+    // convert from vector<vector<uint8_t>>> to vector<Certificate>*
     *outCertificateChain = vector<Certificate>();
-    for (const vector<uint8_t>& cert : splitCertChain.value()) {
+    for (const vector<uint8_t>& cert : certificateChain_) {
         Certificate c = Certificate();
         c.encodedCertificate = byteStringToSigned(cert);
         outCertificateChain->push_back(std::move(c));
diff --git a/identity/aidl/default/WritableIdentityCredential.h b/identity/aidl/default/WritableIdentityCredential.h
index b380f89..b182862 100644
--- a/identity/aidl/default/WritableIdentityCredential.h
+++ b/identity/aidl/default/WritableIdentityCredential.h
@@ -64,10 +64,13 @@
     string docType_;
     bool testCredential_;
 
-    // These are set in initialize().
+    // This is set in initialize().
     vector<uint8_t> storageKey_;
+
+    // These are set in getAttestationCertificate().
     vector<uint8_t> credentialPrivKey_;
     vector<uint8_t> credentialPubKey_;
+    vector<vector<uint8_t>> certificateChain_;
 
     // These fields are initialized during startPersonalization()
     size_t numAccessControlProfileRemaining_;
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index 21ff440..cecc814 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -7,10 +7,11 @@
     srcs: ["VtsHalIdentityTargetTest.cpp"],
     shared_libs: [
         "libbinder",
-        "libcppbor",
-        "android.hardware.identity-support-lib",
+        "libcrypto",
     ],
     static_libs: [
+        "libcppbor",
+        "android.hardware.identity-support-lib",
         "android.hardware.identity-cpp",
         "android.hardware.keymaster-cpp",
     ],
diff --git a/identity/aidl/vts/VtsHalIdentityTargetTest.cpp b/identity/aidl/vts/VtsHalIdentityTargetTest.cpp
index 5abe5a2..ea37fdc 100644
--- a/identity/aidl/vts/VtsHalIdentityTargetTest.cpp
+++ b/identity/aidl/vts/VtsHalIdentityTargetTest.cpp
@@ -352,10 +352,15 @@
                                    readerCertificate.value());
     ASSERT_TRUE(readerSignature);
 
+    // Generate the key that will be used to sign AuthenticatedData.
+    vector<uint8_t> signingKeyBlob;
+    Certificate signingKeyCertificate;
+    ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
+
     ASSERT_TRUE(credential
                         ->startRetrieval(returnedSecureProfiles, authToken, itemsRequestBytes,
-                                         sessionTranscriptBytes, readerSignature.value(),
-                                         testEntriesEntryCounts)
+                                         signingKeyBlob, sessionTranscriptBytes,
+                                         readerSignature.value(), testEntriesEntryCounts)
                         .isOk());
 
     for (const auto& entry : testEntries) {
@@ -377,14 +382,9 @@
         EXPECT_EQ(content, entry.valueCbor);
     }
 
-    // Generate the key that will be used to sign AuthenticatedData.
-    vector<uint8_t> signingKeyBlob;
-    Certificate signingKeyCertificate;
-    ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
-
     vector<uint8_t> mac;
     vector<uint8_t> deviceNameSpacesBytes;
-    ASSERT_TRUE(credential->finishRetrieval(signingKeyBlob, &mac, &deviceNameSpacesBytes).isOk());
+    ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesBytes).isOk());
     cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {});
     ASSERT_EQ(
             "{\n"
diff --git a/identity/support/Android.bp b/identity/support/Android.bp
index 7b4546b..2b6c695 100644
--- a/identity/support/Android.bp
+++ b/identity/support/Android.bp
@@ -23,10 +23,14 @@
         "include",
     ],
     shared_libs: [
+        "android.hardware.keymaster@4.0",
         "libcrypto",
         "libbase",
         "libhidlbase",
         "libhardware",
+        "libkeymaster_portable",
+        "libsoft_attestation_cert",
+        "libpuresoftkeymasterdevice",
     ],
     static_libs: [
         "libcppbor",
diff --git a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
index 4533ad9..507e914 100644
--- a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
+++ b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
@@ -21,6 +21,7 @@
 #include <optional>
 #include <string>
 #include <tuple>
+#include <utility>
 #include <vector>
 
 namespace android {
@@ -106,6 +107,17 @@
 // ---------------------------------------------------------------------------
 // EC crypto functionality / abstraction (only supports P-256).
 // ---------------------------------------------------------------------------
+// Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the
+// PKCS#8 encoded key-pair.  Also generates an attestation
+// certificate using the |challenge| and |applicationId|, and returns the generated
+// certificate in X.509 certificate chain format.
+//
+// The attestation time fields used will be the current time, and expires in one year.
+//
+// The first parameter of the return value is the keyPair generated, second return in
+// the pair is the attestation certificate generated.
+optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
+        const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId);
 
 // Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the
 // PKCS#8 encoded key-pair.
diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp
index e2828bf..bf6a5c3 100644
--- a/identity/support/src/IdentityCredentialSupport.cpp
+++ b/identity/support/src/IdentityCredentialSupport.cpp
@@ -47,6 +47,13 @@
 #include <cppbor.h>
 #include <cppbor_parse.h>
 
+#include <android/hardware/keymaster/4.0/types.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/contexts/pure_soft_keymaster_context.h>
+#include <keymaster/contexts/soft_attestation_cert.h>
+#include <keymaster/keymaster_tags.h>
+#include <keymaster/km_openssl/attestation_utils.h>
+
 namespace android {
 namespace hardware {
 namespace identity {
@@ -816,6 +823,138 @@
     return hmac;
 }
 
+// Generates the attestation certificate with the parameters passed in.  Note
+// that the passed in |activeTimeMilliSeconds| |expireTimeMilliSeconds| are in
+// milli seconds since epoch.  We are setting them to milliseconds due to
+// requirement in AuthorizationSet KM_DATE fields.  The certificate created is
+// actually in seconds.
+optional<vector<vector<uint8_t>>> createAttestation(const EVP_PKEY* key,
+                                                    const vector<uint8_t>& applicationId,
+                                                    const vector<uint8_t>& challenge,
+                                                    uint64_t activeTimeMilliSeconds,
+                                                    uint64_t expireTimeMilliSeconds) {
+    ::keymaster::AuthorizationSet auth_set(
+            ::keymaster::AuthorizationSetBuilder()
+                    .Authorization(::keymaster::TAG_ATTESTATION_CHALLENGE, challenge.data(),
+                                   challenge.size())
+                    .Authorization(::keymaster::TAG_ACTIVE_DATETIME, activeTimeMilliSeconds)
+                    // Even though identity attestation hal said the application
+                    // id should be in software enforced authentication set,
+                    // keymaster portable lib expect the input in this
+                    // parameter because the software enforced in input to keymaster
+                    // refers to the key software enforced properties. And this
+                    // parameter refers to properties of the attestation which
+                    // includes app id.
+                    .Authorization(::keymaster::TAG_ATTESTATION_APPLICATION_ID,
+                                   applicationId.data(), applicationId.size())
+                    .Authorization(::keymaster::TAG_USAGE_EXPIRE_DATETIME, expireTimeMilliSeconds));
+
+    // Unique id and device id is not applicable for identity credential attestation,
+    // so we don't need to set those or application id.
+    ::keymaster::AuthorizationSet swEnforced(::keymaster::AuthorizationSetBuilder().Authorization(
+            ::keymaster::TAG_CREATION_DATETIME, activeTimeMilliSeconds));
+
+    ::keymaster::AuthorizationSet hwEnforced(
+            ::keymaster::AuthorizationSetBuilder()
+                    .Authorization(::keymaster::TAG_PURPOSE, KM_PURPOSE_SIGN)
+                    .Authorization(::keymaster::TAG_KEY_SIZE, 256)
+                    .Authorization(::keymaster::TAG_ALGORITHM, KM_ALGORITHM_EC)
+                    .Authorization(::keymaster::TAG_NO_AUTH_REQUIRED)
+                    .Authorization(::keymaster::TAG_DIGEST, KM_DIGEST_SHA_2_256)
+                    .Authorization(::keymaster::TAG_EC_CURVE, KM_EC_CURVE_P_256)
+                    .Authorization(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY));
+
+    const keymaster_cert_chain_t* attestation_chain =
+            ::keymaster::getAttestationChain(KM_ALGORITHM_EC, nullptr);
+
+    if (attestation_chain == nullptr) {
+        LOG(ERROR) << "Error getting attestation chain";
+        return {};
+    }
+
+    const keymaster_key_blob_t* attestation_signing_key =
+            ::keymaster::getAttestationKey(KM_ALGORITHM_EC, nullptr);
+    if (attestation_signing_key == nullptr) {
+        LOG(ERROR) << "Error getting attestation key";
+        return {};
+    }
+
+    keymaster_error_t error;
+    ::keymaster::CertChainPtr cert_chain_out;
+    ::keymaster::PureSoftKeymasterContext context;
+
+    // set identity version to 10 per hal requirements specified in IWriteableCredential.hal
+    // For now, the identity version in the attestation is set in the keymaster
+    // version field in the portable keymaster lib, which is a bit misleading.
+    uint identity_version = 10;
+    error = generate_attestation_from_EVP(key, swEnforced, hwEnforced, auth_set, context,
+                                          identity_version, *attestation_chain,
+                                          *attestation_signing_key, &cert_chain_out);
+
+    if (KM_ERROR_OK != error || !cert_chain_out) {
+        LOG(ERROR) << "Error generate attestation from EVP key" << error;
+        return {};
+    }
+
+    // translate certificate format from keymaster_cert_chain_t to vector<uint8_t>.
+    vector<vector<uint8_t>> attestationCertificate;
+    for (int i = 0; i < cert_chain_out->entry_count; i++) {
+        attestationCertificate.insert(
+                attestationCertificate.end(),
+                vector<uint8_t>(
+                        cert_chain_out->entries[i].data,
+                        cert_chain_out->entries[i].data + cert_chain_out->entries[i].data_length));
+    }
+
+    return attestationCertificate;
+}
+
+optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
+        const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId) {
+    auto ec_key = ::keymaster::EC_KEY_Ptr(EC_KEY_new());
+    auto pkey = ::keymaster::EVP_PKEY_Ptr(EVP_PKEY_new());
+    auto group = ::keymaster::EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+
+    if (ec_key.get() == nullptr || pkey.get() == nullptr) {
+        LOG(ERROR) << "Memory allocation failed";
+        return {};
+    }
+
+    if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 ||
+        EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) {
+        LOG(ERROR) << "Error generating key";
+        return {};
+    }
+
+    if (EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()) != 1) {
+        LOG(ERROR) << "Error getting private key";
+        return {};
+    }
+
+    uint64_t now = time(nullptr);
+    uint64_t secondsInOneYear = 365 * 24 * 60 * 60;
+    uint64_t expireTimeMs = (now + secondsInOneYear) * 1000;
+
+    optional<vector<vector<uint8_t>>> attestationCert =
+            createAttestation(pkey.get(), applicationId, challenge, now * 1000, expireTimeMs);
+    if (!attestationCert) {
+        LOG(ERROR) << "Error create attestation from key and challenge";
+        return {};
+    }
+
+    int size = i2d_PrivateKey(pkey.get(), nullptr);
+    if (size == 0) {
+        LOG(ERROR) << "Error generating public key encoding";
+        return {};
+    }
+
+    vector<uint8_t> keyPair(size);
+    unsigned char* p = keyPair.data();
+    i2d_PrivateKey(pkey.get(), &p);
+
+    return make_pair(keyPair, attestationCert.value());
+}
+
 optional<vector<uint8_t>> createEcKeyPair() {
     auto ec_key = EC_KEY_Ptr(EC_KEY_new());
     auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new());
diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
index 6c186f6..40eb142 100644
--- a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
@@ -101,6 +101,7 @@
 DECLARE_KM_4_1_TYPED_TAG(EARLY_BOOT_ONLY);
 DECLARE_KM_4_1_TYPED_TAG(DEVICE_UNIQUE_ATTESTATION);
 DECLARE_KM_4_1_TYPED_TAG(STORAGE_KEY);
+DECLARE_KM_4_1_TYPED_TAG(IDENTITY_CREDENTIAL_KEY);
 
 }  // namespace android::hardware::keymaster::V4_1