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#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
18#define FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
19
20#include <getopt.h>
21#include <stdint.h>
22
23#include <fstream>
24#include <string>
25#include <vector>
26
27#include <android-base/macros.h>
28#include <android/hidl/manager/1.0/IServiceManager.h>
29#include <hidl-util/FQName.h>
30
31#include "Command.h"
32#include "NullableOStream.h"
33#include "TableEntry.h"
34#include "TextTable.h"
35#include "utils.h"
36
37namespace android {
38namespace lshal {
39
40class Lshal;
41
42struct PidInfo {
43    std::map<uint64_t, Pids> refPids; // pids that are referenced
44    uint32_t threadUsage; // number of threads in use
45    uint32_t threadCount; // number of threads total
46};
47
48class ListCommand : public Command {
49public:
50    ListCommand(Lshal &lshal) : Command(lshal) {}
51    virtual ~ListCommand() = default;
52    Status main(const Arg &arg) override;
53    void usage() const override;
54    std::string getSimpleDescription() const override;
55    std::string getName() const override { return GetName(); }
56
57    static std::string GetName();
58
59    struct RegisteredOption {
60        // short alternative, e.g. 'v'. If '\0', no short options is available.
61        char shortOption;
62        // long alternative, e.g. 'init-vintf'
63        std::string longOption;
64        // no_argument, required_argument or optional_argument
65        int hasArg;
66        // value written to 'flag' by getopt_long
67        int val;
68        // operation when the argument is present
69        std::function<Status(ListCommand* thiz, const char* arg)> op;
70        // help message
71        std::string help;
72
73        const std::string& getHelpMessageForArgument() const;
74    };
75    // A list of acceptable command line options
76    // key: value returned by getopt_long
77    using RegisteredOptions = std::vector<RegisteredOption>;
78
79    static std::string INIT_VINTF_NOTES;
80
81protected:
82    Status parseArgs(const Arg &arg);
83    Status fetch();
84    virtual void postprocess();
85    Status dump();
86    void putEntry(TableEntrySource source, TableEntry &&entry);
87    Status fetchPassthrough(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
88    Status fetchBinderized(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
89    Status fetchAllLibraries(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
90
91    Status fetchBinderizedEntry(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager,
92                                TableEntry *entry);
93
94    // Get relevant information for a PID by parsing files under /d/binder.
95    // It is a virtual member function so that it can be mocked.
96    virtual bool getPidInfo(pid_t serverPid, PidInfo *info) const;
97    // Retrieve from mCachedPidInfos and call getPidInfo if necessary.
98    const PidInfo* getPidInfoCached(pid_t serverPid);
99
100    void dumpTable(const NullableOStream<std::ostream>& out) const;
101    void dumpVintf(const NullableOStream<std::ostream>& out) const;
102    void addLine(TextTable *table, const std::string &interfaceName, const std::string &transport,
103                 const std::string &arch, const std::string &threadUsage, const std::string &server,
104                 const std::string &serverCmdline, const std::string &address,
105                 const std::string &clients, const std::string &clientCmdlines) const;
106    void addLine(TextTable *table, const TableEntry &entry);
107    // Read and return /proc/{pid}/cmdline.
108    virtual std::string parseCmdline(pid_t pid) const;
109    // Return /proc/{pid}/cmdline if it exists, else empty string.
110    const std::string& getCmdline(pid_t pid);
111    // Call getCmdline on all pid in pids. If it returns empty string, the process might
112    // have died, and the pid is removed from pids.
113    void removeDeadProcesses(Pids *pids);
114
115    virtual Partition getPartition(pid_t pid);
116    Partition resolvePartition(Partition processPartition, const FQName& fqName) const;
117
118    void forEachTable(const std::function<void(Table &)> &f);
119    void forEachTable(const std::function<void(const Table &)> &f) const;
120
121    NullableOStream<std::ostream> err() const;
122    NullableOStream<std::ostream> out() const;
123
124    void registerAllOptions();
125
126    Table mServicesTable{};
127    Table mPassthroughRefTable{};
128    Table mImplementationsTable{};
129
130    std::string mFileOutputPath;
131    TableEntryCompare mSortColumn = nullptr;
132
133    bool mEmitDebugInfo = false;
134
135    // If true, output in VINTF format. Output only entries from the specified partition.
136    bool mVintf = false;
137    Partition mVintfPartition = Partition::UNKNOWN;
138
139    // If true, explanatory text are not emitted.
140    bool mNeat = false;
141
142    // If an entry does not exist, need to ask /proc/{pid}/cmdline to get it.
143    // If an entry exist but is an empty string, process might have died.
144    // If an entry exist and not empty, it contains the cached content of /proc/{pid}/cmdline.
145    std::map<pid_t, std::string> mCmdlines;
146
147    // Cache for getPidInfo.
148    std::map<pid_t, PidInfo> mCachedPidInfos;
149
150    // Cache for getPartition.
151    std::map<pid_t, Partition> mPartitions;
152
153    RegisteredOptions mOptions;
154    // All selected columns
155    std::vector<TableColumnType> mSelectedColumns;
156    // If true, emit cmdlines instead of PIDs
157    bool mEnableCmdlines = false;
158
159private:
160    DISALLOW_COPY_AND_ASSIGN(ListCommand);
161};
162
163
164}  // namespace lshal
165}  // namespace android
166
167#endif  // FRAMEWORK_NATIVE_CMDS_LSHAL_LIST_COMMAND_H_
168