• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef ANDROID_VINTF_HAL_GROUP_H
18 #define ANDROID_VINTF_HAL_GROUP_H
19 
20 #include <map>
21 #include <set>
22 
23 #include "MapValueIterator.h"
24 #include "Version.h"
25 
26 namespace android {
27 namespace vintf {
28 
29 // A HalGroup is a wrapped multimap from name to Hal.
30 // Hal.getName() must return a string indicating the name.
31 template <typename Hal>
32 struct HalGroup {
33     using InstanceType = typename Hal::InstanceType;
34 
35    public:
~HalGroupHalGroup36     virtual ~HalGroup() {}
37     // Move all hals from another HalGroup to this.
38     bool addAllHals(HalGroup* other, std::string* error = nullptr) {
39         for (auto& pair : other->mHals) {
40             if (!add(std::move(pair.second))) {
41                 if (error) {
42                     *error = "HAL \"" + pair.first + "\" has a conflict.";
43                 }
44                 return false;
45             }
46         }
47         other->mHals.clear();
48         return true;
49     }
50 
51     // Add an hal to this HalGroup so that it can be constructed programatically.
addHalGroup52     virtual bool add(Hal&& hal) { return addInternal(std::move(hal)) != nullptr; }
53 
54    protected:
55     // Get all hals with the given name (e.g "android.hardware.camera").
56     // There could be multiple hals that matches the same given name.
getHalsHalGroup57     std::vector<const Hal*> getHals(const std::string& name) const {
58         std::vector<const Hal*> ret;
59         auto range = mHals.equal_range(name);
60         for (auto it = range.first; it != range.second; ++it) {
61             ret.push_back(&it->second);
62         }
63         return ret;
64     }
65 
66     // Get all hals with the given name (e.g "android.hardware.camera").
67     // There could be multiple hals that matches the same given name.
68     // Non-const version of the above getHals() method.
getHalsHalGroup69     std::vector<Hal*> getHals(const std::string& name) {
70         std::vector<Hal*> ret;
71         auto range = mHals.equal_range(name);
72         for (auto it = range.first; it != range.second; ++it) {
73             ret.push_back(&it->second);
74         }
75         return ret;
76     }
77 
78    public:
79     // Apply func to all instances.
forEachInstanceHalGroup80     bool forEachInstance(const std::function<bool(const InstanceType&)>& func) const {
81         for (const auto& hal : getHals()) {
82             bool cont = hal.forEachInstance(func);
83             if (!cont) return false;
84         }
85         return true;
86     }
87 
forEachInstanceOfPackageHalGroup88     bool forEachInstanceOfPackage(const std::string& package,
89                                   const std::function<bool(const InstanceType&)>& func) const {
90         for (const auto* hal : getHals(package)) {
91             if (!hal->forEachInstance(func)) {
92                 return false;
93             }
94         }
95         return true;
96     }
97 
98     // Apply func to all instances of package@expectVersion::*/*.
99     // For example, if a.h.foo@1.1::IFoo/default is in "this" and getFqInstances
100     // is called with a.h.foo@1.0, then a.h.foo@1.1::IFoo/default is returned.
101     virtual bool forEachInstanceOfVersion(
102         const std::string& package, const Version& expectVersion,
103         const std::function<bool(const InstanceType&)>& func) const = 0;
104 
105     // Apply func to instances of package@expectVersion::interface/*.
106     // For example, if a.h.foo@1.1::IFoo/default is in "this" and getFqInstances
107     // is called with a.h.foo@1.0::IFoo, then a.h.foo@1.1::IFoo/default is returned.
forEachInstanceOfInterfaceHalGroup108     bool forEachInstanceOfInterface(const std::string& package, const Version& expectVersion,
109                                     const std::string& interface,
110                                     const std::function<bool(const InstanceType&)>& func) const {
111         return forEachInstanceOfVersion(package, expectVersion,
112                                         [&func, &interface](const InstanceType& e) {
113                                             if (e.interface() == interface) {
114                                                 return func(e);
115                                             }
116                                             return true;
117                                         });
118     }
119 
120     // Alternative to forEachInstanceOfInterface if you need a vector instead.
121     // If interface is empty, returns all instances of package@version;
122     // else return all instances of package@version::interface.
123     std::vector<InstanceType> getFqInstances(const std::string& package,
124                                              const Version& expectVersion,
125                                              const std::string& interface = "") const {
126         std::vector<InstanceType> v;
127         auto mapToVector = [&v](const auto& e) {
128             v.push_back(e);
129             return true;
130         };
131         if (interface.empty()) {
132             (void)forEachInstanceOfVersion(package, expectVersion, mapToVector);
133         } else {
134             (void)forEachInstanceOfInterface(package, expectVersion, interface, mapToVector);
135         }
136         return v;
137     }
138 
139    protected:
140     // sorted map from component name to the component.
141     // The component name looks like: android.hardware.foo
142     std::multimap<std::string, Hal> mHals;
143 
144     // override this to filter for add.
shouldAddHalGroup145     virtual bool shouldAdd(const Hal&) const { return true; }
146 
147     // Return an iterable to all Hal objects. Call it as follows:
148     // for (const auto& e : vm.getHals()) { }
getHalsHalGroup149     ConstMultiMapValueIterable<std::string, Hal> getHals() const { return iterateValues(mHals); }
150 
151     // Return an iterable to all Hal objects. Call it as follows:
152     // for (const auto& e : vm.getHals()) { }
getHalsHalGroup153     MultiMapValueIterable<std::string, Hal> getHals() { return iterateValues(mHals); }
154 
155     // Get any HAL component based on the component name. Return any one
156     // if multiple. Return nullptr if the component does not exist. This is only
157     // for creating objects programatically.
158     // The component name looks like:
159     // android.hardware.foo
getAnyHalHalGroup160     Hal* getAnyHal(const std::string& name) {
161         auto it = mHals.find(name);
162         if (it == mHals.end()) {
163             return nullptr;
164         }
165         return &(it->second);
166     }
167 
addInternalHalGroup168     Hal* addInternal(Hal&& hal) {
169         if (!shouldAdd(hal)) {
170             return nullptr;
171         }
172         std::string name = hal.getName();
173         auto it = mHals.emplace(std::move(name), std::move(hal));  // always succeeds
174         return &it->second;
175     }
176 };
177 
178 }  // namespace vintf
179 }  // namespace android
180 
181 #endif  // ANDROID_VINTF_HAL_GROUP_H
182