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 #define LOG_TAG "libvintf"
18 #include <android-base/logging.h>
19 
20 #include "HalManifest.h"
21 
22 #include <dirent.h>
23 
24 #include <mutex>
25 #include <set>
26 
27 #include "parse_string.h"
28 #include "parse_xml.h"
29 #include "utils.h"
30 #include "CompatibilityMatrix.h"
31 
32 namespace android {
33 namespace vintf {
34 
35 constexpr Version HalManifest::kVersion;
36 
37 // Check <version> tag for all <hal> with the same name.
shouldAdd(const ManifestHal & hal) const38 bool HalManifest::shouldAdd(const ManifestHal& hal) const {
39     if (!hal.isValid()) {
40         return false;
41     }
42     auto existingHals = mHals.equal_range(hal.name);
43     std::set<size_t> existingMajorVersions;
44     for (auto it = existingHals.first; it != existingHals.second; ++it) {
45         for (const auto& v : it->second.versions) {
46             // Assume integrity on existingHals, so no check on emplace().second
47             existingMajorVersions.insert(v.majorVer);
48         }
49     }
50     for (const auto& v : hal.versions) {
51         if (!existingMajorVersions.emplace(v.majorVer).second /* no insertion */) {
52             return false;
53         }
54     }
55     return true;
56 }
57 
add(ManifestHal && hal)58 bool HalManifest::add(ManifestHal&& hal) {
59     if (!shouldAdd(hal)) {
60         return false;
61     }
62     mHals.emplace(hal.name, std::move(hal));  // always succeed
63     return true;
64 }
65 
getHalNames() const66 std::set<std::string> HalManifest::getHalNames() const {
67     std::set<std::string> names{};
68     for (const auto &hal : mHals) {
69         names.insert(hal.first);
70     }
71     return names;
72 }
73 
getHalNamesAndVersions() const74 std::set<std::string> HalManifest::getHalNamesAndVersions() const {
75     std::set<std::string> names{};
76     for (const auto &hal : getHals()) {
77         for (const auto &version : hal.versions) {
78             names.insert(hal.name + "@" + to_string(version));
79         }
80     }
81     return names;
82 }
83 
getInterfaceNames(const std::string & name) const84 std::set<std::string> HalManifest::getInterfaceNames(const std::string &name) const {
85     std::set<std::string> interfaceNames{};
86     for (const ManifestHal *hal : getHals(name)) {
87         for (const auto &iface : hal->interfaces) {
88             interfaceNames.insert(iface.first);
89         }
90     }
91     return interfaceNames;
92 }
93 
getAnyHal(const std::string & name)94 ManifestHal *HalManifest::getAnyHal(const std::string &name) {
95     auto it = mHals.find(name);
96     if (it == mHals.end()) {
97         return nullptr;
98     }
99     return &(it->second);
100 }
101 
getHals(const std::string & name) const102 std::vector<const ManifestHal *> HalManifest::getHals(const std::string &name) const {
103     std::vector<const ManifestHal *> ret;
104     auto range = mHals.equal_range(name);
105     for (auto it = range.first; it != range.second; ++it) {
106         ret.push_back(&it->second);
107     }
108     return ret;
109 }
getHals(const std::string & name)110 std::vector<ManifestHal *> HalManifest::getHals(const std::string &name) {
111     std::vector<ManifestHal *> ret;
112     auto range = mHals.equal_range(name);
113     for (auto it = range.first; it != range.second; ++it) {
114         ret.push_back(&it->second);
115     }
116     return ret;
117 }
118 
getTransport(const std::string & package,const Version & v,const std::string & interfaceName,const std::string & instanceName) const119 Transport HalManifest::getTransport(const std::string &package, const Version &v,
120             const std::string &interfaceName, const std::string &instanceName) const {
121 
122     for (const ManifestHal *hal : getHals(package)) {
123         if (std::find(hal->versions.begin(), hal->versions.end(), v) == hal->versions.end()) {
124             LOG(DEBUG) << "HalManifest::getTransport(" << to_string(mType) << "): Cannot find "
125                       << to_string(v) << " in supported versions of " << package;
126             continue;
127         }
128         auto it = hal->interfaces.find(interfaceName);
129         if (it == hal->interfaces.end()) {
130             LOG(DEBUG) << "HalManifest::getTransport(" << to_string(mType) << "): Cannot find interface '"
131                       << interfaceName << "' in " << package << "@" << to_string(v);
132             continue;
133         }
134         const auto &instances = it->second.instances;
135         if (instances.find(instanceName) == instances.end()) {
136             LOG(DEBUG) << "HalManifest::getTransport(" << to_string(mType) << "): Cannot find instance '"
137                       << instanceName << "' in "
138                       << package << "@" << to_string(v) << "::" << interfaceName;
139             continue;
140         }
141         return hal->transportArch.transport;
142     }
143     LOG(DEBUG) << "HalManifest::getTransport(" << to_string(mType) << "): Cannot get transport for "
144                  << package << "@" << v << "::" << interfaceName << "/" << instanceName;
145     return Transport::EMPTY;
146 
147 }
148 
getHals() const149 ConstMultiMapValueIterable<std::string, ManifestHal> HalManifest::getHals() const {
150     return ConstMultiMapValueIterable<std::string, ManifestHal>(mHals);
151 }
152 
getSupportedVersions(const std::string & name) const153 std::set<Version> HalManifest::getSupportedVersions(const std::string &name) const {
154     std::set<Version> ret;
155     for (const ManifestHal *hal : getHals(name)) {
156         ret.insert(hal->versions.begin(), hal->versions.end());
157     }
158     return ret;
159 }
160 
161 
getInstances(const std::string & halName,const std::string & interfaceName) const162 std::set<std::string> HalManifest::getInstances(
163         const std::string &halName, const std::string &interfaceName) const {
164     std::set<std::string> ret;
165     for (const ManifestHal *hal : getHals(halName)) {
166         auto it = hal->interfaces.find(interfaceName);
167         if (it != hal->interfaces.end()) {
168             ret.insert(it->second.instances.begin(), it->second.instances.end());
169         }
170     }
171     return ret;
172 }
173 
hasInstance(const std::string & halName,const std::string & interfaceName,const std::string & instanceName) const174 bool HalManifest::hasInstance(const std::string &halName,
175         const std::string &interfaceName, const std::string &instanceName) const {
176     const auto &instances = getInstances(halName, interfaceName);
177     return instances.find(instanceName) != instances.end();
178 }
179 
180 using InstancesOfVersion = std::map<std::string /* interface */,
181                                     std::set<std::string /* instance */>>;
182 using Instances = std::map<Version, InstancesOfVersion>;
183 
satisfyVersion(const MatrixHal & matrixHal,const Version & manifestHalVersion)184 static bool satisfyVersion(const MatrixHal& matrixHal, const Version& manifestHalVersion) {
185     for (const VersionRange &matrixVersionRange : matrixHal.versionRanges) {
186         // If Compatibility Matrix says 2.5-2.7, the "2.7" is purely informational;
187         // the framework can work with all 2.5-2.infinity.
188         if (matrixVersionRange.supportedBy(manifestHalVersion)) {
189             return true;
190         }
191     }
192     return false;
193 }
194 
195 // Check if matrixHal.interfaces is a subset of instancesOfVersion
satisfyAllInstances(const MatrixHal & matrixHal,const InstancesOfVersion & instancesOfVersion)196 static bool satisfyAllInstances(const MatrixHal& matrixHal,
197         const InstancesOfVersion &instancesOfVersion) {
198     for (const auto& matrixHalInterfacePair : matrixHal.interfaces) {
199         const std::string& interface = matrixHalInterfacePair.first;
200         auto it = instancesOfVersion.find(interface);
201         if (it == instancesOfVersion.end()) {
202             return false;
203         }
204         const std::set<std::string>& manifestInterfaceInstances = it->second;
205         const std::set<std::string>& matrixInterfaceInstances =
206                 matrixHalInterfacePair.second.instances;
207         if (!std::includes(manifestInterfaceInstances.begin(), manifestInterfaceInstances.end(),
208                            matrixInterfaceInstances.begin(), matrixInterfaceInstances.end())) {
209             return false;
210         }
211     }
212     return true;
213 }
214 
isCompatible(const MatrixHal & matrixHal) const215 bool HalManifest::isCompatible(const MatrixHal& matrixHal) const {
216     Instances instances;
217     // Do the cross product version x interface x instance and sort them,
218     // because interfaces / instances can span in multiple HALs.
219     // This is efficient for small <hal> entries.
220     for (const ManifestHal* manifestHal : getHals(matrixHal.name)) {
221         for (const Version& manifestHalVersion : manifestHal->versions) {
222             instances[manifestHalVersion] = {};
223             for (const auto& halInterfacePair : manifestHal->interfaces) {
224                 const std::string& interface = halInterfacePair.first;
225                 const auto& toAdd = halInterfacePair.second.instances;
226                 instances[manifestHalVersion][interface].insert(toAdd.begin(), toAdd.end());
227             }
228         }
229     }
230     for (const auto& instanceMapPair : instances) {
231         const Version& manifestHalVersion = instanceMapPair.first;
232         const InstancesOfVersion& instancesOfVersion = instanceMapPair.second;
233         if (!satisfyVersion(matrixHal, manifestHalVersion)) {
234             continue;
235         }
236         if (!satisfyAllInstances(matrixHal, instancesOfVersion)) {
237             continue;
238         }
239         return true; // match!
240     }
241     return false;
242 }
243 
244 // For each hal in mat, there must be a hal in manifest that supports this.
checkIncompatibility(const CompatibilityMatrix & mat,bool includeOptional) const245 std::vector<std::string> HalManifest::checkIncompatibility(const CompatibilityMatrix &mat,
246         bool includeOptional) const {
247     std::vector<std::string> incompatible;
248     for (const MatrixHal &matrixHal : mat.getHals()) {
249         if (!includeOptional && matrixHal.optional) {
250             continue;
251         }
252         // don't check optional; put it in the incompatibility list as well.
253         if (!isCompatible(matrixHal)) {
254             incompatible.push_back(matrixHal.name);
255         }
256     }
257     return incompatible;
258 }
259 
checkCompatibility(const CompatibilityMatrix & mat,std::string * error) const260 bool HalManifest::checkCompatibility(const CompatibilityMatrix &mat, std::string *error) const {
261     if (mType == mat.mType) {
262         if (error != nullptr) {
263             *error = "Wrong type; checking " + to_string(mType) + " manifest against "
264                     + to_string(mat.mType) + " compatibility matrix";
265         }
266         return false;
267     }
268     std::vector<std::string> incompatibleHals =
269             checkIncompatibility(mat, false /* includeOptional */);
270     if (!incompatibleHals.empty()) {
271         if (error != nullptr) {
272             *error = "HALs incompatible.";
273             for (const auto &name : incompatibleHals) {
274                 *error += " " + name;
275             }
276         }
277         return false;
278     }
279     if (mType == SchemaType::FRAMEWORK) {
280     // TODO(b/36400653) enable this. It is disabled since vndk is not yet defined.
281 #ifdef VINTF_CHECK_VNDK
282         bool match = false;
283         const auto &matVndk = mat.device.mVndk;
284         for (const auto &vndk : framework.mVndks) {
285             if (!vndk.mVersionRange.in(matVndk.mVersionRange)) {
286                 continue;
287             }
288             // version matches, check libaries
289             std::vector<std::string> diff;
290             std::set_difference(matVndk.mLibraries.begin(), matVndk.mLibraries.end(),
291                     vndk.mLibraries.begin(), vndk.mLibraries.end(),
292                     std::inserter(diff, diff.begin()))
293             if (!diff.empty()) {
294                 if (error != nullptr) {
295                     *error = "Vndk libs incompatible.";
296                     for (const auto &name : diff) {
297                         *error += " " + name;
298                     }
299                 }
300                 return false;
301             }
302             match = true;
303             break;
304         }
305         if (!match) {
306             if (error != nullptr) {
307                 *error = "Vndk version " + to_string(matVndk.mVersionRange) + " is not supported.";
308             }
309         }
310 #endif
311     } else if (mType == SchemaType::DEVICE) {
312         bool match = false;
313         for (const auto &range : mat.framework.mSepolicy.sepolicyVersions()) {
314             if (range.supportedBy(device.mSepolicyVersion)) {
315                 match = true;
316                 break;
317             }
318         }
319         if (!match) {
320             if (error != nullptr) {
321                 *error = "Sepolicy version " + to_string(device.mSepolicyVersion)
322                         + " doesn't satisify the requirements.";
323             }
324             return false;
325         }
326     }
327 
328     return true;
329 }
330 
generateCompatibleMatrix() const331 CompatibilityMatrix HalManifest::generateCompatibleMatrix() const {
332     CompatibilityMatrix matrix;
333 
334     for (const ManifestHal &manifestHal : getHals()) {
335         MatrixHal matrixHal{
336             .format = manifestHal.format,
337             .name = manifestHal.name,
338             .optional = true,
339             .interfaces = manifestHal.interfaces
340         };
341         for (const Version &manifestVersion : manifestHal.versions) {
342             matrixHal.versionRanges.push_back({manifestVersion.majorVer, manifestVersion.minorVer});
343         }
344         matrix.add(std::move(matrixHal));
345     }
346     if (mType == SchemaType::FRAMEWORK) {
347         matrix.mType = SchemaType::DEVICE;
348         // VNDK does not need to be added for compatibility
349     } else if (mType == SchemaType::DEVICE) {
350         matrix.mType = SchemaType::FRAMEWORK;
351         matrix.framework.mSepolicy = Sepolicy(0u /* kernelSepolicyVersion */,
352                 {{device.mSepolicyVersion.majorVer, device.mSepolicyVersion.minorVer}});
353     }
354 
355     return matrix;
356 }
357 
fetchAllInformation(const std::string & path)358 status_t HalManifest::fetchAllInformation(const std::string &path) {
359     return details::fetchAllInformation(path, gHalManifestConverter, this);
360 }
361 
type() const362 SchemaType HalManifest::type() const {
363     return mType;
364 }
365 
sepolicyVersion() const366 const Version &HalManifest::sepolicyVersion() const {
367     CHECK(mType == SchemaType::DEVICE);
368     return device.mSepolicyVersion;
369 }
370 
vndks() const371 const std::vector<Vndk> &HalManifest::vndks() const {
372     CHECK(mType == SchemaType::FRAMEWORK);
373     return framework.mVndks;
374 }
375 
operator ==(const HalManifest & lft,const HalManifest & rgt)376 bool operator==(const HalManifest &lft, const HalManifest &rgt) {
377     return lft.mType == rgt.mType &&
378            lft.mHals == rgt.mHals &&
379            (lft.mType != SchemaType::DEVICE || (
380                 lft.device.mSepolicyVersion == rgt.device.mSepolicyVersion)) &&
381            (lft.mType != SchemaType::FRAMEWORK || (
382                 lft.framework.mVndks == rgt.framework.mVndks));
383 }
384 
385 } // namespace vintf
386 } // namespace android
387