Loading cmds/lshal/Android.bp +3 −1 Original line number Diff line number Diff line Loading @@ -18,8 +18,10 @@ cc_binary { "libbase", "libutils", "libhidlbase", "android.hidl.manager@1.0", "libhidltransport", "libhidl-gen-utils", "libvintf", "android.hidl.manager@1.0", ], srcs: [ "Lshal.cpp" Loading cmds/lshal/Lshal.cpp +124 −9 Original line number Diff line number Diff line Loading @@ -28,6 +28,9 @@ #include <android-base/parseint.h> #include <android/hidl/manager/1.0/IServiceManager.h> #include <hidl/ServiceManagement.h> #include <hidl-util/FQName.h> #include <vintf/HalManifest.h> #include <vintf/parse_xml.h> #include "Timeout.h" Loading Loading @@ -58,12 +61,13 @@ static std::string toHexString(uint64_t t) { return os.str(); } static std::pair<hidl_string, hidl_string> split(const hidl_string &s, char c) { template<typename String> static std::pair<String, String> splitFirst(const String &s, char c) { const char *pos = strchr(s.c_str(), c); if (pos == nullptr) { return {s, {}}; } return {hidl_string(s.c_str(), pos - s.c_str()), hidl_string(pos + 1)}; return {String(s.c_str(), pos - s.c_str()), String(pos + 1)}; } static std::vector<std::string> split(const std::string &s, char c) { Loading @@ -81,6 +85,14 @@ static std::vector<std::string> split(const std::string &s, char c) { return components; } static void replaceAll(std::string *s, char from, char to) { for (size_t i = 0; i < s->size(); ++i) { if (s->at(i) == from) { s->at(i) = to; } } } std::string getCmdline(pid_t pid) { std::ifstream ifs("/proc/" + std::to_string(pid) + "/cmdline"); std::string cmdline; Loading Loading @@ -189,7 +201,78 @@ void Lshal::printLine( mOut << std::endl; } void Lshal::dump() const { void Lshal::dumpVintf() const { vintf::HalManifest manifest; for (const TableEntry &entry : mTable) { std::string fqInstanceName = entry.interfaceName; if (entry.source == LIST_DLLIB) { // Quick hack to work around *'s replaceAll(&fqInstanceName, '*', 'D'); } auto splittedFqInstanceName = splitFirst(fqInstanceName, '/'); FQName fqName(splittedFqInstanceName.first); if (!fqName.isValid()) { mErr << "Warning: '" << splittedFqInstanceName.first << "' is not a valid FQName." << std::endl; continue; } // Strip out system libs. // TODO(b/34772739): might want to add other framework HAL packages if (fqName.inPackage("android.hidl")) { continue; } std::string interfaceName = entry.source == LIST_DLLIB ? "" : fqName.name(); std::string instanceName = entry.source == LIST_DLLIB ? "" : splittedFqInstanceName.second; vintf::Transport transport; if (entry.transport == "hwbinder") { transport = vintf::Transport::HWBINDER; } else if (entry.transport == "passthrough") { transport = vintf::Transport::PASSTHROUGH; } else { mErr << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl; continue; } vintf::ManifestHal *hal = manifest.getHal(fqName.package()); if (hal == nullptr) { if (!manifest.add(vintf::ManifestHal{ .format = vintf::HalFormat::HIDL, .name = fqName.package(), .impl = {.implLevel = vintf::ImplLevel::GENERIC, .impl = ""}, .transport = transport })) { mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl; continue; } hal = manifest.getHal(fqName.package()); } if (hal == nullptr) { mErr << "Warning: cannot get hal '" << fqInstanceName << "' after adding it" << std::endl; continue; } vintf::Version version{fqName.getPackageMajorVersion(), fqName.getPackageMinorVersion()}; if (std::find(hal->versions.begin(), hal->versions.end(), version) == hal->versions.end()) { hal->versions.push_back(version); } if (entry.source != LIST_DLLIB) { auto it = hal->interfaces.find(interfaceName); if (it == hal->interfaces.end()) { hal->interfaces.insert({interfaceName, {interfaceName, {{instanceName}}}}); } else { it->second.instances.insert(instanceName); } } } mOut << vintf::gHalManifestConverter(manifest); } void Lshal::dumpTable() const { mOut << "All services:" << std::endl; mOut << std::left; printLine("Interface", "Transport", "Server", "Server CMD", "PTR", "Clients", "Clients CMD"); Loading @@ -204,6 +287,20 @@ void Lshal::dump() const { } } void Lshal::dump() { if (mVintf) { dumpVintf(); if (!!mFileOutput) { mFileOutput.buf().close(); delete &mFileOutput.buf(); mFileOutput = nullptr; } mOut = std::cout; } else { dumpTable(); } } void Lshal::putEntry(TableEntry &&entry) { mTable.push_back(std::forward<TableEntry>(entry)); } Loading @@ -219,7 +316,8 @@ Status Lshal::fetchAllLibraries(const sp<IServiceManager> &manager) { .transport = "passthrough", .serverPid = NO_PID, .serverObjectAddress = NO_PTR, .clientPids = {} .clientPids = {}, .source = LIST_DLLIB }); } }); Loading @@ -244,7 +342,8 @@ Status Lshal::fetchPassthrough(const sp<IServiceManager> &manager) { .transport = "passthrough", .serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID, .serverObjectAddress = NO_PTR, .clientPids = info.clientPids .clientPids = info.clientPids, .source = PTSERVICEMANAGER_REG_CLIENT }); } }); Loading Loading @@ -279,7 +378,7 @@ Status Lshal::fetchBinderized(const sp<IServiceManager> &manager) { std::map<std::string, DebugInfo> allDebugInfos; std::map<pid_t, std::map<uint64_t, Pids>> allPids; for (const auto &fqInstanceName : fqInstanceNames) { const auto pair = split(fqInstanceName, '/'); const auto pair = splitFirst(fqInstanceName, '/'); const auto &serviceName = pair.first; const auto &instanceName = pair.second; auto getRet = timeoutIPC(manager, &IServiceManager::get, serviceName, instanceName); Loading Loading @@ -326,7 +425,8 @@ Status Lshal::fetchBinderized(const sp<IServiceManager> &manager) { .transport = mode, .serverPid = NO_PID, .serverObjectAddress = NO_PTR, .clientPids = {} .clientPids = {}, .source = HWSERVICEMANAGER_LIST }); continue; } Loading @@ -337,7 +437,8 @@ Status Lshal::fetchBinderized(const sp<IServiceManager> &manager) { .serverPid = info.pid, .serverObjectAddress = info.ptr, .clientPids = info.pid == NO_PID || info.ptr == NO_PTR ? Pids{} : allPids[info.pid][info.ptr] ? Pids{} : allPids[info.pid][info.ptr], .source = HWSERVICEMANAGER_LIST }); } return status; Loading Loading @@ -371,7 +472,7 @@ void Lshal::usage() const { << " Dump all hals with default ordering and columns [-itpc]." << std::endl << " lshal [--interface|-i] [--transport|-t]" << std::endl << " [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]" << std::endl << " [--sort={interface|i|pid|p}]" << std::endl << " [--sort={interface|i|pid|p}] [--init-vintf[=path]]" << std::endl << " -i, --interface: print the interface name column" << std::endl << " -n, --instance: print the instance name column" << std::endl << " -t, --transport: print the transport mode column" << std::endl Loading @@ -382,6 +483,8 @@ void Lshal::usage() const { << " -m, --cmdline: print cmdline instead of PIDs" << std::endl << " --sort=i, --sort=interface: sort by interface name" << std::endl << " --sort=p, --sort=pid: sort by server pid" << std::endl << " --init-vintf=path: form a skeleton HAL manifest to specified file " << std::endl << " (stdout if no file specified)" << std::endl << " lshal [-h|--help]" << std::endl << " -h, --help: show this help information." << std::endl; } Loading @@ -399,6 +502,7 @@ Status Lshal::parseArgs(int argc, char **argv) { // long options without short alternatives {"sort", required_argument, 0, 's' }, {"init-vintf",optional_argument, 0, 'v' }, { 0, 0, 0, 0 } }; Loading @@ -424,6 +528,17 @@ Status Lshal::parseArgs(int argc, char **argv) { } break; } case 'v': { 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; } } mVintf = true; } case 'i': { mSelectedColumns |= ENABLE_INTERFACE_NAME; break; Loading cmds/lshal/Lshal.h +11 −5 Original line number Diff line number Diff line Loading @@ -19,12 +19,13 @@ #include <stdint.h> #include <iostream> #include <fstream> #include <string> #include <vector> #include <android/hidl/manager/1.0/IServiceManager.h> #include "NullableOStream.h" #include "TableEntry.h" namespace android { Loading @@ -38,6 +39,7 @@ enum : unsigned int { DUMP_BINDERIZED_ERROR = 1 << 3, DUMP_PASSTHROUGH_ERROR = 1 << 4, DUMP_ALL_LIBS_ERROR = 1 << 5, IO_ERROR = 1 << 6, }; using Status = unsigned int; Loading @@ -49,7 +51,7 @@ private: Status parseArgs(int argc, char **argv); Status fetch(); void postprocess(); void dump() const; void dump(); void usage() const; void putEntry(TableEntry &&entry); Status fetchPassthrough(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager); Loading @@ -57,6 +59,8 @@ private: Status fetchAllLibraries(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager); bool getReferencedPids( pid_t serverPid, std::map<uint64_t, Pids> *objects) const; void dumpTable() const; void dumpVintf() const; void printLine( const std::string &interfaceName, const std::string &transport, const std::string &server, Loading @@ -70,12 +74,14 @@ private: void removeDeadProcesses(Pids *pids); Table mTable{}; std::ostream &mErr = std::cerr; std::ostream &mOut = std::cout; NullableOStream<std::ostream> mErr = std::cerr; NullableOStream<std::ostream> mOut = std::cout; NullableOStream<std::ofstream> mFileOutput = nullptr; TableEntryCompare mSortColumn = nullptr; TableEntrySelect mSelectedColumns = 0; // If true, cmdlines will be printed instead of pid. bool mEnableCmdlines; bool mEnableCmdlines = 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. // If an entry exist and not empty, it contains the cached content of /proc/{pid}/cmdline. Loading cmds/lshal/NullableOStream.h 0 → 100644 +73 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 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_NULLABLE_O_STREAM_H_ #define FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_ #include <iostream> namespace android { namespace lshal { template<typename S> class NullableOStream { public: NullableOStream(S &os) : mOs(&os) {} NullableOStream(S *os) : mOs(os) {} NullableOStream &operator=(S &os) { mOs = &os; return *this; } NullableOStream &operator=(S *os) { mOs = os; return *this; } template<typename Other> NullableOStream &operator=(const NullableOStream<Other> &other) { mOs = other.mOs; return *this; } const NullableOStream &operator<<(std::ostream& (*pf)(std::ostream&)) const { if (mOs) { (*mOs) << pf; } return *this; } template<typename T> const NullableOStream &operator<<(const T &rhs) const { if (mOs) { (*mOs) << rhs; } return *this; } S& buf() const { return *mOs; } operator bool() const { return mOs != nullptr; } private: template<typename> friend class NullableOStream; S *mOs = nullptr; }; } // namespace lshal } // namespace android #endif // FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_ cmds/lshal/TableEntry.h +8 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,13 @@ namespace lshal { using Pids = std::vector<int32_t>; enum : unsigned int { HWSERVICEMANAGER_LIST, // through defaultServiceManager()->list() PTSERVICEMANAGER_REG_CLIENT, // through registerPassthroughClient LIST_DLLIB, // through listing dynamic libraries }; using TableEntrySource = unsigned int; struct TableEntry { std::string interfaceName; std::string transport; Loading @@ -36,6 +43,7 @@ struct TableEntry { uint64_t serverObjectAddress; Pids clientPids; std::vector<std::string> clientCmdlines; TableEntrySource source; static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) { return a.interfaceName < b.interfaceName; Loading Loading
cmds/lshal/Android.bp +3 −1 Original line number Diff line number Diff line Loading @@ -18,8 +18,10 @@ cc_binary { "libbase", "libutils", "libhidlbase", "android.hidl.manager@1.0", "libhidltransport", "libhidl-gen-utils", "libvintf", "android.hidl.manager@1.0", ], srcs: [ "Lshal.cpp" Loading
cmds/lshal/Lshal.cpp +124 −9 Original line number Diff line number Diff line Loading @@ -28,6 +28,9 @@ #include <android-base/parseint.h> #include <android/hidl/manager/1.0/IServiceManager.h> #include <hidl/ServiceManagement.h> #include <hidl-util/FQName.h> #include <vintf/HalManifest.h> #include <vintf/parse_xml.h> #include "Timeout.h" Loading Loading @@ -58,12 +61,13 @@ static std::string toHexString(uint64_t t) { return os.str(); } static std::pair<hidl_string, hidl_string> split(const hidl_string &s, char c) { template<typename String> static std::pair<String, String> splitFirst(const String &s, char c) { const char *pos = strchr(s.c_str(), c); if (pos == nullptr) { return {s, {}}; } return {hidl_string(s.c_str(), pos - s.c_str()), hidl_string(pos + 1)}; return {String(s.c_str(), pos - s.c_str()), String(pos + 1)}; } static std::vector<std::string> split(const std::string &s, char c) { Loading @@ -81,6 +85,14 @@ static std::vector<std::string> split(const std::string &s, char c) { return components; } static void replaceAll(std::string *s, char from, char to) { for (size_t i = 0; i < s->size(); ++i) { if (s->at(i) == from) { s->at(i) = to; } } } std::string getCmdline(pid_t pid) { std::ifstream ifs("/proc/" + std::to_string(pid) + "/cmdline"); std::string cmdline; Loading Loading @@ -189,7 +201,78 @@ void Lshal::printLine( mOut << std::endl; } void Lshal::dump() const { void Lshal::dumpVintf() const { vintf::HalManifest manifest; for (const TableEntry &entry : mTable) { std::string fqInstanceName = entry.interfaceName; if (entry.source == LIST_DLLIB) { // Quick hack to work around *'s replaceAll(&fqInstanceName, '*', 'D'); } auto splittedFqInstanceName = splitFirst(fqInstanceName, '/'); FQName fqName(splittedFqInstanceName.first); if (!fqName.isValid()) { mErr << "Warning: '" << splittedFqInstanceName.first << "' is not a valid FQName." << std::endl; continue; } // Strip out system libs. // TODO(b/34772739): might want to add other framework HAL packages if (fqName.inPackage("android.hidl")) { continue; } std::string interfaceName = entry.source == LIST_DLLIB ? "" : fqName.name(); std::string instanceName = entry.source == LIST_DLLIB ? "" : splittedFqInstanceName.second; vintf::Transport transport; if (entry.transport == "hwbinder") { transport = vintf::Transport::HWBINDER; } else if (entry.transport == "passthrough") { transport = vintf::Transport::PASSTHROUGH; } else { mErr << "Warning: '" << entry.transport << "' is not a valid transport." << std::endl; continue; } vintf::ManifestHal *hal = manifest.getHal(fqName.package()); if (hal == nullptr) { if (!manifest.add(vintf::ManifestHal{ .format = vintf::HalFormat::HIDL, .name = fqName.package(), .impl = {.implLevel = vintf::ImplLevel::GENERIC, .impl = ""}, .transport = transport })) { mErr << "Warning: cannot add hal '" << fqInstanceName << "'" << std::endl; continue; } hal = manifest.getHal(fqName.package()); } if (hal == nullptr) { mErr << "Warning: cannot get hal '" << fqInstanceName << "' after adding it" << std::endl; continue; } vintf::Version version{fqName.getPackageMajorVersion(), fqName.getPackageMinorVersion()}; if (std::find(hal->versions.begin(), hal->versions.end(), version) == hal->versions.end()) { hal->versions.push_back(version); } if (entry.source != LIST_DLLIB) { auto it = hal->interfaces.find(interfaceName); if (it == hal->interfaces.end()) { hal->interfaces.insert({interfaceName, {interfaceName, {{instanceName}}}}); } else { it->second.instances.insert(instanceName); } } } mOut << vintf::gHalManifestConverter(manifest); } void Lshal::dumpTable() const { mOut << "All services:" << std::endl; mOut << std::left; printLine("Interface", "Transport", "Server", "Server CMD", "PTR", "Clients", "Clients CMD"); Loading @@ -204,6 +287,20 @@ void Lshal::dump() const { } } void Lshal::dump() { if (mVintf) { dumpVintf(); if (!!mFileOutput) { mFileOutput.buf().close(); delete &mFileOutput.buf(); mFileOutput = nullptr; } mOut = std::cout; } else { dumpTable(); } } void Lshal::putEntry(TableEntry &&entry) { mTable.push_back(std::forward<TableEntry>(entry)); } Loading @@ -219,7 +316,8 @@ Status Lshal::fetchAllLibraries(const sp<IServiceManager> &manager) { .transport = "passthrough", .serverPid = NO_PID, .serverObjectAddress = NO_PTR, .clientPids = {} .clientPids = {}, .source = LIST_DLLIB }); } }); Loading @@ -244,7 +342,8 @@ Status Lshal::fetchPassthrough(const sp<IServiceManager> &manager) { .transport = "passthrough", .serverPid = info.clientPids.size() == 1 ? info.clientPids[0] : NO_PID, .serverObjectAddress = NO_PTR, .clientPids = info.clientPids .clientPids = info.clientPids, .source = PTSERVICEMANAGER_REG_CLIENT }); } }); Loading Loading @@ -279,7 +378,7 @@ Status Lshal::fetchBinderized(const sp<IServiceManager> &manager) { std::map<std::string, DebugInfo> allDebugInfos; std::map<pid_t, std::map<uint64_t, Pids>> allPids; for (const auto &fqInstanceName : fqInstanceNames) { const auto pair = split(fqInstanceName, '/'); const auto pair = splitFirst(fqInstanceName, '/'); const auto &serviceName = pair.first; const auto &instanceName = pair.second; auto getRet = timeoutIPC(manager, &IServiceManager::get, serviceName, instanceName); Loading Loading @@ -326,7 +425,8 @@ Status Lshal::fetchBinderized(const sp<IServiceManager> &manager) { .transport = mode, .serverPid = NO_PID, .serverObjectAddress = NO_PTR, .clientPids = {} .clientPids = {}, .source = HWSERVICEMANAGER_LIST }); continue; } Loading @@ -337,7 +437,8 @@ Status Lshal::fetchBinderized(const sp<IServiceManager> &manager) { .serverPid = info.pid, .serverObjectAddress = info.ptr, .clientPids = info.pid == NO_PID || info.ptr == NO_PTR ? Pids{} : allPids[info.pid][info.ptr] ? Pids{} : allPids[info.pid][info.ptr], .source = HWSERVICEMANAGER_LIST }); } return status; Loading Loading @@ -371,7 +472,7 @@ void Lshal::usage() const { << " Dump all hals with default ordering and columns [-itpc]." << std::endl << " lshal [--interface|-i] [--transport|-t]" << std::endl << " [--pid|-p] [--address|-a] [--clients|-c] [--cmdline|-m]" << std::endl << " [--sort={interface|i|pid|p}]" << std::endl << " [--sort={interface|i|pid|p}] [--init-vintf[=path]]" << std::endl << " -i, --interface: print the interface name column" << std::endl << " -n, --instance: print the instance name column" << std::endl << " -t, --transport: print the transport mode column" << std::endl Loading @@ -382,6 +483,8 @@ void Lshal::usage() const { << " -m, --cmdline: print cmdline instead of PIDs" << std::endl << " --sort=i, --sort=interface: sort by interface name" << std::endl << " --sort=p, --sort=pid: sort by server pid" << std::endl << " --init-vintf=path: form a skeleton HAL manifest to specified file " << std::endl << " (stdout if no file specified)" << std::endl << " lshal [-h|--help]" << std::endl << " -h, --help: show this help information." << std::endl; } Loading @@ -399,6 +502,7 @@ Status Lshal::parseArgs(int argc, char **argv) { // long options without short alternatives {"sort", required_argument, 0, 's' }, {"init-vintf",optional_argument, 0, 'v' }, { 0, 0, 0, 0 } }; Loading @@ -424,6 +528,17 @@ Status Lshal::parseArgs(int argc, char **argv) { } break; } case 'v': { 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; } } mVintf = true; } case 'i': { mSelectedColumns |= ENABLE_INTERFACE_NAME; break; Loading
cmds/lshal/Lshal.h +11 −5 Original line number Diff line number Diff line Loading @@ -19,12 +19,13 @@ #include <stdint.h> #include <iostream> #include <fstream> #include <string> #include <vector> #include <android/hidl/manager/1.0/IServiceManager.h> #include "NullableOStream.h" #include "TableEntry.h" namespace android { Loading @@ -38,6 +39,7 @@ enum : unsigned int { DUMP_BINDERIZED_ERROR = 1 << 3, DUMP_PASSTHROUGH_ERROR = 1 << 4, DUMP_ALL_LIBS_ERROR = 1 << 5, IO_ERROR = 1 << 6, }; using Status = unsigned int; Loading @@ -49,7 +51,7 @@ private: Status parseArgs(int argc, char **argv); Status fetch(); void postprocess(); void dump() const; void dump(); void usage() const; void putEntry(TableEntry &&entry); Status fetchPassthrough(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager); Loading @@ -57,6 +59,8 @@ private: Status fetchAllLibraries(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager); bool getReferencedPids( pid_t serverPid, std::map<uint64_t, Pids> *objects) const; void dumpTable() const; void dumpVintf() const; void printLine( const std::string &interfaceName, const std::string &transport, const std::string &server, Loading @@ -70,12 +74,14 @@ private: void removeDeadProcesses(Pids *pids); Table mTable{}; std::ostream &mErr = std::cerr; std::ostream &mOut = std::cout; NullableOStream<std::ostream> mErr = std::cerr; NullableOStream<std::ostream> mOut = std::cout; NullableOStream<std::ofstream> mFileOutput = nullptr; TableEntryCompare mSortColumn = nullptr; TableEntrySelect mSelectedColumns = 0; // If true, cmdlines will be printed instead of pid. bool mEnableCmdlines; bool mEnableCmdlines = 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. // If an entry exist and not empty, it contains the cached content of /proc/{pid}/cmdline. Loading
cmds/lshal/NullableOStream.h 0 → 100644 +73 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 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_NULLABLE_O_STREAM_H_ #define FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_ #include <iostream> namespace android { namespace lshal { template<typename S> class NullableOStream { public: NullableOStream(S &os) : mOs(&os) {} NullableOStream(S *os) : mOs(os) {} NullableOStream &operator=(S &os) { mOs = &os; return *this; } NullableOStream &operator=(S *os) { mOs = os; return *this; } template<typename Other> NullableOStream &operator=(const NullableOStream<Other> &other) { mOs = other.mOs; return *this; } const NullableOStream &operator<<(std::ostream& (*pf)(std::ostream&)) const { if (mOs) { (*mOs) << pf; } return *this; } template<typename T> const NullableOStream &operator<<(const T &rhs) const { if (mOs) { (*mOs) << rhs; } return *this; } S& buf() const { return *mOs; } operator bool() const { return mOs != nullptr; } private: template<typename> friend class NullableOStream; S *mOs = nullptr; }; } // namespace lshal } // namespace android #endif // FRAMEWORK_NATIVE_CMDS_LSHAL_NULLABLE_O_STREAM_H_
cmds/lshal/TableEntry.h +8 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,13 @@ namespace lshal { using Pids = std::vector<int32_t>; enum : unsigned int { HWSERVICEMANAGER_LIST, // through defaultServiceManager()->list() PTSERVICEMANAGER_REG_CLIENT, // through registerPassthroughClient LIST_DLLIB, // through listing dynamic libraries }; using TableEntrySource = unsigned int; struct TableEntry { std::string interfaceName; std::string transport; Loading @@ -36,6 +43,7 @@ struct TableEntry { uint64_t serverObjectAddress; Pids clientPids; std::vector<std::string> clientCmdlines; TableEntrySource source; static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) { return a.interfaceName < b.interfaceName; Loading