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 string 40 get_build_var(const string& name, bool quiet) 41 { 42 int err; 43 44 map<string,string>::iterator it = g_buildVars.find(name); 45 if (it == g_buildVars.end()) { 46 Command cmd("build/soong/soong_ui.bash"); 47 cmd.AddArg("--dumpvar-mode"); 48 cmd.AddArg(name); 49 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 62 string 63 sniff_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 94 void 95 json_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 104 static void 105 get_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 123 void 124 read_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" 170 || cl == "APPS" || cl == "NATIVE_TESTS")) { 171 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 193 int 194 build_goals(const vector<string>& goals) 195 { 196 Command cmd("build/soong/soong_ui.bash"); 197 cmd.AddArg("--make-mode"); 198 for (size_t i=0; i<goals.size(); i++) { 199 cmd.AddArg(goals[i]); 200 } 201 202 return run_command(cmd); 203 } 204 205