AssembleVintf.cpp revision ea25dd45961fc0b23ae9ba602c6d090590aa8241
14d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong/*
24d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * Copyright (C) 2017 The Android Open Source Project
34d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong *
44d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * Licensed under the Apache License, Version 2.0 (the "License");
54d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * you may not use this file except in compliance with the License.
64d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * You may obtain a copy of the License at
74d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong *
84d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong *      http://www.apache.org/licenses/LICENSE-2.0
94d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong *
104d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * Unless required by applicable law or agreed to in writing, software
114d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * distributed under the License is distributed on an "AS IS" BASIS,
124d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * See the License for the specific language governing permissions and
144d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * limitations under the License.
154d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong */
164d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
179aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong#include <getopt.h>
184d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <stdlib.h>
194d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <unistd.h>
204d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
214d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <fstream>
224d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <iostream>
234d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <unordered_map>
244d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <sstream>
254d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <string>
264d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
279a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong#include <android-base/file.h>
28dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong#include <android-base/parseint.h>
299a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong
3079efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong#include <vintf/KernelConfigParser.h>
314d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <vintf/parse_string.h>
324d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong#include <vintf/parse_xml.h>
334d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
3479efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong#define BUFFER_SIZE sysconf(_SC_PAGESIZE)
3579efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong
364d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hongnamespace android {
374d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hongnamespace vintf {
384d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
399a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hongstatic const std::string gConfigPrefix = "android-base-";
409a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hongstatic const std::string gConfigSuffix = ".cfg";
419a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hongstatic const std::string gBaseConfig = "android-base.cfg";
429a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong
434d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong/**
444d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong * Slurps the device manifest file and add build time flag to it.
454d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong */
464d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hongclass AssembleVintf {
479a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong    using Condition = std::unique_ptr<KernelConfig>;
489a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong    using ConditionedConfig = std::pair<Condition, std::vector<KernelConfig> /* configs */>;
499a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong
509a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong   public:
514d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong    template<typename T>
524d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong    static bool getFlag(const std::string& key, T* value) {
534d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong        const char *envValue = getenv(key.c_str());
544d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong        if (envValue == NULL) {
55488e16a67311194f0fb9aa4a33219af170e6316bYifan Hong            std::cerr << "Warning: " << key << " is missing, defaulted to " << (*value)
56488e16a67311194f0fb9aa4a33219af170e6316bYifan Hong                      << std::endl;
57488e16a67311194f0fb9aa4a33219af170e6316bYifan Hong            return true;
584d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong        }
594d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
604d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong        if (!parse(envValue, value)) {
614d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            std::cerr << "Cannot parse " << envValue << "." << std::endl;
624d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            return false;
634d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong        }
644d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong        return true;
654d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong    }
664d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
67dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    static bool getBooleanFlag(const char* key) {
68dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        const char* envValue = getenv(key);
69dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        return envValue != nullptr && strcmp(envValue, "true") == 0;
70dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    }
71dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong
72dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    static size_t getIntegerFlag(const char* key, size_t defaultValue = 0) {
73dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        std::string envValue = getenv(key);
74dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        if (envValue.empty()) {
75dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            return defaultValue;
76dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        }
77dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        size_t value;
78dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        if (!base::ParseUint(envValue, &value)) {
79dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            std::cerr << "Error: " << key << " must be a number." << std::endl;
80dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            return defaultValue;
81dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        }
82dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        return value;
83dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    }
84dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong
854650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong    static std::string read(std::basic_istream<char>& is) {
864650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong        std::stringstream ss;
874650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong        ss << is.rdbuf();
884650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong        return ss.str();
894650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong    }
904650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong
919a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong    static bool isCommonConfig(const std::string& path) {
929a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong        return ::android::base::Basename(path) == gBaseConfig;
939a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong    }
949a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong
95dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    static Level convertFromApiLevel(size_t apiLevel) {
96dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        if (apiLevel < 26) {
97dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            return Level::LEGACY;
98dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        } else if (apiLevel == 26) {
99dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            return Level::O;
100dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        } else if (apiLevel == 27) {
101dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            return Level::O_MR1;
102dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        } else {
103dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            return Level::UNSPECIFIED;
104dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        }
105dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    }
106dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong
107079ec2492c275b9041584f2f07605982682c559cYifan Hong    // nullptr on any error, otherwise the condition.
108079ec2492c275b9041584f2f07605982682c559cYifan Hong    static Condition generateCondition(const std::string& path) {
109079ec2492c275b9041584f2f07605982682c559cYifan Hong        std::string fname = ::android::base::Basename(path);
110079ec2492c275b9041584f2f07605982682c559cYifan Hong        if (fname.size() <= gConfigPrefix.size() + gConfigSuffix.size() ||
111079ec2492c275b9041584f2f07605982682c559cYifan Hong            !std::equal(gConfigPrefix.begin(), gConfigPrefix.end(), fname.begin()) ||
112079ec2492c275b9041584f2f07605982682c559cYifan Hong            !std::equal(gConfigSuffix.rbegin(), gConfigSuffix.rend(), fname.rbegin())) {
113079ec2492c275b9041584f2f07605982682c559cYifan Hong            return nullptr;
114079ec2492c275b9041584f2f07605982682c559cYifan Hong        }
115079ec2492c275b9041584f2f07605982682c559cYifan Hong
116079ec2492c275b9041584f2f07605982682c559cYifan Hong        std::string sub = fname.substr(gConfigPrefix.size(),
117079ec2492c275b9041584f2f07605982682c559cYifan Hong                                       fname.size() - gConfigPrefix.size() - gConfigSuffix.size());
118079ec2492c275b9041584f2f07605982682c559cYifan Hong        if (sub.empty()) {
119079ec2492c275b9041584f2f07605982682c559cYifan Hong            return nullptr;  // should not happen
120079ec2492c275b9041584f2f07605982682c559cYifan Hong        }
121079ec2492c275b9041584f2f07605982682c559cYifan Hong        for (size_t i = 0; i < sub.size(); ++i) {
122079ec2492c275b9041584f2f07605982682c559cYifan Hong            if (sub[i] == '-') {
123079ec2492c275b9041584f2f07605982682c559cYifan Hong                sub[i] = '_';
124079ec2492c275b9041584f2f07605982682c559cYifan Hong                continue;
125079ec2492c275b9041584f2f07605982682c559cYifan Hong            }
126079ec2492c275b9041584f2f07605982682c559cYifan Hong            if (isalnum(sub[i])) {
127079ec2492c275b9041584f2f07605982682c559cYifan Hong                sub[i] = toupper(sub[i]);
128079ec2492c275b9041584f2f07605982682c559cYifan Hong                continue;
129079ec2492c275b9041584f2f07605982682c559cYifan Hong            }
130079ec2492c275b9041584f2f07605982682c559cYifan Hong            std::cerr << "'" << fname << "' (in " << path
131079ec2492c275b9041584f2f07605982682c559cYifan Hong                      << ") is not a valid kernel config file name. Must match regex: "
132079ec2492c275b9041584f2f07605982682c559cYifan Hong                      << "android-base(-[0-9a-zA-Z-]+)?\\.cfg" << std::endl;
133079ec2492c275b9041584f2f07605982682c559cYifan Hong            return nullptr;
134079ec2492c275b9041584f2f07605982682c559cYifan Hong        }
135079ec2492c275b9041584f2f07605982682c559cYifan Hong        sub.insert(0, "CONFIG_");
136079ec2492c275b9041584f2f07605982682c559cYifan Hong        return std::make_unique<KernelConfig>(std::move(sub), Tristate::YES);
137079ec2492c275b9041584f2f07605982682c559cYifan Hong    }
138079ec2492c275b9041584f2f07605982682c559cYifan Hong
13979efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong    static bool parseFileForKernelConfigs(const std::string& path, std::vector<KernelConfig>* out) {
14079efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        std::ifstream ifs{path};
14179efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        if (!ifs.is_open()) {
14279efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong            std::cerr << "File '" << path << "' does not exist or cannot be read." << std::endl;
14379efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong            return false;
14479efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        }
14502e94004a6d35d20af7df1ea9c66c5b65e4bd9c6Yifan Hong        KernelConfigParser parser(true /* processComments */, true /* relaxedFormat */);
14679efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        std::string content = read(ifs);
14779efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        status_t err = parser.process(content.c_str(), content.size());
14879efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        if (err != OK) {
149ae53a0e6d3f605cc124009cb0172f152f69417a4Yifan Hong            std::cerr << parser.error();
15079efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong            return false;
15179efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        }
15279efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        err = parser.finish();
15379efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        if (err != OK) {
154ae53a0e6d3f605cc124009cb0172f152f69417a4Yifan Hong            std::cerr << parser.error();
15579efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong            return false;
15679efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        }
15779efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong
15879efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        for (auto& configPair : parser.configs()) {
15979efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong            out->push_back({});
16079efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong            KernelConfig& config = out->back();
16179efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong            config.first = std::move(configPair.first);
16279efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong            if (!parseKernelConfigTypedValue(configPair.second, &config.second)) {
16379efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong                std::cerr << "Unknown value type for key = '" << config.first << "', value = '"
16479efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong                          << configPair.second << "'\n";
16579efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong                return false;
16679efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong            }
16779efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        }
16879efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        return true;
16979efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong    }
17079efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong
1719a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong    static bool parseFilesForKernelConfigs(const std::string& path,
1729a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong                                           std::vector<ConditionedConfig>* out) {
1739a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong        out->clear();
1749a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong        ConditionedConfig commonConfig;
1759a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong        bool foundCommonConfig = false;
1760bef86826065d9cfdad3139ea186a98524cf2eddSteve Muckle        bool ret = true;
1770bef86826065d9cfdad3139ea186a98524cf2eddSteve Muckle        char *pathIter;
1780bef86826065d9cfdad3139ea186a98524cf2eddSteve Muckle        char *modPath = new char[path.length() + 1];
1790bef86826065d9cfdad3139ea186a98524cf2eddSteve Muckle        strcpy(modPath, path.c_str());
1800bef86826065d9cfdad3139ea186a98524cf2eddSteve Muckle        pathIter = strtok(modPath, ":");
1810bef86826065d9cfdad3139ea186a98524cf2eddSteve Muckle        while (ret && pathIter != NULL) {
1829a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong            if (isCommonConfig(pathIter)) {
1839a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong                ret &= parseFileForKernelConfigs(pathIter, &commonConfig.second);
1849a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong                foundCommonConfig = true;
1859a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong            } else {
186079ec2492c275b9041584f2f07605982682c559cYifan Hong                Condition condition = generateCondition(pathIter);
187079ec2492c275b9041584f2f07605982682c559cYifan Hong                ret &= (condition != nullptr);
188079ec2492c275b9041584f2f07605982682c559cYifan Hong
1899a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong                std::vector<KernelConfig> kernelConfigs;
1909a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong                if ((ret &= parseFileForKernelConfigs(pathIter, &kernelConfigs)))
191079ec2492c275b9041584f2f07605982682c559cYifan Hong                    out->emplace_back(std::move(condition), std::move(kernelConfigs));
1929a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong            }
1930bef86826065d9cfdad3139ea186a98524cf2eddSteve Muckle            pathIter = strtok(NULL, ":");
1940bef86826065d9cfdad3139ea186a98524cf2eddSteve Muckle        }
19582266ae07e00e0b90bc7f13d3ce77ff10291d346Luis A. Lozano        delete[] modPath;
1969a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong
1979a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong        if (!foundCommonConfig) {
1989a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong            std::cerr << "No android-base.cfg is found in these paths: '" << path << "'"
1999a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong                      << std::endl;
2009a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong        }
2019a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong        ret &= foundCommonConfig;
2029a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong        // first element is always common configs (no conditions).
2039a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong        out->insert(out->begin(), std::move(commonConfig));
2040bef86826065d9cfdad3139ea186a98524cf2eddSteve Muckle        return ret;
2050bef86826065d9cfdad3139ea186a98524cf2eddSteve Muckle    }
2060bef86826065d9cfdad3139ea186a98524cf2eddSteve Muckle
207dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    static std::string getFileNameFromPath(std::string path) {
208dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        auto idx = path.find_last_of("\\/");
209dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        if (idx != std::string::npos) {
210dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            path.erase(0, idx + 1);
211dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        }
212dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        return path;
213dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    }
214dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong
2159aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    std::basic_ostream<char>& out() const {
2169aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        return mOutFileRef == nullptr ? std::cout : *mOutFileRef;
2179aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    }
2189aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
219dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    template <typename S>
220dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    using Schemas = std::vector<std::pair<std::string, S>>;
221dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    using HalManifests = Schemas<HalManifest>;
222dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    using CompatibilityMatrices = Schemas<CompatibilityMatrix>;
223dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong
224dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    bool assembleHalManifest(HalManifests* halManifests) {
2254650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong        std::string error;
226dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        HalManifest* halManifest = &halManifests->front().second;
227dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        for (auto it = halManifests->begin() + 1; it != halManifests->end(); ++it) {
228dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            const std::string& path = it->first;
229dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            HalManifest& halToAdd = it->second;
230dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong
231dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            if (halToAdd.level() != Level::UNSPECIFIED) {
232dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                if (halManifest->level() == Level::UNSPECIFIED) {
233dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                    halManifest->mLevel = halToAdd.level();
234dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                } else if (halManifest->level() != halToAdd.level()) {
235dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                    std::cerr << "Inconsistent FCM Version in HAL manifests:" << std::endl
236dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                              << "    File '" << halManifests->front().first << "' has level "
237dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                              << halManifest->level() << std::endl
238dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                              << "    File '" << path << "' has level " << halToAdd.level()
239dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                              << std::endl;
240dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                    return false;
241dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                }
242dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            }
243dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong
244ea25dd45961fc0b23ae9ba602c6d090590aa8241Yifan Hong            if (!halManifest->addAllHals(&halToAdd, &error)) {
245dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                std::cerr << "File \"" << path << "\" cannot be added: conflict on HAL \"" << error
246dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                          << "\" with an existing HAL. See <hal> with the same name "
247dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                          << "in previously parsed files or previously declared in this file."
248dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                          << std::endl;
249dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                return false;
250dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            }
251dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        }
2524d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
2539aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        if (halManifest->mType == SchemaType::DEVICE) {
2549aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            if (!getFlag("BOARD_SEPOLICY_VERS", &halManifest->device.mSepolicyVersion)) {
2559aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                return false;
2564d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            }
257dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            if (!setDeviceFcmVersion(halManifest)) {
258dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                return false;
259dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            }
2609aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        }
2614d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
2629aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        if (mOutputMatrix) {
2639aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            CompatibilityMatrix generatedMatrix = halManifest->generateCompatibleMatrix();
2649aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            if (!halManifest->checkCompatibility(generatedMatrix, &error)) {
2659aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                std::cerr << "FATAL ERROR: cannot generate a compatible matrix: " << error
2669aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                          << std::endl;
267a59d2567783cad6f675d2fc1f2fcce4bce3e34e3Yifan Hong            }
2689aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            out() << "<!-- \n"
2699aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                     "    Autogenerated skeleton compatibility matrix. \n"
2709aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                     "    Use with caution. Modify it to suit your needs.\n"
2719aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                     "    All HALs are set to optional.\n"
2729aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                     "    Many entries other than HALs are zero-filled and\n"
2739aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                     "    require human attention. \n"
2749aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                     "-->\n"
275a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong                  << gCompatibilityMatrixConverter(generatedMatrix, mSerializeFlags);
2769aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        } else {
277a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong            out() << gHalManifestConverter(*halManifest, mSerializeFlags);
2789aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        }
2799aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        out().flush();
2809aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
2819aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        if (mCheckFile.is_open()) {
2829aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            CompatibilityMatrix checkMatrix;
2839aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            if (!gCompatibilityMatrixConverter(&checkMatrix, read(mCheckFile))) {
2849aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                std::cerr << "Cannot parse check file as a compatibility matrix: "
2859aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                          << gCompatibilityMatrixConverter.lastError() << std::endl;
2869aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                return false;
2874650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong            }
2889aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            if (!halManifest->checkCompatibility(checkMatrix, &error)) {
2899aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                std::cerr << "Not compatible: " << error << std::endl;
2909aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                return false;
2919aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            }
2929aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        }
2934650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong
2949aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        return true;
2959aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    }
2969aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
297e88e16721117aaf97548bebbffd6c8ea81b681efYifan Hong    bool assembleFrameworkCompatibilityMatrixKernels(CompatibilityMatrix* matrix) {
2984c34fee9175766bf69b53c4d75ea251ef976185bYifan Hong        if (!matrix->framework.mKernels.empty()) {
2994c34fee9175766bf69b53c4d75ea251ef976185bYifan Hong            // Remove hard-coded <kernel version="x.y.z" /> in legacy files.
3004c34fee9175766bf69b53c4d75ea251ef976185bYifan Hong            std::cerr << "WARNING: framework compatibility matrix has hard-coded kernel"
3014c34fee9175766bf69b53c4d75ea251ef976185bYifan Hong                      << " requirements for version";
3024c34fee9175766bf69b53c4d75ea251ef976185bYifan Hong            for (const auto& kernel : matrix->framework.mKernels) {
3034c34fee9175766bf69b53c4d75ea251ef976185bYifan Hong                std::cerr << " " << kernel.minLts();
3044c34fee9175766bf69b53c4d75ea251ef976185bYifan Hong            }
3054c34fee9175766bf69b53c4d75ea251ef976185bYifan Hong            std::cerr << ". Hard-coded requirements are removed." << std::endl;
3064c34fee9175766bf69b53c4d75ea251ef976185bYifan Hong            matrix->framework.mKernels.clear();
3074c34fee9175766bf69b53c4d75ea251ef976185bYifan Hong        }
308e88e16721117aaf97548bebbffd6c8ea81b681efYifan Hong        for (const auto& pair : mKernels) {
3099a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong            std::vector<ConditionedConfig> conditionedConfigs;
3109a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong            if (!parseFilesForKernelConfigs(pair.second, &conditionedConfigs)) {
311e88e16721117aaf97548bebbffd6c8ea81b681efYifan Hong                return false;
312e88e16721117aaf97548bebbffd6c8ea81b681efYifan Hong            }
3139a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong            for (ConditionedConfig& conditionedConfig : conditionedConfigs) {
31448602dfa0ef4a40b58c6376bab82c6e46d6f6a0bYifan Hong                MatrixKernel kernel(KernelVersion{pair.first.majorVer, pair.first.minorVer, 0u},
31548602dfa0ef4a40b58c6376bab82c6e46d6f6a0bYifan Hong                                    std::move(conditionedConfig.second));
316079ec2492c275b9041584f2f07605982682c559cYifan Hong                if (conditionedConfig.first != nullptr)
317079ec2492c275b9041584f2f07605982682c559cYifan Hong                    kernel.mConditions.push_back(std::move(*conditionedConfig.first));
318079ec2492c275b9041584f2f07605982682c559cYifan Hong                matrix->framework.mKernels.push_back(std::move(kernel));
3199a8b1a7cec9f39953001a2f113cb976ae73eb211Yifan Hong            }
320e88e16721117aaf97548bebbffd6c8ea81b681efYifan Hong        }
321e88e16721117aaf97548bebbffd6c8ea81b681efYifan Hong        return true;
322e88e16721117aaf97548bebbffd6c8ea81b681efYifan Hong    }
323e88e16721117aaf97548bebbffd6c8ea81b681efYifan Hong
324dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    bool setDeviceFcmVersion(HalManifest* manifest) {
325dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        size_t shippingApiLevel = getIntegerFlag("PRODUCT_SHIPPING_API_LEVEL");
326dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong
327dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        if (manifest->level() != Level::UNSPECIFIED) {
328dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            return true;
329dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        }
330dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        if (!getBooleanFlag("PRODUCT_ENFORCE_VINTF_MANIFEST")) {
331dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            manifest->mLevel = Level::LEGACY;
332dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            return true;
333dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        }
334dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        // TODO(b/70628538): Do not infer from Shipping API level.
335dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        if (shippingApiLevel) {
336dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            std::cerr << "Warning: Shipping FCM Version is inferred from Shipping API level. "
337dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                      << "Declare Shipping FCM Version in device manifest directly." << std::endl;
338dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            manifest->mLevel = convertFromApiLevel(shippingApiLevel);
339dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            if (manifest->mLevel == Level::UNSPECIFIED) {
340dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                std::cerr << "Error: Shipping FCM Version cannot be inferred from Shipping API "
341dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                          << "level " << shippingApiLevel << "."
342dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                          << "Declare Shipping FCM Version in device manifest directly."
343dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                          << std::endl;
344dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                return false;
345dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            }
346dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            return true;
347dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        }
348dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        // TODO(b/69638851): should be an error if Shipping API level is not defined.
349dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        // For now, just leave it empty; when framework compatibility matrix is built,
350dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        // lowest FCM Version is assumed.
351dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        std::cerr << "Warning: Shipping FCM Version cannot be inferred, because:" << std::endl
352dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                  << "    (1) It is not explicitly declared in device manifest;" << std::endl
353dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                  << "    (2) PRODUCT_ENFORCE_VINTF_MANIFEST is set to true;" << std::endl
354dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                  << "    (3) PRODUCT_SHIPPING_API_LEVEL is undefined." << std::endl
355dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                  << "Assuming 'unspecified' Shipping FCM Version. " << std::endl
356dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                  << "To remove this warning, define 'level' attribute in device manifest."
357dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                  << std::endl;
358dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        return true;
359dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    }
3609aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
361dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    Level getLowestFcmVersion(const CompatibilityMatrices& matrices) {
362dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        Level ret = Level::UNSPECIFIED;
363dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        for (const auto& e : matrices) {
364dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            if (ret == Level::UNSPECIFIED || ret > e.second.level()) {
365dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                ret = e.second.level();
366dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            }
367dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        }
368dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        return ret;
369dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    }
370dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong
371dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong    bool assembleCompatibilityMatrix(CompatibilityMatrices* matrices) {
372dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        std::string error;
373dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        CompatibilityMatrix* matrix = nullptr;
3749aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        KernelSepolicyVersion kernelSepolicyVers;
3759aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        Version sepolicyVers;
376dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        std::unique_ptr<HalManifest> checkManifest;
377dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        if (matrices->front().second.mType == SchemaType::DEVICE) {
378dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            matrix = &matrices->front().second;
379dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        }
380dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong
381dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        if (matrices->front().second.mType == SchemaType::FRAMEWORK) {
382dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            Level deviceLevel = Level::UNSPECIFIED;
383dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            std::vector<std::string> fileList;
384dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            if (mCheckFile.is_open()) {
385dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                checkManifest = std::make_unique<HalManifest>();
386dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                if (!gHalManifestConverter(checkManifest.get(), read(mCheckFile))) {
387dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                    std::cerr << "Cannot parse check file as a HAL manifest: "
388dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                              << gHalManifestConverter.lastError() << std::endl;
389dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                    return false;
390dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                }
391dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                deviceLevel = checkManifest->level();
392dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            }
393dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong
394dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            if (deviceLevel == Level::UNSPECIFIED) {
395dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                // For GSI build, legacy devices that do not have a HAL manifest,
396dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                // and devices in development, merge all compatibility matrices.
397dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                deviceLevel = getLowestFcmVersion(*matrices);
398dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            }
399dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong
400dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            for (auto& e : *matrices) {
401dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                if (e.second.level() == deviceLevel) {
402dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                    fileList.push_back(e.first);
403dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                    matrix = &e.second;
404dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                }
405dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            }
406dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            if (matrix == nullptr) {
407dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                std::cerr << "FATAL ERROR: cannot find matrix with level '" << deviceLevel << "'"
408dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                          << std::endl;
409dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                return false;
410dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            }
411dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            for (auto& e : *matrices) {
412dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                if (e.second.level() <= deviceLevel) {
413dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                    continue;
414dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                }
415dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                fileList.push_back(e.first);
416dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                if (!matrix->addAllHalsAsOptional(&e.second, &error)) {
417dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                    std::cerr << "File \"" << e.first << "\" cannot be added: " << error
418dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                              << ". See <hal> with the same name "
419dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                              << "in previously parsed files or previously declared in this file."
420dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                              << std::endl;
421dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                    return false;
422dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                }
423dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            }
424dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong
4259aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            if (!getFlag("BOARD_SEPOLICY_VERS", &sepolicyVers)) {
4269aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                return false;
4279aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            }
4289aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            if (!getFlag("POLICYVERS", &kernelSepolicyVers)) {
4299aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                return false;
4309aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            }
431e88e16721117aaf97548bebbffd6c8ea81b681efYifan Hong
432e88e16721117aaf97548bebbffd6c8ea81b681efYifan Hong            if (!assembleFrameworkCompatibilityMatrixKernels(matrix)) {
433e88e16721117aaf97548bebbffd6c8ea81b681efYifan Hong                return false;
43479efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong            }
435e88e16721117aaf97548bebbffd6c8ea81b681efYifan Hong
4369aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            matrix->framework.mSepolicy =
4379aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                Sepolicy(kernelSepolicyVers, {{sepolicyVers.majorVer, sepolicyVers.minorVer}});
4387f6c00c77c755f4efef49e5371058470a461193fYifan Hong
4397f6c00c77c755f4efef49e5371058470a461193fYifan Hong            Version avbMetaVersion;
4407f6c00c77c755f4efef49e5371058470a461193fYifan Hong            if (!getFlag("FRAMEWORK_VBMETA_VERSION", &avbMetaVersion)) {
4417f6c00c77c755f4efef49e5371058470a461193fYifan Hong                return false;
4427f6c00c77c755f4efef49e5371058470a461193fYifan Hong            }
4437f6c00c77c755f4efef49e5371058470a461193fYifan Hong            matrix->framework.mAvbMetaVersion = avbMetaVersion;
444dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong
445dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            out() << "<!--" << std::endl;
446dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            out() << "    Input:" << std::endl;
447dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            for (const auto& path : fileList) {
448dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                out() << "        " << getFileNameFromPath(path) << std::endl;
449dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            }
450dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            out() << "-->" << std::endl;
451a59d2567783cad6f675d2fc1f2fcce4bce3e34e3Yifan Hong        }
452a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong        out() << gCompatibilityMatrixConverter(*matrix, mSerializeFlags);
4539aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        out().flush();
454a59d2567783cad6f675d2fc1f2fcce4bce3e34e3Yifan Hong
455dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        if (checkManifest != nullptr && getBooleanFlag("PRODUCT_ENFORCE_VINTF_MANIFEST") &&
456dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            !checkManifest->checkCompatibility(*matrix, &error)) {
457dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            std::cerr << "Not compatible: " << error << std::endl;
458dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            return false;
4599aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        }
4609aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
4619aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        return true;
4629aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    }
4639aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
464bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    enum AssembleStatus { SUCCESS, FAIL_AND_EXIT, TRY_NEXT };
465bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    template <typename Schema, typename AssembleFunc>
466bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    AssembleStatus tryAssemble(const XmlConverter<Schema>& converter, const std::string& schemaName,
467bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                               AssembleFunc assemble) {
468dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        Schemas<Schema> schemas;
469bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        Schema schema;
470bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        if (!converter(&schema, read(mInFiles.front()))) {
471bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong            return TRY_NEXT;
472bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        }
473bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        auto firstType = schema.type();
474dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        schemas.emplace_back(mInFilePaths.front(), std::move(schema));
475dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong
476bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        for (auto it = mInFiles.begin() + 1; it != mInFiles.end(); ++it) {
477bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong            Schema additionalSchema;
478dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            const std::string fileName = mInFilePaths[std::distance(mInFiles.begin(), it)];
479bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong            if (!converter(&additionalSchema, read(*it))) {
480dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                std::cerr << "File \"" << fileName << "\" is not a valid " << firstType << " "
481dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                          << schemaName << " (but the first file is a valid " << firstType << " "
482dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                          << schemaName << "). Error: " << converter.lastError() << std::endl;
483bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                return FAIL_AND_EXIT;
484bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong            }
485bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong            if (additionalSchema.type() != firstType) {
486dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                std::cerr << "File \"" << fileName << "\" is a " << additionalSchema.type() << " "
487dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                          << schemaName << " (but a " << firstType << " " << schemaName
488dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong                          << " is expected)." << std::endl;
489eb14e3013ea11b3d47d40fa860f16345c607fef6Yifan Hong                return FAIL_AND_EXIT;
490eb14e3013ea11b3d47d40fa860f16345c607fef6Yifan Hong            }
491dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong
492dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong            schemas.emplace_back(fileName, std::move(additionalSchema));
493bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        }
494dbe9db35fe506f6547d33b44ec5e20b70bf343c2Yifan Hong        return assemble(&schemas) ? SUCCESS : FAIL_AND_EXIT;
495bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    }
496bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong
4979aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    bool assemble() {
498bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        using std::placeholders::_1;
499bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        if (mInFiles.empty()) {
5009aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            std::cerr << "Missing input file." << std::endl;
5019aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong            return false;
5029aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        }
5039aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
504bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        auto status = tryAssemble(gHalManifestConverter, "manifest",
505bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                                  std::bind(&AssembleVintf::assembleHalManifest, this, _1));
506bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        if (status == SUCCESS) return true;
507bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        if (status == FAIL_AND_EXIT) return false;
5089aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
509bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        resetInFiles();
5104650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong
511bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        status = tryAssemble(gCompatibilityMatrixConverter, "compatibility matrix",
512bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                             std::bind(&AssembleVintf::assembleCompatibilityMatrix, this, _1));
513bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        if (status == SUCCESS) return true;
514bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        if (status == FAIL_AND_EXIT) return false;
5154d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
516959ee1bf8b922980542f72ce9ad1929fc7d8b55cYifan Hong        std::cerr << "Input file has unknown format." << std::endl
517959ee1bf8b922980542f72ce9ad1929fc7d8b55cYifan Hong                  << "Error when attempting to convert to manifest: "
518959ee1bf8b922980542f72ce9ad1929fc7d8b55cYifan Hong                  << gHalManifestConverter.lastError() << std::endl
519959ee1bf8b922980542f72ce9ad1929fc7d8b55cYifan Hong                  << "Error when attempting to convert to compatibility matrix: "
520959ee1bf8b922980542f72ce9ad1929fc7d8b55cYifan Hong                  << gCompatibilityMatrixConverter.lastError() << std::endl;
521959ee1bf8b922980542f72ce9ad1929fc7d8b55cYifan Hong        return false;
5224d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong    }
5239aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
5249aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    bool openOutFile(const char* path) {
5259aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        mOutFileRef = std::make_unique<std::ofstream>();
5269aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        mOutFileRef->open(path);
5279aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        return mOutFileRef->is_open();
5289aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    }
5299aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
5309aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    bool openInFile(const char* path) {
531bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        mInFilePaths.push_back(path);
532bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        mInFiles.push_back({});
533bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        mInFiles.back().open(path);
534bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        return mInFiles.back().is_open();
5359aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    }
5369aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
5379aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    bool openCheckFile(const char* path) {
5389aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        mCheckFile.open(path);
5399aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong        return mCheckFile.is_open();
5409aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    }
5419aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
542bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    void resetInFiles() {
543bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        for (auto& inFile : mInFiles) {
544bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong            inFile.clear();
545bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong            inFile.seekg(0);
546bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong        }
547bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    }
548bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong
5499aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    void setOutputMatrix() { mOutputMatrix = true; }
5509aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
551a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong    bool setHalsOnly() {
552a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong        if (mSerializeFlags) return false;
553a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong        mSerializeFlags |= SerializeFlag::HALS_ONLY;
554a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong        return true;
555a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong    }
556a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong
557a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong    bool setNoHals() {
558a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong        if (mSerializeFlags) return false;
559a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong        mSerializeFlags |= SerializeFlag::NO_HALS;
560a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong        return true;
561a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong    }
562a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong
56379efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong    bool addKernel(const std::string& kernelArg) {
56479efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        auto ind = kernelArg.find(':');
56579efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        if (ind == std::string::npos) {
56679efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong            std::cerr << "Unrecognized --kernel option '" << kernelArg << "'" << std::endl;
56779efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong            return false;
56879efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        }
56979efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        std::string kernelVerStr{kernelArg.begin(), kernelArg.begin() + ind};
57079efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        std::string kernelConfigPath{kernelArg.begin() + ind + 1, kernelArg.end()};
57179efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        Version kernelVer;
57279efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        if (!parse(kernelVerStr, &kernelVer)) {
57379efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong            std::cerr << "Unrecognized kernel version '" << kernelVerStr << "'" << std::endl;
57479efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong            return false;
57579efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        }
57648602dfa0ef4a40b58c6376bab82c6e46d6f6a0bYifan Hong        if (mKernels.find(kernelVer) != mKernels.end()) {
57748602dfa0ef4a40b58c6376bab82c6e46d6f6a0bYifan Hong            std::cerr << "Multiple --kernel for " << kernelVer << " is specified." << std::endl;
57848602dfa0ef4a40b58c6376bab82c6e46d6f6a0bYifan Hong            return false;
57948602dfa0ef4a40b58c6376bab82c6e46d6f6a0bYifan Hong        }
58048602dfa0ef4a40b58c6376bab82c6e46d6f6a0bYifan Hong        mKernels[kernelVer] = kernelConfigPath;
58179efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong        return true;
58279efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong    }
58379efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong
5849aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong   private:
585bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    std::vector<std::string> mInFilePaths;
586bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    std::vector<std::ifstream> mInFiles;
5879aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    std::unique_ptr<std::ofstream> mOutFileRef;
5889aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    std::ifstream mCheckFile;
5899aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    bool mOutputMatrix = false;
590a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong    SerializeFlags mSerializeFlags = SerializeFlag::EVERYTHING;
59148602dfa0ef4a40b58c6376bab82c6e46d6f6a0bYifan Hong    std::map<Version, std::string> mKernels;
5924d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong};
5934d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
5944d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong}  // namespace vintf
5954d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong}  // namespace android
5964d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
5974d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hongvoid help() {
5989aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    std::cerr << "assemble_vintf: Checks if a given manifest / matrix file is valid and \n"
5999aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "    fill in build-time flags into the given file.\n"
6009aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "assemble_vintf -h\n"
6019aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               Display this help text.\n"
602bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                 "assemble_vintf -i <input file>[:<input file>[...]] [-o <output file>] [-m]\n"
603bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                 "               [-c [<check file>]]\n"
6049aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               Fill in build-time flags into the given file.\n"
605bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                 "    -i <input file>[:<input file>[...]]\n"
606bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                 "               A list of input files. Format is automatically detected for the\n"
607bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                 "               first file, and the remaining files must have the same format.\n"
608bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                 "               Files other than the first file should only have <hal> defined;\n"
609bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                 "               other entries are ignored.\n"
6109aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "    -o <output file>\n"
6119aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               Optional output file. If not specified, write to stdout.\n"
6129aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "    -m\n"
6139aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               a compatible compatibility matrix is\n"
6149aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               generated instead; for example, given a device manifest,\n"
6159aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               a framework compatibility matrix is generated. This flag\n"
6169aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               is ignored when input is a compatibility matrix.\n"
6179aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "    -c [<check file>]\n"
6189aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               After writing the output file, check compatibility between\n"
6199aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               output file and check file.\n"
6209aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               If -c is set but the check file is not specified, a warning\n"
6219aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               message is written to stderr. Return 0.\n"
6229aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                 "               If the check file is specified but is not compatible, an error\n"
62379efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong                 "               message is written to stderr. Return 1.\n"
6240bef86826065d9cfdad3139ea186a98524cf2eddSteve Muckle                 "    --kernel=<version>:<android-base.cfg>[:<android-base-arch.cfg>[...]]\n"
62579efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong                 "               Add a kernel entry to framework compatibility matrix.\n"
62679efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong                 "               Ignored for other input format.\n"
62779efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong                 "               <version> has format: 3.18\n"
6280bef86826065d9cfdad3139ea186a98524cf2eddSteve Muckle                 "               <android-base.cfg> is the location of android-base.cfg\n"
6290bef86826065d9cfdad3139ea186a98524cf2eddSteve Muckle                 "               <android-base-arch.cfg> is the location of an optional\n"
630a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong                 "               arch-specific config fragment, more than one may be specified\n"
631a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong                 "    -l, --hals-only\n"
632a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong                 "               Output has only <hal> entries. Cannot be used with -n.\n"
633a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong                 "    -n, --no-hals\n"
634a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong                 "               Output has no <hal> entries (but all other entries).\n"
635a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong                 "               Cannot be used with -l.\n";
6364d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong}
6374d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
6384d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hongint main(int argc, char **argv) {
639a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong    const struct option longopts[] = {{"kernel", required_argument, NULL, 'k'},
640a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong                                      {"hals-only", no_argument, NULL, 'l'},
641a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong                                      {"no-hals", no_argument, NULL, 'n'},
642a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong                                      {0, 0, 0, 0}};
6439aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong
644bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong    std::string outFilePath;
6459aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    ::android::vintf::AssembleVintf assembleVintf;
6464d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong    int res;
6479aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    int optind;
648a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong    while ((res = getopt_long(argc, argv, "hi:o:mc:nl", longopts, &optind)) >= 0) {
6494d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong        switch (res) {
6504d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            case 'i': {
651bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                char* inFilePath = strtok(optarg, ":");
652bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                while (inFilePath != NULL) {
653bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                    if (!assembleVintf.openInFile(inFilePath)) {
654bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                        std::cerr << "Failed to open " << optarg << std::endl;
655bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                        return 1;
656bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                    }
657bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                    inFilePath = strtok(NULL, ":");
6584d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong                }
6594d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            } break;
6604d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
6614d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            case 'o': {
662bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                outFilePath = optarg;
6639aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                if (!assembleVintf.openOutFile(optarg)) {
6644d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong                    std::cerr << "Failed to open " << optarg << std::endl;
6654d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong                    return 1;
6664d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong                }
6674d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            } break;
6684d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
669a59d2567783cad6f675d2fc1f2fcce4bce3e34e3Yifan Hong            case 'm': {
6709aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                assembleVintf.setOutputMatrix();
671a59d2567783cad6f675d2fc1f2fcce4bce3e34e3Yifan Hong            } break;
672a59d2567783cad6f675d2fc1f2fcce4bce3e34e3Yifan Hong
6734650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong            case 'c': {
6744650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong                if (strlen(optarg) != 0) {
6759aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong                    if (!assembleVintf.openCheckFile(optarg)) {
6764650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong                        std::cerr << "Failed to open " << optarg << std::endl;
6774650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong                        return 1;
6784650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong                    }
6794650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong                } else {
6804650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong                    std::cerr << "WARNING: no compatibility check is done on "
681bfb3c1dc59144dd784d1d81af3ce81c97ea2e45aYifan Hong                              << (outFilePath.empty() ? "output" : outFilePath) << std::endl;
6824650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong                }
6834650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong            } break;
6844650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong
68579efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong            case 'k': {
68679efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong                if (!assembleVintf.addKernel(optarg)) {
68779efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong                    std::cerr << "ERROR: Unrecognized --kernel argument." << std::endl;
68879efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong                    return 1;
68979efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong                }
69079efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong            } break;
69179efa8a35e677cb8ac79041737e2700b0e50de15Yifan Hong
692a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong            case 'l': {
693a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong                if (!assembleVintf.setHalsOnly()) {
694a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong                    return 1;
695a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong                }
696a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong            } break;
697a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong
698a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong            case 'n': {
699a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong                if (!assembleVintf.setNoHals()) {
700a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong                    return 1;
701a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong                }
702a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong            } break;
703a2635c418cdc039d582a50fa91f8dbaa85ce7b02Yifan Hong
7044d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            case 'h':
7054d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            default: {
7064d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong                help();
7074d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong                return 1;
7084d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong            } break;
7094d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong        }
7104d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong    }
7114d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong
7129aa6370fa16fa1c04a15677d1c22401fa94dc4e7Yifan Hong    bool success = assembleVintf.assemble();
7134650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong
7144650ad8e0353ee4404a85300937f66a8c92d7f98Yifan Hong    return success ? 0 : 1;
7154d18bcc9a3de245edb20c2469718f8442c758d97Yifan Hong}
716