1 /*
2  * Copyright (C) 2017 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 <stdlib.h>
18 #include <unistd.h>
19 
20 #include <fstream>
21 #include <iostream>
22 #include <sstream>
23 #include <string>
24 #include <unordered_map>
25 
26 #include <aidl/metadata.h>
27 #include <android-base/file.h>
28 #include <android-base/parseint.h>
29 #include <android-base/strings.h>
30 #include <libvts_vintf_test_common/common.h>
31 #include <vintf/AssembleVintf.h>
32 #include <vintf/KernelConfigParser.h>
33 #include <vintf/parse_string.h>
34 #include <vintf/parse_xml.h>
35 #include "constants-private.h"
36 #include "utils.h"
37 
38 #define BUFFER_SIZE sysconf(_SC_PAGESIZE)
39 
40 namespace android {
41 namespace vintf {
42 
43 static const std::string gConfigPrefix = "android-base-";
44 static const std::string gConfigSuffix = ".config";
45 static const std::string gBaseConfig = "android-base.config";
46 
47 // An input stream with a name.
48 // The input stream may be an actual file, or a stringstream for testing.
49 // It takes ownership on the istream.
50 class NamedIstream {
51    public:
52     NamedIstream() = default;
NamedIstream(const std::string & name,std::unique_ptr<std::istream> && stream)53     NamedIstream(const std::string& name, std::unique_ptr<std::istream>&& stream)
54         : mName(name), mStream(std::move(stream)) {}
name() const55     const std::string& name() const { return mName; }
stream()56     std::istream& stream() { return *mStream; }
hasStream()57     bool hasStream() { return mStream != nullptr; }
58 
59    private:
60     std::string mName;
61     std::unique_ptr<std::istream> mStream;
62 };
63 
64 /**
65  * Slurps the device manifest file and add build time flag to it.
66  */
67 class AssembleVintfImpl : public AssembleVintf {
68     using Condition = std::unique_ptr<KernelConfig>;
69     using ConditionedConfig = std::pair<Condition, std::vector<KernelConfig> /* configs */>;
70 
71    public:
setFakeAidlMetadata(const std::vector<AidlInterfaceMetadata> & metadata)72     void setFakeAidlMetadata(const std::vector<AidlInterfaceMetadata>& metadata) override {
73         mFakeAidlMetadata = metadata;
74     }
75 
getAidlMetadata() const76     std::vector<AidlInterfaceMetadata> getAidlMetadata() const {
77         if (!mFakeAidlMetadata.empty()) {
78             return mFakeAidlMetadata;
79         } else {
80             return AidlInterfaceMetadata::all();
81         }
82     }
83 
setFakeAidlUseUnfrozen(const std::optional<bool> & use)84     void setFakeAidlUseUnfrozen(const std::optional<bool>& use) override {
85         mFakeAidlUseUnfrozen = use;
86     }
87 
getAidlUseUnfrozen() const88     bool getAidlUseUnfrozen() const {
89         if (mFakeAidlUseUnfrozen.has_value()) {
90             return *mFakeAidlUseUnfrozen;
91         } else {
92 #ifdef AIDL_USE_UNFROZEN
93             return true;
94 #else
95             return false;
96 #endif
97         }
98     }
99 
setFakeEnv(const std::string & key,const std::string & value)100     void setFakeEnv(const std::string& key, const std::string& value) { mFakeEnv[key] = value; }
101 
getEnv(const std::string & key) const102     std::string getEnv(const std::string& key) const {
103         auto it = mFakeEnv.find(key);
104         if (it != mFakeEnv.end()) {
105             return it->second;
106         }
107         const char* envValue = getenv(key.c_str());
108         return envValue != nullptr ? std::string(envValue) : std::string();
109     }
110 
111     // Get environment variable and split with space.
getEnvList(const std::string & key) const112     std::vector<std::string> getEnvList(const std::string& key) const {
113         std::vector<std::string> ret;
114         for (auto&& v : base::Split(getEnv(key), " ")) {
115             v = base::Trim(v);
116             if (!v.empty()) {
117                 ret.push_back(v);
118             }
119         }
120         return ret;
121     }
122 
123     template <typename T>
getFlag(const std::string & key,T * value,bool log=true) const124     bool getFlag(const std::string& key, T* value, bool log = true) const {
125         std::string envValue = getEnv(key);
126         if (envValue.empty()) {
127             if (log) {
128                 err() << "Warning: " << key << " is missing, defaulted to " << (*value) << "."
129                       << std::endl;
130             }
131             return true;
132         }
133 
134         if (!parse(envValue, value)) {
135             err() << "Cannot parse " << envValue << "." << std::endl;
136             return false;
137         }
138         return true;
139     }
140 
141     /**
142      * Set *out to environment variable only if *out is default constructed.
143      * Return false if a fatal error has occurred:
144      * - The environment variable has an unknown format
145      * - The value of the environment variable does not match a predefined variable in the files
146      */
147     template <typename T>
getFlagIfUnset(const std::string & envKey,T * out) const148     bool getFlagIfUnset(const std::string& envKey, T* out) const {
149         bool hasExistingValue = !(*out == T{});
150 
151         bool hasEnvValue = false;
152         T envValue;
153         std::string envStrValue = getEnv(envKey);
154         if (!envStrValue.empty()) {
155             if (!parse(envStrValue, &envValue)) {
156                 err() << "Cannot parse " << envValue << "." << std::endl;
157                 return false;
158             }
159             hasEnvValue = true;
160         }
161 
162         if (hasExistingValue) {
163             if (hasEnvValue && (*out != envValue)) {
164                 err() << "Cannot override existing value " << *out << " with " << envKey
165                       << " (which is " << envValue << ")." << std::endl;
166                 return false;
167             }
168             return true;
169         }
170         if (hasEnvValue) {
171             *out = envValue;
172         }
173         return true;
174     }
175 
getBooleanFlag(const std::string & key) const176     bool getBooleanFlag(const std::string& key) const { return getEnv(key) == std::string("true"); }
177 
getIntegerFlag(const std::string & key,size_t defaultValue=0) const178     size_t getIntegerFlag(const std::string& key, size_t defaultValue = 0) const {
179         std::string envValue = getEnv(key);
180         if (envValue.empty()) {
181             return defaultValue;
182         }
183         size_t value;
184         if (!base::ParseUint(envValue, &value)) {
185             err() << "Error: " << key << " must be a number." << std::endl;
186             return defaultValue;
187         }
188         return value;
189     }
190 
read(std::basic_istream<char> & is)191     static std::string read(std::basic_istream<char>& is) {
192         std::stringstream ss;
193         ss << is.rdbuf();
194         return ss.str();
195     }
196 
197     // Return true if name of file is "android-base.config". This file must be specified
198     // exactly once for each kernel version. These requirements do not have any conditions.
isCommonConfig(const std::string & path)199     static bool isCommonConfig(const std::string& path) {
200         return ::android::base::Basename(path) == gBaseConfig;
201     }
202 
203     // Return true if name of file matches "android-base-foo.config".
204     // Zero or more conditional configs may be specified for each kernel version. These
205     // requirements are conditional on CONFIG_FOO=y.
isConditionalConfig(const std::string & path)206     static bool isConditionalConfig(const std::string& path) {
207         auto fname = ::android::base::Basename(path);
208         return ::android::base::StartsWith(fname, gConfigPrefix) &&
209                ::android::base::EndsWith(fname, gConfigSuffix);
210     }
211 
212     // Return true for all other file names (i.e. not android-base.config, and not conditional
213     // configs.)
214     // Zero or more conditional configs may be specified for each kernel version.
215     // These requirements do not have any conditions.
isExtraCommonConfig(const std::string & path)216     static bool isExtraCommonConfig(const std::string& path) {
217         return !isCommonConfig(path) && !isConditionalConfig(path);
218     }
219 
220     // nullptr on any error, otherwise the condition.
generateCondition(const std::string & path)221     Condition generateCondition(const std::string& path) {
222         if (!isConditionalConfig(path)) {
223             return nullptr;
224         }
225         auto fname = ::android::base::Basename(path);
226         std::string sub = fname.substr(gConfigPrefix.size(),
227                                        fname.size() - gConfigPrefix.size() - gConfigSuffix.size());
228         if (sub.empty()) {
229             return nullptr;  // should not happen
230         }
231         for (size_t i = 0; i < sub.size(); ++i) {
232             if (sub[i] == '-') {
233                 sub[i] = '_';
234                 continue;
235             }
236             if (isalnum(sub[i])) {
237                 sub[i] = toupper(sub[i]);
238                 continue;
239             }
240             err() << "'" << fname << "' (in " << path
241                   << ") is not a valid kernel config file name. Must match regex: "
242                   << "android-base(-[0-9a-zA-Z-]+)?\\" << gConfigSuffix << std::endl;
243             return nullptr;
244         }
245         sub.insert(0, "CONFIG_");
246         return std::make_unique<KernelConfig>(std::move(sub), Tristate::YES);
247     }
248 
parseFileForKernelConfigs(std::basic_istream<char> & stream,std::vector<KernelConfig> * out)249     bool parseFileForKernelConfigs(std::basic_istream<char>& stream,
250                                    std::vector<KernelConfig>* out) {
251         KernelConfigParser parser(true /* processComments */, true /* relaxedFormat */);
252         status_t status = parser.processAndFinish(read(stream));
253         if (status != OK) {
254             err() << parser.error();
255             return false;
256         }
257 
258         for (auto& configPair : parser.configs()) {
259             out->push_back({});
260             KernelConfig& config = out->back();
261             config.first = std::move(configPair.first);
262             if (!parseKernelConfigTypedValue(configPair.second, &config.second)) {
263                 err() << "Unknown value type for key = '" << config.first << "', value = '"
264                       << configPair.second << "'\n";
265                 return false;
266             }
267         }
268         return true;
269     }
270 
parseFilesForKernelConfigs(std::vector<NamedIstream> * streams,std::vector<ConditionedConfig> * out)271     bool parseFilesForKernelConfigs(std::vector<NamedIstream>* streams,
272                                     std::vector<ConditionedConfig>* out) {
273         out->clear();
274         ConditionedConfig commonConfig;
275         bool foundCommonConfig = false;
276         bool ret = true;
277 
278         for (auto& namedStream : *streams) {
279             if (isCommonConfig(namedStream.name()) || isExtraCommonConfig(namedStream.name())) {
280                 if (!parseFileForKernelConfigs(namedStream.stream(), &commonConfig.second)) {
281                     err() << "Failed to generate common configs for file " << namedStream.name();
282                     ret = false;
283                 }
284                 if (isCommonConfig(namedStream.name())) {
285                     foundCommonConfig = true;
286                 }
287             } else {
288                 Condition condition = generateCondition(namedStream.name());
289                 if (condition == nullptr) {
290                     err() << "Failed to generate conditional configs for file "
291                           << namedStream.name();
292                     ret = false;
293                 }
294 
295                 std::vector<KernelConfig> kernelConfigs;
296                 if ((ret &= parseFileForKernelConfigs(namedStream.stream(), &kernelConfigs)))
297                     out->emplace_back(std::move(condition), std::move(kernelConfigs));
298             }
299         }
300 
301         if (!foundCommonConfig) {
302             err() << "No " << gBaseConfig << " is found in these paths:" << std::endl;
303             for (auto& namedStream : *streams) {
304                 err() << "    " << namedStream.name() << std::endl;
305             }
306             ret = false;
307         }
308         // first element is always common configs (no conditions).
309         out->insert(out->begin(), std::move(commonConfig));
310         return ret;
311     }
312 
out() const313     std::basic_ostream<char>& out() const { return mOutRef == nullptr ? std::cout : *mOutRef; }
err() const314     std::basic_ostream<char>& err() const override {
315         return mErrRef == nullptr ? std::cerr : *mErrRef;
316     }
317 
318     // If -c is provided, check it.
checkDualFile(const HalManifest & manifest,const CompatibilityMatrix & matrix)319     bool checkDualFile(const HalManifest& manifest, const CompatibilityMatrix& matrix) {
320         if (getBooleanFlag("PRODUCT_ENFORCE_VINTF_MANIFEST")) {
321             std::string error;
322             if (!manifest.checkCompatibility(matrix, &error, mCheckFlags)) {
323                 err() << "Not compatible: " << error << std::endl;
324                 return false;
325             }
326         }
327         return true;
328     }
329 
330     using HalManifests = std::vector<HalManifest>;
331     using CompatibilityMatrices = std::vector<CompatibilityMatrix>;
332 
333     template <typename M>
outputInputs(const std::vector<M> & inputs)334     void outputInputs(const std::vector<M>& inputs) {
335         out() << "<!--" << std::endl;
336         out() << "    Input:" << std::endl;
337         for (const auto& e : inputs) {
338             if (!e.fileName().empty()) {
339                 out() << "        " << e.fileName() << std::endl;
340             }
341         }
342         out() << "-->" << std::endl;
343     }
344 
345     // Parse --kernel arguments and write to output manifest.
setDeviceManifestKernel(HalManifest * manifest)346     bool setDeviceManifestKernel(HalManifest* manifest) {
347         if (mKernels.empty()) {
348             return true;
349         }
350         if (mKernels.size() > 1) {
351             err() << "Warning: multiple --kernel is specified when building device manifest. "
352                   << "Only the first one will be used." << std::endl;
353         }
354         auto& kernelArg = *mKernels.begin();
355         const auto& kernelVer = kernelArg.first;
356         auto& kernelConfigFiles = kernelArg.second;
357         // addKernel() guarantees that !kernelConfigFiles.empty().
358         if (kernelConfigFiles.size() > 1) {
359             err() << "Warning: multiple config files are specified in --kernel when building "
360                   << "device manfiest. Only the first one will be used." << std::endl;
361         }
362 
363         KernelConfigParser parser(true /* processComments */, false /* relaxedFormat */);
364         status_t status = parser.processAndFinish(read(kernelConfigFiles[0].stream()));
365         if (status != OK) {
366             err() << parser.error();
367             return false;
368         }
369 
370         // Set version and configs in manifest.
371         auto kernel_info = std::make_optional<KernelInfo>();
372         kernel_info->mVersion = kernelVer;
373         kernel_info->mConfigs = parser.configs();
374         std::string error;
375         if (!manifest->mergeKernel(&kernel_info, &error)) {
376             err() << error << "\n";
377             return false;
378         }
379         return true;
380     }
381 
382     // Check to see if each HAL manifest entry only contains interfaces from the
383     // same aidl_interface module by finding the AidlInterfaceMetadata object
384     // associated with the interfaces in the manifest entry.
verifyAidlMetadataPerManifestEntry(const HalManifest & halManifest)385     bool verifyAidlMetadataPerManifestEntry(const HalManifest& halManifest) {
386         const std::vector<AidlInterfaceMetadata> aidlMetadata = getAidlMetadata();
387         for (const auto& hal : halManifest.getHals()) {
388             if (hal.format != HalFormat::AIDL) continue;
389             for (const auto& metadata : aidlMetadata) {
390                 std::map<std::string, bool> isInterfaceInMetadata;
391                 // get the types of each instance
392                 hal.forEachInstance([&](const ManifestInstance& instance) -> bool {
393                     std::string interfaceName = instance.package() + "." + instance.interface();
394                     // check if that instance is covered by this metadata object
395                     if (std::find(metadata.types.begin(), metadata.types.end(), interfaceName) !=
396                         metadata.types.end()) {
397                         isInterfaceInMetadata[interfaceName] = true;
398                     } else {
399                         isInterfaceInMetadata[interfaceName] = false;
400                     }
401                     // Keep going through the rest of the instances
402                     return true;
403                 });
404                 bool found = false;
405                 if (!isInterfaceInMetadata.empty()) {
406                     // Check that all of these entries were found or not
407                     // found in this metadata entry.
408                     found = isInterfaceInMetadata.begin()->second;
409                     if (!std::all_of(
410                             isInterfaceInMetadata.begin(), isInterfaceInMetadata.end(),
411                             [&](const auto& entry) -> bool { return found == entry.second; })) {
412                         err() << "HAL manifest entries must only contain interfaces from the same "
413                                  "aidl_interface"
414                               << std::endl;
415                         for (auto& [interface, isIn] : isInterfaceInMetadata) {
416                             if (isIn) {
417                                 err() << "    " << interface << " is in " << metadata.name
418                                       << std::endl;
419                             } else {
420                                 err() << "    "
421                                       << interface << " is from another AIDL interface module "
422                                       << std::endl;
423                             }
424                         }
425                         return false;
426                     }
427                 }
428                 // If we found the AidlInterfaceMetadata associated with this
429                 // HAL, then there is no need to keep looking.
430                 if (found) break;
431             }
432         }
433         return true;
434     }
435 
436     // get the first interface name including the package.
437     // Example: android.foo.IFoo
getFirstInterfaceName(const ManifestHal & manifestHal)438     static std::string getFirstInterfaceName(const ManifestHal& manifestHal) {
439         std::string interfaceName;
440         manifestHal.forEachInstance([&](const ManifestInstance& instance) -> bool {
441             interfaceName = instance.package() + "." + instance.interface();
442             return false;
443         });
444         return interfaceName;
445     }
446 
447     // Check if this HAL is covered by this metadata entry. The name field in
448     // AidlInterfaceMetadata is the module name, which isn't the same as the
449     // package that would be found in the manifest, so we check all of the types
450     // in the metadata.
451     // Implementation detail: Returns true if the interface of the first
452     // <fqname> is in `aidlMetadata.types`
isInMetadata(const ManifestHal & manifestHal,const AidlInterfaceMetadata & aidlMetadata)453     static bool isInMetadata(const ManifestHal& manifestHal,
454                              const AidlInterfaceMetadata& aidlMetadata) {
455         // Get the first interface type. The instance isn't
456         // needed to find a matching AidlInterfaceMetadata
457         std::string interfaceName = getFirstInterfaceName(manifestHal);
458         return std::find(aidlMetadata.types.begin(), aidlMetadata.types.end(), interfaceName) !=
459                aidlMetadata.types.end();
460     }
461 
462     // Set the manifest version for AIDL interfaces to 'version - 1' if the HAL is
463     // implementing the latest unfrozen version and the release configuration
464     // prevents the use of the unfrozen version.
465     // If the AIDL interface has no previous frozen version, then the HAL
466     // manifest entry is removed entirely.
setManifestAidlHalVersion(HalManifest * manifest)467     bool setManifestAidlHalVersion(HalManifest* manifest) {
468         if (getAidlUseUnfrozen()) {
469             // If we are using unfrozen interfaces, then we have no work to do.
470             return true;
471         }
472         const std::vector<AidlInterfaceMetadata> aidlMetadata = getAidlMetadata();
473         std::vector<std::string> halsToRemove;
474         for (ManifestHal& hal : manifest->getHals()) {
475             if (hal.format != HalFormat::AIDL) continue;
476             if (hal.versions.size() != 1) {
477                 err() << "HAL manifest entries must only contain one version of an AIDL HAL but "
478                          "found "
479                       << hal.versions.size() << " for " << hal.getName() << std::endl;
480                 return false;
481             }
482             size_t halVersion = hal.versions.front().minorVer;
483             bool foundMetadata = false;
484             for (const AidlInterfaceMetadata& metadata : aidlMetadata) {
485                 if (!isInMetadata(hal, metadata)) continue;
486                 foundMetadata = true;
487                 if (!metadata.has_development) continue;
488                 if (metadata.use_unfrozen) {
489                     err() << "INFO: " << hal.getName()
490                           << " is explicitly marked to use unfrozen version, so it will not be "
491                              "downgraded. If this interface is used, it will fail "
492                              "vts_treble_vintf_vendor_test.";
493                     continue;
494                 }
495 
496                 auto it = std::max_element(metadata.versions.begin(), metadata.versions.end());
497                 if (it == metadata.versions.end()) {
498                     // v1 manifest entries that are declaring unfrozen versions must be removed
499                     // from the manifest when the release configuration prevents the use of
500                     // unfrozen versions. this ensures service manager will deny registration.
501                     halsToRemove.push_back(hal.getName());
502                 } else {
503                     size_t latestVersion = *it;
504                     if (latestVersion < halVersion) {
505                         if (halVersion - latestVersion != 1) {
506                             err()
507                                 << "The declared version of " << hal.getName() << " (" << halVersion
508                                 << ") can't be more than one greater than its last frozen version ("
509                                 << latestVersion << ")." << std::endl;
510                             return false;
511                         }
512                         err() << "INFO: Downgrading HAL " << hal.getName()
513                               << " in the manifest from V" << halVersion << " to V"
514                               << halVersion - 1
515                               << " because it is unfrozen and unfrozen interfaces "
516                               << "are not allowed in this release configuration." << std::endl;
517                         hal.versions[0] = hal.versions[0].withMinor(halVersion - 1);
518                     }
519                 }
520             }
521             if (!foundMetadata) {
522                 // This can happen for prebuilt interfaces from partners that we
523                 // don't know about. We can ignore them here since the AIDL tool
524                 // is not going to build the libraries differently anyways.
525                 err() << "INFO: Couldn't find AIDL metadata for: " << getFirstInterfaceName(hal)
526                       << " in file " << hal.fileName() << ". Check spelling? This is expected"
527                       << " for prebuilt interfaces." << std::endl;
528             }
529         }
530         for (const auto& name : halsToRemove) {
531             // These services should not be installed on the device, but there
532             // are cases where the service is also service other HAL interfaces
533             // and will remain on the device.
534             err() << "INFO: Removing HAL from the manifest because it is declaring V1 of a new "
535                      "unfrozen interface which is not allowed in this release configuration: "
536                   << name << std::endl;
537             manifest->removeHals(name, details::kDefaultAidlVersion.majorVer);
538         }
539         return true;
540     }
541 
checkDeviceManifestNoKernelLevel(const HalManifest & manifest)542     bool checkDeviceManifestNoKernelLevel(const HalManifest& manifest) {
543         if (manifest.level() != Level::UNSPECIFIED &&
544             manifest.level() >= details::kEnforceDeviceManifestNoKernelLevel &&
545             // Use manifest.kernel()->level() directly because inferredKernelLevel()
546             // reads manifest.level().
547             manifest.kernel().has_value() && manifest.kernel()->level() != Level::UNSPECIFIED) {
548             err() << "Error: Device manifest with level " << manifest.level()
549                   << " must not set kernel level " << manifest.kernel()->level() << std::endl;
550             return false;
551         }
552         return true;
553     }
554 
assembleHalManifest(HalManifests * halManifests)555     bool assembleHalManifest(HalManifests* halManifests) {
556         std::string error;
557         HalManifest* halManifest = &halManifests->front();
558         HalManifest* manifestWithLevel = nullptr;
559         if (halManifest->level() != Level::UNSPECIFIED) {
560             manifestWithLevel = halManifest;
561         }
562 
563         for (auto it = halManifests->begin() + 1; it != halManifests->end(); ++it) {
564             const std::string& path = it->fileName();
565             HalManifest& manifestToAdd = *it;
566 
567             if (manifestToAdd.level() != Level::UNSPECIFIED) {
568                 if (halManifest->level() == Level::UNSPECIFIED) {
569                     halManifest->mLevel = manifestToAdd.level();
570                     manifestWithLevel = &manifestToAdd;
571                 } else if (halManifest->level() != manifestToAdd.level()) {
572                     err() << "Inconsistent FCM Version in HAL manifests:" << std::endl
573                           << "    File '"
574                           << (manifestWithLevel ? manifestWithLevel->fileName() : "<unknown>")
575                           << "' has level " << halManifest->level() << std::endl
576                           << "    File '" << path << "' has level " << manifestToAdd.level()
577                           << std::endl;
578                     return false;
579                 }
580             }
581 
582             if (!halManifest->addAll(&manifestToAdd, &error)) {
583                 err() << "File \"" << path << "\" cannot be added: " << error << std::endl;
584                 return false;
585             }
586         }
587 
588         if (halManifest->mType == SchemaType::DEVICE) {
589             if (!getFlagIfUnset("BOARD_SEPOLICY_VERS", &halManifest->device.mSepolicyVersion)) {
590                 return false;
591             }
592 
593             if (!getBooleanFlag("VINTF_IGNORE_TARGET_FCM_VERSION") &&
594                 !getBooleanFlag("PRODUCT_ENFORCE_VINTF_MANIFEST")) {
595                 halManifest->mLevel = Level::LEGACY;
596             }
597 
598             if (!setDeviceManifestKernel(halManifest)) {
599                 return false;
600             }
601 
602             if (!checkDeviceManifestNoKernelLevel(*halManifest)) {
603                 return false;
604             }
605         }
606 
607         if (halManifest->mType == SchemaType::FRAMEWORK) {
608             for (auto&& v : getEnvList("PROVIDED_VNDK_VERSIONS")) {
609                 halManifest->framework.mVendorNdks.emplace_back(std::move(v));
610             }
611 
612             for (auto&& v : getEnvList("PLATFORM_SYSTEMSDK_VERSIONS")) {
613                 halManifest->framework.mSystemSdk.mVersions.emplace(std::move(v));
614             }
615         }
616 
617         if (!verifyAidlMetadataPerManifestEntry(*halManifest)) {
618             return false;
619         }
620 
621         if (!setManifestAidlHalVersion(halManifest)) {
622             return false;
623         }
624 
625         outputInputs(*halManifests);
626 
627         if (mOutputMatrix) {
628             CompatibilityMatrix generatedMatrix = halManifest->generateCompatibleMatrix();
629             if (!halManifest->checkCompatibility(generatedMatrix, &error, mCheckFlags)) {
630                 err() << "FATAL ERROR: cannot generate a compatible matrix: " << error << std::endl;
631             }
632             out() << "<!-- \n"
633                      "    Autogenerated skeleton compatibility matrix. \n"
634                      "    Use with caution. Modify it to suit your needs.\n"
635                      "    All HALs are set to optional.\n"
636                      "    Many entries other than HALs are zero-filled and\n"
637                      "    require human attention. \n"
638                      "-->\n"
639                   << toXml(generatedMatrix, mSerializeFlags);
640         } else {
641             out() << toXml(*halManifest, mSerializeFlags);
642         }
643         out().flush();
644 
645         if (mCheckFile.hasStream()) {
646             CompatibilityMatrix checkMatrix;
647             checkMatrix.setFileName(mCheckFile.name());
648             if (!fromXml(&checkMatrix, read(mCheckFile.stream()), &error)) {
649                 err() << "Cannot parse check file as a compatibility matrix: " << error
650                       << std::endl;
651                 return false;
652             }
653             if (!checkDualFile(*halManifest, checkMatrix)) {
654                 return false;
655             }
656         }
657 
658         return true;
659     }
660 
661     // Parse --kernel arguments and write to output matrix.
assembleFrameworkCompatibilityMatrixKernels(CompatibilityMatrix * matrix)662     bool assembleFrameworkCompatibilityMatrixKernels(CompatibilityMatrix* matrix) {
663         for (auto& pair : mKernels) {
664             std::vector<ConditionedConfig> conditionedConfigs;
665             if (!parseFilesForKernelConfigs(&pair.second, &conditionedConfigs)) {
666                 return false;
667             }
668             for (ConditionedConfig& conditionedConfig : conditionedConfigs) {
669                 MatrixKernel kernel(KernelVersion{pair.first}, std::move(conditionedConfig.second));
670                 if (conditionedConfig.first != nullptr)
671                     kernel.mConditions.push_back(std::move(*conditionedConfig.first));
672                 std::string error;
673                 if (!matrix->addKernel(std::move(kernel), &error)) {
674                     err() << "Error:" << error << std::endl;
675                     return false;
676                 };
677             }
678         }
679         return true;
680     }
681 
getLowestFcmVersion(const CompatibilityMatrices & matrices)682     Level getLowestFcmVersion(const CompatibilityMatrices& matrices) {
683         Level ret = Level::UNSPECIFIED;
684         for (const auto& e : matrices) {
685             if (ret == Level::UNSPECIFIED || ret > e.level()) {
686                 ret = e.level();
687             }
688         }
689         return ret;
690     }
691 
assembleCompatibilityMatrix(CompatibilityMatrices * matrices)692     bool assembleCompatibilityMatrix(CompatibilityMatrices* matrices) {
693         std::string error;
694         CompatibilityMatrix* matrix = nullptr;
695         std::unique_ptr<HalManifest> checkManifest;
696         std::unique_ptr<CompatibilityMatrix> builtMatrix;
697 
698         if (mCheckFile.hasStream()) {
699             checkManifest = std::make_unique<HalManifest>();
700             checkManifest->setFileName(mCheckFile.name());
701             if (!fromXml(checkManifest.get(), read(mCheckFile.stream()), &error)) {
702                 err() << "Cannot parse check file as a HAL manifest: " << error << std::endl;
703                 return false;
704             }
705         }
706 
707         if (matrices->front().mType == SchemaType::DEVICE) {
708             builtMatrix = CompatibilityMatrix::combineDeviceMatrices(matrices, &error);
709             matrix = builtMatrix.get();
710 
711             if (matrix == nullptr) {
712                 err() << error << std::endl;
713                 return false;
714             }
715 
716             auto vndkVersion = base::Trim(getEnv("REQUIRED_VNDK_VERSION"));
717             if (!vndkVersion.empty()) {
718                 auto& valueInMatrix = matrix->device.mVendorNdk;
719                 if (!valueInMatrix.version().empty() && valueInMatrix.version() != vndkVersion) {
720                     err() << "Hard-coded <vendor-ndk> version in device compatibility matrix ("
721                           << matrices->front().fileName() << "), '" << valueInMatrix.version()
722                           << "', does not match value inferred "
723                           << "from BOARD_VNDK_VERSION '" << vndkVersion << "'" << std::endl;
724                     return false;
725                 }
726                 valueInMatrix = VendorNdk{std::move(vndkVersion)};
727             }
728 
729             for (auto&& v : getEnvList("BOARD_SYSTEMSDK_VERSIONS")) {
730                 matrix->device.mSystemSdk.mVersions.emplace(std::move(v));
731             }
732         }
733 
734         if (matrices->front().mType == SchemaType::FRAMEWORK) {
735             Level deviceLevel =
736                 checkManifest != nullptr ? checkManifest->level() : Level::UNSPECIFIED;
737             if (deviceLevel == Level::UNSPECIFIED) {
738                 deviceLevel = getLowestFcmVersion(*matrices);
739                 if (checkManifest != nullptr && deviceLevel != Level::UNSPECIFIED) {
740                     err() << "Warning: No Target FCM Version for device. Assuming \""
741                           << to_string(deviceLevel)
742                           << "\" when building final framework compatibility matrix." << std::endl;
743                 }
744             }
745             // No <kernel> tags to assemble at this point
746             const auto kernelLevel = Level::UNSPECIFIED;
747             builtMatrix = CompatibilityMatrix::combine(deviceLevel, kernelLevel, matrices, &error);
748             matrix = builtMatrix.get();
749 
750             if (matrix == nullptr) {
751                 err() << error << std::endl;
752                 return false;
753             }
754 
755             if (!assembleFrameworkCompatibilityMatrixKernels(matrix)) {
756                 return false;
757             }
758 
759             // Add PLATFORM_SEPOLICY_* to sepolicy.sepolicy-version. Remove dupes.
760             std::set<SepolicyVersion> sepolicyVersions;
761             auto sepolicyVersionStrings = getEnvList("PLATFORM_SEPOLICY_COMPAT_VERSIONS");
762             auto currentSepolicyVersionString = getEnv("PLATFORM_SEPOLICY_VERSION");
763             if (!currentSepolicyVersionString.empty()) {
764                 sepolicyVersionStrings.push_back(currentSepolicyVersionString);
765             }
766             for (auto&& s : sepolicyVersionStrings) {
767                 SepolicyVersion v;
768                 if (!parse(s, &v)) {
769                     err() << "Error: unknown sepolicy version '" << s << "' specified by "
770                           << (s == currentSepolicyVersionString
771                                   ? "PLATFORM_SEPOLICY_VERSION"
772                                   : "PLATFORM_SEPOLICY_COMPAT_VERSIONS")
773                           << ".";
774                     return false;
775                 }
776                 sepolicyVersions.insert(v);
777             }
778             for (auto&& v : sepolicyVersions) {
779                 matrix->framework.mSepolicy.mSepolicyVersionRanges.emplace_back(v.majorVer,
780                                                                                 v.minorVer);
781             }
782 
783             if (!getFlagIfUnset("POLICYVERS",
784                                 &matrix->framework.mSepolicy.mKernelSepolicyVersion)) {
785                 return false;
786             }
787             if (!getFlagIfUnset("FRAMEWORK_VBMETA_VERSION", &matrix->framework.mAvbMetaVersion)) {
788                 return false;
789             }
790             // Hard-override existing AVB version
791             getFlag("FRAMEWORK_VBMETA_VERSION_OVERRIDE", &matrix->framework.mAvbMetaVersion,
792                     false /* log */);
793         }
794         outputInputs(*matrices);
795         out() << toXml(*matrix, mSerializeFlags);
796         out().flush();
797 
798         if (checkManifest != nullptr && !checkDualFile(*checkManifest, *matrix)) {
799             return false;
800         }
801 
802         return true;
803     }
804 
805     enum AssembleStatus { SUCCESS, FAIL_AND_EXIT, TRY_NEXT };
806     template <typename Schema, typename AssembleFunc>
tryAssemble(const std::string & schemaName,AssembleFunc assemble,std::string * error)807     AssembleStatus tryAssemble(const std::string& schemaName, AssembleFunc assemble,
808                                std::string* error) {
809         std::vector<Schema> schemas;
810         Schema schema;
811         schema.setFileName(mInFiles.front().name());
812         if (!fromXml(&schema, read(mInFiles.front().stream()), error)) {
813             return TRY_NEXT;
814         }
815         auto firstType = schema.type();
816         schemas.emplace_back(std::move(schema));
817 
818         for (auto it = mInFiles.begin() + 1; it != mInFiles.end(); ++it) {
819             Schema additionalSchema;
820             const std::string& fileName = it->name();
821             additionalSchema.setFileName(fileName);
822             if (!fromXml(&additionalSchema, read(it->stream()), error)) {
823                 err() << "File \"" << fileName << "\" is not a valid " << firstType << " "
824                       << schemaName << " (but the first file is a valid " << firstType << " "
825                       << schemaName << "). Error: " << *error << std::endl;
826                 return FAIL_AND_EXIT;
827             }
828             if (additionalSchema.type() != firstType) {
829                 err() << "File \"" << fileName << "\" is a " << additionalSchema.type() << " "
830                       << schemaName << " (but a " << firstType << " " << schemaName
831                       << " is expected)." << std::endl;
832                 return FAIL_AND_EXIT;
833             }
834 
835             schemas.emplace_back(std::move(additionalSchema));
836         }
837         return assemble(&schemas) ? SUCCESS : FAIL_AND_EXIT;
838     }
839 
assemble()840     bool assemble() override {
841         using std::placeholders::_1;
842         if (mInFiles.empty()) {
843             err() << "Missing input file." << std::endl;
844             return false;
845         }
846 
847         std::string manifestError;
848         auto status = tryAssemble<HalManifest>(
849             "manifest", std::bind(&AssembleVintfImpl::assembleHalManifest, this, _1),
850             &manifestError);
851         if (status == SUCCESS) return true;
852         if (status == FAIL_AND_EXIT) return false;
853 
854         resetInFiles();
855 
856         std::string matrixError;
857         status = tryAssemble<CompatibilityMatrix>(
858             "compatibility matrix",
859             std::bind(&AssembleVintfImpl::assembleCompatibilityMatrix, this, _1), &matrixError);
860         if (status == SUCCESS) return true;
861         if (status == FAIL_AND_EXIT) return false;
862 
863         err() << "Input file has unknown format." << std::endl
864               << "Error when attempting to convert to manifest: " << manifestError << std::endl
865               << "Error when attempting to convert to compatibility matrix: " << matrixError
866               << std::endl;
867         return false;
868     }
869 
setOutputStream(Ostream && out)870     std::ostream& setOutputStream(Ostream&& out) override {
871         mOutRef = std::move(out);
872         return *mOutRef;
873     }
874 
setErrorStream(Ostream && err)875     std::ostream& setErrorStream(Ostream&& err) override {
876         mErrRef = std::move(err);
877         return *mErrRef;
878     }
879 
addInputStream(const std::string & name,Istream && in)880     std::istream& addInputStream(const std::string& name, Istream&& in) override {
881         auto it = mInFiles.emplace(mInFiles.end(), name, std::move(in));
882         return it->stream();
883     }
884 
setCheckInputStream(const std::string & name,Istream && in)885     std::istream& setCheckInputStream(const std::string& name, Istream&& in) override {
886         mCheckFile = NamedIstream(name, std::move(in));
887         return mCheckFile.stream();
888     }
889 
hasKernelVersion(const KernelVersion & kernelVer) const890     bool hasKernelVersion(const KernelVersion& kernelVer) const override {
891         return mKernels.find(kernelVer) != mKernels.end();
892     }
893 
addKernelConfigInputStream(const KernelVersion & kernelVer,const std::string & name,Istream && in)894     std::istream& addKernelConfigInputStream(const KernelVersion& kernelVer,
895                                              const std::string& name, Istream&& in) override {
896         auto&& kernel = mKernels[kernelVer];
897         auto it = kernel.emplace(kernel.end(), name, std::move(in));
898         return it->stream();
899     }
900 
resetInFiles()901     void resetInFiles() {
902         for (auto& inFile : mInFiles) {
903             inFile.stream().clear();
904             inFile.stream().seekg(0);
905         }
906     }
907 
setOutputMatrix()908     void setOutputMatrix() override { mOutputMatrix = true; }
909 
setHalsOnly()910     bool setHalsOnly() override {
911         if (mHasSetHalsOnlyFlag) {
912             err() << "Error: Cannot set --hals-only with --no-hals." << std::endl;
913             return false;
914         }
915         // Just override it with HALS_ONLY because other flags that modify mSerializeFlags
916         // does not interfere with this (except --no-hals).
917         mSerializeFlags = SerializeFlags::HALS_ONLY;
918         mHasSetHalsOnlyFlag = true;
919         return true;
920     }
921 
setNoHals()922     bool setNoHals() override {
923         if (mHasSetHalsOnlyFlag) {
924             err() << "Error: Cannot set --hals-only with --no-hals." << std::endl;
925             return false;
926         }
927         mSerializeFlags = mSerializeFlags.disableHals();
928         mHasSetHalsOnlyFlag = true;
929         return true;
930     }
931 
setNoKernelRequirements()932     bool setNoKernelRequirements() override {
933         mSerializeFlags = mSerializeFlags.disableKernelConfigs().disableKernelMinorRevision();
934         mCheckFlags = mCheckFlags.disableKernel();
935         return true;
936     }
937 
938    private:
939     std::vector<NamedIstream> mInFiles;
940     Ostream mOutRef;
941     Ostream mErrRef;
942     NamedIstream mCheckFile;
943     bool mOutputMatrix = false;
944     bool mHasSetHalsOnlyFlag = false;
945     SerializeFlags::Type mSerializeFlags = SerializeFlags::EVERYTHING;
946     std::map<KernelVersion, std::vector<NamedIstream>> mKernels;
947     std::map<std::string, std::string> mFakeEnv;
948     std::vector<AidlInterfaceMetadata> mFakeAidlMetadata;
949     std::optional<bool> mFakeAidlUseUnfrozen;
950     CheckFlags::Type mCheckFlags = CheckFlags::DEFAULT;
951 };
952 
openOutFile(const std::string & path)953 bool AssembleVintf::openOutFile(const std::string& path) {
954     return static_cast<std::ofstream&>(setOutputStream(std::make_unique<std::ofstream>(path)))
955         .is_open();
956 }
957 
openInFile(const std::string & path)958 bool AssembleVintf::openInFile(const std::string& path) {
959     return static_cast<std::ifstream&>(addInputStream(path, std::make_unique<std::ifstream>(path)))
960         .is_open();
961 }
962 
openCheckFile(const std::string & path)963 bool AssembleVintf::openCheckFile(const std::string& path) {
964     return static_cast<std::ifstream&>(
965                setCheckInputStream(path, std::make_unique<std::ifstream>(path)))
966         .is_open();
967 }
968 
addKernel(const std::string & kernelArg)969 bool AssembleVintf::addKernel(const std::string& kernelArg) {
970     auto tokens = base::Split(kernelArg, ":");
971     if (tokens.size() <= 1) {
972         err() << "Unrecognized --kernel option '" << kernelArg << "'" << std::endl;
973         return false;
974     }
975     KernelVersion kernelVer;
976     if (!parse(tokens.front(), &kernelVer)) {
977         err() << "Unrecognized kernel version '" << tokens.front() << "'" << std::endl;
978         return false;
979     }
980     if (hasKernelVersion(kernelVer)) {
981         err() << "Multiple --kernel for " << kernelVer << " is specified." << std::endl;
982         return false;
983     }
984     for (auto it = tokens.begin() + 1; it != tokens.end(); ++it) {
985         bool opened =
986             static_cast<std::ifstream&>(
987                 addKernelConfigInputStream(kernelVer, *it, std::make_unique<std::ifstream>(*it)))
988                 .is_open();
989         if (!opened) {
990             err() << "Cannot open file '" << *it << "'." << std::endl;
991             return false;
992         }
993     }
994     return true;
995 }
996 
newInstance()997 std::unique_ptr<AssembleVintf> AssembleVintf::newInstance() {
998     return std::make_unique<AssembleVintfImpl>();
999 }
1000 
1001 }  // namespace vintf
1002 }  // namespace android
1003