blob: 7e7e5071560853d37872d6cd5ca85721982daab6 [file] [log] [blame]
David Anderson12211d12018-07-24 15:21:20 -07001/*
2 * Copyright (C) 2018 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#include "flashing.h"
17
18#include <fcntl.h>
19#include <sys/stat.h>
20#include <unistd.h>
21
22#include <algorithm>
23#include <memory>
David Anderson23243492019-12-17 00:58:31 -080024#include <optional>
Mark Salyzyn044f04b2018-10-12 09:33:44 -070025#include <set>
26#include <string>
David Anderson12211d12018-07-24 15:21:20 -070027
Mark Salyzyn044f04b2018-10-12 09:33:44 -070028#include <android-base/file.h>
David Anderson12211d12018-07-24 15:21:20 -070029#include <android-base/logging.h>
30#include <android-base/strings.h>
31#include <ext4_utils/ext4_utils.h>
Mark Salyzyn044f04b2018-10-12 09:33:44 -070032#include <fs_mgr_overlayfs.h>
33#include <fstab/fstab.h>
David Anderson38b3c7a2018-08-15 16:27:42 -070034#include <liblp/builder.h>
35#include <liblp/liblp.h>
Yifan Hong0e13bba2019-08-29 16:29:22 -070036#include <libsnapshot/snapshot.h>
David Anderson12211d12018-07-24 15:21:20 -070037#include <sparse/sparse.h>
38
39#include "fastboot_device.h"
40#include "utility.h"
41
Mark Salyzyn044f04b2018-10-12 09:33:44 -070042using namespace android::fs_mgr;
43using namespace std::literals;
44
David Anderson12211d12018-07-24 15:21:20 -070045namespace {
46
47constexpr uint32_t SPARSE_HEADER_MAGIC = 0xed26ff3a;
48
Mark Salyzyn044f04b2018-10-12 09:33:44 -070049void WipeOverlayfsForPartition(FastbootDevice* device, const std::string& partition_name) {
50 // May be called, in the case of sparse data, multiple times so cache/skip.
51 static std::set<std::string> wiped;
52 if (wiped.find(partition_name) != wiped.end()) return;
53 wiped.insert(partition_name);
54 // Following appears to have a first time 2% impact on flashing speeds.
David Anderson12211d12018-07-24 15:21:20 -070055
Mark Salyzyn044f04b2018-10-12 09:33:44 -070056 // Convert partition_name to a validated mount point and wipe.
Tom Cherryb688d912019-01-28 12:34:33 -080057 Fstab fstab;
58 ReadDefaultFstab(&fstab);
59
David Anderson23243492019-12-17 00:58:31 -080060 std::optional<AutoMountMetadata> mount_metadata;
Tom Cherryb688d912019-01-28 12:34:33 -080061 for (const auto& entry : fstab) {
62 auto partition = android::base::Basename(entry.mount_point);
63 if ("/" == entry.mount_point) {
64 partition = "system";
65 }
66
Mark Salyzyn044f04b2018-10-12 09:33:44 -070067 if ((partition + device->GetCurrentSlot()) == partition_name) {
David Anderson23243492019-12-17 00:58:31 -080068 mount_metadata.emplace();
Tom Cherryb688d912019-01-28 12:34:33 -080069 fs_mgr_overlayfs_teardown(entry.mount_point.c_str());
Mark Salyzyn044f04b2018-10-12 09:33:44 -070070 }
71 }
72}
73
74} // namespace
David Anderson38b3c7a2018-08-15 16:27:42 -070075
David Anderson12211d12018-07-24 15:21:20 -070076int FlashRawDataChunk(int fd, const char* data, size_t len) {
77 size_t ret = 0;
78 while (ret < len) {
79 int this_len = std::min(static_cast<size_t>(1048576UL * 8), len - ret);
80 int this_ret = write(fd, data, this_len);
81 if (this_ret < 0) {
82 PLOG(ERROR) << "Failed to flash data of len " << len;
83 return -1;
84 }
85 data += this_ret;
86 ret += this_ret;
87 }
88 return 0;
89}
90
91int FlashRawData(int fd, const std::vector<char>& downloaded_data) {
92 int ret = FlashRawDataChunk(fd, downloaded_data.data(), downloaded_data.size());
93 if (ret < 0) {
94 return -errno;
95 }
96 return ret;
97}
98
99int WriteCallback(void* priv, const void* data, size_t len) {
100 int fd = reinterpret_cast<long long>(priv);
101 if (!data) {
102 return lseek64(fd, len, SEEK_CUR) >= 0 ? 0 : -errno;
103 }
104 return FlashRawDataChunk(fd, reinterpret_cast<const char*>(data), len);
105}
106
107int FlashSparseData(int fd, std::vector<char>& downloaded_data) {
Hridya Valsarajuaec0de52018-10-10 13:09:41 -0700108 struct sparse_file* file = sparse_file_import_buf(downloaded_data.data(), true, false);
David Anderson12211d12018-07-24 15:21:20 -0700109 if (!file) {
110 return -ENOENT;
111 }
112 return sparse_file_callback(file, false, false, WriteCallback, reinterpret_cast<void*>(fd));
113}
114
115int FlashBlockDevice(int fd, std::vector<char>& downloaded_data) {
116 lseek64(fd, 0, SEEK_SET);
117 if (downloaded_data.size() >= sizeof(SPARSE_HEADER_MAGIC) &&
118 *reinterpret_cast<uint32_t*>(downloaded_data.data()) == SPARSE_HEADER_MAGIC) {
119 return FlashSparseData(fd, downloaded_data);
120 } else {
121 return FlashRawData(fd, downloaded_data);
122 }
123}
124
125int Flash(FastbootDevice* device, const std::string& partition_name) {
126 PartitionHandle handle;
127 if (!OpenPartition(device, partition_name, &handle)) {
128 return -ENOENT;
129 }
130
131 std::vector<char> data = std::move(device->download_data());
132 if (data.size() == 0) {
133 return -EINVAL;
134 } else if (data.size() > get_block_device_size(handle.fd())) {
135 return -EOVERFLOW;
136 }
Mark Salyzyn044f04b2018-10-12 09:33:44 -0700137 WipeOverlayfsForPartition(device, partition_name);
David Anderson12211d12018-07-24 15:21:20 -0700138 return FlashBlockDevice(handle.fd(), data);
139}
David Anderson38b3c7a2018-08-15 16:27:42 -0700140
David Andersonb6134a62018-10-26 13:08:44 -0700141bool UpdateSuper(FastbootDevice* device, const std::string& super_name, bool wipe) {
David Anderson38b3c7a2018-08-15 16:27:42 -0700142 std::vector<char> data = std::move(device->download_data());
143 if (data.empty()) {
144 return device->WriteFail("No data available");
145 }
146
147 std::unique_ptr<LpMetadata> new_metadata = ReadFromImageBlob(data.data(), data.size());
148 if (!new_metadata) {
149 return device->WriteFail("Data is not a valid logical partition metadata image");
150 }
151
David Andersona48f86b2018-12-20 16:55:04 -0800152 if (!FindPhysicalPartition(super_name)) {
153 return device->WriteFail("Cannot find " + super_name +
154 ", build may be missing broken or missing boot_devices");
155 }
156
David Anderson38b3c7a2018-08-15 16:27:42 -0700157 // If we are unable to read the existing metadata, then the super partition
158 // is corrupt. In this case we reflash the whole thing using the provided
159 // image.
160 std::string slot_suffix = device->GetCurrentSlot();
161 uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix);
David Anderson96a9fd42018-11-05 15:21:44 -0800162 std::unique_ptr<LpMetadata> old_metadata = ReadMetadata(super_name, slot_number);
163 if (wipe || !old_metadata) {
David Andersonb6134a62018-10-26 13:08:44 -0700164 if (!FlashPartitionTable(super_name, *new_metadata.get())) {
David Anderson38b3c7a2018-08-15 16:27:42 -0700165 return device->WriteFail("Unable to flash new partition table");
166 }
Mark Salyzyn307a41f2018-11-26 09:57:17 -0800167 fs_mgr_overlayfs_teardown();
David Anderson38b3c7a2018-08-15 16:27:42 -0700168 return device->WriteOkay("Successfully flashed partition table");
169 }
170
David Anderson96a9fd42018-11-05 15:21:44 -0800171 std::set<std::string> partitions_to_keep;
172 for (const auto& partition : old_metadata->partitions) {
173 // Preserve partitions in the other slot, but not the current slot.
174 std::string partition_name = GetPartitionName(partition);
175 if (!slot_suffix.empty() && GetPartitionSlotSuffix(partition_name) == slot_suffix) {
176 continue;
177 }
Yifan Hong0e13bba2019-08-29 16:29:22 -0700178 std::string group_name = GetPartitionGroupName(old_metadata->groups[partition.group_index]);
179 // Skip partitions in the COW group
180 if (group_name == android::snapshot::kCowGroupName) {
181 continue;
182 }
David Anderson96a9fd42018-11-05 15:21:44 -0800183 partitions_to_keep.emplace(partition_name);
184 }
185
186 // Do not preserve the scratch partition.
187 partitions_to_keep.erase("scratch");
188
189 if (!partitions_to_keep.empty()) {
190 std::unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(*new_metadata.get());
191 if (!builder->ImportPartitions(*old_metadata.get(), partitions_to_keep)) {
192 return device->WriteFail(
193 "Old partitions are not compatible with the new super layout; wipe needed");
194 }
195
196 new_metadata = builder->Export();
197 if (!new_metadata) {
198 return device->WriteFail("Unable to build new partition table; wipe needed");
199 }
200 }
201
David Anderson38b3c7a2018-08-15 16:27:42 -0700202 // Write the new table to every metadata slot.
David Anderson4d307b02018-12-17 17:07:34 -0800203 if (!UpdateAllPartitionMetadata(device, super_name, *new_metadata.get())) {
David Anderson38b3c7a2018-08-15 16:27:42 -0700204 return device->WriteFail("Unable to write new partition table");
205 }
Mark Salyzyn307a41f2018-11-26 09:57:17 -0800206 fs_mgr_overlayfs_teardown();
David Anderson38b3c7a2018-08-15 16:27:42 -0700207 return device->WriteOkay("Successfully updated partition table");
208}