Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 829f3c6d authored by Andreas Huber's avatar Andreas Huber Committed by android-build-merger
Browse files

Merge "Enable --debug option for "lshal" command." am: 16175ca7

am: 674d3acd

Change-Id: If87550eb68a9c8e280d8863063b4311a44ff6896
parents 400e9a72 674d3acd
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ cc_binary {
    name: "lshal",
    shared_libs: [
        "libbase",
        "libcutils",
        "libutils",
        "libhidlbase",
        "libhidltransport",
@@ -24,6 +25,7 @@ cc_binary {
        "android.hidl.manager@1.0",
    ],
    srcs: [
        "Lshal.cpp"
        "Lshal.cpp",
        "PipeRelay.cpp"
    ],
}
+81 −1
Original line number Diff line number Diff line
@@ -25,13 +25,17 @@
#include <sstream>
#include <regex>

#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl/ServiceManagement.h>
#include <hidl-util/FQName.h>
#include <private/android_filesystem_config.h>
#include <sys/stat.h>
#include <vintf/HalManifest.h>
#include <vintf/parse_xml.h>

#include "PipeRelay.h"
#include "Timeout.h"

using ::android::hardware::hidl_string;
@@ -357,6 +361,52 @@ static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo:
    }
}

// A unique_ptr type using a custom deleter function.
template<typename T>
using deleted_unique_ptr = std::unique_ptr<T, std::function<void(T *)> >;

void Lshal::emitDebugInfo(
        const sp<IServiceManager> &serviceManager,
        const std::string &interfaceName,
        const std::string &instanceName) const {
    using android::hidl::base::V1_0::IBase;

    hardware::Return<sp<IBase>> retBase =
        serviceManager->get(interfaceName, instanceName);

    sp<IBase> base;
    if (!retBase.isOk() || (base = retBase) == nullptr) {
        // There's a small race, where a service instantiated while collecting
        // the list of services has by now terminated, so this isn't anything
        // to be concerned about.
        return;
    }

    PipeRelay relay(mOut.buf());

    if (relay.initCheck() != OK) {
        LOG(ERROR) << "PipeRelay::initCheck() FAILED w/ " << relay.initCheck();
        return;
    }

    deleted_unique_ptr<native_handle_t> fdHandle(
        native_handle_create(1 /* numFds */, 0 /* numInts */),
        native_handle_delete);

    fdHandle->data[0] = relay.fd();

    hardware::hidl_vec<hardware::hidl_string> options;
    hardware::Return<void> ret = base->debug(fdHandle.get(), options);

    if (!ret.isOk()) {
        LOG(ERROR)
            << interfaceName
            << "::debug(...) FAILED. (instance "
            << instanceName
            << ")";
    }
}

void Lshal::dumpTable() {
    mServicesTable.description =
            "All binderized services (registered services through hwservicemanager)";
@@ -374,6 +424,16 @@ void Lshal::dumpTable() {
        mOut << std::left;
        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,
@@ -383,6 +443,11 @@ void Lshal::dumpTable() {
                    entry.serverObjectAddress == NO_PTR ? "N/A" : toHexString(entry.serverObjectAddress),
                    join(entry.clientPids, " "),
                    join(entry.clientCmdlines, ";"));

            if (serviceManager != nullptr) {
                auto pair = splitFirst(entry.interfaceName, '/');
                emitDebugInfo(serviceManager, pair.first, pair.second);
            }
        }
        mOut << std::endl;
    });
@@ -626,6 +691,7 @@ Status Lshal::parseArgs(int argc, char **argv) {
        {"address",   no_argument,       0, 'a' },
        {"clients",   no_argument,       0, 'c' },
        {"cmdline",   no_argument,       0, 'm' },
        {"debug",     optional_argument, 0, 'd' },

        // long options without short alternatives
        {"sort",      required_argument, 0, 's' },
@@ -638,7 +704,7 @@ Status Lshal::parseArgs(int argc, char **argv) {
    optind = 1;
    for (;;) {
        // using getopt_long in case we want to add other options in the future
        c = getopt_long(argc, argv, "hitrpacm", longOptions, &optionIndex);
        c = getopt_long(argc, argv, "hitrpacmd", longOptions, &optionIndex);
        if (c == -1) {
            break;
        }
@@ -694,6 +760,20 @@ Status Lshal::parseArgs(int argc, char **argv) {
            mEnableCmdlines = true;
            break;
        }
        case 'd': {
            mEmitDebugInfo = true;

            if (optarg) {
                mFileOutput = new std::ofstream{optarg};
                mOut = mFileOutput;
                if (!mFileOutput.buf().is_open()) {
                    mErr << "Could not open file '" << optarg << "'." << std::endl;
                    return IO_ERROR;
                }
                chown(optarg, AID_SHELL, AID_SHELL);
            }
            break;
        }
        case 'h': // falls through
        default: // see unrecognized options
            usage();
+9 −0
Original line number Diff line number Diff line
@@ -77,6 +77,11 @@ private:
    void forEachTable(const std::function<void(Table &)> &f);
    void forEachTable(const std::function<void(const Table &)> &f) const;

    void emitDebugInfo(
            const sp<hidl::manager::V1_0::IServiceManager> &serviceManager,
            const std::string &interfaceName,
            const std::string &instanceName) const;

    Table mServicesTable{};
    Table mPassthroughRefTable{};
    Table mImplementationsTable{};
@@ -88,6 +93,10 @@ private:
    TableEntrySelect mSelectedColumns = 0;
    // If true, cmdlines will be printed instead of pid.
    bool mEnableCmdlines = false;

    // If true, calls IBase::debug(...) on each service.
    bool mEmitDebugInfo = false;

    bool mVintf = false;
    // If an entry does not exist, need to ask /proc/{pid}/cmdline to get it.
    // If an entry exist but is an empty string, process might have died.
+108 −0
Original line number Diff line number Diff line
/*
 * 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 "PipeRelay.h"

#include <sys/socket.h>
#include <utils/Thread.h>

namespace android {
namespace lshal {

struct PipeRelay::RelayThread : public Thread {
    explicit RelayThread(int fd, std::ostream &os);

    bool threadLoop() override;

private:
    int mFd;
    std::ostream &mOutStream;

    DISALLOW_COPY_AND_ASSIGN(RelayThread);
};

////////////////////////////////////////////////////////////////////////////////

PipeRelay::RelayThread::RelayThread(int fd, std::ostream &os)
    : mFd(fd),
      mOutStream(os) {
}

bool PipeRelay::RelayThread::threadLoop() {
    char buffer[1024];
    ssize_t n = read(mFd, buffer, sizeof(buffer));

    if (n <= 0) {
        return false;
    }

    mOutStream.write(buffer, n);

    return true;
}

////////////////////////////////////////////////////////////////////////////////

PipeRelay::PipeRelay(std::ostream &os)
    : mOutStream(os),
      mInitCheck(NO_INIT) {
    int res = socketpair(AF_UNIX, SOCK_STREAM, 0 /* protocol */, mFds);

    if (res < 0) {
        mInitCheck = -errno;
        return;
    }

    mThread = new RelayThread(mFds[0], os);
    mInitCheck = mThread->run("RelayThread");
}

// static
void PipeRelay::CloseFd(int *fd) {
    if (*fd >= 0) {
        close(*fd);
        *fd = -1;
    }
}

PipeRelay::~PipeRelay() {
    if (mFds[1] >= 0) {
        shutdown(mFds[1], SHUT_WR);
    }

    if (mFds[0] >= 0) {
        shutdown(mFds[0], SHUT_RD);
    }

    if (mThread != NULL) {
        mThread->join();
        mThread.clear();
    }

    CloseFd(&mFds[1]);
    CloseFd(&mFds[0]);
}

status_t PipeRelay::initCheck() const {
    return mInitCheck;
}

int PipeRelay::fd() const {
    return mFds[1];
}

}  // namespace lshal
}  // namespace android

cmds/lshal/PipeRelay.h

0 → 100644
+59 −0
Original line number Diff line number Diff line
/*
 * 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 FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_

#define FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_

#include <android-base/macros.h>
#include <ostream>
#include <utils/Errors.h>
#include <utils/RefBase.h>

namespace android {
namespace lshal {

/* Creates an AF_UNIX socketpair and spawns a thread that relays any data
 * written to the "write"-end of the pair to the specified output stream "os".
 */
struct PipeRelay {
    explicit PipeRelay(std::ostream &os);
    ~PipeRelay();

    status_t initCheck() const;

    // Returns the file descriptor corresponding to the "write"-end of the
    // connection.
    int fd() const;

private:
    struct RelayThread;

    std::ostream &mOutStream;
    status_t mInitCheck;
    int mFds[2];
    sp<RelayThread> mThread;

    static void CloseFd(int *fd);

    DISALLOW_COPY_AND_ASSIGN(PipeRelay);
};

}  // namespace lshal
}  // namespace android

#endif  // FRAMEWORKS_NATIVE_CMDS_LSHAL_PIPE_RELAY_H_