1*4e2b41f1SAndroid Build Coastguard Worker /*
2*4e2b41f1SAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*4e2b41f1SAndroid Build Coastguard Worker *
4*4e2b41f1SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*4e2b41f1SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*4e2b41f1SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*4e2b41f1SAndroid Build Coastguard Worker *
8*4e2b41f1SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*4e2b41f1SAndroid Build Coastguard Worker *
10*4e2b41f1SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*4e2b41f1SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*4e2b41f1SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4e2b41f1SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*4e2b41f1SAndroid Build Coastguard Worker * limitations under the License.
15*4e2b41f1SAndroid Build Coastguard Worker */
16*4e2b41f1SAndroid Build Coastguard Worker
17*4e2b41f1SAndroid Build Coastguard Worker #include "partition_installer.h"
18*4e2b41f1SAndroid Build Coastguard Worker
19*4e2b41f1SAndroid Build Coastguard Worker #include <sys/statvfs.h>
20*4e2b41f1SAndroid Build Coastguard Worker
21*4e2b41f1SAndroid Build Coastguard Worker #include <android-base/file.h>
22*4e2b41f1SAndroid Build Coastguard Worker #include <android-base/logging.h>
23*4e2b41f1SAndroid Build Coastguard Worker #include <android-base/properties.h>
24*4e2b41f1SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
25*4e2b41f1SAndroid Build Coastguard Worker #include <ext4_utils/ext4_utils.h>
26*4e2b41f1SAndroid Build Coastguard Worker #include <fs_mgr.h>
27*4e2b41f1SAndroid Build Coastguard Worker #include <fs_mgr_dm_linear.h>
28*4e2b41f1SAndroid Build Coastguard Worker #include <libdm/dm.h>
29*4e2b41f1SAndroid Build Coastguard Worker #include <libgsi/libgsi.h>
30*4e2b41f1SAndroid Build Coastguard Worker #include <liblp/partition_opener.h>
31*4e2b41f1SAndroid Build Coastguard Worker
32*4e2b41f1SAndroid Build Coastguard Worker #include "file_paths.h"
33*4e2b41f1SAndroid Build Coastguard Worker #include "gsi_service.h"
34*4e2b41f1SAndroid Build Coastguard Worker #include "libgsi_private.h"
35*4e2b41f1SAndroid Build Coastguard Worker
36*4e2b41f1SAndroid Build Coastguard Worker namespace android {
37*4e2b41f1SAndroid Build Coastguard Worker namespace gsi {
38*4e2b41f1SAndroid Build Coastguard Worker
39*4e2b41f1SAndroid Build Coastguard Worker using namespace std::literals;
40*4e2b41f1SAndroid Build Coastguard Worker using namespace android::dm;
41*4e2b41f1SAndroid Build Coastguard Worker using namespace android::fiemap;
42*4e2b41f1SAndroid Build Coastguard Worker using namespace android::fs_mgr;
43*4e2b41f1SAndroid Build Coastguard Worker using android::base::unique_fd;
44*4e2b41f1SAndroid Build Coastguard Worker
PartitionInstaller(GsiService * service,const std::string & install_dir,const std::string & name,const std::string & active_dsu,int64_t size,bool read_only)45*4e2b41f1SAndroid Build Coastguard Worker PartitionInstaller::PartitionInstaller(GsiService* service, const std::string& install_dir,
46*4e2b41f1SAndroid Build Coastguard Worker const std::string& name, const std::string& active_dsu,
47*4e2b41f1SAndroid Build Coastguard Worker int64_t size, bool read_only)
48*4e2b41f1SAndroid Build Coastguard Worker : service_(service),
49*4e2b41f1SAndroid Build Coastguard Worker install_dir_(install_dir),
50*4e2b41f1SAndroid Build Coastguard Worker name_(name),
51*4e2b41f1SAndroid Build Coastguard Worker active_dsu_(active_dsu),
52*4e2b41f1SAndroid Build Coastguard Worker size_(size),
53*4e2b41f1SAndroid Build Coastguard Worker readOnly_(read_only) {
54*4e2b41f1SAndroid Build Coastguard Worker images_ = ImageManager::Open(MetadataDir(active_dsu), install_dir_);
55*4e2b41f1SAndroid Build Coastguard Worker }
56*4e2b41f1SAndroid Build Coastguard Worker
~PartitionInstaller()57*4e2b41f1SAndroid Build Coastguard Worker PartitionInstaller::~PartitionInstaller() {
58*4e2b41f1SAndroid Build Coastguard Worker if (FinishInstall() != IGsiService::INSTALL_OK) {
59*4e2b41f1SAndroid Build Coastguard Worker LOG(ERROR) << "Installation failed: install_dir=" << install_dir_
60*4e2b41f1SAndroid Build Coastguard Worker << ", dsu_slot=" << active_dsu_ << ", partition_name=" << name_;
61*4e2b41f1SAndroid Build Coastguard Worker }
62*4e2b41f1SAndroid Build Coastguard Worker if (IsAshmemMapped()) {
63*4e2b41f1SAndroid Build Coastguard Worker UnmapAshmem();
64*4e2b41f1SAndroid Build Coastguard Worker }
65*4e2b41f1SAndroid Build Coastguard Worker }
66*4e2b41f1SAndroid Build Coastguard Worker
FinishInstall()67*4e2b41f1SAndroid Build Coastguard Worker int PartitionInstaller::FinishInstall() {
68*4e2b41f1SAndroid Build Coastguard Worker if (finished_) {
69*4e2b41f1SAndroid Build Coastguard Worker return finished_status_;
70*4e2b41f1SAndroid Build Coastguard Worker }
71*4e2b41f1SAndroid Build Coastguard Worker finished_ = true;
72*4e2b41f1SAndroid Build Coastguard Worker finished_status_ = CheckInstallState();
73*4e2b41f1SAndroid Build Coastguard Worker system_device_ = nullptr;
74*4e2b41f1SAndroid Build Coastguard Worker if (finished_status_ != IGsiService::INSTALL_OK) {
75*4e2b41f1SAndroid Build Coastguard Worker auto file = GetBackingFile(name_);
76*4e2b41f1SAndroid Build Coastguard Worker LOG(ERROR) << "Installation failed, clean up: " << file;
77*4e2b41f1SAndroid Build Coastguard Worker if (images_->IsImageMapped(file)) {
78*4e2b41f1SAndroid Build Coastguard Worker LOG(ERROR) << "unmap " << file;
79*4e2b41f1SAndroid Build Coastguard Worker images_->UnmapImageDevice(file);
80*4e2b41f1SAndroid Build Coastguard Worker }
81*4e2b41f1SAndroid Build Coastguard Worker images_->DeleteBackingImage(file);
82*4e2b41f1SAndroid Build Coastguard Worker }
83*4e2b41f1SAndroid Build Coastguard Worker return finished_status_;
84*4e2b41f1SAndroid Build Coastguard Worker }
85*4e2b41f1SAndroid Build Coastguard Worker
StartInstall()86*4e2b41f1SAndroid Build Coastguard Worker int PartitionInstaller::StartInstall() {
87*4e2b41f1SAndroid Build Coastguard Worker if (int status = PerformSanityChecks()) {
88*4e2b41f1SAndroid Build Coastguard Worker return status;
89*4e2b41f1SAndroid Build Coastguard Worker }
90*4e2b41f1SAndroid Build Coastguard Worker if (int status = Preallocate()) {
91*4e2b41f1SAndroid Build Coastguard Worker return status;
92*4e2b41f1SAndroid Build Coastguard Worker }
93*4e2b41f1SAndroid Build Coastguard Worker if (!readOnly_) {
94*4e2b41f1SAndroid Build Coastguard Worker if (!Format()) {
95*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_ERROR_GENERIC;
96*4e2b41f1SAndroid Build Coastguard Worker }
97*4e2b41f1SAndroid Build Coastguard Worker } else {
98*4e2b41f1SAndroid Build Coastguard Worker // Map ${name}_gsi so we can write to it.
99*4e2b41f1SAndroid Build Coastguard Worker system_device_ = OpenPartition(GetBackingFile(name_));
100*4e2b41f1SAndroid Build Coastguard Worker if (!system_device_) {
101*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_ERROR_GENERIC;
102*4e2b41f1SAndroid Build Coastguard Worker }
103*4e2b41f1SAndroid Build Coastguard Worker
104*4e2b41f1SAndroid Build Coastguard Worker // Clear the progress indicator.
105*4e2b41f1SAndroid Build Coastguard Worker service_->UpdateProgress(IGsiService::STATUS_NO_OPERATION, 0);
106*4e2b41f1SAndroid Build Coastguard Worker }
107*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_OK;
108*4e2b41f1SAndroid Build Coastguard Worker }
109*4e2b41f1SAndroid Build Coastguard Worker
PerformSanityChecks()110*4e2b41f1SAndroid Build Coastguard Worker int PartitionInstaller::PerformSanityChecks() {
111*4e2b41f1SAndroid Build Coastguard Worker if (!images_) {
112*4e2b41f1SAndroid Build Coastguard Worker LOG(ERROR) << "unable to create image manager";
113*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_ERROR_GENERIC;
114*4e2b41f1SAndroid Build Coastguard Worker }
115*4e2b41f1SAndroid Build Coastguard Worker if (size_ < 0) {
116*4e2b41f1SAndroid Build Coastguard Worker LOG(ERROR) << "image size " << size_ << " is negative";
117*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_ERROR_GENERIC;
118*4e2b41f1SAndroid Build Coastguard Worker }
119*4e2b41f1SAndroid Build Coastguard Worker if (android::gsi::IsGsiRunning()) {
120*4e2b41f1SAndroid Build Coastguard Worker LOG(ERROR) << "cannot install gsi inside a live gsi";
121*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_ERROR_GENERIC;
122*4e2b41f1SAndroid Build Coastguard Worker }
123*4e2b41f1SAndroid Build Coastguard Worker
124*4e2b41f1SAndroid Build Coastguard Worker struct statvfs sb;
125*4e2b41f1SAndroid Build Coastguard Worker if (statvfs(install_dir_.c_str(), &sb)) {
126*4e2b41f1SAndroid Build Coastguard Worker PLOG(ERROR) << "failed to read file system stats";
127*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_ERROR_GENERIC;
128*4e2b41f1SAndroid Build Coastguard Worker }
129*4e2b41f1SAndroid Build Coastguard Worker
130*4e2b41f1SAndroid Build Coastguard Worker // This is the same as android::vold::GetFreebytes() but we also
131*4e2b41f1SAndroid Build Coastguard Worker // need the total file system size so we open code it here.
132*4e2b41f1SAndroid Build Coastguard Worker uint64_t free_space = static_cast<uint64_t>(sb.f_bavail) * sb.f_frsize;
133*4e2b41f1SAndroid Build Coastguard Worker if (free_space <= (size_)) {
134*4e2b41f1SAndroid Build Coastguard Worker LOG(ERROR) << "not enough free space (only " << free_space << " bytes available)";
135*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_ERROR_NO_SPACE;
136*4e2b41f1SAndroid Build Coastguard Worker }
137*4e2b41f1SAndroid Build Coastguard Worker
138*4e2b41f1SAndroid Build Coastguard Worker const auto free_space_threshold = GetMinimumFreeSpaceThreshold(install_dir_);
139*4e2b41f1SAndroid Build Coastguard Worker if (!free_space_threshold.has_value()) {
140*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_ERROR_GENERIC;
141*4e2b41f1SAndroid Build Coastguard Worker }
142*4e2b41f1SAndroid Build Coastguard Worker if (free_space < size_ + *free_space_threshold) {
143*4e2b41f1SAndroid Build Coastguard Worker LOG(ERROR) << "post-installation free space (" << free_space << " - " << size_
144*4e2b41f1SAndroid Build Coastguard Worker << ") would be below the minimum threshold of " << *free_space_threshold;
145*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_ERROR_FILE_SYSTEM_CLUTTERED;
146*4e2b41f1SAndroid Build Coastguard Worker }
147*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_OK;
148*4e2b41f1SAndroid Build Coastguard Worker }
149*4e2b41f1SAndroid Build Coastguard Worker
Preallocate()150*4e2b41f1SAndroid Build Coastguard Worker int PartitionInstaller::Preallocate() {
151*4e2b41f1SAndroid Build Coastguard Worker std::string file = GetBackingFile(name_);
152*4e2b41f1SAndroid Build Coastguard Worker if (!images_->UnmapImageIfExists(file)) {
153*4e2b41f1SAndroid Build Coastguard Worker LOG(ERROR) << "failed to UnmapImageIfExists " << file;
154*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_ERROR_GENERIC;
155*4e2b41f1SAndroid Build Coastguard Worker }
156*4e2b41f1SAndroid Build Coastguard Worker // always delete the old one when it presents in case there might a partition
157*4e2b41f1SAndroid Build Coastguard Worker // with same name but different size.
158*4e2b41f1SAndroid Build Coastguard Worker if (images_->BackingImageExists(file)) {
159*4e2b41f1SAndroid Build Coastguard Worker if (!images_->DeleteBackingImage(file)) {
160*4e2b41f1SAndroid Build Coastguard Worker LOG(ERROR) << "failed to DeleteBackingImage " << file;
161*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_ERROR_GENERIC;
162*4e2b41f1SAndroid Build Coastguard Worker }
163*4e2b41f1SAndroid Build Coastguard Worker }
164*4e2b41f1SAndroid Build Coastguard Worker service_->StartAsyncOperation("create " + name_, size_);
165*4e2b41f1SAndroid Build Coastguard Worker if (!CreateImage(file, size_)) {
166*4e2b41f1SAndroid Build Coastguard Worker LOG(ERROR) << "Could not create userdata image";
167*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_ERROR_GENERIC;
168*4e2b41f1SAndroid Build Coastguard Worker }
169*4e2b41f1SAndroid Build Coastguard Worker service_->UpdateProgress(IGsiService::STATUS_COMPLETE, 0);
170*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_OK;
171*4e2b41f1SAndroid Build Coastguard Worker }
172*4e2b41f1SAndroid Build Coastguard Worker
CreateImage(const std::string & name,uint64_t size)173*4e2b41f1SAndroid Build Coastguard Worker bool PartitionInstaller::CreateImage(const std::string& name, uint64_t size) {
174*4e2b41f1SAndroid Build Coastguard Worker auto progress = [this](uint64_t bytes, uint64_t /* total */) -> bool {
175*4e2b41f1SAndroid Build Coastguard Worker service_->UpdateProgress(IGsiService::STATUS_WORKING, bytes);
176*4e2b41f1SAndroid Build Coastguard Worker if (service_->should_abort()) return false;
177*4e2b41f1SAndroid Build Coastguard Worker return true;
178*4e2b41f1SAndroid Build Coastguard Worker };
179*4e2b41f1SAndroid Build Coastguard Worker int flags = ImageManager::CREATE_IMAGE_DEFAULT;
180*4e2b41f1SAndroid Build Coastguard Worker if (readOnly_) {
181*4e2b41f1SAndroid Build Coastguard Worker flags |= ImageManager::CREATE_IMAGE_READONLY;
182*4e2b41f1SAndroid Build Coastguard Worker }
183*4e2b41f1SAndroid Build Coastguard Worker return images_->CreateBackingImage(name, size, flags, std::move(progress));
184*4e2b41f1SAndroid Build Coastguard Worker }
185*4e2b41f1SAndroid Build Coastguard Worker
OpenPartition(const std::string & name)186*4e2b41f1SAndroid Build Coastguard Worker std::unique_ptr<MappedDevice> PartitionInstaller::OpenPartition(const std::string& name) {
187*4e2b41f1SAndroid Build Coastguard Worker return MappedDevice::Open(images_.get(), 10s, name);
188*4e2b41f1SAndroid Build Coastguard Worker }
189*4e2b41f1SAndroid Build Coastguard Worker
CommitGsiChunk(int stream_fd,int64_t bytes)190*4e2b41f1SAndroid Build Coastguard Worker bool PartitionInstaller::CommitGsiChunk(int stream_fd, int64_t bytes) {
191*4e2b41f1SAndroid Build Coastguard Worker service_->StartAsyncOperation("write " + name_, size_);
192*4e2b41f1SAndroid Build Coastguard Worker
193*4e2b41f1SAndroid Build Coastguard Worker if (bytes < 0) {
194*4e2b41f1SAndroid Build Coastguard Worker LOG(ERROR) << "chunk size " << bytes << " is negative";
195*4e2b41f1SAndroid Build Coastguard Worker return false;
196*4e2b41f1SAndroid Build Coastguard Worker }
197*4e2b41f1SAndroid Build Coastguard Worker
198*4e2b41f1SAndroid Build Coastguard Worker static const size_t kBlockSize = 4096;
199*4e2b41f1SAndroid Build Coastguard Worker auto buffer = std::make_unique<char[]>(kBlockSize);
200*4e2b41f1SAndroid Build Coastguard Worker
201*4e2b41f1SAndroid Build Coastguard Worker int progress = -1;
202*4e2b41f1SAndroid Build Coastguard Worker uint64_t remaining = bytes;
203*4e2b41f1SAndroid Build Coastguard Worker while (remaining) {
204*4e2b41f1SAndroid Build Coastguard Worker size_t max_to_read = std::min(static_cast<uint64_t>(kBlockSize), remaining);
205*4e2b41f1SAndroid Build Coastguard Worker ssize_t rv = TEMP_FAILURE_RETRY(read(stream_fd, buffer.get(), max_to_read));
206*4e2b41f1SAndroid Build Coastguard Worker if (rv < 0) {
207*4e2b41f1SAndroid Build Coastguard Worker PLOG(ERROR) << "read gsi chunk";
208*4e2b41f1SAndroid Build Coastguard Worker return false;
209*4e2b41f1SAndroid Build Coastguard Worker }
210*4e2b41f1SAndroid Build Coastguard Worker if (rv == 0) {
211*4e2b41f1SAndroid Build Coastguard Worker LOG(ERROR) << "no bytes left in stream";
212*4e2b41f1SAndroid Build Coastguard Worker return false;
213*4e2b41f1SAndroid Build Coastguard Worker }
214*4e2b41f1SAndroid Build Coastguard Worker if (!CommitGsiChunk(buffer.get(), rv)) {
215*4e2b41f1SAndroid Build Coastguard Worker return false;
216*4e2b41f1SAndroid Build Coastguard Worker }
217*4e2b41f1SAndroid Build Coastguard Worker CHECK(static_cast<uint64_t>(rv) <= remaining);
218*4e2b41f1SAndroid Build Coastguard Worker remaining -= rv;
219*4e2b41f1SAndroid Build Coastguard Worker
220*4e2b41f1SAndroid Build Coastguard Worker // Only update the progress when the % (or permille, in this case)
221*4e2b41f1SAndroid Build Coastguard Worker // significantly changes.
222*4e2b41f1SAndroid Build Coastguard Worker int new_progress = ((size_ - remaining) * 1000) / size_;
223*4e2b41f1SAndroid Build Coastguard Worker if (new_progress != progress) {
224*4e2b41f1SAndroid Build Coastguard Worker service_->UpdateProgress(IGsiService::STATUS_WORKING, size_ - remaining);
225*4e2b41f1SAndroid Build Coastguard Worker }
226*4e2b41f1SAndroid Build Coastguard Worker }
227*4e2b41f1SAndroid Build Coastguard Worker
228*4e2b41f1SAndroid Build Coastguard Worker service_->UpdateProgress(IGsiService::STATUS_COMPLETE, size_);
229*4e2b41f1SAndroid Build Coastguard Worker return true;
230*4e2b41f1SAndroid Build Coastguard Worker }
231*4e2b41f1SAndroid Build Coastguard Worker
IsFinishedWriting()232*4e2b41f1SAndroid Build Coastguard Worker bool PartitionInstaller::IsFinishedWriting() {
233*4e2b41f1SAndroid Build Coastguard Worker return gsi_bytes_written_ == size_;
234*4e2b41f1SAndroid Build Coastguard Worker }
235*4e2b41f1SAndroid Build Coastguard Worker
IsAshmemMapped()236*4e2b41f1SAndroid Build Coastguard Worker bool PartitionInstaller::IsAshmemMapped() {
237*4e2b41f1SAndroid Build Coastguard Worker return ashmem_data_ != MAP_FAILED;
238*4e2b41f1SAndroid Build Coastguard Worker }
239*4e2b41f1SAndroid Build Coastguard Worker
CommitGsiChunk(const void * data,size_t bytes)240*4e2b41f1SAndroid Build Coastguard Worker bool PartitionInstaller::CommitGsiChunk(const void* data, size_t bytes) {
241*4e2b41f1SAndroid Build Coastguard Worker if (static_cast<uint64_t>(bytes) > size_ - gsi_bytes_written_) {
242*4e2b41f1SAndroid Build Coastguard Worker // We cannot write past the end of the image file.
243*4e2b41f1SAndroid Build Coastguard Worker LOG(ERROR) << "chunk size " << bytes << " exceeds remaining image size (" << size_
244*4e2b41f1SAndroid Build Coastguard Worker << " expected, " << gsi_bytes_written_ << " written)";
245*4e2b41f1SAndroid Build Coastguard Worker return false;
246*4e2b41f1SAndroid Build Coastguard Worker }
247*4e2b41f1SAndroid Build Coastguard Worker if (service_->should_abort()) {
248*4e2b41f1SAndroid Build Coastguard Worker return false;
249*4e2b41f1SAndroid Build Coastguard Worker }
250*4e2b41f1SAndroid Build Coastguard Worker if (!android::base::WriteFully(system_device_->fd(), data, bytes)) {
251*4e2b41f1SAndroid Build Coastguard Worker PLOG(ERROR) << "write failed";
252*4e2b41f1SAndroid Build Coastguard Worker return false;
253*4e2b41f1SAndroid Build Coastguard Worker }
254*4e2b41f1SAndroid Build Coastguard Worker gsi_bytes_written_ += bytes;
255*4e2b41f1SAndroid Build Coastguard Worker return true;
256*4e2b41f1SAndroid Build Coastguard Worker }
257*4e2b41f1SAndroid Build Coastguard Worker
GetPartitionFd()258*4e2b41f1SAndroid Build Coastguard Worker int PartitionInstaller::GetPartitionFd() {
259*4e2b41f1SAndroid Build Coastguard Worker if (!system_device_) {
260*4e2b41f1SAndroid Build Coastguard Worker return -1;
261*4e2b41f1SAndroid Build Coastguard Worker }
262*4e2b41f1SAndroid Build Coastguard Worker return system_device_->fd();
263*4e2b41f1SAndroid Build Coastguard Worker }
264*4e2b41f1SAndroid Build Coastguard Worker
MapAshmem(int fd,size_t size)265*4e2b41f1SAndroid Build Coastguard Worker bool PartitionInstaller::MapAshmem(int fd, size_t size) {
266*4e2b41f1SAndroid Build Coastguard Worker ashmem_size_ = size;
267*4e2b41f1SAndroid Build Coastguard Worker ashmem_data_ = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
268*4e2b41f1SAndroid Build Coastguard Worker return ashmem_data_ != MAP_FAILED;
269*4e2b41f1SAndroid Build Coastguard Worker }
270*4e2b41f1SAndroid Build Coastguard Worker
UnmapAshmem()271*4e2b41f1SAndroid Build Coastguard Worker void PartitionInstaller::UnmapAshmem() {
272*4e2b41f1SAndroid Build Coastguard Worker if (munmap(ashmem_data_, ashmem_size_) != 0) {
273*4e2b41f1SAndroid Build Coastguard Worker PLOG(ERROR) << "cannot munmap";
274*4e2b41f1SAndroid Build Coastguard Worker return;
275*4e2b41f1SAndroid Build Coastguard Worker }
276*4e2b41f1SAndroid Build Coastguard Worker ashmem_data_ = MAP_FAILED;
277*4e2b41f1SAndroid Build Coastguard Worker ashmem_size_ = -1;
278*4e2b41f1SAndroid Build Coastguard Worker }
279*4e2b41f1SAndroid Build Coastguard Worker
CommitGsiChunk(size_t bytes)280*4e2b41f1SAndroid Build Coastguard Worker bool PartitionInstaller::CommitGsiChunk(size_t bytes) {
281*4e2b41f1SAndroid Build Coastguard Worker if (!IsAshmemMapped()) {
282*4e2b41f1SAndroid Build Coastguard Worker PLOG(ERROR) << "ashmem is not mapped";
283*4e2b41f1SAndroid Build Coastguard Worker return false;
284*4e2b41f1SAndroid Build Coastguard Worker }
285*4e2b41f1SAndroid Build Coastguard Worker bool success = CommitGsiChunk(ashmem_data_, bytes);
286*4e2b41f1SAndroid Build Coastguard Worker if (success && IsFinishedWriting()) {
287*4e2b41f1SAndroid Build Coastguard Worker UnmapAshmem();
288*4e2b41f1SAndroid Build Coastguard Worker }
289*4e2b41f1SAndroid Build Coastguard Worker return success;
290*4e2b41f1SAndroid Build Coastguard Worker }
291*4e2b41f1SAndroid Build Coastguard Worker
GetBackingFile(std::string name)292*4e2b41f1SAndroid Build Coastguard Worker const std::string PartitionInstaller::GetBackingFile(std::string name) {
293*4e2b41f1SAndroid Build Coastguard Worker return name + "_gsi";
294*4e2b41f1SAndroid Build Coastguard Worker }
295*4e2b41f1SAndroid Build Coastguard Worker
Format()296*4e2b41f1SAndroid Build Coastguard Worker bool PartitionInstaller::Format() {
297*4e2b41f1SAndroid Build Coastguard Worker auto file = GetBackingFile(name_);
298*4e2b41f1SAndroid Build Coastguard Worker auto device = OpenPartition(file);
299*4e2b41f1SAndroid Build Coastguard Worker if (!device) {
300*4e2b41f1SAndroid Build Coastguard Worker return false;
301*4e2b41f1SAndroid Build Coastguard Worker }
302*4e2b41f1SAndroid Build Coastguard Worker
303*4e2b41f1SAndroid Build Coastguard Worker // libcutils checks the first 4K, no matter the block size.
304*4e2b41f1SAndroid Build Coastguard Worker std::string zeroes(4096, 0);
305*4e2b41f1SAndroid Build Coastguard Worker if (!android::base::WriteFully(device->fd(), zeroes.data(), zeroes.size())) {
306*4e2b41f1SAndroid Build Coastguard Worker PLOG(ERROR) << "write " << file;
307*4e2b41f1SAndroid Build Coastguard Worker return false;
308*4e2b41f1SAndroid Build Coastguard Worker }
309*4e2b41f1SAndroid Build Coastguard Worker return true;
310*4e2b41f1SAndroid Build Coastguard Worker }
311*4e2b41f1SAndroid Build Coastguard Worker
CheckInstallState()312*4e2b41f1SAndroid Build Coastguard Worker int PartitionInstaller::CheckInstallState() {
313*4e2b41f1SAndroid Build Coastguard Worker if (readOnly_ && !IsFinishedWriting()) {
314*4e2b41f1SAndroid Build Coastguard Worker // We cannot boot if the image is incomplete.
315*4e2b41f1SAndroid Build Coastguard Worker LOG(ERROR) << "image incomplete; expected " << size_ << " bytes, waiting for "
316*4e2b41f1SAndroid Build Coastguard Worker << (size_ - gsi_bytes_written_) << " bytes";
317*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_ERROR_GENERIC;
318*4e2b41f1SAndroid Build Coastguard Worker }
319*4e2b41f1SAndroid Build Coastguard Worker if (system_device_ != nullptr && fsync(GetPartitionFd())) {
320*4e2b41f1SAndroid Build Coastguard Worker PLOG(ERROR) << "fsync failed for " << GetBackingFile(name_);
321*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_ERROR_GENERIC;
322*4e2b41f1SAndroid Build Coastguard Worker }
323*4e2b41f1SAndroid Build Coastguard Worker // If files moved (are no longer pinned), the metadata file will be invalid.
324*4e2b41f1SAndroid Build Coastguard Worker // This check can be removed once b/133967059 is fixed.
325*4e2b41f1SAndroid Build Coastguard Worker if (!images_->Validate()) {
326*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_ERROR_GENERIC;
327*4e2b41f1SAndroid Build Coastguard Worker }
328*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_OK;
329*4e2b41f1SAndroid Build Coastguard Worker }
330*4e2b41f1SAndroid Build Coastguard Worker
WipeWritable(const std::string & active_dsu,const std::string & install_dir,const std::string & name)331*4e2b41f1SAndroid Build Coastguard Worker int PartitionInstaller::WipeWritable(const std::string& active_dsu, const std::string& install_dir,
332*4e2b41f1SAndroid Build Coastguard Worker const std::string& name) {
333*4e2b41f1SAndroid Build Coastguard Worker auto image = ImageManager::Open(MetadataDir(active_dsu), install_dir);
334*4e2b41f1SAndroid Build Coastguard Worker // The device object has to be destroyed before the image object
335*4e2b41f1SAndroid Build Coastguard Worker auto device = MappedDevice::Open(image.get(), 10s, name);
336*4e2b41f1SAndroid Build Coastguard Worker if (!device) {
337*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_ERROR_GENERIC;
338*4e2b41f1SAndroid Build Coastguard Worker }
339*4e2b41f1SAndroid Build Coastguard Worker
340*4e2b41f1SAndroid Build Coastguard Worker // Wipe the first 1MiB of the device, ensuring both the first block and
341*4e2b41f1SAndroid Build Coastguard Worker // the superblock are destroyed.
342*4e2b41f1SAndroid Build Coastguard Worker static constexpr uint64_t kEraseSize = 1024 * 1024;
343*4e2b41f1SAndroid Build Coastguard Worker
344*4e2b41f1SAndroid Build Coastguard Worker std::string zeroes(4096, 0);
345*4e2b41f1SAndroid Build Coastguard Worker uint64_t erase_size = std::min(kEraseSize, get_block_device_size(device->fd()));
346*4e2b41f1SAndroid Build Coastguard Worker for (uint64_t i = 0; i < erase_size; i += zeroes.size()) {
347*4e2b41f1SAndroid Build Coastguard Worker if (!android::base::WriteFully(device->fd(), zeroes.data(), zeroes.size())) {
348*4e2b41f1SAndroid Build Coastguard Worker PLOG(ERROR) << "write " << name;
349*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_ERROR_GENERIC;
350*4e2b41f1SAndroid Build Coastguard Worker }
351*4e2b41f1SAndroid Build Coastguard Worker }
352*4e2b41f1SAndroid Build Coastguard Worker return IGsiService::INSTALL_OK;
353*4e2b41f1SAndroid Build Coastguard Worker }
354*4e2b41f1SAndroid Build Coastguard Worker
GetMinimumFreeSpaceThreshold(const std::string & install_dir)355*4e2b41f1SAndroid Build Coastguard Worker std::optional<uint64_t> PartitionInstaller::GetMinimumFreeSpaceThreshold(
356*4e2b41f1SAndroid Build Coastguard Worker const std::string& install_dir) {
357*4e2b41f1SAndroid Build Coastguard Worker // No need to retain any space if we were not installing to the internal storage
358*4e2b41f1SAndroid Build Coastguard Worker // or device is not using VAB.
359*4e2b41f1SAndroid Build Coastguard Worker if (!android::base::StartsWith(install_dir, "/data"s)
360*4e2b41f1SAndroid Build Coastguard Worker || !android::base::GetBoolProperty("ro.virtual_ab.enabled", false)) {
361*4e2b41f1SAndroid Build Coastguard Worker return 0;
362*4e2b41f1SAndroid Build Coastguard Worker }
363*4e2b41f1SAndroid Build Coastguard Worker // Dynamic Partitions device must have a "super" block device.
364*4e2b41f1SAndroid Build Coastguard Worker BlockDeviceInfo info;
365*4e2b41f1SAndroid Build Coastguard Worker PartitionOpener opener;
366*4e2b41f1SAndroid Build Coastguard Worker if (!opener.GetInfo(fs_mgr_get_super_partition_name(), &info)) {
367*4e2b41f1SAndroid Build Coastguard Worker // We shouldn't reach here, but handle it just in case.
368*4e2b41f1SAndroid Build Coastguard Worker LOG(ERROR) << "could not get block device info of super";
369*4e2b41f1SAndroid Build Coastguard Worker return std::nullopt;
370*4e2b41f1SAndroid Build Coastguard Worker }
371*4e2b41f1SAndroid Build Coastguard Worker // Reserve |super partition| of storage space so we don't disable VAB.
372*4e2b41f1SAndroid Build Coastguard Worker return info.size;
373*4e2b41f1SAndroid Build Coastguard Worker }
374*4e2b41f1SAndroid Build Coastguard Worker
375*4e2b41f1SAndroid Build Coastguard Worker } // namespace gsi
376*4e2b41f1SAndroid Build Coastguard Worker } // namespace android
377