summaryrefslogtreecommitdiff
path: root/build_gki_apex_manifest.cpp
blob: 016c216f2d5ae690f086b607cd4fc18602a7b71c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include <sysexits.h>

#include <android-base/file.h>
#include <android-base/logging.h>
#include <gflags/gflags.h>
#include <json/json.h>
#include <kver/kernel_release.h>
#include <kver/kmi_version.h>
#include <kver/utils.h>

using android::kver::GetFactoryApexVersion;
using android::kver::KernelRelease;
using android::kver::KmiVersion;

namespace {

int CheckKmi(const KernelRelease& kernel_release, const KmiVersion& kmi_version) {
  const auto& actual_kmi_version = kernel_release.kmi_version();
  if (actual_kmi_version != kmi_version) {
    LOG(ERROR) << "KMI version does not match. Actual: " << actual_kmi_version.string()
               << ", expected: " << kmi_version.string();
    return EX_SOFTWARE;
  }
  return EX_OK;
}

int WriteApexManifest(const std::string& apex_name, Json::UInt64 apex_version,
                      const std::string& out_file) {
  Json::Value root;
  root["name"] = apex_name;
  root["version"] = apex_version;
  root["preInstallHook"] = "bin/com.android.gki.preinstall";
  Json::StreamWriterBuilder factory;
  std::string json_string = Json::writeString(factory, root);
  if (!android::base::WriteStringToFile(json_string, out_file)) {
    PLOG(ERROR) << "Cannot write to " << out_file;
    return EX_SOFTWARE;
  }
  return EX_OK;
}

}  // namespace

DEFINE_string(kernel_release_file, "",
              "Input file that contains a kernel release string parsed from the boot image. "
              "Exactly one of --kernel_release_file or --factory must be set.");
DEFINE_bool(factory, false,
            "Set to true for factory APEX package. Exactly one of --kernel_release_file or "
            "--factory must be set.");
DEFINE_string(kmi_version, "", "Declared KMI version for this APEX.");
DEFINE_string(apex_manifest, "", "Output APEX manifest JSON file.");
DEFINE_uint64(apex_version, GetFactoryApexVersion(),
              "Override APEX version in APEX manifest. Use factory APEX version if unspecified.");

int main(int argc, char** argv) {
  gflags::ParseCommandLineFlags(&argc, &argv, true);

  if (FLAGS_kmi_version.empty()) {
    LOG(ERROR) << "--kmi_version must be set.";
    return EX_SOFTWARE;
  }
  auto kmi_version = KmiVersion::Parse(FLAGS_kmi_version);
  if (!kmi_version.has_value()) {
    LOG(ERROR) << "--kmi_version is not a valid KMI version.";
    return EX_SOFTWARE;
  }

  if (FLAGS_factory + (!FLAGS_kernel_release_file.empty()) != 1) {
    LOG(ERROR) << "Exactly one of --kernel_release_file or --factory must be set.";
    return EX_SOFTWARE;
  }

  if (!FLAGS_kernel_release_file.empty()) {
    std::string kernel_release_string;
    if (!android::base::ReadFileToString(FLAGS_kernel_release_file, &kernel_release_string)) {
      PLOG(ERROR) << "Cannot read " << FLAGS_kernel_release_file;
      return EX_SOFTWARE;
    }
    auto kernel_release = KernelRelease::Parse(kernel_release_string, true /* allow_suffix */);
    if (!kernel_release.has_value()) {
      LOG(ERROR) << kernel_release_string << " is not a valid GKI kernel release string";
      return EX_SOFTWARE;
    }
    int res = CheckKmi(*kernel_release, *kmi_version);
    if (res != EX_OK) return res;
  }

  std::string apex_name = GetApexName(*kmi_version);
  uint64_t apex_version = FLAGS_apex_version;

  if (FLAGS_apex_manifest.empty()) {
    LOG(WARNING) << "Skip writing APEX manifest because --apex_manifest is not set.";
  } else {
    int res = WriteApexManifest(apex_name, apex_version, FLAGS_apex_manifest);
    if (res != EX_OK) return res;
  }

  return EX_OK;
}