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
CheckKmi(const KernelRelease & kernel_release,const KmiVersion & kmi_version)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
WriteApexManifest(const std::string & apex_name,Json::UInt64 apex_version,const std::string & out_file)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
main(int argc,char ** argv)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