1 /*
2  * Copyright (C) 2021 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 <filesystem>
18 
19 #include <android-base/properties.h>
20 #include <gmock/gmock.h>
21 #include <gtest/gtest.h>
22 #include <kver/kernel_release.h>
23 #include <vintf/VintfObject.h>
24 #include <vintf/parse_string.h>
25 
26 #include "ramdisk_utils.h"
27 
28 using android::base::GetBoolProperty;
29 using android::base::GetProperty;
30 using android::kver::KernelRelease;
31 using android::vintf::RuntimeInfo;
32 using android::vintf::Version;
33 using android::vintf::VintfObject;
34 using testing::IsSupersetOf;
35 
36 class GenericBootImageTest : public testing::Test {
37  public:
SetUp()38   void SetUp() override {
39     auto vintf = VintfObject::GetInstance();
40     ASSERT_NE(nullptr, vintf);
41     runtime_info = vintf->getRuntimeInfo(RuntimeInfo::FetchFlag::CPU_VERSION);
42     ASSERT_NE(nullptr, runtime_info);
43   }
44   std::shared_ptr<const RuntimeInfo> runtime_info;
45 };
46 
TEST_F(GenericBootImageTest,KernelReleaseFormat)47 TEST_F(GenericBootImageTest, KernelReleaseFormat) {
48   // On "GKI 2.0" with 5.10+ kernels, VTS runs once with the device kernel,
49   // so this test is meaningful.
50   if (runtime_info->kernelVersion().dropMinor() < Version{5, 10}) {
51     GTEST_SKIP() << "Exempt generic kernel image (GKI) test on kernel "
52                  << runtime_info->kernelVersion()
53                  << ". Only required on 5.10+.";
54   }
55 
56   const std::string& release = runtime_info->osRelease();
57   ASSERT_TRUE(
58       KernelRelease::Parse(release, true /* allow_suffix */).has_value())
59       << "Kernel release '" << release
60       << "' does not have generic kernel image (GKI) release format. It must "
61          "match this regex:\n"
62       << R"(^(?P<w>\d+)[.](?P<x>\d+)[.](?P<y>\d+)-(?P<z>android\d+)-(?P<k>\d+).*$)"
63       << "\nExample: 5.4.42-android12-0-something";
64 }
65 
TEST_F(GenericBootImageTest,GenericRamdisk)66 TEST_F(GenericBootImageTest, GenericRamdisk) {
67   // On "GKI 2.0" with 5.10+ kernels, VTS runs once with the device kernel,
68   // so this test is meaningful.
69   if (runtime_info->kernelVersion().dropMinor() < Version{5, 10}) {
70     GTEST_SKIP() << "Exempt generic ramdisk test on kernel "
71                  << runtime_info->kernelVersion()
72                  << ". Only required on 5.10+.";
73   }
74 
75   using std::filesystem::recursive_directory_iterator;
76 
77   std::string slot_suffix = GetProperty("ro.boot.slot_suffix", "");
78   std::string boot_path = "/dev/block/by-name/boot" + slot_suffix;
79   if (0 != access(boot_path.c_str(), F_OK)) {
80     int saved_errno = errno;
81     FAIL() << "Can't access " << boot_path << ": " << strerror(saved_errno);
82   }
83 
84   auto extracted_ramdisk = android::ExtractRamdiskToDirectory(boot_path);
85   ASSERT_RESULT_OK(extracted_ramdisk);
86 
87   std::set<std::string> actual_files;
88   std::filesystem::path extracted_ramdisk_path((*extracted_ramdisk)->path);
89   for (auto& p : recursive_directory_iterator(extracted_ramdisk_path)) {
90     if (p.is_directory()) continue;
91     EXPECT_TRUE(p.is_regular_file())
92         << "Unexpected non-regular file " << p.path();
93     auto rel_path = p.path().lexically_relative(extracted_ramdisk_path);
94     actual_files.insert(rel_path.string());
95   }
96 
97   std::set<std::string> generic_ramdisk_allowlist{
98       "init",
99       "system/etc/ramdisk/build.prop",
100   };
101   if (GetBoolProperty("ro.debuggable", false)) {
102     EXPECT_THAT(actual_files, IsSupersetOf(generic_ramdisk_allowlist))
103         << "Missing files required by non-debuggable generic ramdisk.";
104     std::set<std::string> debuggable_allowlist{
105         "adb_debug.prop",
106         "force_debuggable",
107         "userdebug_plat_sepolicy.cil",
108     };
109     generic_ramdisk_allowlist.insert(debuggable_allowlist.begin(),
110                                      debuggable_allowlist.end());
111     EXPECT_THAT(generic_ramdisk_allowlist, IsSupersetOf(actual_files))
112         << "Contains files disallowed by debuggable generic ramdisk";
113   } else {
114     EXPECT_EQ(actual_files, generic_ramdisk_allowlist);
115   }
116 }
117