1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "common/debug.h"
16 #include "compiler/compiler.h"
17 #include "maintenance/controller.h"
18 #include "db/clean_up.h"
19 
20 #include <android-base/parseint.h>
21 #include <android-base/properties.h>
22 #include <android-base/logging.h>
23 
24 #include <iostream>
25 #include <optional>
26 
27 #if defined(IORAP_MAINTENANCE_MAIN)
28 
29 namespace iorap::maintenance {
30 
Usage(char ** argv)31 void Usage(char** argv) {
32   std::cerr << "Usage: " << argv[0] << " <path of sqlite db>" << std::endl;
33   std::cerr << "" << std::endl;
34   std::cerr << "  Compile the perfetto trace for an package and activity." << std::endl;
35   std::cerr << "  The info of perfetto trace is stored in the sqlite db." << std::endl;
36   std::cerr << "" << std::endl;
37   std::cerr << "  Optional flags:" << std::endl;
38   std::cerr << "    --package $,-p $           Package name." << std::endl;
39   std::cerr << "    --version $,-ve $          Package version." << std::endl;
40   std::cerr << "    --activity $,-a $          Activity name." << std::endl;
41   std::cerr << "    --inode-textcache $,-it $  Resolve inode->filename from textcache." << std::endl;
42   std::cerr << "    --help,-h                  Print this Usage." << std::endl;
43   std::cerr << "    --recompile,-r             Force re-compilation, which replace the existing compiled trace ." << std::endl;
44   std::cerr << "    --purge-package,-pp        Purge all files associated with a package." << std::endl;
45   std::cerr << "    --verbose,-v               Set verbosity (default off)." << std::endl;
46   std::cerr << "    --output-text,-ot          Output ascii text instead of protobuf (default off)." << std::endl;
47   std::cerr << "    --min_traces,-mt           The min number of perfetto traces needed "
48             << "for compilation (default 1)." << std::endl;
49   std::cerr << "    --exclude-dex-files,-edf   Set of exclude dex files" << std::endl;
50   exit(1);
51 }
52 
53 
Main(int argc,char ** argv)54 int Main(int argc, char** argv){
55   android::base::InitLogging(argv);
56   android::base::SetLogger(android::base::StderrLogger);
57 
58   if (argc == 1) {
59     // Need at least 1 input file to do anything.
60     Usage(argv);
61   }
62 
63   std::vector<std::string> arg_input_filenames;
64   std::optional<std::string> arg_package;
65   std::optional<std::string> arg_purge_package;
66   int arg_version = -1;
67   std::optional<std::string> arg_activity;
68   std::optional<std::string> arg_inode_textcache;
69   bool recompile = false;
70   bool enable_verbose = false;
71   bool arg_output_text = false;
72   uint64_t arg_min_traces = 1;
73   bool exclude_dex_files = false;
74 
75   for (int arg = 1; arg < argc; ++arg) {
76     std::string argstr = argv[arg];
77     bool has_arg_next = (arg+1)<argc;
78     std::string arg_next = has_arg_next ? argv[arg+1] : "";
79 
80     if (argstr == "--help" || argstr == "-h") {
81       Usage(argv);
82     } else if (argstr == "--package" || argstr == "-p") {
83       if (!has_arg_next) {
84         std::cerr << "Missing --package <value>" << std::endl;
85         return 1;
86       }
87       arg_package = arg_next;
88       ++arg;
89     } else if (argstr == "--version" || argstr == "-ve") {
90       if (!has_arg_next) {
91         std::cerr << "Missing --version <value>" << std::endl;
92         return 1;
93       }
94       int version;
95       if (!android::base::ParseInt<int>(arg_next, &version)) {
96         std::cerr << "Invalid --version " << arg_next << std::endl;
97         return 1;
98       }
99       arg_version = version;
100       ++arg;
101     } else if (argstr == "--activity" || argstr == "-a") {
102       if (!has_arg_next) {
103         std::cerr << "Missing --activity <value>" << std::endl;
104         return 1;
105       }
106       arg_activity = arg_next;
107       ++arg;
108     } else if (argstr == "--inode-textcache" || argstr == "-it") {
109       if (!has_arg_next) {
110         std::cerr << "Missing --inode-textcache <value>" << std::endl;
111         return 1;
112       }
113       arg_inode_textcache = arg_next;
114       ++arg;
115     } else if (argstr == "--purge-package" || argstr == "-pp") {
116       if (!has_arg_next) {
117         std::cerr << "Missing --purge-package <value>" << std::endl;
118         return 1;
119       }
120       arg_purge_package = arg_next;
121       ++arg;
122     } else if (argstr == "--verbose" || argstr == "-v") {
123       enable_verbose = true;
124     } else if (argstr == "--recompile" || argstr == "-r") {
125       recompile = true;
126     } else if (argstr == "--output-text" || argstr == "-ot") {
127       arg_output_text = true;
128     } else if (argstr == "--min_traces" || argstr == "-mt") {
129       if (!has_arg_next) {
130         std::cerr << "Missing --min_traces <value>" << std::endl;
131         return 1;
132       }
133       arg_min_traces = std::stoul(arg_next);
134       ++arg;
135     } else if (argstr == "--exclude-dex-files" || argstr == "-edf") {
136       exclude_dex_files = true;
137     } else {
138       arg_input_filenames.push_back(argstr);
139     }
140   }
141 
142   if (arg_input_filenames.empty()) {
143     LOG(ERROR) << "Missing filename to a sqlite database.";
144     Usage(argv);
145   } else if (arg_input_filenames.size() > 1) {
146     LOG(ERROR) << "More than one filename to a sqlite database.";
147     Usage(argv);
148   }
149 
150   std::string db_path = arg_input_filenames[0];
151 
152   if (enable_verbose) {
153     android::base::SetMinimumLogSeverity(android::base::VERBOSE);
154 
155     LOG(VERBOSE) << "Verbose check";
156     LOG(VERBOSE) << "Debug check: " << ::iorap::kIsDebugBuild;
157   } else {
158     android::base::SetMinimumLogSeverity(android::base::DEBUG);
159   }
160 
161   if (arg_purge_package) {
162     db::CleanUpFilesForPackage(db_path, *arg_purge_package);
163     return 0;
164     // Don't do any more work because SchemaModel can only be created once.
165   }
166 
167   maintenance::ControllerParameters params{
168     arg_output_text,
169     arg_inode_textcache,
170     enable_verbose,
171     recompile,
172     arg_min_traces,
173     std::make_shared<Exec>(),
174     exclude_dex_files};
175 
176   int ret_code = 0;
177   if (arg_package && arg_activity) {
178     ret_code = !Compile(std::move(db_path),
179                         std::move(*arg_package),
180                         std::move(*arg_activity),
181                         arg_version,
182                         params);
183   } else if (arg_package) {
184     ret_code = !Compile(std::move(db_path), std::move(*arg_package), arg_version, params);
185   } else {
186     ret_code = !Compile(std::move(db_path), params);
187   }
188   return ret_code;
189 }
190 
191 } // iorap::maintenance
192 
main(int argc,char ** argv)193 int main(int argc, char** argv) {
194   return ::iorap::maintenance::Main(argc, argv);
195 }
196 
197 
198 #endif  // IORAP_MAINTENANCE_MAIN
199