blob: 5a9ab22719cb0a5f41b653df7b8c74b651cf5740 [file] [log] [blame]
Joe Onorato0578cbc2016-10-19 17:03:06 -07001/*
2 * Copyright (C) 2016 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#include "make.h"
18
19#include "command.h"
20#include "print.h"
21#include "util.h"
22
23#include <json/reader.h>
24#include <json/value.h>
25
26#include <fstream>
27#include <string>
28#include <map>
Romain Guyd973aff2017-01-11 18:34:57 -080029#include <thread>
Joe Onorato0578cbc2016-10-19 17:03:06 -070030
31#include <sys/types.h>
32#include <dirent.h>
33#include <string.h>
34
35using namespace std;
36
37map<string,string> g_buildVars;
38
39string
Dan Willemsena40118d2017-10-17 17:46:41 -070040get_build_var(const string& name, bool quiet)
Joe Onorato0578cbc2016-10-19 17:03:06 -070041{
42 int err;
43
44 map<string,string>::iterator it = g_buildVars.find(name);
45 if (it == g_buildVars.end()) {
Dan Willemsena40118d2017-10-17 17:46:41 -070046 Command cmd("build/soong/soong_ui.bash");
47 cmd.AddArg("--dumpvar-mode");
48 cmd.AddArg(name);
Joe Onorato0578cbc2016-10-19 17:03:06 -070049
50 string output = trim(get_command_output(cmd, &err, quiet));
51 if (err == 0) {
52 g_buildVars[name] = output;
53 return output;
54 } else {
55 return string();
56 }
57 } else {
58 return it->second;
59 }
60}
61
62string
63sniff_device_name(const string& buildOut, const string& product)
64{
65 string match("ro.build.product=" + product);
66
67 string base(buildOut + "/target/product");
68 DIR* dir = opendir(base.c_str());
69 if (dir == NULL) {
70 return string();
71 }
72
73 dirent* entry;
74 while ((entry = readdir(dir)) != NULL) {
75 if (entry->d_name[0] == '.') {
76 continue;
77 }
78 if (entry->d_type == DT_DIR) {
79 string filename(base + "/" + entry->d_name + "/system/build.prop");
80 vector<string> lines;
81 split_lines(&lines, read_file(filename));
82 for (size_t i=0; i<lines.size(); i++) {
83 if (lines[i] == match) {
84 return entry->d_name;
85 }
86 }
87 }
88 }
89
90 closedir(dir);
91 return string();
92}
93
94void
95json_error(const string& filename, const char* error, bool quiet)
96{
97 if (!quiet) {
98 print_error("Unable to parse module info file (%s): %s", error, filename.c_str());
99 print_error("Have you done a full build?");
100 }
101 exit(1);
102}
103
104static void
105get_values(const Json::Value& json, const string& name, vector<string>* result)
106{
107 Json::Value nullValue;
108
109 const Json::Value& value = json.get(name, nullValue);
110 if (!value.isArray()) {
111 return;
112 }
113
114 const int N = value.size();
115 for (int i=0; i<N; i++) {
116 const Json::Value& child = value[i];
117 if (child.isString()) {
118 result->push_back(child.asString());
119 }
120 }
121}
122
123void
124read_modules(const string& buildOut, const string& device, map<string,Module>* result, bool quiet)
125{
126 string filename(string(buildOut + "/target/product/") + device + "/module-info.json");
127 std::ifstream stream(filename, std::ifstream::binary);
128
129 if (stream.fail()) {
130 if (!quiet) {
131 print_error("Unable to open module info file: %s", filename.c_str());
132 print_error("Have you done a full build?");
133 }
134 exit(1);
135 }
136
137 Json::Value json;
138 Json::Reader reader;
139 if (!reader.parse(stream, json)) {
140 json_error(filename, "can't parse json format", quiet);
141 return;
142 }
143
144 if (!json.isObject()) {
145 json_error(filename, "root element not an object", quiet);
146 return;
147 }
148
149 vector<string> names = json.getMemberNames();
150 const int N = names.size();
151 for (int i=0; i<N; i++) {
152 const string& name = names[i];
153
154 const Json::Value& value = json[name];
155 if (!value.isObject()) {
156 continue;
157 }
158
159 Module module;
160
161 module.name = name;
162 get_values(value, "class", &module.classes);
163 get_values(value, "path", &module.paths);
164 get_values(value, "installed", &module.installed);
165
166 // Only keep classes we can handle
167 for (ssize_t i = module.classes.size() - 1; i >= 0; i--) {
168 string cl = module.classes[i];
169 if (!(cl == "JAVA_LIBRARIES" || cl == "EXECUTABLES" || cl == "SHARED_LIBRARIES"
Joe Onorato0520afd2017-10-12 00:16:10 -0700170 || cl == "APPS" || cl == "NATIVE_TESTS")) {
Joe Onorato0578cbc2016-10-19 17:03:06 -0700171 module.classes.erase(module.classes.begin() + i);
172 }
173 }
174 if (module.classes.size() == 0) {
175 continue;
176 }
177
178 // Only target modules (not host)
179 for (ssize_t i = module.installed.size() - 1; i >= 0; i--) {
180 string fn = module.installed[i];
181 if (!starts_with(fn, buildOut + "/target/")) {
182 module.installed.erase(module.installed.begin() + i);
183 }
184 }
185 if (module.installed.size() == 0) {
186 continue;
187 }
188
189 (*result)[name] = module;
190 }
191}
192
193int
194build_goals(const vector<string>& goals)
195{
Dan Willemsena40118d2017-10-17 17:46:41 -0700196 Command cmd("build/soong/soong_ui.bash");
197 cmd.AddArg("--make-mode");
Joe Onorato0578cbc2016-10-19 17:03:06 -0700198 for (size_t i=0; i<goals.size(); i++) {
199 cmd.AddArg(goals[i]);
200 }
201
202 return run_command(cmd);
203}
204