Add 'exclude parent' option to debug.

We could add this to list in the future if it seems useful.

This allows someone to call debug on all registered hal instances
without dumping subclasses multiple times.

Bug: 72123369
Test: w/ bugreport using this and manual
Change-Id: Ib201194a9f81ae1aded7105d123ac6399c847494
diff --git a/cmds/lshal/DebugCommand.cpp b/cmds/lshal/DebugCommand.cpp
index f371320..dd8812d 100644
--- a/cmds/lshal/DebugCommand.cpp
+++ b/cmds/lshal/DebugCommand.cpp
@@ -35,6 +35,14 @@
     if (optind >= arg.argc) {
         return USAGE;
     }
+
+    // Optargs cannnot be used because the flag should not be considered set
+    // if it should really be contained in mOptions.
+    if (std::string(arg.argv[optind]) == "-E") {
+        mExcludesParentInstances = true;
+        optind++;
+    }
+
     mInterfaceName = arg.argv[optind];
     ++optind;
     for (; optind < arg.argc; ++optind) {
@@ -59,6 +67,7 @@
 
     return mLshal.emitDebugInfo(
             pair.first, pair.second.empty() ? "default" : pair.second, mOptions,
+            mExcludesParentInstances,
             mLshal.out().buf(),
             mLshal.err());
 }
@@ -67,8 +76,9 @@
 
     static const std::string debug =
             "debug:\n"
-            "    lshal debug <interface> [options [options [...]]] \n"
+            "    lshal debug [-E] <interface> [options [options [...]]] \n"
             "        Print debug information of a specified interface.\n"
+            "        -E: excludes debug output if HAL is actually a subclass.\n"
             "        <inteface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n"
             "            If instance name is missing `default` is used.\n"
             "        options: space separated options to IBase::debug.\n";
diff --git a/cmds/lshal/DebugCommand.h b/cmds/lshal/DebugCommand.h
index 9b91084..6e12008 100644
--- a/cmds/lshal/DebugCommand.h
+++ b/cmds/lshal/DebugCommand.h
@@ -43,6 +43,10 @@
     std::string mInterfaceName;
     std::vector<std::string> mOptions;
 
+    // Outputs the actual descriptor of a hal instead of the debug output
+    // if the arguments provided are a superclass of the actual hal impl.
+    bool mExcludesParentInstances;
+
     DISALLOW_COPY_AND_ASSIGN(DebugCommand);
 };
 
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 7399692..e4b3c90 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -397,7 +397,8 @@
             emitDebugInfo = [this](const auto& iName) {
                 std::stringstream ss;
                 auto pair = splitFirst(iName, '/');
-                mLshal.emitDebugInfo(pair.first, pair.second, {}, ss,
+                mLshal.emitDebugInfo(pair.first, pair.second, {},
+                                     false /* excludesParentInstances */, ss,
                                      NullableOStream<std::ostream>(nullptr));
                 return ss.str();
             };
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index c6f28ac..8c83457 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -23,6 +23,7 @@
 #include <string>
 
 #include <hidl/ServiceManagement.h>
+#include <hidl/HidlTransportUtils.h>
 
 #include "DebugCommand.h"
 #include "ListCommand.h"
@@ -97,9 +98,11 @@
         const std::string &interfaceName,
         const std::string &instanceName,
         const std::vector<std::string> &options,
+        bool excludesParentInstances,
         std::ostream &out,
         NullableOStream<std::ostream> err) const {
     using android::hidl::base::V1_0::IBase;
+    using android::hardware::details::getDescriptor;
 
     hardware::Return<sp<IBase>> retBase = serviceManager()->get(interfaceName, instanceName);
 
@@ -120,6 +123,18 @@
         return NO_INTERFACE;
     }
 
+    if (excludesParentInstances) {
+        const std::string descriptor = getDescriptor(base.get());
+        if (descriptor.empty()) {
+            std::string msg = interfaceName + "/" + instanceName + " getDescriptor failed";
+            err << msg << std::endl;
+            LOG(ERROR) << msg;
+        }
+        if (descriptor != interfaceName) {
+            return OK;
+        }
+    }
+
     PipeRelay relay(out);
 
     if (relay.initCheck() != OK) {
diff --git a/cmds/lshal/Lshal.h b/cmds/lshal/Lshal.h
index 690f30e..9457f1e 100644
--- a/cmds/lshal/Lshal.h
+++ b/cmds/lshal/Lshal.h
@@ -51,6 +51,7 @@
             const std::string &interfaceName,
             const std::string &instanceName,
             const std::vector<std::string> &options,
+            bool excludesParentInstances,
             std::ostream &out,
             NullableOStream<std::ostream> err) const;