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__anon0455a8e80111::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__anon0455a8e80111::ActualKmi64   [[nodiscard]] android::vintf::Version kernel_version() const {
65     return kernel_version_.dropMinor();
66   }
67 
android_release__anon0455a8e80111::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__anon0455a8e80111::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   *error = error_stream.str();
265   return false;
266 }
267 
268 // If ro.build.version.codename == REL, expect the given condition is true.
269 // Otherwise, only log a warning message, but don't fail the test.
270 struct ExpectTrueOnRelease : public std::stringstream {
ExpectTrueOnRelease__anon0455a8e80111::ExpectTrueOnRelease271   explicit ExpectTrueOnRelease(bool cond) : cond_(cond) {}
~ExpectTrueOnRelease__anon0455a8e80111::ExpectTrueOnRelease272   ~ExpectTrueOnRelease() override {
273     if (cond_) {
274       return;
275     }
276     if (!IsReleasedAndroidVersion()) {
277       GTEST_LOG_(ERROR) << str() << " This will be an error upon release.";
278     } else {
279       ADD_FAILURE() << str();
280     }
281   }
282 
283  private:
284   bool cond_;
285 };
286 
IsGrf()287 bool IsGrf() {
288   return !android::base::GetProperty("ro.board.first_api_level", "").empty();
289 }
290 
291 // Returns true if the device has the specified feature.
DeviceSupportsFeature(const char * feature)292 bool DeviceSupportsFeature(const char* feature) {
293   bool device_supports_feature = false;
294   FILE* p = popen("pm list features", "re");
295   if (p) {
296     char* line = NULL;
297     size_t len = 0;
298     while (getline(&line, &len, p) > 0) {
299       if (strstr(line, feature)) {
300         device_supports_feature = true;
301         break;
302       }
303     }
304     pclose(p);
305   }
306   return device_supports_feature;
307 }
308 
TEST(KernelVersionTest,AgainstPlatformRelease)309 TEST(KernelVersionTest, AgainstPlatformRelease) {
310   auto raw_kernel_version_matrix = ReadRawKernelVersionMatrix();
311   ASSERT_TRUE(raw_kernel_version_matrix.has_value());
312   ASSERT_GT(raw_kernel_version_matrix->release_requirements_size(), 0);
313 
314   auto kernel_version_matrix = FromRaw(*raw_kernel_version_matrix);
315   ASSERT_TRUE(kernel_version_matrix.has_value());
316   ASSERT_FALSE(kernel_version_matrix->empty());
317 
318   auto android_platform_release = GetSdkLevel();
319 
320   auto min_enforcing_android_release = kernel_version_matrix->begin()->first;
321   if (android_platform_release < min_enforcing_android_release) {
322     GTEST_SKIP() << "Kernel version is not enforced for platform SDK level "
323                  << android_platform_release << " ( < "
324                  << min_enforcing_android_release << " )";
325   }
326 
327   auto product_first_api_level = GetProductFirstApiLevel();
328   ExpectTrueOnRelease(product_first_api_level <= android_platform_release)
329       << "Product first API level " << product_first_api_level
330       << " should not exceed the platform release " << android_platform_release
331       << ".";
332 
333   const static bool is_tv_device =
334       DeviceSupportsFeature("android.software.leanback");
335   if (product_first_api_level <= 33 && is_tv_device) {
336     GTEST_SKIP()
337         << "Exempt from GKI test on TV devices launched before Android U";
338   }
339 
340   bool is_launch = product_first_api_level >= android_platform_release;
341 
342   auto requirements = GetKernelVersionRequirements(
343       *kernel_version_matrix, android_platform_release, is_launch, IsGrf());
344   ASSERT_NE(requirements, nullptr);
345 
346   auto actual = GetActualKmi();
347   ASSERT_TRUE(actual.has_value());
348 
349   std::string error;
350   ExpectTrueOnRelease(KernelVersionIsSupported(*actual, *requirements, &error))
351       << error;
352 }
353 
TEST(KernelVersionTest,GrfDevicesMustUseLatestKernel)354 TEST(KernelVersionTest, GrfDevicesMustUseLatestKernel) {
355   if (!IsGrf()) {
356     GTEST_SKIP() << "Non-GRF device kernel requirements are checked in "
357                     "SystemVendorTest.KernelCompatibility";
358   }
359 
360   auto vendor_api_level = GetVendorApiLevel();
361   ASSERT_TRUE(vendor_api_level != 0)
362       << "Unable to determine board API level on GRF devices";
363 
364   if (vendor_api_level <= __ANDROID_API_R__) {
365     GTEST_SKIP() << "[VSR-3.4.1-001] does not enforce latest kernel x.y for "
366                  << "vendor_api_level == " << vendor_api_level << " <= R";
367   }
368 
369   auto corresponding_vintf_level =
370       android::vintf::testing::GetFcmVersionFromApiLevel(vendor_api_level);
371   ASSERT_THAT(corresponding_vintf_level, Ok());
372 
373   auto latest_min_lts =
374       android::vintf::VintfObject::GetInstance()->getLatestMinLtsAtFcmVersion(
375           *corresponding_vintf_level);
376   ASSERT_THAT(latest_min_lts, Ok());
377   auto runtime_info =
378       android::vintf::VintfObject::GetInstance()->getRuntimeInfo(
379           android::vintf::RuntimeInfo::FetchFlag::CPU_VERSION);
380   ASSERT_NE(runtime_info, nullptr);
381   auto kernel_version = runtime_info->kernelVersion();
382 
383   ASSERT_GE(kernel_version, *latest_min_lts)
384       << "[VSR-3.4.1-001] CHIPSETs that are on GRF and are frozen on API level "
385       << vendor_api_level << " (corresponding to VINTF level "
386       << *corresponding_vintf_level << ") must use kernel version ("
387       << *latest_min_lts << ")+, but kernel version is " << kernel_version;
388 }
389 
390 }  // namespace
391