lshal: --debug omits info on parent objects.
Instead, print a short message that contains the information on the row that it should look up. Test: lshal --debug Test: lshal debug -E android.hardware.health@2.0::IHealth/default Test: lshal_test Fixes: 160745145 Change-Id: I7d5ab9fba097c0fb0b080ec52682084c65ba9f50
This commit is contained in:
parent
5cceea8d0b
commit
6884b87a37
7 changed files with 132 additions and 9 deletions
|
@ -39,7 +39,7 @@ Status DebugCommand::parseArgs(const Arg &arg) {
|
|||
// 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;
|
||||
mParentDebugInfoLevel = ParentDebugInfoLevel::NOTHING;
|
||||
optind++;
|
||||
}
|
||||
|
||||
|
@ -67,7 +67,7 @@ Status DebugCommand::main(const Arg &arg) {
|
|||
|
||||
return mLshal.emitDebugInfo(
|
||||
pair.first, pair.second.empty() ? "default" : pair.second, mOptions,
|
||||
mExcludesParentInstances,
|
||||
mParentDebugInfoLevel,
|
||||
mLshal.out().buf(),
|
||||
mLshal.err());
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <android-base/macros.h>
|
||||
|
||||
#include "Command.h"
|
||||
#include "ParentDebugInfoLevel.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace android {
|
||||
|
@ -42,9 +43,8 @@ private:
|
|||
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;
|
||||
// See comment on ParentDebugInfoLevel.
|
||||
ParentDebugInfoLevel mParentDebugInfoLevel = ParentDebugInfoLevel::FULL;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DebugCommand);
|
||||
};
|
||||
|
|
|
@ -555,7 +555,7 @@ void ListCommand::dumpTable(const NullableOStream<std::ostream>& out) const {
|
|||
std::stringstream ss;
|
||||
auto pair = splitFirst(iName, '/');
|
||||
mLshal.emitDebugInfo(pair.first, pair.second, {},
|
||||
false /* excludesParentInstances */, ss,
|
||||
ParentDebugInfoLevel::FQNAME_ONLY, ss,
|
||||
NullableOStream<std::ostream>(nullptr));
|
||||
return ss.str();
|
||||
};
|
||||
|
|
|
@ -101,7 +101,7 @@ Status Lshal::emitDebugInfo(
|
|||
const std::string &interfaceName,
|
||||
const std::string &instanceName,
|
||||
const std::vector<std::string> &options,
|
||||
bool excludesParentInstances,
|
||||
ParentDebugInfoLevel parentDebugInfoLevel,
|
||||
std::ostream &out,
|
||||
NullableOStream<std::ostream> err) const {
|
||||
using android::hidl::base::V1_0::IBase;
|
||||
|
@ -126,7 +126,7 @@ Status Lshal::emitDebugInfo(
|
|||
return NO_INTERFACE;
|
||||
}
|
||||
|
||||
if (excludesParentInstances) {
|
||||
if (parentDebugInfoLevel != ParentDebugInfoLevel::FULL) {
|
||||
const std::string descriptor = getDescriptor(base.get());
|
||||
if (descriptor.empty()) {
|
||||
std::string msg = interfaceName + "/" + instanceName + " getDescriptor failed";
|
||||
|
@ -134,6 +134,9 @@ Status Lshal::emitDebugInfo(
|
|||
LOG(ERROR) << msg;
|
||||
}
|
||||
if (descriptor != interfaceName) {
|
||||
if (parentDebugInfoLevel == ParentDebugInfoLevel::FQNAME_ONLY) {
|
||||
out << "[See " << descriptor << "/" << instanceName << "]";
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "Command.h"
|
||||
#include "NullableOStream.h"
|
||||
#include "ParentDebugInfoLevel.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace android {
|
||||
|
@ -49,7 +50,7 @@ public:
|
|||
const std::string &interfaceName,
|
||||
const std::string &instanceName,
|
||||
const std::vector<std::string> &options,
|
||||
bool excludesParentInstances,
|
||||
ParentDebugInfoLevel parentDebugInfoLevel,
|
||||
std::ostream &out,
|
||||
NullableOStream<std::ostream> err) const;
|
||||
|
||||
|
|
34
cmds/lshal/ParentDebugInfoLevel.h
Normal file
34
cmds/lshal/ParentDebugInfoLevel.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
namespace android {
|
||||
namespace lshal {
|
||||
|
||||
// Describe verbosity when dumping debug information on a HAL service by
|
||||
// referring to a parent HAL interface FQName (for example, when dumping debug information
|
||||
// on foo@1.0::IFoo but the HAL implementation is foo@1.1::IFoo).
|
||||
enum class ParentDebugInfoLevel {
|
||||
// Write nothing.
|
||||
NOTHING,
|
||||
// Write a short description that includes the FQName of the real implementation.
|
||||
FQNAME_ONLY,
|
||||
// Write full debug info.
|
||||
FULL,
|
||||
};
|
||||
|
||||
} // namespace lshal
|
||||
} // namespace android
|
|
@ -793,6 +793,91 @@ TEST_F(ListTest, Vintf) {
|
|||
EXPECT_EQ("", err.str());
|
||||
}
|
||||
|
||||
// Fake service returned by mocked IServiceManager::get for DumpDebug.
|
||||
// The interfaceChain and getHashChain functions returns
|
||||
// foo(id - 1) -> foo(id - 2) -> ... foo1 -> IBase.
|
||||
class InheritingService : public IBase {
|
||||
public:
|
||||
explicit InheritingService(pid_t id) : mId(id) {}
|
||||
android::hardware::Return<void> interfaceDescriptor(interfaceDescriptor_cb cb) override {
|
||||
cb(getInterfaceName(mId));
|
||||
return hardware::Void();
|
||||
}
|
||||
android::hardware::Return<void> interfaceChain(interfaceChain_cb cb) override {
|
||||
std::vector<hidl_string> ret;
|
||||
for (auto i = mId; i > 0; --i) {
|
||||
ret.push_back(getInterfaceName(i));
|
||||
}
|
||||
ret.push_back(IBase::descriptor);
|
||||
cb(ret);
|
||||
return hardware::Void();
|
||||
}
|
||||
android::hardware::Return<void> getHashChain(getHashChain_cb cb) override {
|
||||
std::vector<hidl_hash> ret;
|
||||
for (auto i = mId; i > 0; --i) {
|
||||
ret.push_back(getHashFromId(i));
|
||||
}
|
||||
ret.push_back(getHashFromId(0xff));
|
||||
cb(ret);
|
||||
return hardware::Void();
|
||||
}
|
||||
android::hardware::Return<void> debug(const hidl_handle& hh,
|
||||
const hidl_vec<hidl_string>&) override {
|
||||
const native_handle_t* handle = hh.getNativeHandle();
|
||||
if (handle->numFds < 1) {
|
||||
return Void();
|
||||
}
|
||||
int fd = handle->data[0];
|
||||
std::string content = "debug info for ";
|
||||
content += getInterfaceName(mId);
|
||||
ssize_t written = write(fd, content.c_str(), content.size());
|
||||
if (written != (ssize_t)content.size()) {
|
||||
LOG(WARNING) << "SERVER(" << descriptor << ") debug writes " << written << " bytes < "
|
||||
<< content.size() << " bytes, errno = " << errno;
|
||||
}
|
||||
return Void();
|
||||
}
|
||||
|
||||
private:
|
||||
pid_t mId;
|
||||
};
|
||||
|
||||
TEST_F(ListTest, DumpDebug) {
|
||||
size_t inheritanceLevel = 3;
|
||||
sp<IBase> service = new InheritingService(inheritanceLevel);
|
||||
|
||||
EXPECT_CALL(*serviceManager, list(_)).WillRepeatedly(Invoke([&](IServiceManager::list_cb cb) {
|
||||
std::vector<hidl_string> ret;
|
||||
for (auto i = 1; i <= inheritanceLevel; ++i) {
|
||||
ret.push_back(getInterfaceName(i) + "/default");
|
||||
}
|
||||
cb(ret);
|
||||
return hardware::Void();
|
||||
}));
|
||||
EXPECT_CALL(*serviceManager, get(_, _))
|
||||
.WillRepeatedly(
|
||||
Invoke([&](const hidl_string&, const hidl_string& instance) -> sp<IBase> {
|
||||
int id = getIdFromInstanceName(instance);
|
||||
if (id > inheritanceLevel) return nullptr;
|
||||
return sp<IBase>(service);
|
||||
}));
|
||||
|
||||
const std::string expected = "[fake description 0]\n"
|
||||
"Interface\n"
|
||||
"a.h.foo1@1.0::IFoo/default\n"
|
||||
"[See a.h.foo3@3.0::IFoo/default]\n"
|
||||
"a.h.foo2@2.0::IFoo/default\n"
|
||||
"[See a.h.foo3@3.0::IFoo/default]\n"
|
||||
"a.h.foo3@3.0::IFoo/default\n"
|
||||
"debug info for a.h.foo3@3.0::IFoo\n"
|
||||
"\n";
|
||||
|
||||
optind = 1; // mimic Lshal::parseArg()
|
||||
EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--types=b", "-id"})));
|
||||
EXPECT_EQ(expected, out.str());
|
||||
EXPECT_EQ("", err.str());
|
||||
}
|
||||
|
||||
class ListVintfTest : public ListTest {
|
||||
public:
|
||||
virtual void SetUp() override {
|
||||
|
|
Loading…
Reference in a new issue