1 // 2 // Copyright (C) 2020 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 <sysexits.h> 18 19 #include <android-base/file.h> 20 #include <android-base/logging.h> 21 #include <android-base/strings.h> 22 #include <gflags/gflags.h> 23 #include <json/json.h> 24 #include <kver/kernel_release.h> 25 #include <kver/kmi_version.h> 26 #include <kver/utils.h> 27 28 using android::kver::GetFactoryApexVersion; 29 using android::kver::KernelRelease; 30 using android::kver::KmiVersion; 31 32 static constexpr uint64_t UNSTABLE_GENERATION = UINT64_MAX; 33 34 namespace { 35 36 int CheckKmi(const KernelRelease& kernel_release, const KmiVersion& kmi_version) { 37 const auto& actual_kmi_version = kernel_release.kmi_version(); 38 if (actual_kmi_version == kmi_version) { 39 return EX_OK; 40 } 41 if (kmi_version.generation() == UNSTABLE_GENERATION && 42 kmi_version.version() == actual_kmi_version.version() && 43 kmi_version.patch_level() == actual_kmi_version.patch_level() && 44 kmi_version.android_release() == actual_kmi_version.android_release()) { 45 LOG(WARNING) << "Actual KMI version " << actual_kmi_version.string() 46 << " matches unstable KMI version"; 47 return EX_OK; 48 } 49 LOG(ERROR) << "KMI version does not match. Actual: " << actual_kmi_version.string() 50 << ", expected: " << kmi_version.string(); 51 return EX_SOFTWARE; 52 } 53 54 int WriteApexManifest(const std::string& apex_name, Json::UInt64 apex_version, 55 const std::string& out_file) { 56 Json::Value root; 57 root["name"] = apex_name; 58 root["version"] = apex_version; 59 root["preInstallHook"] = "bin/com.android.gki.preinstall"; 60 Json::StreamWriterBuilder factory; 61 std::string json_string = Json::writeString(factory, root); 62 if (!android::base::WriteStringToFile(json_string, out_file)) { 63 PLOG(ERROR) << "Cannot write to " << out_file; 64 return EX_SOFTWARE; 65 } 66 return EX_OK; 67 } 68 69 } // namespace 70 71 DEFINE_string(kernel_release_file, "", 72 "Input file that contains a kernel release string parsed from the boot image. " 73 "Exactly one of --kernel_release_file or --factory must be set."); 74 DEFINE_bool(factory, false, 75 "Set to true for factory APEX package. Exactly one of --kernel_release_file or " 76 "--factory must be set."); 77 DEFINE_string(kmi_version, "", "Declared KMI version for this APEX."); 78 DEFINE_string(apex_manifest, "", "Output APEX manifest JSON file."); 79 DEFINE_uint64(apex_version, GetFactoryApexVersion(), 80 "Override APEX version in APEX manifest. Use factory APEX version if unspecified."); 81 82 int main(int argc, char** argv) { 83 gflags::ParseCommandLineFlags(&argc, &argv, true); 84 85 if (FLAGS_kmi_version.empty()) { 86 LOG(ERROR) << "--kmi_version must be set."; 87 return EX_SOFTWARE; 88 } 89 std::string_view kmi_version_sv(FLAGS_kmi_version); 90 std::string kmi_version_string; 91 if (android::base::ConsumeSuffix(&kmi_version_sv, "unstable")) { 92 kmi_version_string = std::string(kmi_version_sv) + std::to_string(UNSTABLE_GENERATION); 93 } else { 94 kmi_version_string = kmi_version_sv; 95 } 96 auto kmi_version = KmiVersion::Parse(kmi_version_string); 97 if (!kmi_version.has_value()) { 98 LOG(ERROR) << "--kmi_version is not a valid KMI version."; 99 return EX_SOFTWARE; 100 } 101 102 if (FLAGS_factory + (!FLAGS_kernel_release_file.empty()) != 1) { 103 LOG(ERROR) << "Exactly one of --kernel_release_file or --factory must be set."; 104 return EX_SOFTWARE; 105 } 106 107 if (!FLAGS_kernel_release_file.empty()) { 108 std::string kernel_release_string; 109 if (!android::base::ReadFileToString(FLAGS_kernel_release_file, &kernel_release_string)) { 110 PLOG(ERROR) << "Cannot read " << FLAGS_kernel_release_file; 111 return EX_SOFTWARE; 112 } 113 auto kernel_release = KernelRelease::Parse(kernel_release_string, true /* allow_suffix */); 114 if (!kernel_release.has_value()) { 115 LOG(ERROR) << kernel_release_string << " is not a valid GKI kernel release string"; 116 return EX_SOFTWARE; 117 } 118 int res = CheckKmi(*kernel_release, *kmi_version); 119 if (res != EX_OK) return res; 120 } 121 122 std::string apex_name = GetApexName(*kmi_version); 123 uint64_t apex_version = FLAGS_apex_version; 124 125 if (FLAGS_apex_manifest.empty()) { 126 LOG(WARNING) << "Skip writing APEX manifest because --apex_manifest is not set."; 127 } else { 128 int res = WriteApexManifest(apex_name, apex_version, FLAGS_apex_manifest); 129 if (res != EX_OK) return res; 130 } 131 132 return EX_OK; 133 } 134