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

Commit f31aa05f authored by Yifan Hong's avatar Yifan Hong
Browse files

lshal --init-vintf: can specify manifest partition

lshal --init-vintf [--init-vintf-partition=vendor] generates
device manifest.

lshal --init-vintf --init-vintf-partition=system generates
framework manifest.

lshal --init-vintf --init-vintf-partition=odm generates odm manifest.

Test: the above commands
      health/backup is in system manifest
      IBase is not in any manifest
      graphics.composer/vr is in system manifest

Test: lshal_test

Fixes: 71802285
Change-Id: Ie16c8914218ece5c3cd698c93f2bada1be3ee29f
parent 1cd975c0
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -24,6 +24,9 @@ cc_library_shared {
        "libhidl-gen-utils",
        "libvintf",
    ],
    static_libs: [
        "libprocpartition",
    ],
    srcs: [
        "DebugCommand.cpp",
        "HelpCommand.cpp",
@@ -45,10 +48,14 @@ cc_defaults {
    shared_libs: [
        "libbase",
        "libhidlbase",
        "libhidl-gen-utils",
        "libhidltransport",
        "liblshal",
        "libutils",
    ],
    static_libs: [
        "libprocpartition",
    ],
    cflags: ["-Wall", "-Werror"],
}

+85 −21
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <sstream>
#include <regex>

#include <android-base/file.h>
#include <android-base/parseint.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl-hash/Hash.h>
@@ -32,6 +33,7 @@
#include <private/android_filesystem_config.h>
#include <sys/stat.h>
#include <vintf/HalManifest.h>
#include <vintf/parse_string.h>
#include <vintf/parse_xml.h>

#include "Lshal.h"
@@ -48,6 +50,10 @@ using ::android::hidl::manager::V1_0::IServiceManager;
namespace android {
namespace lshal {

vintf::SchemaType toSchemaType(Partition p) {
    return (p == Partition::SYSTEM) ? vintf::SchemaType::FRAMEWORK : vintf::SchemaType::DEVICE;
}

NullableOStream<std::ostream> ListCommand::out() const {
    return mLshal.out();
}
@@ -64,13 +70,7 @@ std::string ListCommand::getSimpleDescription() const {
}

std::string ListCommand::parseCmdline(pid_t pid) const {
    std::ifstream ifs("/proc/" + std::to_string(pid) + "/cmdline");
    std::string cmdline;
    if (!ifs.is_open()) {
        return "";
    }
    ifs >> cmdline;
    return cmdline;
    return android::procpartition::getCmdline(pid);
}

const std::string &ListCommand::getCmdline(pid_t pid) {
@@ -89,6 +89,42 @@ void ListCommand::removeDeadProcesses(Pids *pids) {
    }), pids->end());
}

Partition ListCommand::getPartition(pid_t pid) {
    auto it = mPartitions.find(pid);
    if (it != mPartitions.end()) {
        return it->second;
    }
    Partition partition = android::procpartition::getPartition(pid);
    mPartitions.emplace(pid, partition);
    return partition;
}

// Give sensible defaults when nothing can be inferred from runtime.
// process: Partition inferred from executable location or cmdline.
Partition ListCommand::resolvePartition(Partition process, const FQName& fqName) const {
    if (fqName.inPackage("vendor") ||
        fqName.inPackage("com")) {
        return Partition::VENDOR;
    }

    if (fqName.inPackage("android.frameworks") ||
        fqName.inPackage("android.system") ||
        fqName.inPackage("android.hidl")) {
        return Partition::SYSTEM;
    }

    // Some android.hardware HALs are served from system. Check the value from executable
    // location / cmdline first.
    if (fqName.inPackage("android.hardware")) {
        if (process != Partition::UNKNOWN) {
            return process;
        }
        return Partition::VENDOR;
    }

    return process;
}

static bool scanBinderContext(pid_t pid,
        const std::string &contextName,
        std::function<void(const std::string&)> eachLine) {
@@ -209,6 +245,9 @@ void ListCommand::postprocess() {
                entry.clientCmdlines.push_back(this->getCmdline(pid));
            }
        }
        for (TableEntry& entry : table) {
            entry.partition = getPartition(entry.serverPid);
        }
    });
    // use a double for loop here because lshal doesn't care about efficiency.
    for (TableEntry &packageEntry : mImplementationsTable) {
@@ -256,18 +295,10 @@ static inline bool findAndBumpVersion(vintf::ManifestHal* hal, const vintf::Vers

void ListCommand::dumpVintf(const NullableOStream<std::ostream>& out) const {
    using vintf::operator|=;
    out << "<!-- " << std::endl
         << "    This is a skeleton device manifest. Notes: " << std::endl
         << "    1. android.hidl.*, android.frameworks.*, android.system.* are not included." << std::endl
         << "    2. If a HAL is supported in both hwbinder and passthrough transport, " << std::endl
         << "       only hwbinder is shown." << std::endl
         << "    3. It is likely that HALs in passthrough transport does not have" << std::endl
         << "       <interface> declared; users will have to write them by hand." << std::endl
         << "    4. A HAL with lower minor version can be overridden by a HAL with" << std::endl
         << "       higher minor version if they have the same name and major version." << std::endl
         << "-->" << std::endl;
    using vintf::operator<<;

    vintf::HalManifest manifest;
    manifest.setType(toSchemaType(mVintfPartition));
    forEachTable([this, &manifest] (const Table &table) {
        for (const TableEntry &entry : table) {

@@ -284,12 +315,23 @@ void ListCommand::dumpVintf(const NullableOStream<std::ostream>& out) const {
                     << "' is not a valid FQName." << std::endl;
                continue;
            }
            // Strip out system libs.
            if (fqName.inPackage("android.hidl") ||
                fqName.inPackage("android.frameworks") ||
                fqName.inPackage("android.system")) {

            if (fqName.package() == gIBaseFqName.package()) {
                continue; // always remove IBase from manifest
            }

            Partition partition = resolvePartition(entry.partition, fqName);

            if (partition == Partition::UNKNOWN) {
                err() << "Warning: Cannot guess the partition of instance " << fqInstanceName
                      << ". It is removed from the generated manifest." << std::endl;
                continue;
            }

            if (partition != mVintfPartition) {
                continue; // strip out instances that is in a different partition.
            }

            std::string interfaceName =
                    &table == &mImplementationsTable ? "" : fqName.name();
            std::string instanceName =
@@ -361,9 +403,22 @@ void ListCommand::dumpVintf(const NullableOStream<std::ostream>& out) const {
            }
        }
    });
    out << "<!-- " << std::endl
         << "    This is a skeleton " << manifest.type() << " manifest. Notes: " << std::endl
         << INIT_VINTF_NOTES
         << "-->" << std::endl;
    out << vintf::gHalManifestConverter(manifest, vintf::SerializeFlag::HALS_ONLY);
}

std::string ListCommand::INIT_VINTF_NOTES{
    "    1. If a HAL is supported in both hwbinder and passthrough transport, \n"
    "       only hwbinder is shown.\n"
    "    2. It is likely that HALs in passthrough transport does not have\n"
    "       <interface> declared; users will have to write them by hand.\n"
    "    3. A HAL with lower minor version can be overridden by a HAL with\n"
    "       higher minor version if they have the same name and major version.\n"
};

static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
    switch (a) {
        case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_64BIT:
@@ -710,9 +765,18 @@ void ListCommand::registerAllOptions() {
    // long options without short alternatives
    mOptions.push_back({'\0', "init-vintf", no_argument, v++, [](ListCommand* thiz, const char* arg) {
        thiz->mVintf = true;
        if (thiz->mVintfPartition == Partition::UNKNOWN)
            thiz->mVintfPartition = Partition::VENDOR;
        if (arg) thiz->mFileOutputPath = arg;
        return OK;
    }, "form a skeleton HAL manifest to specified file,\nor stdout if no file specified."});
    mOptions.push_back({'\0', "init-vintf-partition", required_argument, v++, [](ListCommand* thiz, const char* arg) {
        if (!arg) return USAGE;
        thiz->mVintfPartition = android::procpartition::parsePartition(arg);
        if (thiz->mVintfPartition == Partition::UNKNOWN) return USAGE;
        return OK;
    }, "Specify the partition of the HAL manifest\ngenerated by --init-vintf.\n"
       "Valid values are 'system', 'vendor', and 'odm'. Default is 'vendor'."});
    mOptions.push_back({'\0', "sort", required_argument, v++, [](ListCommand* thiz, const char* arg) {
        if (strcmp(arg, "interface") == 0 || strcmp(arg, "i") == 0) {
            thiz->mSortColumn = TableEntry::sortByInterfaceName;
+13 −2
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@

#include <android-base/macros.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl-util/FQName.h>

#include "Command.h"
#include "NullableOStream.h"
@@ -75,6 +76,8 @@ public:
    // key: value returned by getopt_long
    using RegisteredOptions = std::vector<RegisteredOption>;

    static std::string INIT_VINTF_NOTES;

protected:
    Status parseArgs(const Arg &arg);
    Status fetch();
@@ -108,6 +111,10 @@ protected:
    // Call getCmdline on all pid in pids. If it returns empty string, the process might
    // have died, and the pid is removed from pids.
    void removeDeadProcesses(Pids *pids);

    virtual Partition getPartition(pid_t pid);
    Partition resolvePartition(Partition processPartition, const FQName& fqName) const;

    void forEachTable(const std::function<void(Table &)> &f);
    void forEachTable(const std::function<void(const Table &)> &f) const;

@@ -125,8 +132,9 @@ protected:

    bool mEmitDebugInfo = false;

    // If true, output in VINTF format.
    // If true, output in VINTF format. Output only entries from the specified partition.
    bool mVintf = false;
    Partition mVintfPartition = Partition::UNKNOWN;

    // If true, explanatory text are not emitted.
    bool mNeat = false;
@@ -139,6 +147,9 @@ protected:
    // Cache for getPidInfo.
    std::map<pid_t, PidInfo> mCachedPidInfos;

    // Cache for getPartition.
    std::map<pid_t, Partition> mPartitions;

    RegisteredOptions mOptions;
    // All selected columns
    std::vector<TableColumnType> mSelectedColumns;
+4 −0
Original line number Diff line number Diff line
@@ -23,11 +23,14 @@
#include <vector>
#include <iostream>

#include <procpartition/procpartition.h>

#include "TextTable.h"

namespace android {
namespace lshal {

using android::procpartition::Partition;
using Pids = std::vector<int32_t>;

enum : unsigned int {
@@ -77,6 +80,7 @@ struct TableEntry {
    Architecture arch{ARCH_UNKNOWN};
    // empty: unknown, all zeros: unreleased, otherwise: released
    std::string hash{};
    Partition partition{Partition::UNKNOWN};

    static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) {
        return a.interfaceName < b.interfaceName;
+3 −14
Original line number Diff line number Diff line
@@ -206,6 +206,7 @@ public:
    MOCK_METHOD0(postprocess, void());
    MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
    MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
    MOCK_METHOD1(getPartition, Partition(pid_t));
};

class ListParseArgsTest : public ::testing::Test {
@@ -333,6 +334,7 @@ public:
                table.setDescription("[fake description " + std::to_string(i++) + "]");
            });
        }));
        ON_CALL(*mockList, getPartition(_)).WillByDefault(Return(Partition::VENDOR));
    }

    void initMockServiceManager() {
@@ -418,17 +420,7 @@ TEST_F(ListTest, Fetch) {
TEST_F(ListTest, DumpVintf) {
    const std::string expected =
        "<!-- \n"
        "    This is a skeleton device manifest. Notes: \n"
        "    1. android.hidl.*, android.frameworks.*, android.system.* are not included.\n"
        "    2. If a HAL is supported in both hwbinder and passthrough transport, \n"
        "       only hwbinder is shown.\n"
        "    3. It is likely that HALs in passthrough transport does not have\n"
        "       <interface> declared; users will have to write them by hand.\n"
        "    4. A HAL with lower minor version can be overridden by a HAL with\n"
        "       higher minor version if they have the same name and major version.\n"
        "    5. sepolicy version is set to 0.0. It is recommended that the entry\n"
        "       is removed from the manifest file and written by assemble_vintf\n"
        "       at build time.\n"
        "    This is a skeleton device manifest. Notes: \n" + ListCommand::INIT_VINTF_NOTES +
        "-->\n"
        "<manifest version=\"1.0\" type=\"device\">\n"
        "    <hal format=\"hidl\">\n"
@@ -477,9 +469,6 @@ TEST_F(ListTest, DumpVintf) {
        "        <transport arch=\"32\">passthrough</transport>\n"
        "        <version>6.0</version>\n"
        "    </hal>\n"
        "    <sepolicy>\n"
        "        <version>0.0</version>\n"
        "    </sepolicy>\n"
        "</manifest>\n";

    optind = 1; // mimic Lshal::parseArg()