Added VehicleHal.dump()

This (optional) function allows the HAL implementation customize lshal debug;
for example, it could:
  - augment dump() by dumping its own state
  - disable dump()
  - dump specific state based on arguments
  - run custom commands based on arguments

This CL also implements this method in the emulated vehicle HAL, where it adds
options to dump the user-related state.

Bug: 146207078

Test: adb shell lshal debug android.hardware.automotive.vehicle@2.0::IVehicle/default --user-hal
Test: atest android.hardware.automotive.vehicle@2.0-manager-unit-tests \
          android.hardware.automotive.vehicle@2.0-default-impl-unit-tests

Change-Id: If04e8222a31448f170ab2b54552051196b6ab958
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
index d40f122..00b5afe 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleConnector.h
@@ -65,6 +65,12 @@
     // updateStatus is true if and only if the value is
     // generated by car (ECU/fake generator/injected)
     virtual void onPropertyValue(const VehiclePropValue& value, bool updateStatus) = 0;
+
+    // Dump method forwarded from HIDL's debug()
+    // If implemented, it must return whether the caller should dump its state.
+    virtual bool dump(const hidl_handle& /* handle */, const hidl_vec<hidl_string>& /* options */) {
+        return true;
+    }
 };
 
 /**
@@ -97,6 +103,13 @@
     // updateStatus is true if and only if the value is
     // generated by car (ECU/fake generator/injected)
     virtual void onPropertyValueFromCar(const VehiclePropValue& value, bool updateStatus) = 0;
+
+    // Dump method forwarded from HIDL's debug()
+    // If implemented, it must return whether the caller should dump its state.
+    virtual bool onDump(const hidl_handle& /* handle */,
+                        const hidl_vec<hidl_string>& /* options */) {
+        return true;
+    }
 };
 
 /**
@@ -134,6 +147,10 @@
         return this->onPropertyValue(value, updateStatus);
     }
 
+    bool dump(const hidl_handle& handle, const hidl_vec<hidl_string>& options) override {
+        return this->onDump(handle, options);
+    }
+
     // To be implemented:
     // virtual std::vector<VehiclePropConfig> onGetAllPropertyConfig() = 0;
     // virtual void onPropertyValue(const VehiclePropValue& value) = 0;
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
index fd28483..fe01867 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHal.h
@@ -70,6 +70,26 @@
      */
     virtual void onCreate() {}
 
+    /**
+     * Dump method forwarded from HIDL's debug().
+     *
+     * By default it doesn't dump anything and let caller dump its properties, but it could be
+     * override to change the behavior. For example:
+     *
+     * - To augment caller's dump, it should dump its state and return true.
+     * - To not dump anything at all, it should just return false.
+     * - To provide custom dump (like dumping just specific state or executing a custom command),
+     *   it should check if options is not empty, handle the options accordingly, then return false.
+     *
+     * @param handle handle used to dump the contents.
+     * @param options options passed to dump.
+     *
+     * @return whether the caller should dump its state.
+     */
+    virtual bool dump(const hidl_handle& /* handle */, const hidl_vec<hidl_string>& /* options */) {
+        return true;
+    }
+
     void init(
         VehiclePropValuePool* valueObjectPool,
         const HalEventFunction& onHalEvent,
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
index 4f42e63..5bebd1e 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
@@ -186,11 +186,19 @@
 }
 
 Return<void> VehicleHalManager::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
-    if (fd.getNativeHandle() != nullptr && fd->numFds > 0) {
-        cmdDump(fd->data[0], options);
-    } else {
+    if (fd.getNativeHandle() == nullptr || fd->numFds == 0) {
         ALOGE("Invalid parameters passed to debug()");
+        return Void();
     }
+
+    bool shouldContinue = mHal->dump(fd, options);
+    if (!shouldContinue) {
+        ALOGI("Dumped HAL only");
+        return Void();
+    }
+
+    // Do our dump
+    cmdDump(fd->data[0], options);
     return Void();
 }
 
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 197c6db..63ad93c 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
@@ -16,6 +16,8 @@
 
 #define LOG_TAG "automotive.vehicle@2.0-connector"
 
+#include <fstream>
+
 #include <android-base/logging.h>
 #include <utils/SystemClock.h>
 
@@ -370,6 +372,43 @@
     return StatusCode::OK;
 }
 
+bool EmulatedVehicleServer::onDump(const hidl_handle& handle,
+                                   const hidl_vec<hidl_string>& options) {
+    int fd = handle->data[0];
+
+    if (options.size() > 0) {
+        if (options[0] == "--help") {
+            dprintf(fd, "Emulator-specific usage:\n");
+            dprintf(fd, "--user-hal: dumps state used for user management \n");
+            dprintf(fd, "\n");
+            // Include caller's help options
+            return true;
+        } else if (options[0] == "--user-hal") {
+            dumpUserHal(fd, "");
+            return false;
+
+        } else {
+            // Let caller handle the options...
+            return true;
+        }
+    }
+
+    dprintf(fd, "Emulator-specific state:\n");
+    dumpUserHal(fd, "  ");
+    dprintf(fd, "\n");
+
+    return true;
+}
+
+void EmulatedVehicleServer::dumpUserHal(int fd, std::string indent) {
+    if (mInitialUserResponseFromCmd != nullptr) {
+        dprintf(fd, "%sInitial User Info: %s\n", indent.c_str(),
+                toString(*mInitialUserResponseFromCmd).c_str());
+    } else {
+        dprintf(fd, "%sNo Initial User Info\n", indent.c_str());
+    }
+}
+
 EmulatedPassthroughConnectorPtr 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 6d927b0..4850d32 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
@@ -54,6 +54,8 @@
 
     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);
 
@@ -81,6 +83,7 @@
     // 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
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 5c16bf7..692c7f7 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
@@ -131,6 +131,10 @@
     return v;
 }
 
+bool EmulatedVehicleHal::dump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
+    return mVehicleClient->dump(fd, options);
+}
+
 StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
     constexpr bool updateStatus = false;
 
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 a8378da..ebc405e 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
@@ -57,6 +57,7 @@
     StatusCode set(const VehiclePropValue& propValue) override;
     StatusCode subscribe(int32_t property, float sampleRate) override;
     StatusCode unsubscribe(int32_t property) override;
+    bool dump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
 
     //  Methods from EmulatedVehicleHalIface
     bool setPropertyFromVehicle(const VehiclePropValue& propValue) override;