1 /*
2 * Copyright (C) 2018 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 <optional>
18 #include <set>
19
20 #include <android-base/logging.h>
21 #include <gflags/gflags.h>
22 #include <hidl-util/FqInstance.h>
23 #include <vintf/FileSystem.h>
24 #include <vintf/parse_string.h>
25 #include <vintf/parse_xml.h>
26
27 namespace android {
28 namespace vintf {
29
30 namespace {
31
32 template <typename T>
readObject(const std::string & path)33 std::optional<T> readObject(const std::string& path) {
34 std::string xml;
35 std::string error;
36 status_t err = details::FileSystemImpl().fetch(path, &xml, &error);
37 if (err != OK) {
38 LOG(ERROR) << "Cannot read '" << path << "': " << error;
39 return std::nullopt;
40 }
41 auto ret = std::make_optional<T>();
42 if (!fromXml(&ret.value(), xml, &error)) {
43 LOG(ERROR) << "Cannot parse '" << path << "': " << error;
44 return std::nullopt;
45 }
46 return ret;
47 }
48
49 template <typename F>
getDescription(const CompatibilityMatrix & mat,F descriptionFn,bool emitReq)50 std::set<std::string> getDescription(const CompatibilityMatrix& mat, F descriptionFn,
51 bool emitReq) {
52 std::set<std::string> set;
53 mat.forEachInstance([&set, descriptionFn, emitReq](const auto& matrixInstance) {
54 for (auto minorVer = matrixInstance.versionRange().minMinor;
55 minorVer >= matrixInstance.versionRange().minMinor &&
56 minorVer <= matrixInstance.versionRange().maxMinor;
57 ++minorVer) {
58 Version version{matrixInstance.versionRange().majorVer, minorVer};
59 std::string s = std::invoke(descriptionFn, matrixInstance, version);
60 if (emitReq) {
61 s += (matrixInstance.optional() ? " optional" : " required");
62 }
63 set.insert(s);
64 }
65 return true; // continue
66 });
67 return set;
68 }
69
70 } // namespace
71
GetDescription(Level level)72 std::string GetDescription(Level level) {
73 switch (level) {
74 case Level::LEGACY:
75 return "Level legacy";
76 case Level::O:
77 return "Android 8.0 (O)";
78 case Level::O_MR1:
79 return "Android 8.1 (O-MR1)";
80 case Level::P:
81 return "Android 9 (P)";
82 case Level::Q:
83 return "Android 10 (Q)";
84 case Level::R:
85 return "Android 11 (R)";
86 case Level::S:
87 return "Android 12 (S)";
88 case Level::T:
89 return "Android 13 (T)";
90 case Level::UNSPECIFIED:
91 return "Level unspecified";
92 default:
93 return "Level " + std::to_string(level);
94 }
95 }
96
97 } // namespace vintf
98 } // namespace android
99
100 DEFINE_string(input, "", "Input compatibility matrix file");
ValidateInput(const char *,const std::string & value)101 static bool ValidateInput(const char* /* flagname */, const std::string& value) {
102 return !value.empty();
103 }
104 DEFINE_validator(input, &ValidateInput);
105
106 DEFINE_bool(level, false, "Write level (FCM version) of the compatibility matrix.");
107 DEFINE_bool(level_name, false, "Write level name (FCM version) of the compatibility matrix.");
108 DEFINE_bool(interfaces, false, "Write strings like \"android.hardware.foo@1.0::IFoo\".");
109 DEFINE_bool(instances, false, "Write strings like \"android.hardware.foo@1.0::IFoo/default\".");
110 DEFINE_bool(requirement, false, "Append optional/required after each interface / instance.");
111
main(int argc,char ** argv)112 int main(int argc, char** argv) {
113 using namespace android::vintf;
114
115 gflags::ParseCommandLineFlags(&argc, &argv, true /* remove flags */);
116
117 auto mat = readObject<CompatibilityMatrix>(FLAGS_input);
118 if (!mat) {
119 return 1;
120 }
121
122 bool written = false;
123
124 if (FLAGS_level) {
125 if (mat->level() == Level::UNSPECIFIED) {
126 LOG(WARNING) << "FCM version is unspecified.";
127 }
128 std::cout << mat->level() << std::endl;
129
130 written = true;
131 }
132
133 if (FLAGS_level_name) {
134 if (mat->level() == Level::UNSPECIFIED) {
135 LOG(WARNING) << "FCM version is unspecified.";
136 }
137 std::cout << GetDescription(mat->level()) << std::endl;
138
139 written = true;
140 }
141
142 if (FLAGS_interfaces) {
143 auto interfaces =
144 getDescription(*mat, &MatrixInstance::interfaceDescription, FLAGS_requirement);
145 if (interfaces.empty()) {
146 LOG(WARNING) << "No interfaces are found.";
147 }
148
149 for (const auto& interface : interfaces) {
150 std::cout << interface << std::endl;
151 }
152
153 written = true;
154 }
155
156 if (FLAGS_instances) {
157 auto instances = getDescription(*mat, &MatrixInstance::description, FLAGS_requirement);
158 if (instances.empty()) {
159 LOG(WARNING) << "No instances are found.";
160 }
161
162 for (const auto& instance : instances) {
163 std::cout << instance << std::endl;
164 }
165
166 written = true;
167 }
168
169 if (!written) {
170 LOG(ERROR) << "No output format is set.";
171 return 1;
172 }
173
174 return 0;
175 }
176