1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #define LOG_TAG "lshal"
17 #include <android-base/logging.h>
18 
19 #include <map>
20 
21 #include <android-base/strings.h>
22 #include <hidl-hash/Hash.h>
23 #include <vintf/parse_string.h>
24 
25 #include "TableEntry.h"
26 
27 #include "TextTable.h"
28 #include "utils.h"
29 
30 namespace android {
31 namespace lshal {
32 
getArchString(vintf::Arch arch)33 static const std::string &getArchString(vintf::Arch arch) {
34     static const std::string sStr64 = "64";
35     static const std::string sStr32 = "32";
36     static const std::string sStrBoth = "32+64";
37     static const std::string sStrUnknown = "?";
38     switch (arch) {
39         case vintf::Arch::ARCH_64:
40             return sStr64;
41         case vintf::Arch::ARCH_32:
42             return sStr32;
43         case vintf::Arch::ARCH_32_64:
44             return sStrBoth;
45         case vintf::Arch::ARCH_EMPTY: // fall through
46         default:
47             return sStrUnknown;
48     }
49 }
50 
getTitle(TableColumnType type)51 static std::string getTitle(TableColumnType type) {
52     switch (type) {
53         case TableColumnType::INTERFACE_NAME:   return "Interface";
54         case TableColumnType::TRANSPORT:        return "Transport";
55         case TableColumnType::SERVER_PID:       return "Server";
56         case TableColumnType::SERVER_CMD:       return "Server CMD";
57         case TableColumnType::SERVER_ADDR:      return "PTR";
58         case TableColumnType::CLIENT_PIDS:      return "Clients";
59         case TableColumnType::CLIENT_CMDS:      return "Clients CMD";
60         case TableColumnType::ARCH:             return "Arch";
61         case TableColumnType::THREADS:          return "Thread Use";
62         case TableColumnType::RELEASED:         return "R";
63         case TableColumnType::HASH:             return "Hash";
64         case TableColumnType::VINTF:            return "VINTF";
65         case TableColumnType::SERVICE_STATUS:   return "Status";
66         default:
67             LOG(FATAL) << __func__ << "Should not reach here. " << static_cast<int>(type);
68             return "";
69     }
70 }
71 
getField(TableColumnType type) const72 std::string TableEntry::getField(TableColumnType type) const {
73     switch (type) {
74         case TableColumnType::INTERFACE_NAME:
75             return interfaceName;
76         case TableColumnType::TRANSPORT:
77             return vintf::to_string(transport);
78         case TableColumnType::SERVER_PID:
79             return serverPid == NO_PID ? "N/A" : std::to_string(serverPid);
80         case TableColumnType::SERVER_CMD:
81             return serverCmdline;
82         case TableColumnType::SERVER_ADDR:
83             return serverObjectAddress == NO_PTR ? "N/A" : toHexString(serverObjectAddress);
84         case TableColumnType::CLIENT_PIDS:
85             return join(clientPids, " ");
86         case TableColumnType::CLIENT_CMDS:
87             return join(clientCmdlines, ";");
88         case TableColumnType::ARCH:
89             return getArchString(arch);
90         case TableColumnType::THREADS:
91             return getThreadUsage();
92         case TableColumnType::RELEASED:
93             return isReleased();
94         case TableColumnType::HASH:
95             return hash;
96         case TableColumnType::VINTF:
97             return getVintfInfo();
98         case TableColumnType::SERVICE_STATUS:
99             return lshal::to_string(serviceStatus);
100         default:
101             LOG(FATAL) << __func__ << "Should not reach here. " << static_cast<int>(type);
102             return "";
103     }
104 }
105 
isReleased() const106 std::string TableEntry::isReleased() const {
107     static const std::string unreleased = Hash::hexString(Hash::kEmptyHash);
108 
109     if (hash.empty()) {
110         return "?";
111     }
112     if (hash == unreleased) {
113         return "N"; // unknown or unreleased
114     }
115     return "Y"; // released
116 }
117 
getVintfInfo() const118 std::string TableEntry::getVintfInfo() const {
119     static const std::map<VintfInfo, std::string> values{
120             {DEVICE_MANIFEST, "DM"},
121             {DEVICE_MATRIX, "DC"},
122             {FRAMEWORK_MANIFEST, "FM"},
123             {FRAMEWORK_MATRIX, "FC"},
124     };
125     std::vector<std::string> ret;
126     for (const auto& pair : values) {
127         if (vintfInfo & pair.first) {
128             ret.push_back(pair.second);
129         }
130     }
131     auto joined = base::Join(ret, ',');
132     return joined.empty() ? "X" : joined;
133 }
134 
to_string(ServiceStatus s)135 std::string to_string(ServiceStatus s) {
136     switch (s) {
137         case ServiceStatus::ALIVE: return "alive";
138         case ServiceStatus::NON_RESPONSIVE: return "non-responsive";
139         case ServiceStatus::DECLARED: return "declared";
140         case ServiceStatus::UNKNOWN: return "N/A";
141     }
142 
143     LOG(FATAL) << __func__ << "Should not reach here." << static_cast<int>(s);
144     return "";
145 }
146 
createTextTable(bool neat,const std::function<std::string (const std::string &)> & emitDebugInfo) const147 TextTable Table::createTextTable(bool neat,
148     const std::function<std::string(const std::string&)>& emitDebugInfo) const {
149 
150     TextTable textTable;
151     std::vector<std::string> row;
152     if (!neat) {
153         textTable.add(mDescription);
154 
155         row.clear();
156         for (TableColumnType type : mSelectedColumns) {
157             row.push_back(getTitle(type));
158         }
159         textTable.add(std::move(row));
160     }
161 
162     for (const auto& entry : mEntries) {
163         row.clear();
164         for (TableColumnType type : mSelectedColumns) {
165             row.push_back(entry.getField(type));
166         }
167         textTable.add(std::move(row));
168 
169         if (emitDebugInfo) {
170             std::string debugInfo = emitDebugInfo(entry.interfaceName);
171             if (!debugInfo.empty()) textTable.add(debugInfo);
172         }
173     }
174     return textTable;
175 }
176 
createTextTable()177 TextTable MergedTable::createTextTable() {
178     TextTable textTable;
179     for (const Table* table : mTables) {
180         textTable.addAll(table->createTextTable());
181     }
182     return textTable;
183 }
184 
operator ==(const TableEntry & other) const185 bool TableEntry::operator==(const TableEntry& other) const {
186     if (this == &other) {
187         return true;
188     }
189     return interfaceName == other.interfaceName && transport == other.transport &&
190         serverPid == other.serverPid && threadUsage == other.threadUsage &&
191         threadCount == other.threadCount && serverCmdline == other.serverCmdline &&
192         serverObjectAddress == other.serverObjectAddress && clientPids == other.clientPids &&
193         clientCmdlines == other.clientCmdlines && arch == other.arch;
194 }
195 
to_string() const196 std::string TableEntry::to_string() const {
197     using vintf::operator<<;
198     std::stringstream ss;
199     ss << "name=" << interfaceName << ";transport=" << transport << ";thread=" << getThreadUsage()
200        << ";server=" << serverPid
201        << "(" << serverObjectAddress << ";" << serverCmdline << ");clients=["
202        << join(clientPids, ";") << "](" << join(clientCmdlines, ";") << ");arch="
203        << getArchString(arch);
204     return ss.str();
205 
206 }
207 
208 } // namespace lshal
209 } // namespace android
210