summaryrefslogtreecommitdiff
path: root/runtime/oat/sdc_file.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/oat/sdc_file.cc')
-rw-r--r--runtime/oat/sdc_file.cc113
1 files changed, 113 insertions, 0 deletions
diff --git a/runtime/oat/sdc_file.cc b/runtime/oat/sdc_file.cc
new file mode 100644
index 0000000000..35a759e576
--- /dev/null
+++ b/runtime/oat/sdc_file.cc
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2025 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 "sdc_file.h"
+
+#include <memory>
+#include <regex>
+#include <string>
+#include <string_view>
+#include <unordered_map>
+#include <vector>
+
+#include "android-base/file.h"
+#include "android-base/parseint.h"
+#include "android-base/scopeguard.h"
+#include "base/macros.h"
+#include "base/utils.h"
+
+namespace art HIDDEN {
+
+using ::android::base::ParseInt;
+using ::android::base::ReadFileToString;
+using ::android::base::WriteStringToFd;
+
+std::unique_ptr<SdcReader> SdcReader::Load(const std::string filename, std::string* error_msg) {
+ std::unique_ptr<SdcReader> reader(new SdcReader());
+
+ // The sdc file is supposed to be small, so read fully into memory for simplicity.
+ if (!ReadFileToString(filename, &reader->content_)) {
+ *error_msg = ART_FORMAT("Failed to load sdc file '{}': {}", filename, strerror(errno));
+ return nullptr;
+ }
+
+ std::vector<std::string_view> lines;
+ Split(reader->content_, '\n', &lines);
+ std::unordered_map<std::string_view, std::string_view> map;
+ for (std::string_view line : lines) {
+ size_t pos = line.find('=');
+ if (pos == std::string_view::npos || pos == 0) {
+ *error_msg = ART_FORMAT("Malformed line '{}' in sdc file '{}'", line, filename);
+ return nullptr;
+ }
+ if (!map.try_emplace(line.substr(0, pos), line.substr(pos + 1)).second) {
+ *error_msg = ART_FORMAT("Duplicate key '{}' in sdc file '{}'", line.substr(0, pos), filename);
+ return nullptr;
+ }
+ }
+
+ decltype(map)::iterator it;
+ if ((it = map.find("sdm-timestamp")) == map.end()) {
+ *error_msg = ART_FORMAT("Missing key 'sdm-timestamp' in sdc file '{}'", filename);
+ return nullptr;
+ }
+ if (!ParseInt(std::string(it->second), &reader->sdm_timestamp_, /*min=*/1l)) {
+ *error_msg = ART_FORMAT("Invalid 'sdm-timestamp' {}", it->second);
+ return nullptr;
+ }
+
+ if ((it = map.find("apex-versions")) == map.end()) {
+ *error_msg = ART_FORMAT("Missing key 'apex-versions' in sdc file '{}'", filename);
+ return nullptr;
+ }
+ if (!std::regex_match(it->second.begin(), it->second.end(), std::regex("[0-9/]*"))) {
+ *error_msg = ART_FORMAT("Invalid 'apex-versions' {}", it->second);
+ return nullptr;
+ }
+ reader->apex_versions_ = it->second;
+
+ if (map.size() > 2) {
+ *error_msg = ART_FORMAT("Malformed sdc file '{}'. Unrecognized keys", filename);
+ return nullptr;
+ }
+
+ return reader;
+}
+
+bool SdcWriter::Save(std::string* error_msg) {
+ auto cleanup = android::base::make_scope_guard([this] { (void)file_.FlushClose(); });
+ if (sdm_timestamp_ <= 0) {
+ *error_msg = ART_FORMAT("Invalid 'sdm-timestamp' {}", sdm_timestamp_);
+ return false;
+ }
+ DCHECK_EQ(file_.GetLength(), 0);
+ std::string content =
+ ART_FORMAT("sdm-timestamp={}\napex-versions={}\n", sdm_timestamp_, apex_versions_);
+ if (!WriteStringToFd(content, file_.Fd())) {
+ *error_msg = ART_FORMAT("Failed to write sdc file '{}': {}", file_.GetPath(), strerror(errno));
+ return false;
+ }
+ int res = file_.FlushClose();
+ if (res != 0) {
+ *error_msg =
+ ART_FORMAT("Failed to flush close sdc file '{}': {}", file_.GetPath(), strerror(-res));
+ return false;
+ }
+ cleanup.Disable();
+ return true;
+}
+
+} // namespace art