1 /*
2 * Copyright (C) 2019 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 "updater/dynamic_partitions.h"
18
19 #include <sys/stat.h>
20 #include <sys/types.h>
21
22 #include <memory>
23 #include <string>
24 #include <vector>
25
26 #include <android-base/file.h>
27 #include <android-base/logging.h>
28 #include <android-base/strings.h>
29
30 #include "edify/expr.h"
31 #include "edify/updater_runtime_interface.h"
32 #include "otautil/error_code.h"
33 #include "otautil/paths.h"
34 #include "private/utils.h"
35
ReadStringArgs(const char * name,State * state,const std::vector<std::unique_ptr<Expr>> & argv,const std::vector<std::string> & arg_names)36 static std::vector<std::string> ReadStringArgs(const char* name, State* state,
37 const std::vector<std::unique_ptr<Expr>>& argv,
38 const std::vector<std::string>& arg_names) {
39 if (argv.size() != arg_names.size()) {
40 ErrorAbort(state, kArgsParsingFailure, "%s expects %zu arguments, got %zu", name,
41 arg_names.size(), argv.size());
42 return {};
43 }
44
45 std::vector<std::unique_ptr<Value>> args;
46 if (!ReadValueArgs(state, argv, &args)) {
47 return {};
48 }
49
50 CHECK_EQ(args.size(), arg_names.size());
51
52 for (size_t i = 0; i < arg_names.size(); ++i) {
53 if (args[i]->type != Value::Type::STRING) {
54 ErrorAbort(state, kArgsParsingFailure, "%s argument to %s must be string",
55 arg_names[i].c_str(), name);
56 return {};
57 }
58 }
59
60 std::vector<std::string> ret;
61 std::transform(args.begin(), args.end(), std::back_inserter(ret),
62 [](const auto& arg) { return arg->data; });
63 return ret;
64 }
65
UnmapPartitionFn(const char * name,State * state,const std::vector<std::unique_ptr<Expr>> & argv)66 Value* UnmapPartitionFn(const char* name, State* state,
67 const std::vector<std::unique_ptr<Expr>>& argv) {
68 auto args = ReadStringArgs(name, state, argv, { "name" });
69 if (args.empty()) return StringValue("");
70
71 auto updater_runtime = state->updater->GetRuntime();
72 return updater_runtime->UnmapPartitionOnDeviceMapper(args[0]) ? StringValue("t")
73 : StringValue("");
74 }
75
MapPartitionFn(const char * name,State * state,const std::vector<std::unique_ptr<Expr>> & argv)76 Value* MapPartitionFn(const char* name, State* state,
77 const std::vector<std::unique_ptr<Expr>>& argv) {
78 auto args = ReadStringArgs(name, state, argv, { "name" });
79 if (args.empty()) return StringValue("");
80
81 std::string path;
82 auto updater_runtime = state->updater->GetRuntime();
83 bool result = updater_runtime->MapPartitionOnDeviceMapper(args[0], &path);
84 return result ? StringValue(path) : StringValue("");
85 }
86
87 static constexpr char kMetadataUpdatedMarker[] = "/dynamic_partition_metadata.UPDATED";
88
UpdateDynamicPartitionsFn(const char * name,State * state,const std::vector<std::unique_ptr<Expr>> & argv)89 Value* UpdateDynamicPartitionsFn(const char* name, State* state,
90 const std::vector<std::unique_ptr<Expr>>& argv) {
91 if (argv.size() != 1) {
92 ErrorAbort(state, kArgsParsingFailure, "%s expects 1 arguments, got %zu", name, argv.size());
93 return StringValue("");
94 }
95 std::vector<std::unique_ptr<Value>> args;
96 if (!ReadValueArgs(state, argv, &args)) {
97 return nullptr;
98 }
99 const std::unique_ptr<Value>& op_list_value = args[0];
100 if (op_list_value->type != Value::Type::BLOB) {
101 ErrorAbort(state, kArgsParsingFailure, "op_list argument to %s must be blob", name);
102 return StringValue("");
103 }
104
105 std::string updated_marker = Paths::Get().stash_directory_base() + kMetadataUpdatedMarker;
106 if (state->is_retry) {
107 struct stat sb;
108 int result = stat(updated_marker.c_str(), &sb);
109 if (result == 0) {
110 LOG(INFO) << "Skipping already updated dynamic partition metadata based on marker";
111 return StringValue("t");
112 }
113 } else {
114 // Delete the obsolete marker if any.
115 std::string err;
116 if (!android::base::RemoveFileIfExists(updated_marker, &err)) {
117 LOG(ERROR) << "Failed to remove dynamic partition metadata updated marker " << updated_marker
118 << ": " << err;
119 return StringValue("");
120 }
121 }
122
123 auto updater_runtime = state->updater->GetRuntime();
124 if (!updater_runtime->UpdateDynamicPartitions(op_list_value->data)) {
125 return StringValue("");
126 }
127
128 if (!SetUpdatedMarker(updated_marker)) {
129 LOG(ERROR) << "Failed to set metadata updated marker.";
130 return StringValue("");
131 }
132
133 return StringValue("t");
134 }
135
RegisterDynamicPartitionsFunctions()136 void RegisterDynamicPartitionsFunctions() {
137 RegisterFunction("unmap_partition", UnmapPartitionFn);
138 RegisterFunction("map_partition", MapPartitionFn);
139 RegisterFunction("update_dynamic_partitions", UpdateDynamicPartitionsFn);
140 }
141