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 <android-base/properties.h>
18 #include <android/api-level.h>
19 #include <elf.h>
20 #include <gtest/gtest.h>
21 #include <libelf64/parse.h>
22
23 class Vts16KPageSizeTest : public ::testing::Test {
24 protected:
VendorApiLevel()25 static int VendorApiLevel() {
26 // "ro.vendor.api_level" is added in Android T.
27 // Undefined indicates S or below
28 return android::base::GetIntProperty("ro.vendor.api_level", __ANDROID_API_S__);
29 }
30
NoBionicPageSizeMacroProperty()31 static bool NoBionicPageSizeMacroProperty() {
32 // "ro.product.build.no_bionic_page_size_macro" was added in Android V and is
33 // set to true when Android is build with PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO := true.
34 return android::base::GetBoolProperty("ro.product.build.no_bionic_page_size_macro", false);
35 }
36
Architecture()37 static std::string Architecture() { return android::base::GetProperty("ro.bionic.arch", ""); }
38
MaxPageSize(const std::string & filepath)39 static ssize_t MaxPageSize(const std::string& filepath) {
40 ssize_t maxPageSize = -1;
41
42 android::elf64::Elf64Binary elf;
43
44 if (!android::elf64::Elf64Parser::ParseElfFile(filepath, elf)) {
45 return -1;
46 }
47
48 for (int i = 0; i < elf.phdrs.size(); i++) {
49 Elf64_Phdr phdr = elf.phdrs[i];
50
51 if ((phdr.p_type != PT_LOAD) || !(phdr.p_type & PF_X)) {
52 continue;
53 }
54
55 maxPageSize = phdr.p_align;
56 break;
57 }
58
59 return maxPageSize;
60 }
61
SetUpTestSuite()62 static void SetUpTestSuite() {
63 if (VendorApiLevel() < __ANDROID_API_V__) {
64 GTEST_SKIP() << "16kB support is only required on V and later releases.";
65 }
66 }
67
68 /*
69 * x86_64 also needs to be at least 16KB aligned, since Android
70 * supports page size emulation in x86_64 for app development.
71 */
RequiredMaxPageSize()72 size_t RequiredMaxPageSize() {
73 if (mArch == "arm64" || mArch == "aarch64" || mArch == "x86_64") {
74 return 0x4000;
75 } else {
76 return 0x1000;
77 }
78 }
79
80 const std::string mArch = Architecture();
81 };
82
83 /**
84 * Checks the max-page-size of init against the architecture's
85 * required max-page-size.
86 *
87 * Note: a more comprehensive version of this test exists in
88 * elf_alignment_test. This has turned out to be a canary test
89 * to give visibility on this when checking all 16K tests.
90 */
91 // @VsrTest = 3.14.1
TEST_F(Vts16KPageSizeTest,InitMaxPageSizeTest)92 TEST_F(Vts16KPageSizeTest, InitMaxPageSizeTest) {
93 constexpr char initPath[] = "/system/bin/init";
94
95 ssize_t expectedMaxPageSize = RequiredMaxPageSize();
96 ASSERT_NE(expectedMaxPageSize, -1)
97 << "Failed to get required max page size for arch: " << mArch;
98
99 ssize_t initMaxPageSize = MaxPageSize(initPath);
100 ASSERT_NE(initMaxPageSize, -1) << "Failed to get max page size of ELF: " << initPath;
101
102 ASSERT_EQ(initMaxPageSize % expectedMaxPageSize, 0)
103 << "ELF " << initPath << " with page size " << initMaxPageSize
104 << " was not built with the required max-page-size " << expectedMaxPageSize;
105 }
106
107 /**
108 * Checks if the vendor's build was compiled with the define
109 * PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO based on the product property
110 * ro.product.build.no_bionic_page_size_macro.
111 */
112 // @VsrTest = 3.14.2
TEST_F(Vts16KPageSizeTest,NoBionicPageSizeMacro)113 TEST_F(Vts16KPageSizeTest, NoBionicPageSizeMacro) {
114 /**
115 * TODO(b/315034809): switch to error when final decision is made.
116 */
117 if (!NoBionicPageSizeMacroProperty())
118 GTEST_SKIP() << "Device was not built with: PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO := true";
119 }
120