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