Home | History | Annotate | Download | only in bit
      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