OSDN Git Service

Add `lshal debug` command.
authorYifan Hong <elsk@google.com>
Wed, 10 May 2017 02:33:08 +0000 (19:33 -0700)
committerYifan Hong <elsk@google.com>
Mon, 15 May 2017 18:02:43 +0000 (11:02 -0700)
Supported command:
    lshal debug android.hardware.foo@1.0::IFoo option option

Test: adb unroot && lshal --debug ; echo $?
Test: adb unroot && lshal debug android.hardware.nfc@1.0::INfc ; echo $?
Test: adb root && lshal --debug ; echo $?
Test: adb root && lshal debug android.hardware.nfc@1.0::INfc ; echo $?

Bug: 37725279
Change-Id: Ia2f4c9c0d3fb0a7bb26e76f01d02f49dc426e7f8
Merged-In: Ia2f4c9c0d3fb0a7bb26e76f01d02f49dc426e7f8

cmds/lshal/Android.bp
cmds/lshal/DebugCommand.cpp [new file with mode: 0644]
cmds/lshal/DebugCommand.h [new file with mode: 0644]
cmds/lshal/ListCommand.cpp
cmds/lshal/Lshal.cpp
cmds/lshal/Lshal.h
cmds/lshal/utils.h

index 13d3170..0ff94d9 100644 (file)
@@ -25,6 +25,7 @@ cc_binary {
         "android.hidl.manager@1.0",
     ],
     srcs: [
+        "DebugCommand.cpp",
         "Lshal.cpp",
         "ListCommand.cpp",
         "PipeRelay.cpp",
diff --git a/cmds/lshal/DebugCommand.cpp b/cmds/lshal/DebugCommand.cpp
new file mode 100644 (file)
index 0000000..672cad6
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 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 "DebugCommand.h"
+
+#include "Lshal.h"
+
+namespace android {
+namespace lshal {
+
+DebugCommand::DebugCommand(Lshal &lshal) : mLshal(lshal) {
+}
+
+Status DebugCommand::parseArgs(const std::string &command, const Arg &arg) {
+    if (optind >= arg.argc) {
+        mLshal.usage(command);
+        return USAGE;
+    }
+    mInterfaceName = arg.argv[optind];
+    ++optind;
+    for (; optind < arg.argc; ++optind) {
+        mOptions.push_back(arg.argv[optind]);
+    }
+    return OK;
+}
+
+Status DebugCommand::main(const std::string &command, const Arg &arg) {
+    Status status = parseArgs(command, arg);
+    if (status != OK) {
+        return status;
+    }
+    auto pair = splitFirst(mInterfaceName, '/');
+    return mLshal.emitDebugInfo(
+            pair.first, pair.second.empty() ? "default" : pair.second, mOptions,
+            mLshal.out().buf(),
+            mLshal.err());
+}
+
+}  // namespace lshal
+}  // namespace android
+
diff --git a/cmds/lshal/DebugCommand.h b/cmds/lshal/DebugCommand.h
new file mode 100644 (file)
index 0000000..fa0f0fa
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_
+
+#include <string>
+
+#include <android-base/macros.h>
+
+#include "utils.h"
+
+namespace android {
+namespace lshal {
+
+class Lshal;
+
+class DebugCommand {
+public:
+    DebugCommand(Lshal &lshal);
+    Status main(const std::string &command, const Arg &arg);
+private:
+    Status parseArgs(const std::string &command, const Arg &arg);
+
+    Lshal &mLshal;
+    std::string mInterfaceName;
+    std::vector<std::string> mOptions;
+
+    DISALLOW_COPY_AND_ASSIGN(DebugCommand);
+};
+
+
+}  // namespace lshal
+}  // namespace android
+
+#endif  // FRAMEWORK_NATIVE_CMDS_LSHAL_DEBUG_COMMAND_H_
index 5696843..a0ed7a3 100644 (file)
@@ -350,15 +350,6 @@ void ListCommand::dumpTable() {
         printLine("Interface", "Transport", "Arch", "Server", "Server CMD",
                   "PTR", "Clients", "Clients CMD");
 
-        // We're only interested in dumping debug info for already
-        // instantiated services. There's little value in dumping the
-        // debug info for a service we create on the fly, so we only operate
-        // on the "mServicesTable".
-        sp<IServiceManager> serviceManager;
-        if (mEmitDebugInfo && &table == &mServicesTable) {
-            serviceManager = ::android::hardware::defaultServiceManager();
-        }
-
         for (const auto &entry : table) {
             printLine(entry.interfaceName,
                     entry.transport,
@@ -369,9 +360,14 @@ void ListCommand::dumpTable() {
                     join(entry.clientPids, " "),
                     join(entry.clientCmdlines, ";"));
 
-            if (serviceManager != nullptr) {
+            // We're only interested in dumping debug info for already
+            // instantiated services. There's little value in dumping the
+            // debug info for a service we create on the fly, so we only operate
+            // on the "mServicesTable".
+            if (mEmitDebugInfo && &table == &mServicesTable) {
                 auto pair = splitFirst(entry.interfaceName, '/');
-                mLshal.emitDebugInfo(serviceManager, pair.first, pair.second, {}, mOut.buf());
+                mLshal.emitDebugInfo(pair.first, pair.second, {}, mOut.buf(),
+                        NullableOStream<std::ostream>(nullptr));
             }
         }
         mOut << std::endl;
index 43108b7..bf4ba2c 100644 (file)
  * limitations under the License.
  */
 
+#define LOG_TAG "lshal"
+#include <android-base/logging.h>
+
 #include "Lshal.h"
 
 #include <set>
 #include <string>
 
+#include <hidl/ServiceManagement.h>
+
+#include "DebugCommand.h"
 #include "ListCommand.h"
 #include "PipeRelay.h"
 
@@ -111,29 +117,41 @@ static hardware::hidl_vec<hardware::hidl_string> convert(const std::vector<std::
     return hv;
 }
 
-// static
-void Lshal::emitDebugInfo(
-        const sp<IServiceManager> &serviceManager,
+Status Lshal::emitDebugInfo(
         const std::string &interfaceName,
         const std::string &instanceName,
         const std::vector<std::string> &options,
-        std::ostream &out) {
+        std::ostream &out,
+        NullableOStream<std::ostream> err) const {
     using android::hidl::base::V1_0::IBase;
 
     hardware::Return<sp<IBase>> retBase =
-        serviceManager->get(interfaceName, instanceName);
+        ::android::hardware::defaultServiceManager()->get(interfaceName, instanceName);
+
+    if (!retBase.isOk()) {
+        std::string msg = "Cannot get " + interfaceName + "/" + instanceName + ": "
+                + retBase.description();
+        err << msg << std::endl;
+        LOG(ERROR) << msg;
+        return TRANSACTION_ERROR;
+    }
 
-    sp<IBase> base;
-    if (!retBase.isOk() || (base = retBase) == nullptr) {
-        mErr << interfaceName << "/" << instanceName << " does not exist." << std::endl;
-        return;
+    sp<IBase> base = retBase;
+    if (base == nullptr) {
+        std::string msg = interfaceName + "/" + instanceName + " does not exist, or "
+                + "no permission to connect.";
+        err << msg << std::endl;
+        LOG(ERROR) << msg;
+        return NO_INTERFACE;
     }
 
     PipeRelay relay(out);
 
     if (relay.initCheck() != OK) {
-        mErr << "PipeRelay::initCheck() FAILED w/ " << relay.initCheck() << std::endl;
-        return;
+        std::string msg = "PipeRelay::initCheck() FAILED w/ " + std::to_string(relay.initCheck());
+        err << msg << std::endl;
+        LOG(ERROR) << msg;
+        return IO_ERROR;
     }
 
     deleted_unique_ptr<native_handle_t> fdHandle(
@@ -145,12 +163,13 @@ void Lshal::emitDebugInfo(
     hardware::Return<void> ret = base->debug(fdHandle.get(), convert(options));
 
     if (!ret.isOk()) {
-        LOG(ERROR)
-            << interfaceName
-            << "::debug(...) FAILED. (instance "
-            << instanceName
-            << ")";
+        std::string msg = "debug() FAILED on " + interfaceName + "/" + instanceName + ": "
+                + ret.description();
+        err << msg << std::endl;
+        LOG(ERROR) << msg;
+        return TRANSACTION_ERROR;
     }
+    return OK;
 }
 
 Status Lshal::parseArgs(const Arg &arg) {
@@ -191,8 +210,7 @@ Status Lshal::main(const Arg &arg) {
         return ListCommand{*this}.main(mCommand, arg);
     }
     if (mCommand == "debug") {
-        // TODO(b/37725279) implement this
-        return OK;
+        return DebugCommand{*this}.main(mCommand, arg);
     }
     usage();
     return USAGE;
index cabf503..cf77b6b 100644 (file)
@@ -38,12 +38,12 @@ public:
     NullableOStream<std::ostream> err() const;
     NullableOStream<std::ostream> out() const;
 
-    static void emitDebugInfo(
-            const sp<hidl::manager::V1_0::IServiceManager> &serviceManager,
+    Status emitDebugInfo(
             const std::string &interfaceName,
             const std::string &instanceName,
             const std::vector<std::string> &options,
-            std::ostream &out);
+            std::ostream &out,
+            NullableOStream<std::ostream> err) const;
 private:
     Status parseArgs(const Arg &arg);
     std::string mCommand;
index 9720094..45b922c 100644 (file)
@@ -36,6 +36,8 @@ enum : unsigned int {
     DUMP_PASSTHROUGH_ERROR                  = 1 << 4,
     DUMP_ALL_LIBS_ERROR                     = 1 << 5,
     IO_ERROR                                = 1 << 6,
+    NO_INTERFACE                            = 1 << 7,
+    TRANSACTION_ERROR                       = 1 << 8,
 };
 using Status = unsigned int;