• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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>
29 #include <thread>
30 
31 #include <sys/types.h>
32 #include <dirent.h>
33 #include <string.h>
34 
35 using namespace std;
36 
37 map<string,string> g_buildVars;
38 
39 static unsigned int
get_thread_count()40 get_thread_count()
41 {
42     unsigned int threads = std::thread::hardware_concurrency();
43     // Guess if the value cannot be computed
44     return threads == 0 ? 4 : static_cast<unsigned int>(threads * 1.3f);
45 }
46 
47 string
get_build_var(const string & buildTop,const string & name,bool quiet)48 get_build_var(const string& buildTop, const string& name, bool quiet)
49 {
50     int err;
51 
52     map<string,string>::iterator it = g_buildVars.find(name);
53     if (it == g_buildVars.end()) {
54         Command cmd("make");
55         cmd.AddArg("--no-print-directory");
56         cmd.AddArg(string("-j") + std::to_string(get_thread_count()));
57         cmd.AddArg("-C");
58         cmd.AddArg(buildTop);
59         cmd.AddArg("-f");
60         cmd.AddArg("build/core/config.mk");
61         cmd.AddArg(string("dumpvar-") + name);
62         cmd.AddEnv("CALLED_FROM_SETUP", "true");
63         cmd.AddEnv("BUILD_SYSTEM", "build/core");
64 
65         string output = trim(get_command_output(cmd, &err, quiet));
66         if (err == 0) {
67             g_buildVars[name] = output;
68             return output;
69         } else {
70             return string();
71         }
72     } else {
73         return it->second;
74     }
75 }
76 
77 string
sniff_device_name(const string & buildOut,const string & product)78 sniff_device_name(const string& buildOut, const string& product)
79 {
80     string match("ro.build.product=" + product);
81 
82     string base(buildOut + "/target/product");
83     DIR* dir = opendir(base.c_str());
84     if (dir == NULL) {
85         return string();
86     }
87 
88     dirent* entry;
89     while ((entry = readdir(dir)) != NULL) {
90         if (entry->d_name[0] == '.') {
91             continue;
92         }
93         if (entry->d_type == DT_DIR) {
94             string filename(base + "/" + entry->d_name + "/system/build.prop");
95             vector<string> lines;
96             split_lines(&lines, read_file(filename));
97             for (size_t i=0; i<lines.size(); i++) {
98                 if (lines[i] == match) {
99                     return entry->d_name;
100                 }
101             }
102         }
103     }
104 
105     closedir(dir);
106     return string();
107 }
108 
109 void
json_error(const string & filename,const char * error,bool quiet)110 json_error(const string& filename, const char* error, bool quiet)
111 {
112     if (!quiet) {
113         print_error("Unable to parse module info file (%s): %s", error, filename.c_str());
114         print_error("Have you done a full build?");
115     }
116     exit(1);
117 }
118 
119 static void
get_values(const Json::Value & json,const string & name,vector<string> * result)120 get_values(const Json::Value& json, const string& name, vector<string>* result)
121 {
122     Json::Value nullValue;
123 
124     const Json::Value& value = json.get(name, nullValue);
125     if (!value.isArray()) {
126         return;
127     }
128 
129     const int N = value.size();
130     for (int i=0; i<N; i++) {
131         const Json::Value& child = value[i];
132         if (child.isString()) {
133             result->push_back(child.asString());
134         }
135     }
136 }
137 
138 void
read_modules(const string & buildOut,const string & device,map<string,Module> * result,bool quiet)139 read_modules(const string& buildOut, const string& device, map<string,Module>* result, bool quiet)
140 {
141     string filename(string(buildOut + "/target/product/") + device + "/module-info.json");
142     std::ifstream stream(filename, std::ifstream::binary);
143 
144     if (stream.fail()) {
145         if (!quiet) {
146             print_error("Unable to open module info file: %s", filename.c_str());
147             print_error("Have you done a full build?");
148         }
149         exit(1);
150     }
151 
152     Json::Value json;
153     Json::Reader reader;
154     if (!reader.parse(stream, json)) {
155         json_error(filename, "can't parse json format", quiet);
156         return;
157     }
158 
159     if (!json.isObject()) {
160         json_error(filename, "root element not an object", quiet);
161         return;
162     }
163 
164     vector<string> names = json.getMemberNames();
165     const int N = names.size();
166     for (int i=0; i<N; i++) {
167         const string& name = names[i];
168 
169         const Json::Value& value = json[name];
170         if (!value.isObject()) {
171             continue;
172         }
173 
174         Module module;
175 
176         module.name = name;
177         get_values(value, "class", &module.classes);
178         get_values(value, "path", &module.paths);
179         get_values(value, "installed", &module.installed);
180 
181         // Only keep classes we can handle
182         for (ssize_t i = module.classes.size() - 1; i >= 0; i--) {
183             string cl = module.classes[i];
184             if (!(cl == "JAVA_LIBRARIES" || cl == "EXECUTABLES" || cl == "SHARED_LIBRARIES"
185                     || cl == "APPS")) {
186                 module.classes.erase(module.classes.begin() + i);
187             }
188         }
189         if (module.classes.size() == 0) {
190             continue;
191         }
192 
193         // Only target modules (not host)
194         for (ssize_t i = module.installed.size() - 1; i >= 0; i--) {
195             string fn = module.installed[i];
196             if (!starts_with(fn, buildOut + "/target/")) {
197                 module.installed.erase(module.installed.begin() + i);
198             }
199         }
200         if (module.installed.size() == 0) {
201             continue;
202         }
203 
204         (*result)[name] = module;
205     }
206 }
207 
208 int
build_goals(const vector<string> & goals)209 build_goals(const vector<string>& goals)
210 {
211     Command cmd("make");
212     cmd.AddArg(string("-j") + std::to_string(get_thread_count()));
213     cmd.AddArg("-f");
214     cmd.AddArg("build/core/main.mk");
215     for (size_t i=0; i<goals.size(); i++) {
216         cmd.AddArg(goals[i]);
217     }
218 
219     return run_command(cmd);
220 }
221 
222