Loading cmds/lshal/Android.bp +7 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,9 @@ cc_library_shared { "libhidl-gen-utils", "libvintf", ], static_libs: [ "libprocpartition", ], srcs: [ "DebugCommand.cpp", "HelpCommand.cpp", Loading @@ -45,10 +48,14 @@ cc_defaults { shared_libs: [ "libbase", "libhidlbase", "libhidl-gen-utils", "libhidltransport", "liblshal", "libutils", ], static_libs: [ "libprocpartition", ], cflags: ["-Wall", "-Werror"], } Loading cmds/lshal/ListCommand.cpp +85 −21 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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" Loading @@ -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(); } Loading @@ -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) { Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -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) { Loading @@ -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 = Loading Loading @@ -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: Loading Loading @@ -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; Loading cmds/lshal/ListCommand.h +13 −2 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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(); Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading cmds/lshal/TableEntry.h +4 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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; Loading cmds/lshal/libprocpartition/Android.bp 0 → 100644 +30 −0 Original line number Diff line number Diff line // Copyright (C) 2018 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. cc_library_static { name: "libprocpartition", shared_libs: [ "libbase", ], srcs: [ "procpartition.cpp", ], cflags: [ "-Wall", "-Werror", ], export_include_dirs: [ "include", ] } Loading
cmds/lshal/Android.bp +7 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,9 @@ cc_library_shared { "libhidl-gen-utils", "libvintf", ], static_libs: [ "libprocpartition", ], srcs: [ "DebugCommand.cpp", "HelpCommand.cpp", Loading @@ -45,10 +48,14 @@ cc_defaults { shared_libs: [ "libbase", "libhidlbase", "libhidl-gen-utils", "libhidltransport", "liblshal", "libutils", ], static_libs: [ "libprocpartition", ], cflags: ["-Wall", "-Werror"], } Loading
cmds/lshal/ListCommand.cpp +85 −21 Original line number Diff line number Diff line Loading @@ -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> Loading @@ -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" Loading @@ -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(); } Loading @@ -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) { Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -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) { Loading @@ -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 = Loading Loading @@ -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: Loading Loading @@ -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; Loading
cmds/lshal/ListCommand.h +13 −2 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -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(); Loading Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading
cmds/lshal/TableEntry.h +4 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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; Loading
cmds/lshal/libprocpartition/Android.bp 0 → 100644 +30 −0 Original line number Diff line number Diff line // Copyright (C) 2018 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. cc_library_static { name: "libprocpartition", shared_libs: [ "libbase", ], srcs: [ "procpartition.cpp", ], cflags: [ "-Wall", "-Werror", ], export_include_dirs: [ "include", ] }