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 
17 #pragma once
18 
19 #include <getopt.h>
20 #include <stdint.h>
21 
22 #include <fstream>
23 #include <string>
24 #include <vector>
25 
26 #include <android-base/macros.h>
27 #include <android/hidl/manager/1.0/IServiceManager.h>
28 #include <binderdebug/BinderDebug.h>
29 #include <hidl-util/FqInstance.h>
30 #include <vintf/HalManifest.h>
31 #include <vintf/VintfObject.h>
32 
33 #include "Command.h"
34 #include "NullableOStream.h"
35 #include "TableEntry.h"
36 #include "TextTable.h"
37 #include "utils.h"
38 
39 namespace android {
40 namespace lshal {
41 
42 class Lshal;
43 
44 enum class HalType {
45     BINDERIZED_SERVICES = 0,
46     PASSTHROUGH_CLIENTS,
47     PASSTHROUGH_LIBRARIES,
48     VINTF_MANIFEST,
49     LAZY_HALS,
50 
51     // Not a real HalType. Used to determine all HalTypes.
52     LAST,
53 };
54 
55 class ListCommand : public Command {
56 public:
ListCommand(Lshal & lshal)57     explicit ListCommand(Lshal &lshal) : Command(lshal) {}
58     virtual ~ListCommand() = default;
59     Status main(const Arg &arg) override;
60     void usage() const override;
61     std::string getSimpleDescription() const override;
getName()62     std::string getName() const override { return GetName(); }
63 
64     static std::string GetName();
65 
66     struct RegisteredOption {
67         // short alternative, e.g. 'v'. If '\0', no short options is available.
68         char shortOption;
69         // long alternative, e.g. 'init-vintf'
70         std::string longOption;
71         // no_argument, required_argument or optional_argument
72         int hasArg;
73         // value written to 'flag' by getopt_long
74         int val;
75         // operation when the argument is present
76         std::function<Status(ListCommand* thiz, const char* arg)> op;
77         // help message
78         std::string help;
79 
80         const std::string& getHelpMessageForArgument() const;
81     };
82     // A list of acceptable command line options
83     // key: value returned by getopt_long
84     using RegisteredOptions = std::vector<RegisteredOption>;
85 
86     static std::string INIT_VINTF_NOTES;
87 
88 protected:
89     Status parseArgs(const Arg &arg);
90     // Retrieve first-hand information
91     Status fetch();
92     // Retrieve derived information base on existing table
93     virtual void postprocess();
94     Status dump();
95     void putEntry(HalType type, TableEntry &&entry);
96     Status fetchPassthrough(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
97     Status fetchBinderized(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
98     Status fetchAllLibraries(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
99     Status fetchManifestHals();
100     Status fetchLazyHals();
101 
102     Status fetchBinderizedEntry(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager,
103                                 TableEntry *entry);
104 
105     // Get relevant information for a PID by parsing files under
106     // /dev/binderfs/binder_logs or /d/binder.
107     // It is a virtual member function so that it can be mocked.
108     virtual bool getPidInfo(pid_t serverPid, BinderPidInfo *info) const;
109     // Retrieve from mCachedPidInfos and call getPidInfo if necessary.
110     const BinderPidInfo* getPidInfoCached(pid_t serverPid);
111 
112     void dumpTable(const NullableOStream<std::ostream>& out) const;
113     void dumpVintf(const NullableOStream<std::ostream>& out) const;
114     void addLine(TextTable *table, const std::string &interfaceName, const std::string &transport,
115                  const std::string &arch, const std::string &threadUsage, const std::string &server,
116                  const std::string &serverCmdline, const std::string &address,
117                  const std::string &clients, const std::string &clientCmdlines) const;
118     void addLine(TextTable *table, const TableEntry &entry);
119     // Read and return /proc/{pid}/cmdline.
120     virtual std::string parseCmdline(pid_t pid) const;
121     // Return /proc/{pid}/cmdline if it exists, else empty string.
122     const std::string& getCmdline(pid_t pid);
123     // Call getCmdline on all pid in pids. If it returns empty string, the process might
124     // have died, and the pid is removed from pids.
125     void removeDeadProcesses(Pids *pids);
126 
127     virtual Partition getPartition(pid_t pid);
128     Partition resolvePartition(Partition processPartition, const FqInstance &fqInstance) const;
129 
130     VintfInfo getVintfInfo(const std::string &fqInstanceName, vintf::TransportArch ta) const;
131     // Allow to mock these functions for testing.
132     virtual std::shared_ptr<const vintf::HalManifest> getDeviceManifest() const;
133     virtual std::shared_ptr<const vintf::CompatibilityMatrix> getDeviceMatrix() const;
134     virtual std::shared_ptr<const vintf::HalManifest> getFrameworkManifest() const;
135     virtual std::shared_ptr<const vintf::CompatibilityMatrix> getFrameworkMatrix() const;
136 
137     void forEachTable(const std::function<void(Table &)> &f);
138     void forEachTable(const std::function<void(const Table &)> &f) const;
139     Table* tableForType(HalType type);
140     const Table* tableForType(HalType type) const;
141 
142     NullableOStream<std::ostream> err() const;
143     NullableOStream<std::ostream> out() const;
144 
145     void registerAllOptions();
146 
147     // helper functions to dumpVintf.
148     bool addEntryWithInstance(const TableEntry &entry, vintf::HalManifest *manifest) const;
149     bool addEntryWithoutInstance(const TableEntry &entry, const vintf::HalManifest *manifest) const;
150 
151     // Helper function. Whether to fetch entries corresponding to a given HAL type.
152     bool shouldFetchHalType(const HalType &type) const;
153 
154     void initFetchTypes();
155 
156     // Helper functions ti add HALs that are listed in VINTF manifest to LAZY_HALS table.
157     bool hasHwbinderEntry(const TableEntry& entry) const;
158     bool hasPassthroughEntry(const TableEntry& entry) const;
159 
160     Table mServicesTable{};
161     Table mPassthroughRefTable{};
162     Table mImplementationsTable{};
163     Table mManifestHalsTable{};
164     Table mLazyHalsTable{};
165 
166     std::string mFileOutputPath;
167     TableEntryCompare mSortColumn = nullptr;
168 
169     bool mEmitDebugInfo = false;
170 
171     // If true, output in VINTF format. Output only entries from the specified partition.
172     bool mVintf = false;
173     Partition mVintfPartition = Partition::UNKNOWN;
174 
175     // If true, explanatory text are not emitted.
176     bool mNeat = false;
177 
178     // Type(s) of HAL associations to list.
179     std::vector<HalType> mListTypes{};
180     // Type(s) of HAL associations to fetch.
181     std::set<HalType> mFetchTypes{};
182 
183     // If an entry does not exist, need to ask /proc/{pid}/cmdline to get it.
184     // If an entry exist but is an empty string, process might have died.
185     // If an entry exist and not empty, it contains the cached content of /proc/{pid}/cmdline.
186     std::map<pid_t, std::string> mCmdlines;
187 
188     // Cache for getPidInfo.
189     std::map<pid_t, BinderPidInfo> mCachedPidInfos;
190 
191     // Cache for getPartition.
192     std::map<pid_t, Partition> mPartitions;
193 
194     RegisteredOptions mOptions;
195     // All selected columns
196     std::vector<TableColumnType> mSelectedColumns;
197     // If true, emit cmdlines instead of PIDs
198     bool mEnableCmdlines = false;
199 
200 private:
201     DISALLOW_COPY_AND_ASSIGN(ListCommand);
202 };
203 
204 
205 }  // namespace lshal
206 }  // namespace android
207