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