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 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 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 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 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 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 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 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