Add lshal debug
command.
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: 37954458 Change-Id: Ia2f4c9c0d3fb0a7bb26e76f01d02f49dc426e7f8
This commit is contained in:
parent
443df7932c
commit
48dc9f8586
7 changed files with 152 additions and 32 deletions
|
@ -24,6 +24,7 @@ cc_binary {
|
|||
"libvintf",
|
||||
],
|
||||
srcs: [
|
||||
"DebugCommand.cpp",
|
||||
"Lshal.cpp",
|
||||
"ListCommand.cpp",
|
||||
"PipeRelay.cpp",
|
||||
|
|
54
cmds/lshal/DebugCommand.cpp
Normal file
54
cmds/lshal/DebugCommand.cpp
Normal file
|
@ -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
|
||||
|
49
cmds/lshal/DebugCommand.h
Normal file
49
cmds/lshal/DebugCommand.h
Normal file
|
@ -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_
|
|
@ -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;
|
||||
|
|
|
@ -14,11 +14,17 @@
|
|||
* 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);
|
||||
|
||||
sp<IBase> base;
|
||||
if (!retBase.isOk() || (base = retBase) == nullptr) {
|
||||
mErr << interfaceName << "/" << instanceName << " does not exist." << std::endl;
|
||||
return;
|
||||
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 = 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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue