1 /*
2 * Copyright (C) 2023 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 <algorithm>
18 #include <memory>
19 #include <optional>
20 #include <ostream>
21 #include <sstream>
22 #include <string>
23
24 #include <android-base/file.h>
25 #include <android-base/parseint.h>
26 #include <android-base/properties.h>
27 #include <android-base/result-gmock.h>
28 #include <android-base/strings.h>
29 #include <android/api-level.h>
30 #include <gmock/gmock.h>
31 #include <google/protobuf/repeated_field.h>
32 #include <google/protobuf/text_format.h>
33 #include <gtest/gtest.h>
34 #include <kver/kernel_release.h>
35 #include <libvts_vintf_test_common/common.h>
36 #include <vintf/Version.h>
37 #include <vintf/VintfObject.h>
38 #include <vintf/parse_string.h>
39
40 #include "gsi_validation_utils.h"
41 #include "kernel_version_matrix.pb.h"
42
43 namespace {
44
45 using android::base::testing::Ok;
46 using KernelVersionMatrix = std::map<uint64_t, AndroidReleaseRequirement>;
47
operator <<(std::ostream & os,const Kmi & kmi)48 std::ostream& operator<<(std::ostream& os, const Kmi& kmi) {
49 os << "android";
50 if (kmi.android_release() != 0) {
51 os << kmi.android_release();
52 }
53 return os << "-" << kmi.kernel_version().major_version() << "."
54 << kmi.kernel_version().minor_version();
55 }
56
57 // Represents the information about the running kernel.
58 struct ActualKmi {
59 public:
ActualKmi__anon97cd931e0111::ActualKmi60 ActualKmi(const android::vintf::KernelVersion& kernel_version,
61 const std::optional<android::kver::KernelRelease>& kernel_release)
62 : kernel_version_(kernel_version), kernel_release_(kernel_release) {}
63
kernel_version__anon97cd931e0111::ActualKmi64 [[nodiscard]] android::vintf::Version kernel_version() const {
65 return kernel_version_.dropMinor();
66 }
67
android_release__anon97cd931e0111::ActualKmi68 [[nodiscard]] std::optional<uint64_t> android_release() const {
69 if (kernel_release_.has_value()) {
70 return kernel_release_->android_release();
71 }
72 return std::nullopt;
73 }
74
string__anon97cd931e0111::ActualKmi75 [[nodiscard]] std::string string() const {
76 std::string ret = android::vintf::to_string(kernel_version_);
77 if (kernel_release_.has_value()) {
78 ret += " (" + kernel_release_->string() + ")";
79 }
80 return ret;
81 }
82
operator <<(std::ostream & os,const ActualKmi & kmi)83 friend std::ostream& operator<<(std::ostream& os, const ActualKmi& kmi) {
84 os << kmi.kernel_version_;
85 if (kmi.kernel_release_.has_value()) {
86 os << " (" + kmi.kernel_release_->string() << ")";
87 }
88 return os;
89 }
90
91 private:
92 android::vintf::KernelVersion kernel_version_;
93 std::optional<android::kver::KernelRelease> kernel_release_;
94 };
95
96 // Read the raw compatibility matrix from test data.
ReadRawKernelVersionMatrix()97 std::optional<RawKernelVersionMatrix> ReadRawKernelVersionMatrix() {
98 auto exec_dir = android::base::GetExecutableDirectory();
99 auto matrix_path = exec_dir + "/kernel_version_matrix.textproto";
100 std::string matrix_content;
101 if (!android::base::ReadFileToString(matrix_path, &matrix_content)) {
102 ADD_FAILURE() << "Can't read " << matrix_path;
103 return std::nullopt;
104 }
105
106 RawKernelVersionMatrix ret;
107 if (!google::protobuf::TextFormat::ParseFromString(matrix_content, &ret)) {
108 ADD_FAILURE() << matrix_path << " is not valid";
109 return std::nullopt;
110 }
111 return ret;
112 }
113
114 // Parse a raw KMI string (e.g. "android14-5.15") to structured Kmi object.
FromRaw(const std::string & s,Kmi * mutable_out)115 bool FromRaw(const std::string& s, Kmi* mutable_out) {
116 auto tokens = android::base::Split(s, "-");
117 if (tokens.size() != 2) {
118 ADD_FAILURE() << "Unrecognized requirement: " << s;
119 return false;
120 }
121
122 std::string_view android_release_sv = tokens[0];
123 if (!android::base::ConsumePrefix(&android_release_sv, "android")) {
124 ADD_FAILURE() << "Unrecognized requirement: " << s;
125 return false;
126 }
127
128 uint64_t android_release;
129 if (android_release_sv.empty()) {
130 mutable_out->clear_android_release();
131 } else {
132 if (!android::base::ParseUint(std::string(android_release_sv),
133 &android_release)) {
134 ADD_FAILURE() << "Unrecognized requirement: " << s;
135 return false;
136 }
137 mutable_out->set_android_release(android_release);
138 }
139
140 android::vintf::Version vintf_kernel_version;
141 if (!android::vintf::parse(tokens[1], &vintf_kernel_version)) {
142 ADD_FAILURE() << "Unrecognized requirement: " << s;
143 return false;
144 }
145 mutable_out->mutable_kernel_version()->set_major_version(
146 vintf_kernel_version.majorVer);
147 mutable_out->mutable_kernel_version()->set_minor_version(
148 vintf_kernel_version.minorVer);
149
150 return true;
151 }
152
153 // Parse an array of raw KMI strings to an array of structured Kmi object.
FromRaw(const google::protobuf::RepeatedPtrField<std::string> & raw_in,google::protobuf::RepeatedPtrField<Kmi> * mutable_out)154 bool FromRaw(const google::protobuf::RepeatedPtrField<std::string>& raw_in,
155 google::protobuf::RepeatedPtrField<Kmi>* mutable_out) {
156 mutable_out->Reserve(raw_in.size());
157 for (const auto& raw_s : raw_in) {
158 if (!FromRaw(raw_s, mutable_out->Add())) {
159 return false;
160 }
161 }
162 return true;
163 }
164
165 // Turn the raw compatibility matrix into structured data.
FromRaw(const RawKernelVersionMatrix & raw_kernel_version_matrix)166 std::optional<KernelVersionMatrix> FromRaw(
167 const RawKernelVersionMatrix& raw_kernel_version_matrix) {
168 KernelVersionMatrix ret;
169 for (const auto& [api_level, raw_android_release_requirements] :
170 raw_kernel_version_matrix.release_requirements()) {
171 AndroidReleaseRequirement ret_value;
172 if (!FromRaw(raw_android_release_requirements.upgrade(),
173 ret_value.mutable_upgrade())) {
174 return std::nullopt;
175 }
176 if (!FromRaw(raw_android_release_requirements.launch(),
177 ret_value.mutable_launch())) {
178 return std::nullopt;
179 }
180 if (!FromRaw(raw_android_release_requirements.launch_grf(),
181 ret_value.mutable_launch_grf())) {
182 return std::nullopt;
183 }
184 ret.emplace(api_level, std::move(ret_value));
185 }
186 return ret;
187 }
188
189 // Return requirements on kernel version and KMI for the given platform SDK
190 // level. Return nullptr on failure.
GetKernelVersionRequirements(const KernelVersionMatrix & kernel_version_matrix,uint32_t android_platform_release,bool is_launch,bool is_grf)191 const google::protobuf::RepeatedPtrField<Kmi>* GetKernelVersionRequirements(
192 const KernelVersionMatrix& kernel_version_matrix,
193 uint32_t android_platform_release, bool is_launch, bool is_grf) {
194 auto release_requirements_it =
195 kernel_version_matrix.find(android_platform_release);
196 if (release_requirements_it == kernel_version_matrix.end()) {
197 ADD_FAILURE() << "Unable to find requirement for SDK level "
198 << android_platform_release << ". Is the test updated?";
199 return nullptr;
200 }
201
202 if (is_launch) {
203 if (is_grf) {
204 return &release_requirements_it->second.launch_grf();
205 }
206 return &release_requirements_it->second.launch();
207 }
208 return &release_requirements_it->second.upgrade();
209 }
210
211 // Read the information about the running kernel that this test needs.
GetActualKmi()212 std::optional<ActualKmi> GetActualKmi() {
213 auto vintf_object = android::vintf::VintfObject::GetInstance();
214 if (vintf_object == nullptr) {
215 ADD_FAILURE() << "Cannot get VintfObject instance";
216 return std::nullopt;
217 }
218 auto runtime_info = vintf_object->getRuntimeInfo(
219 android::vintf::RuntimeInfo::FetchFlag::CPU_VERSION);
220 if (runtime_info == nullptr) {
221 ADD_FAILURE() << "Cannot get kernel release";
222 return std::nullopt;
223 }
224
225 auto kernel_release = android::kver::KernelRelease::Parse(
226 runtime_info->osRelease(), true /* allow suffix */);
227 auto kernel_version = runtime_info->kernelVersion();
228
229 return std::make_optional<ActualKmi>(kernel_version, kernel_release);
230 }
231
232 // Check kernel version and KMI against a list of requirements.
KernelVersionIsSupported(const ActualKmi & actual,const google::protobuf::RepeatedPtrField<Kmi> & requirements,std::string * error)233 bool KernelVersionIsSupported(
234 const ActualKmi& actual,
235 const google::protobuf::RepeatedPtrField<Kmi>& requirements,
236 std::string* error) {
237 for (const auto& req : requirements) {
238 if (req.kernel_version().major_version() !=
239 actual.kernel_version().majorVer ||
240 req.kernel_version().minor_version() !=
241 actual.kernel_version().minorVer) {
242 GTEST_LOG_(INFO) << "Failed to match " << actual << " against required "
243 << req << ": kernel version does not match.";
244 continue; // check next item
245 }
246
247 if (req.android_release() != actual.android_release().value_or(0)) {
248 GTEST_LOG_(INFO) << "Failed to match " << actual << " against required "
249 << req
250 << ": The Android release part of KMI does not match.";
251 continue; // check next item
252 }
253
254 GTEST_LOG_(INFO) << "Matched " << actual << " against requirement " << req;
255 return true;
256 }
257
258 std::stringstream error_stream;
259 error_stream << "Kernel " << actual << " is not valid. It must be one of [\n";
260 for (const auto& req : requirements) {
261 error_stream << " " << req << ",\n";
262 }
263 error_stream << "].";
264
265 if (actual.kernel_version() == android::vintf::Version{5, 4} &&
266 !actual.android_release().has_value()) {
267 GTEST_LOG_(INFO)
268 << error_stream.str()
269 << "\nGKI V1 testing is no longer required, skipping (b/390033463).";
270 return true;
271 }
272
273 *error = error_stream.str();
274 return false;
275 }
276
277 // If ro.build.version.codename == REL, expect the given condition is true.
278 // Otherwise, only log a warning message, but don't fail the test.
279 struct ExpectTrueOnRelease : public std::stringstream {
ExpectTrueOnRelease__anon97cd931e0111::ExpectTrueOnRelease280 explicit ExpectTrueOnRelease(bool cond) : cond_(cond) {}
~ExpectTrueOnRelease__anon97cd931e0111::ExpectTrueOnRelease281 ~ExpectTrueOnRelease() override {
282 if (cond_) {
283 return;
284 }
285 if (!IsReleasedAndroidVersion()) {
286 GTEST_LOG_(ERROR) << str() << " This will be an error upon release.";
287 } else {
288 ADD_FAILURE() << str();
289 }
290 }
291
292 private:
293 bool cond_;
294 };
295
IsGrf()296 bool IsGrf() {
297 return !android::base::GetProperty("ro.board.first_api_level", "").empty();
298 }
299
300 // Returns true if the device has the specified feature.
DeviceSupportsFeature(const char * feature)301 bool DeviceSupportsFeature(const char* feature) {
302 bool device_supports_feature = false;
303 FILE* p = popen("pm list features", "re");
304 if (p) {
305 char* line = NULL;
306 size_t len = 0;
307 while (getline(&line, &len, p) > 0) {
308 if (strstr(line, feature)) {
309 device_supports_feature = true;
310 break;
311 }
312 }
313 pclose(p);
314 }
315 return device_supports_feature;
316 }
317
TEST(KernelVersionTest,AgainstPlatformRelease)318 TEST(KernelVersionTest, AgainstPlatformRelease) {
319 auto raw_kernel_version_matrix = ReadRawKernelVersionMatrix();
320 ASSERT_TRUE(raw_kernel_version_matrix.has_value());
321 ASSERT_GT(raw_kernel_version_matrix->release_requirements_size(), 0);
322
323 auto kernel_version_matrix = FromRaw(*raw_kernel_version_matrix);
324 ASSERT_TRUE(kernel_version_matrix.has_value());
325 ASSERT_FALSE(kernel_version_matrix->empty());
326
327 auto android_platform_release = GetSdkLevel();
328
329 auto min_enforcing_android_release = kernel_version_matrix->begin()->first;
330 if (android_platform_release < min_enforcing_android_release) {
331 GTEST_SKIP() << "Kernel version is not enforced for platform SDK level "
332 << android_platform_release << " ( < "
333 << min_enforcing_android_release << " )";
334 }
335
336 auto product_first_api_level = GetProductFirstApiLevel();
337 ExpectTrueOnRelease(product_first_api_level <= android_platform_release)
338 << "Product first API level " << product_first_api_level
339 << " should not exceed the platform release " << android_platform_release
340 << ".";
341
342 auto runtime_info =
343 android::vintf::VintfObject::GetInstance()->getRuntimeInfo(
344 android::vintf::RuntimeInfo::FetchFlag::CPU_VERSION);
345 ASSERT_NE(runtime_info, nullptr);
346
347 const static bool is_tv_device =
348 DeviceSupportsFeature("android.software.leanback");
349
350 if (is_tv_device &&
351 (product_first_api_level <= 33 ||
352 (runtime_info->hardwareId() != "aarch64" &&
353 runtime_info->hardwareId() != "armv8l"))) {
354 GTEST_SKIP()
355 << "Exempt from GKI test on TV devices launched before Android U or using 32bit kernel";
356 }
357
358 bool is_launch = product_first_api_level >= android_platform_release;
359
360 auto requirements = GetKernelVersionRequirements(
361 *kernel_version_matrix, android_platform_release, is_launch, IsGrf());
362 ASSERT_NE(requirements, nullptr);
363
364 auto actual = GetActualKmi();
365 ASSERT_TRUE(actual.has_value());
366
367 std::string error;
368 ExpectTrueOnRelease(KernelVersionIsSupported(*actual, *requirements, &error))
369 << error;
370 }
371
TEST(KernelVersionTest,GrfDevicesMustUseLatestKernel)372 TEST(KernelVersionTest, GrfDevicesMustUseLatestKernel) {
373 if (!IsGrf()) {
374 GTEST_SKIP() << "Non-GRF device kernel requirements are checked in "
375 "SystemVendorTest.KernelCompatibility";
376 }
377
378 auto vendor_api_level = GetVendorApiLevel();
379 ASSERT_TRUE(vendor_api_level != 0)
380 << "Unable to determine board API level on GRF devices";
381
382 if (vendor_api_level <= __ANDROID_API_R__) {
383 GTEST_SKIP() << "[VSR-3.4.1-001] does not enforce latest kernel x.y for "
384 << "vendor_api_level == " << vendor_api_level << " <= R";
385 }
386
387 auto corresponding_vintf_level =
388 android::vintf::testing::GetFcmVersionFromApiLevel(vendor_api_level);
389 ASSERT_THAT(corresponding_vintf_level, Ok());
390
391 auto latest_min_lts =
392 android::vintf::VintfObject::GetInstance()->getLatestMinLtsAtFcmVersion(
393 *corresponding_vintf_level);
394 ASSERT_THAT(latest_min_lts, Ok());
395 auto runtime_info =
396 android::vintf::VintfObject::GetInstance()->getRuntimeInfo(
397 android::vintf::RuntimeInfo::FetchFlag::CPU_VERSION);
398 ASSERT_NE(runtime_info, nullptr);
399 auto kernel_version = runtime_info->kernelVersion();
400
401 ASSERT_GE(kernel_version, *latest_min_lts)
402 << "[VSR-3.4.1-001] CHIPSETs that are on GRF and are frozen on API level "
403 << vendor_api_level << " (corresponding to VINTF level "
404 << *corresponding_vintf_level << ") must use kernel version ("
405 << *latest_min_lts << ")+, but kernel version is " << kernel_version;
406 }
407
408 } // namespace
409