blob: 3b513774b615f6e22d1f23ed7f72f7c6ffece171 [file] [log] [blame]
Songchun Fan3c82a302019-11-29 14:23:45 -08001/*
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#define LOG_TAG "IncrementalService"
18
19#include "IncrementalService.h"
20
21#include <android-base/file.h>
22#include <android-base/logging.h>
23#include <android-base/properties.h>
24#include <android-base/stringprintf.h>
25#include <android-base/strings.h>
26#include <android/content/pm/IDataLoaderStatusListener.h>
27#include <android/os/IVold.h>
28#include <androidfw/ZipFileRO.h>
29#include <androidfw/ZipUtils.h>
30#include <binder/BinderService.h>
31#include <binder/ParcelFileDescriptor.h>
32#include <binder/Status.h>
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -080033#include <openssl/sha.h>
Songchun Fan3c82a302019-11-29 14:23:45 -080034#include <sys/stat.h>
35#include <uuid/uuid.h>
36#include <zlib.h>
37
Alex Buynytskyy18b07a42020-02-03 20:06:00 -080038#include <ctime>
Songchun Fan3c82a302019-11-29 14:23:45 -080039#include <iterator>
40#include <span>
41#include <stack>
42#include <thread>
43#include <type_traits>
44
45#include "Metadata.pb.h"
46
47using namespace std::literals;
48using namespace android::content::pm;
49
50namespace android::incremental {
51
52namespace {
53
54using IncrementalFileSystemControlParcel =
55 ::android::os::incremental::IncrementalFileSystemControlParcel;
56
57struct Constants {
58 static constexpr auto backing = "backing_store"sv;
59 static constexpr auto mount = "mount"sv;
Songchun Fan3c82a302019-11-29 14:23:45 -080060 static constexpr auto storagePrefix = "st"sv;
61 static constexpr auto mountpointMdPrefix = ".mountpoint."sv;
62 static constexpr auto infoMdName = ".info"sv;
Songchun Fan0f8b6fe2020-02-05 17:41:25 -080063 static constexpr auto libDir = "lib"sv;
64 static constexpr auto libSuffix = ".so"sv;
65 static constexpr auto blockSize = 4096;
Songchun Fan3c82a302019-11-29 14:23:45 -080066};
67
68static const Constants& constants() {
69 static Constants c;
70 return c;
71}
72
73template <base::LogSeverity level = base::ERROR>
74bool mkdirOrLog(std::string_view name, int mode = 0770, bool allowExisting = true) {
75 auto cstr = path::c_str(name);
76 if (::mkdir(cstr, mode)) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -080077 if (!allowExisting || errno != EEXIST) {
Songchun Fan3c82a302019-11-29 14:23:45 -080078 PLOG(level) << "Can't create directory '" << name << '\'';
79 return false;
80 }
81 struct stat st;
82 if (::stat(cstr, &st) || !S_ISDIR(st.st_mode)) {
83 PLOG(level) << "Path exists but is not a directory: '" << name << '\'';
84 return false;
85 }
86 }
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -080087 if (::chmod(cstr, mode)) {
88 PLOG(level) << "Changing permission failed for '" << name << '\'';
89 return false;
90 }
91
Songchun Fan3c82a302019-11-29 14:23:45 -080092 return true;
93}
94
95static std::string toMountKey(std::string_view path) {
96 if (path.empty()) {
97 return "@none";
98 }
99 if (path == "/"sv) {
100 return "@root";
101 }
102 if (path::isAbsolute(path)) {
103 path.remove_prefix(1);
104 }
105 std::string res(path);
106 std::replace(res.begin(), res.end(), '/', '_');
107 std::replace(res.begin(), res.end(), '@', '_');
108 return res;
109}
110
111static std::pair<std::string, std::string> makeMountDir(std::string_view incrementalDir,
112 std::string_view path) {
113 auto mountKey = toMountKey(path);
114 const auto prefixSize = mountKey.size();
115 for (int counter = 0; counter < 1000;
116 mountKey.resize(prefixSize), base::StringAppendF(&mountKey, "%d", counter++)) {
117 auto mountRoot = path::join(incrementalDir, mountKey);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800118 if (mkdirOrLog(mountRoot, 0777, false)) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800119 return {mountKey, mountRoot};
120 }
121 }
122 return {};
123}
124
125template <class ProtoMessage, class Control>
126static ProtoMessage parseFromIncfs(const IncFsWrapper* incfs, Control&& control,
127 std::string_view path) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800128 auto md = incfs->getMetadata(control, path);
Songchun Fan3c82a302019-11-29 14:23:45 -0800129 ProtoMessage message;
130 return message.ParseFromArray(md.data(), md.size()) ? message : ProtoMessage{};
131}
132
133static bool isValidMountTarget(std::string_view path) {
134 return path::isAbsolute(path) && path::isEmptyDir(path).value_or(true);
135}
136
137std::string makeBindMdName() {
138 static constexpr auto uuidStringSize = 36;
139
140 uuid_t guid;
141 uuid_generate(guid);
142
143 std::string name;
144 const auto prefixSize = constants().mountpointMdPrefix.size();
145 name.reserve(prefixSize + uuidStringSize);
146
147 name = constants().mountpointMdPrefix;
148 name.resize(prefixSize + uuidStringSize);
149 uuid_unparse(guid, name.data() + prefixSize);
150
151 return name;
152}
153} // namespace
154
155IncrementalService::IncFsMount::~IncFsMount() {
156 incrementalService.mIncrementalManager->destroyDataLoader(mountId);
157 control.reset();
158 LOG(INFO) << "Unmounting and cleaning up mount " << mountId << " with root '" << root << '\'';
159 for (auto&& [target, _] : bindPoints) {
160 LOG(INFO) << "\tbind: " << target;
161 incrementalService.mVold->unmountIncFs(target);
162 }
163 LOG(INFO) << "\troot: " << root;
164 incrementalService.mVold->unmountIncFs(path::join(root, constants().mount));
165 cleanupFilesystem(root);
166}
167
168auto IncrementalService::IncFsMount::makeStorage(StorageId id) -> StorageMap::iterator {
Songchun Fan3c82a302019-11-29 14:23:45 -0800169 std::string name;
170 for (int no = nextStorageDirNo.fetch_add(1, std::memory_order_relaxed), i = 0;
171 i < 1024 && no >= 0; no = nextStorageDirNo.fetch_add(1, std::memory_order_relaxed), ++i) {
172 name.clear();
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800173 base::StringAppendF(&name, "%.*s_%d_%d", int(constants().storagePrefix.size()),
174 constants().storagePrefix.data(), id, no);
175 auto fullName = path::join(root, constants().mount, name);
Songchun Fan96100932020-02-03 19:20:58 -0800176 if (auto err = incrementalService.mIncFs->makeDir(control, fullName, 0755); !err) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800177 std::lock_guard l(lock);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800178 return storages.insert_or_assign(id, Storage{std::move(fullName)}).first;
179 } else if (err != EEXIST) {
180 LOG(ERROR) << __func__ << "(): failed to create dir |" << fullName << "| " << err;
181 break;
Songchun Fan3c82a302019-11-29 14:23:45 -0800182 }
183 }
184 nextStorageDirNo = 0;
185 return storages.end();
186}
187
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800188static std::unique_ptr<DIR, decltype(&::closedir)> openDir(const char* path) {
189 return {::opendir(path), ::closedir};
190}
191
192static int rmDirContent(const char* path) {
193 auto dir = openDir(path);
194 if (!dir) {
195 return -EINVAL;
196 }
197 while (auto entry = ::readdir(dir.get())) {
198 if (entry->d_name == "."sv || entry->d_name == ".."sv) {
199 continue;
200 }
201 auto fullPath = android::base::StringPrintf("%s/%s", path, entry->d_name);
202 if (entry->d_type == DT_DIR) {
203 if (const auto err = rmDirContent(fullPath.c_str()); err != 0) {
204 PLOG(WARNING) << "Failed to delete " << fullPath << " content";
205 return err;
206 }
207 if (const auto err = ::rmdir(fullPath.c_str()); err != 0) {
208 PLOG(WARNING) << "Failed to rmdir " << fullPath;
209 return err;
210 }
211 } else {
212 if (const auto err = ::unlink(fullPath.c_str()); err != 0) {
213 PLOG(WARNING) << "Failed to delete " << fullPath;
214 return err;
215 }
216 }
217 }
218 return 0;
219}
220
Songchun Fan3c82a302019-11-29 14:23:45 -0800221void IncrementalService::IncFsMount::cleanupFilesystem(std::string_view root) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800222 rmDirContent(path::join(root, constants().backing).c_str());
Songchun Fan3c82a302019-11-29 14:23:45 -0800223 ::rmdir(path::join(root, constants().backing).c_str());
224 ::rmdir(path::join(root, constants().mount).c_str());
225 ::rmdir(path::c_str(root));
226}
227
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800228IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_view rootDir)
Songchun Fan3c82a302019-11-29 14:23:45 -0800229 : mVold(sm.getVoldService()),
230 mIncrementalManager(sm.getIncrementalManager()),
231 mIncFs(sm.getIncFs()),
232 mIncrementalDir(rootDir) {
233 if (!mVold) {
234 LOG(FATAL) << "Vold service is unavailable";
235 }
236 if (!mIncrementalManager) {
237 LOG(FATAL) << "IncrementalManager service is unavailable";
238 }
239 // TODO(b/136132412): check that root dir should already exist
240 // TODO(b/136132412): enable mount existing dirs after SELinux rules are merged
241 // mountExistingImages();
242}
243
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800244FileId IncrementalService::idFromMetadata(std::span<const uint8_t> metadata) {
245 incfs::FileId id = {};
246 if (size_t(metadata.size()) <= sizeof(id)) {
247 memcpy(&id, metadata.data(), metadata.size());
248 } else {
249 uint8_t buffer[SHA_DIGEST_LENGTH];
250 static_assert(sizeof(buffer) >= sizeof(id));
251
252 SHA_CTX ctx;
253 SHA1_Init(&ctx);
254 SHA1_Update(&ctx, metadata.data(), metadata.size());
255 SHA1_Final(buffer, &ctx);
256 memcpy(&id, buffer, sizeof(id));
257 }
258 return id;
259}
260
Songchun Fan3c82a302019-11-29 14:23:45 -0800261IncrementalService::~IncrementalService() = default;
262
Alex Buynytskyy18b07a42020-02-03 20:06:00 -0800263inline const char* toString(TimePoint t) {
264 using SystemClock = std::chrono::system_clock;
Songchun Fan0f8b6fe2020-02-05 17:41:25 -0800265 time_t time = SystemClock::to_time_t(
266 SystemClock::now() +
267 std::chrono::duration_cast<SystemClock::duration>(t - Clock::now()));
Alex Buynytskyy18b07a42020-02-03 20:06:00 -0800268 return std::ctime(&time);
269}
270
271inline const char* toString(IncrementalService::BindKind kind) {
272 switch (kind) {
Songchun Fan0f8b6fe2020-02-05 17:41:25 -0800273 case IncrementalService::BindKind::Temporary:
274 return "Temporary";
275 case IncrementalService::BindKind::Permanent:
276 return "Permanent";
Alex Buynytskyy18b07a42020-02-03 20:06:00 -0800277 }
278}
279
280void IncrementalService::onDump(int fd) {
281 dprintf(fd, "Incremental is %s\n", incfs::enabled() ? "ENABLED" : "DISABLED");
282 dprintf(fd, "Incremental dir: %s\n", mIncrementalDir.c_str());
283
284 std::unique_lock l(mLock);
285
286 dprintf(fd, "Mounts (%d):\n", int(mMounts.size()));
287 for (auto&& [id, ifs] : mMounts) {
288 const IncFsMount& mnt = *ifs.get();
289 dprintf(fd, "\t[%d]:\n", id);
290 dprintf(fd, "\t\tmountId: %d\n", mnt.mountId);
291 dprintf(fd, "\t\tnextStorageDirNo: %d\n", mnt.nextStorageDirNo.load());
292 dprintf(fd, "\t\tdataLoaderStatus: %d\n", mnt.dataLoaderStatus.load());
293 dprintf(fd, "\t\tconnectionLostTime: %s\n", toString(mnt.connectionLostTime));
294 if (mnt.savedDataLoaderParams) {
295 const auto& params = mnt.savedDataLoaderParams.value();
296 dprintf(fd, "\t\tsavedDataLoaderParams:\n");
297 dprintf(fd, "\t\t\ttype: %s\n", toString(params.type).c_str());
298 dprintf(fd, "\t\t\tpackageName: %s\n", params.packageName.c_str());
299 dprintf(fd, "\t\t\tclassName: %s\n", params.className.c_str());
300 dprintf(fd, "\t\t\targuments: %s\n", params.arguments.c_str());
301 dprintf(fd, "\t\t\tdynamicArgs: %d\n", int(params.dynamicArgs.size()));
302 }
303 dprintf(fd, "\t\tstorages (%d):\n", int(mnt.storages.size()));
304 for (auto&& [storageId, storage] : mnt.storages) {
305 dprintf(fd, "\t\t\t[%d] -> [%s]\n", storageId, storage.name.c_str());
306 }
307
308 dprintf(fd, "\t\tbindPoints (%d):\n", int(mnt.bindPoints.size()));
309 for (auto&& [target, bind] : mnt.bindPoints) {
310 dprintf(fd, "\t\t\t[%s]->[%d]:\n", target.c_str(), bind.storage);
311 dprintf(fd, "\t\t\t\tsavedFilename: %s\n", bind.savedFilename.c_str());
312 dprintf(fd, "\t\t\t\tsourceDir: %s\n", bind.sourceDir.c_str());
313 dprintf(fd, "\t\t\t\tkind: %s\n", toString(bind.kind));
314 }
315 }
316
317 dprintf(fd, "Sorted binds (%d):\n", int(mBindsByPath.size()));
318 for (auto&& [target, mountPairIt] : mBindsByPath) {
319 const auto& bind = mountPairIt->second;
320 dprintf(fd, "\t\t[%s]->[%d]:\n", target.c_str(), bind.storage);
321 dprintf(fd, "\t\t\tsavedFilename: %s\n", bind.savedFilename.c_str());
322 dprintf(fd, "\t\t\tsourceDir: %s\n", bind.sourceDir.c_str());
323 dprintf(fd, "\t\t\tkind: %s\n", toString(bind.kind));
324 }
325}
326
Songchun Fan3c82a302019-11-29 14:23:45 -0800327std::optional<std::future<void>> IncrementalService::onSystemReady() {
328 std::promise<void> threadFinished;
329 if (mSystemReady.exchange(true)) {
330 return {};
331 }
332
333 std::vector<IfsMountPtr> mounts;
334 {
335 std::lock_guard l(mLock);
336 mounts.reserve(mMounts.size());
337 for (auto&& [id, ifs] : mMounts) {
338 if (ifs->mountId == id) {
339 mounts.push_back(ifs);
340 }
341 }
342 }
343
344 std::thread([this, mounts = std::move(mounts)]() {
345 std::vector<IfsMountPtr> failedLoaderMounts;
346 for (auto&& ifs : mounts) {
347 if (prepareDataLoader(*ifs, nullptr)) {
348 LOG(INFO) << "Successfully started data loader for mount " << ifs->mountId;
349 } else {
350 LOG(WARNING) << "Failed to start data loader for mount " << ifs->mountId;
351 failedLoaderMounts.push_back(std::move(ifs));
352 }
353 }
354
355 while (!failedLoaderMounts.empty()) {
356 LOG(WARNING) << "Deleting failed mount " << failedLoaderMounts.back()->mountId;
357 deleteStorage(*failedLoaderMounts.back());
358 failedLoaderMounts.pop_back();
359 }
360 mPrepareDataLoaders.set_value_at_thread_exit();
361 }).detach();
362 return mPrepareDataLoaders.get_future();
363}
364
365auto IncrementalService::getStorageSlotLocked() -> MountMap::iterator {
366 for (;;) {
367 if (mNextId == kMaxStorageId) {
368 mNextId = 0;
369 }
370 auto id = ++mNextId;
371 auto [it, inserted] = mMounts.try_emplace(id, nullptr);
372 if (inserted) {
373 return it;
374 }
375 }
376}
377
378StorageId IncrementalService::createStorage(std::string_view mountPoint,
379 DataLoaderParamsParcel&& dataLoaderParams,
380 CreateOptions options) {
381 LOG(INFO) << "createStorage: " << mountPoint << " | " << int(options);
382 if (!path::isAbsolute(mountPoint)) {
383 LOG(ERROR) << "path is not absolute: " << mountPoint;
384 return kInvalidStorageId;
385 }
386
387 auto mountNorm = path::normalize(mountPoint);
388 {
389 const auto id = findStorageId(mountNorm);
390 if (id != kInvalidStorageId) {
391 if (options & CreateOptions::OpenExisting) {
392 LOG(INFO) << "Opened existing storage " << id;
393 return id;
394 }
395 LOG(ERROR) << "Directory " << mountPoint << " is already mounted at storage " << id;
396 return kInvalidStorageId;
397 }
398 }
399
400 if (!(options & CreateOptions::CreateNew)) {
401 LOG(ERROR) << "not requirested create new storage, and it doesn't exist: " << mountPoint;
402 return kInvalidStorageId;
403 }
404
405 if (!path::isEmptyDir(mountNorm)) {
406 LOG(ERROR) << "Mounting over existing non-empty directory is not supported: " << mountNorm;
407 return kInvalidStorageId;
408 }
409 auto [mountKey, mountRoot] = makeMountDir(mIncrementalDir, mountNorm);
410 if (mountRoot.empty()) {
411 LOG(ERROR) << "Bad mount point";
412 return kInvalidStorageId;
413 }
414 // Make sure the code removes all crap it may create while still failing.
415 auto firstCleanup = [](const std::string* ptr) { IncFsMount::cleanupFilesystem(*ptr); };
416 auto firstCleanupOnFailure =
417 std::unique_ptr<std::string, decltype(firstCleanup)>(&mountRoot, firstCleanup);
418
419 auto mountTarget = path::join(mountRoot, constants().mount);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800420 const auto backing = path::join(mountRoot, constants().backing);
421 if (!mkdirOrLog(backing, 0777) || !mkdirOrLog(mountTarget)) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800422 return kInvalidStorageId;
423 }
424
Songchun Fan3c82a302019-11-29 14:23:45 -0800425 IncFsMount::Control control;
426 {
427 std::lock_guard l(mMountOperationLock);
428 IncrementalFileSystemControlParcel controlParcel;
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800429
430 if (auto err = rmDirContent(backing.c_str())) {
431 LOG(ERROR) << "Coudn't clean the backing directory " << backing << ": " << err;
432 return kInvalidStorageId;
433 }
434 if (!mkdirOrLog(path::join(backing, ".index"), 0777)) {
435 return kInvalidStorageId;
436 }
437 auto status = mVold->mountIncFs(backing, mountTarget, 0, &controlParcel);
Songchun Fan3c82a302019-11-29 14:23:45 -0800438 if (!status.isOk()) {
439 LOG(ERROR) << "Vold::mountIncFs() failed: " << status.toString8();
440 return kInvalidStorageId;
441 }
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800442 if (controlParcel.cmd.get() < 0 || controlParcel.pendingReads.get() < 0 ||
443 controlParcel.log.get() < 0) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800444 LOG(ERROR) << "Vold::mountIncFs() returned invalid control parcel.";
445 return kInvalidStorageId;
446 }
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800447 control.cmd = controlParcel.cmd.release().release();
448 control.pendingReads = controlParcel.pendingReads.release().release();
449 control.logs = controlParcel.log.release().release();
Songchun Fan3c82a302019-11-29 14:23:45 -0800450 }
451
452 std::unique_lock l(mLock);
453 const auto mountIt = getStorageSlotLocked();
454 const auto mountId = mountIt->first;
455 l.unlock();
456
457 auto ifs =
458 std::make_shared<IncFsMount>(std::move(mountRoot), mountId, std::move(control), *this);
459 // Now it's the |ifs|'s responsibility to clean up after itself, and the only cleanup we need
460 // is the removal of the |ifs|.
461 firstCleanupOnFailure.release();
462
463 auto secondCleanup = [this, &l](auto itPtr) {
464 if (!l.owns_lock()) {
465 l.lock();
466 }
467 mMounts.erase(*itPtr);
468 };
469 auto secondCleanupOnFailure =
470 std::unique_ptr<decltype(mountIt), decltype(secondCleanup)>(&mountIt, secondCleanup);
471
472 const auto storageIt = ifs->makeStorage(ifs->mountId);
473 if (storageIt == ifs->storages.end()) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800474 LOG(ERROR) << "Can't create a default storage directory";
Songchun Fan3c82a302019-11-29 14:23:45 -0800475 return kInvalidStorageId;
476 }
477
478 {
479 metadata::Mount m;
480 m.mutable_storage()->set_id(ifs->mountId);
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800481 m.mutable_loader()->set_type((int)dataLoaderParams.type);
Songchun Fan3c82a302019-11-29 14:23:45 -0800482 m.mutable_loader()->set_package_name(dataLoaderParams.packageName);
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800483 m.mutable_loader()->set_class_name(dataLoaderParams.className);
484 m.mutable_loader()->set_arguments(dataLoaderParams.arguments);
Songchun Fan3c82a302019-11-29 14:23:45 -0800485 const auto metadata = m.SerializeAsString();
486 m.mutable_loader()->release_arguments();
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800487 m.mutable_loader()->release_class_name();
Songchun Fan3c82a302019-11-29 14:23:45 -0800488 m.mutable_loader()->release_package_name();
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800489 if (auto err =
490 mIncFs->makeFile(ifs->control,
491 path::join(ifs->root, constants().mount,
492 constants().infoMdName),
493 0777, idFromMetadata(metadata),
494 {.metadata = {metadata.data(), (IncFsSize)metadata.size()}})) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800495 LOG(ERROR) << "Saving mount metadata failed: " << -err;
496 return kInvalidStorageId;
497 }
498 }
499
500 const auto bk =
501 (options & CreateOptions::PermanentBind) ? BindKind::Permanent : BindKind::Temporary;
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800502 if (auto err = addBindMount(*ifs, storageIt->first, storageIt->second.name,
503 std::string(storageIt->second.name), std::move(mountNorm), bk, l);
Songchun Fan3c82a302019-11-29 14:23:45 -0800504 err < 0) {
505 LOG(ERROR) << "adding bind mount failed: " << -err;
506 return kInvalidStorageId;
507 }
508
509 // Done here as well, all data structures are in good state.
510 secondCleanupOnFailure.release();
511
512 if (!prepareDataLoader(*ifs, &dataLoaderParams)) {
513 LOG(ERROR) << "prepareDataLoader() failed";
514 deleteStorageLocked(*ifs, std::move(l));
515 return kInvalidStorageId;
516 }
517
518 mountIt->second = std::move(ifs);
519 l.unlock();
520 LOG(INFO) << "created storage " << mountId;
521 return mountId;
522}
523
524StorageId IncrementalService::createLinkedStorage(std::string_view mountPoint,
525 StorageId linkedStorage,
526 IncrementalService::CreateOptions options) {
527 if (!isValidMountTarget(mountPoint)) {
528 LOG(ERROR) << "Mount point is invalid or missing";
529 return kInvalidStorageId;
530 }
531
532 std::unique_lock l(mLock);
533 const auto& ifs = getIfsLocked(linkedStorage);
534 if (!ifs) {
535 LOG(ERROR) << "Ifs unavailable";
536 return kInvalidStorageId;
537 }
538
539 const auto mountIt = getStorageSlotLocked();
540 const auto storageId = mountIt->first;
541 const auto storageIt = ifs->makeStorage(storageId);
542 if (storageIt == ifs->storages.end()) {
543 LOG(ERROR) << "Can't create a new storage";
544 mMounts.erase(mountIt);
545 return kInvalidStorageId;
546 }
547
548 l.unlock();
549
550 const auto bk =
551 (options & CreateOptions::PermanentBind) ? BindKind::Permanent : BindKind::Temporary;
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800552 if (auto err = addBindMount(*ifs, storageIt->first, storageIt->second.name,
553 std::string(storageIt->second.name), path::normalize(mountPoint),
554 bk, l);
Songchun Fan3c82a302019-11-29 14:23:45 -0800555 err < 0) {
556 LOG(ERROR) << "bindMount failed with error: " << err;
557 return kInvalidStorageId;
558 }
559
560 mountIt->second = ifs;
561 return storageId;
562}
563
564IncrementalService::BindPathMap::const_iterator IncrementalService::findStorageLocked(
565 std::string_view path) const {
566 auto bindPointIt = mBindsByPath.upper_bound(path);
567 if (bindPointIt == mBindsByPath.begin()) {
568 return mBindsByPath.end();
569 }
570 --bindPointIt;
571 if (!path::startsWith(path, bindPointIt->first)) {
572 return mBindsByPath.end();
573 }
574 return bindPointIt;
575}
576
577StorageId IncrementalService::findStorageId(std::string_view path) const {
578 std::lock_guard l(mLock);
579 auto it = findStorageLocked(path);
580 if (it == mBindsByPath.end()) {
581 return kInvalidStorageId;
582 }
583 return it->second->second.storage;
584}
585
586void IncrementalService::deleteStorage(StorageId storageId) {
587 const auto ifs = getIfs(storageId);
588 if (!ifs) {
589 return;
590 }
591 deleteStorage(*ifs);
592}
593
594void IncrementalService::deleteStorage(IncrementalService::IncFsMount& ifs) {
595 std::unique_lock l(ifs.lock);
596 deleteStorageLocked(ifs, std::move(l));
597}
598
599void IncrementalService::deleteStorageLocked(IncrementalService::IncFsMount& ifs,
600 std::unique_lock<std::mutex>&& ifsLock) {
601 const auto storages = std::move(ifs.storages);
602 // Don't move the bind points out: Ifs's dtor will use them to unmount everything.
603 const auto bindPoints = ifs.bindPoints;
604 ifsLock.unlock();
605
606 std::lock_guard l(mLock);
607 for (auto&& [id, _] : storages) {
608 if (id != ifs.mountId) {
609 mMounts.erase(id);
610 }
611 }
612 for (auto&& [path, _] : bindPoints) {
613 mBindsByPath.erase(path);
614 }
615 mMounts.erase(ifs.mountId);
616}
617
618StorageId IncrementalService::openStorage(std::string_view pathInMount) {
619 if (!path::isAbsolute(pathInMount)) {
620 return kInvalidStorageId;
621 }
622
623 return findStorageId(path::normalize(pathInMount));
624}
625
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800626FileId IncrementalService::nodeFor(StorageId storage, std::string_view subpath) const {
Songchun Fan3c82a302019-11-29 14:23:45 -0800627 const auto ifs = getIfs(storage);
628 if (!ifs) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800629 return kIncFsInvalidFileId;
Songchun Fan3c82a302019-11-29 14:23:45 -0800630 }
631 std::unique_lock l(ifs->lock);
632 auto storageIt = ifs->storages.find(storage);
633 if (storageIt == ifs->storages.end()) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800634 return kIncFsInvalidFileId;
Songchun Fan3c82a302019-11-29 14:23:45 -0800635 }
636 if (subpath.empty() || subpath == "."sv) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800637 return kIncFsInvalidFileId;
Songchun Fan3c82a302019-11-29 14:23:45 -0800638 }
639 auto path = path::join(ifs->root, constants().mount, storageIt->second.name, subpath);
640 l.unlock();
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800641 return mIncFs->getFileId(ifs->control, path);
Songchun Fan3c82a302019-11-29 14:23:45 -0800642}
643
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800644std::pair<FileId, std::string_view> IncrementalService::parentAndNameFor(
Songchun Fan3c82a302019-11-29 14:23:45 -0800645 StorageId storage, std::string_view subpath) const {
646 auto name = path::basename(subpath);
647 if (name.empty()) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800648 return {kIncFsInvalidFileId, {}};
Songchun Fan3c82a302019-11-29 14:23:45 -0800649 }
650 auto dir = path::dirname(subpath);
651 if (dir.empty() || dir == "/"sv) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800652 return {kIncFsInvalidFileId, {}};
Songchun Fan3c82a302019-11-29 14:23:45 -0800653 }
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800654 auto id = nodeFor(storage, dir);
655 return {id, name};
Songchun Fan3c82a302019-11-29 14:23:45 -0800656}
657
658IncrementalService::IfsMountPtr IncrementalService::getIfs(StorageId storage) const {
659 std::lock_guard l(mLock);
660 return getIfsLocked(storage);
661}
662
663const IncrementalService::IfsMountPtr& IncrementalService::getIfsLocked(StorageId storage) const {
664 auto it = mMounts.find(storage);
665 if (it == mMounts.end()) {
666 static const IfsMountPtr kEmpty = {};
667 return kEmpty;
668 }
669 return it->second;
670}
671
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800672int IncrementalService::bind(StorageId storage, std::string_view source, std::string_view target,
673 BindKind kind) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800674 if (!isValidMountTarget(target)) {
675 return -EINVAL;
676 }
677
678 const auto ifs = getIfs(storage);
679 if (!ifs) {
680 return -EINVAL;
681 }
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800682
Songchun Fan3c82a302019-11-29 14:23:45 -0800683 std::unique_lock l(ifs->lock);
684 const auto storageInfo = ifs->storages.find(storage);
685 if (storageInfo == ifs->storages.end()) {
686 return -EINVAL;
687 }
Songchun Fan103ba1d2020-02-03 17:32:32 -0800688 std::string normSource = normalizePathToStorage(ifs, storage, source);
Songchun Fan3c82a302019-11-29 14:23:45 -0800689 l.unlock();
690 std::unique_lock l2(mLock, std::defer_lock);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800691 return addBindMount(*ifs, storage, storageInfo->second.name, std::move(normSource),
692 path::normalize(target), kind, l2);
Songchun Fan3c82a302019-11-29 14:23:45 -0800693}
694
695int IncrementalService::unbind(StorageId storage, std::string_view target) {
696 if (!path::isAbsolute(target)) {
697 return -EINVAL;
698 }
699
700 LOG(INFO) << "Removing bind point " << target;
701
702 // Here we should only look up by the exact target, not by a subdirectory of any existing mount,
703 // otherwise there's a chance to unmount something completely unrelated
704 const auto norm = path::normalize(target);
705 std::unique_lock l(mLock);
706 const auto storageIt = mBindsByPath.find(norm);
707 if (storageIt == mBindsByPath.end() || storageIt->second->second.storage != storage) {
708 return -EINVAL;
709 }
710 const auto bindIt = storageIt->second;
711 const auto storageId = bindIt->second.storage;
712 const auto ifs = getIfsLocked(storageId);
713 if (!ifs) {
714 LOG(ERROR) << "Internal error: storageId " << storageId << " for bound path " << target
715 << " is missing";
716 return -EFAULT;
717 }
718 mBindsByPath.erase(storageIt);
719 l.unlock();
720
721 mVold->unmountIncFs(bindIt->first);
722 std::unique_lock l2(ifs->lock);
723 if (ifs->bindPoints.size() <= 1) {
724 ifs->bindPoints.clear();
725 deleteStorageLocked(*ifs, std::move(l2));
726 } else {
727 const std::string savedFile = std::move(bindIt->second.savedFilename);
728 ifs->bindPoints.erase(bindIt);
729 l2.unlock();
730 if (!savedFile.empty()) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800731 mIncFs->unlink(ifs->control, path::join(ifs->root, constants().mount, savedFile));
Songchun Fan3c82a302019-11-29 14:23:45 -0800732 }
733 }
734 return 0;
735}
736
Songchun Fan103ba1d2020-02-03 17:32:32 -0800737std::string IncrementalService::normalizePathToStorage(const IncrementalService::IfsMountPtr ifs,
738 StorageId storage, std::string_view path) {
739 const auto storageInfo = ifs->storages.find(storage);
740 if (storageInfo == ifs->storages.end()) {
741 return {};
742 }
743 std::string normPath;
744 if (path::isAbsolute(path)) {
745 normPath = path::normalize(path);
746 } else {
747 normPath = path::normalize(path::join(storageInfo->second.name, path));
748 }
749 if (!path::startsWith(normPath, storageInfo->second.name)) {
750 return {};
751 }
752 return normPath;
753}
754
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800755int IncrementalService::makeFile(StorageId storage, std::string_view path, int mode, FileId id,
756 incfs::NewFileParams params) {
757 if (auto ifs = getIfs(storage)) {
Songchun Fan103ba1d2020-02-03 17:32:32 -0800758 std::string normPath = normalizePathToStorage(ifs, storage, path);
759 if (normPath.empty()) {
Songchun Fan54c6aed2020-01-31 16:52:41 -0800760 return -EINVAL;
761 }
762 auto err = mIncFs->makeFile(ifs->control, normPath, mode, id, params);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800763 if (err) {
764 return err;
Songchun Fan3c82a302019-11-29 14:23:45 -0800765 }
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800766 std::vector<uint8_t> metadataBytes;
767 if (params.metadata.data && params.metadata.size > 0) {
768 metadataBytes.assign(params.metadata.data, params.metadata.data + params.metadata.size);
Songchun Fan3c82a302019-11-29 14:23:45 -0800769 }
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800770 mIncrementalManager->newFileForDataLoader(ifs->mountId, id, metadataBytes);
771 return 0;
Songchun Fan3c82a302019-11-29 14:23:45 -0800772 }
773 return -EINVAL;
774}
775
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800776int IncrementalService::makeDir(StorageId storageId, std::string_view path, int mode) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800777 if (auto ifs = getIfs(storageId)) {
Songchun Fan103ba1d2020-02-03 17:32:32 -0800778 std::string normPath = normalizePathToStorage(ifs, storageId, path);
779 if (normPath.empty()) {
780 return -EINVAL;
781 }
782 return mIncFs->makeDir(ifs->control, normPath, mode);
Songchun Fan3c82a302019-11-29 14:23:45 -0800783 }
784 return -EINVAL;
785}
786
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800787int IncrementalService::makeDirs(StorageId storageId, std::string_view path, int mode) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800788 const auto ifs = getIfs(storageId);
789 if (!ifs) {
790 return -EINVAL;
791 }
Songchun Fan103ba1d2020-02-03 17:32:32 -0800792 std::string normPath = normalizePathToStorage(ifs, storageId, path);
793 if (normPath.empty()) {
794 return -EINVAL;
795 }
796 auto err = mIncFs->makeDir(ifs->control, normPath, mode);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800797 if (err == -EEXIST) {
798 return 0;
799 } else if (err != -ENOENT) {
800 return err;
Songchun Fan3c82a302019-11-29 14:23:45 -0800801 }
Songchun Fan103ba1d2020-02-03 17:32:32 -0800802 if (auto err = makeDirs(storageId, path::dirname(normPath), mode)) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800803 return err;
Songchun Fan3c82a302019-11-29 14:23:45 -0800804 }
Songchun Fan103ba1d2020-02-03 17:32:32 -0800805 return mIncFs->makeDir(ifs->control, normPath, mode);
Songchun Fan3c82a302019-11-29 14:23:45 -0800806}
807
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800808int IncrementalService::link(StorageId sourceStorageId, std::string_view oldPath,
809 StorageId destStorageId, std::string_view newPath) {
810 if (auto ifsSrc = getIfs(sourceStorageId), ifsDest = getIfs(destStorageId);
811 ifsSrc && ifsSrc == ifsDest) {
Songchun Fan103ba1d2020-02-03 17:32:32 -0800812 std::string normOldPath = normalizePathToStorage(ifsSrc, sourceStorageId, oldPath);
813 std::string normNewPath = normalizePathToStorage(ifsDest, destStorageId, newPath);
814 if (normOldPath.empty() || normNewPath.empty()) {
815 return -EINVAL;
816 }
817 return mIncFs->link(ifsSrc->control, normOldPath, normNewPath);
Songchun Fan3c82a302019-11-29 14:23:45 -0800818 }
819 return -EINVAL;
820}
821
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800822int IncrementalService::unlink(StorageId storage, std::string_view path) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800823 if (auto ifs = getIfs(storage)) {
Songchun Fan103ba1d2020-02-03 17:32:32 -0800824 std::string normOldPath = normalizePathToStorage(ifs, storage, path);
825 return mIncFs->unlink(ifs->control, normOldPath);
Songchun Fan3c82a302019-11-29 14:23:45 -0800826 }
827 return -EINVAL;
828}
829
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800830int IncrementalService::addBindMount(IncFsMount& ifs, StorageId storage,
831 std::string_view storageRoot, std::string&& source,
Songchun Fan3c82a302019-11-29 14:23:45 -0800832 std::string&& target, BindKind kind,
833 std::unique_lock<std::mutex>& mainLock) {
834 if (!isValidMountTarget(target)) {
835 return -EINVAL;
836 }
837
838 std::string mdFileName;
839 if (kind != BindKind::Temporary) {
840 metadata::BindPoint bp;
841 bp.set_storage_id(storage);
842 bp.set_allocated_dest_path(&target);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800843 bp.set_source_subdir(std::string(path::relativize(storageRoot, source)));
Songchun Fan3c82a302019-11-29 14:23:45 -0800844 const auto metadata = bp.SerializeAsString();
Songchun Fan3c82a302019-11-29 14:23:45 -0800845 bp.release_dest_path();
846 mdFileName = makeBindMdName();
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800847 auto node =
848 mIncFs->makeFile(ifs.control, path::join(ifs.root, constants().mount, mdFileName),
849 0444, idFromMetadata(metadata),
850 {.metadata = {metadata.data(), (IncFsSize)metadata.size()}});
851 if (node) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800852 return int(node);
853 }
854 }
855
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800856 return addBindMountWithMd(ifs, storage, std::move(mdFileName), std::move(source),
Songchun Fan3c82a302019-11-29 14:23:45 -0800857 std::move(target), kind, mainLock);
858}
859
860int IncrementalService::addBindMountWithMd(IncrementalService::IncFsMount& ifs, StorageId storage,
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800861 std::string&& metadataName, std::string&& source,
Songchun Fan3c82a302019-11-29 14:23:45 -0800862 std::string&& target, BindKind kind,
863 std::unique_lock<std::mutex>& mainLock) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800864 {
Songchun Fan3c82a302019-11-29 14:23:45 -0800865 std::lock_guard l(mMountOperationLock);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800866 const auto status = mVold->bindMount(source, target);
Songchun Fan3c82a302019-11-29 14:23:45 -0800867 if (!status.isOk()) {
868 LOG(ERROR) << "Calling Vold::bindMount() failed: " << status.toString8();
869 return status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC
870 ? status.serviceSpecificErrorCode() > 0 ? -status.serviceSpecificErrorCode()
871 : status.serviceSpecificErrorCode() == 0
872 ? -EFAULT
873 : status.serviceSpecificErrorCode()
874 : -EIO;
875 }
876 }
877
878 if (!mainLock.owns_lock()) {
879 mainLock.lock();
880 }
881 std::lock_guard l(ifs.lock);
882 const auto [it, _] =
883 ifs.bindPoints.insert_or_assign(target,
884 IncFsMount::Bind{storage, std::move(metadataName),
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800885 std::move(source), kind});
Songchun Fan3c82a302019-11-29 14:23:45 -0800886 mBindsByPath[std::move(target)] = it;
887 return 0;
888}
889
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800890RawMetadata IncrementalService::getMetadata(StorageId storage, FileId node) const {
Songchun Fan3c82a302019-11-29 14:23:45 -0800891 const auto ifs = getIfs(storage);
892 if (!ifs) {
893 return {};
894 }
895 return mIncFs->getMetadata(ifs->control, node);
896}
897
898std::vector<std::string> IncrementalService::listFiles(StorageId storage) const {
899 const auto ifs = getIfs(storage);
900 if (!ifs) {
901 return {};
902 }
903
904 std::unique_lock l(ifs->lock);
905 auto subdirIt = ifs->storages.find(storage);
906 if (subdirIt == ifs->storages.end()) {
907 return {};
908 }
909 auto dir = path::join(ifs->root, constants().mount, subdirIt->second.name);
910 l.unlock();
911
912 const auto prefixSize = dir.size() + 1;
913 std::vector<std::string> todoDirs{std::move(dir)};
914 std::vector<std::string> result;
915 do {
916 auto currDir = std::move(todoDirs.back());
917 todoDirs.pop_back();
918
919 auto d =
920 std::unique_ptr<DIR, decltype(&::closedir)>(::opendir(currDir.c_str()), ::closedir);
921 while (auto e = ::readdir(d.get())) {
922 if (e->d_type == DT_REG) {
923 result.emplace_back(
924 path::join(std::string_view(currDir).substr(prefixSize), e->d_name));
925 continue;
926 }
927 if (e->d_type == DT_DIR) {
928 if (e->d_name == "."sv || e->d_name == ".."sv) {
929 continue;
930 }
931 todoDirs.emplace_back(path::join(currDir, e->d_name));
932 continue;
933 }
934 }
935 } while (!todoDirs.empty());
936 return result;
937}
938
939bool IncrementalService::startLoading(StorageId storage) const {
940 const auto ifs = getIfs(storage);
941 if (!ifs) {
942 return false;
943 }
944 bool started = false;
945 std::unique_lock l(ifs->lock);
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800946 if (ifs->dataLoaderStatus != IDataLoaderStatusListener::DATA_LOADER_CREATED) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800947 if (ifs->dataLoaderReady.wait_for(l, Seconds(5)) == std::cv_status::timeout) {
948 LOG(ERROR) << "Timeout waiting for data loader to be ready";
949 return false;
950 }
951 }
952 auto status = mIncrementalManager->startDataLoader(ifs->mountId, &started);
953 if (!status.isOk()) {
954 return false;
955 }
956 return started;
957}
958
959void IncrementalService::mountExistingImages() {
960 auto d = std::unique_ptr<DIR, decltype(&::closedir)>(::opendir(mIncrementalDir.c_str()),
961 ::closedir);
962 while (auto e = ::readdir(d.get())) {
963 if (e->d_type != DT_DIR) {
964 continue;
965 }
966 if (e->d_name == "."sv || e->d_name == ".."sv) {
967 continue;
968 }
969 auto root = path::join(mIncrementalDir, e->d_name);
970 if (!mountExistingImage(root, e->d_name)) {
971 IncFsMount::cleanupFilesystem(root);
972 }
973 }
974}
975
976bool IncrementalService::mountExistingImage(std::string_view root, std::string_view key) {
977 LOG(INFO) << "Trying to mount: " << key;
978
979 auto mountTarget = path::join(root, constants().mount);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800980 const auto backing = path::join(root, constants().backing);
Songchun Fan3c82a302019-11-29 14:23:45 -0800981
982 IncFsMount::Control control;
983 IncrementalFileSystemControlParcel controlParcel;
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800984 auto status = mVold->mountIncFs(backing, mountTarget, 0, &controlParcel);
Songchun Fan3c82a302019-11-29 14:23:45 -0800985 if (!status.isOk()) {
986 LOG(ERROR) << "Vold::mountIncFs() failed: " << status.toString8();
987 return false;
988 }
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800989 control.cmd = controlParcel.cmd.release().release();
990 control.pendingReads = controlParcel.pendingReads.release().release();
991 control.logs = controlParcel.log.release().release();
Songchun Fan3c82a302019-11-29 14:23:45 -0800992
993 auto ifs = std::make_shared<IncFsMount>(std::string(root), -1, std::move(control), *this);
994
995 auto m = parseFromIncfs<metadata::Mount>(mIncFs.get(), ifs->control,
996 path::join(mountTarget, constants().infoMdName));
997 if (!m.has_loader() || !m.has_storage()) {
998 LOG(ERROR) << "Bad mount metadata in mount at " << root;
999 return false;
1000 }
1001
1002 ifs->mountId = m.storage().id();
1003 mNextId = std::max(mNextId, ifs->mountId + 1);
1004
1005 std::vector<std::pair<std::string, metadata::BindPoint>> bindPoints;
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -08001006 auto d = openDir(path::c_str(mountTarget));
Songchun Fan3c82a302019-11-29 14:23:45 -08001007 while (auto e = ::readdir(d.get())) {
1008 if (e->d_type == DT_REG) {
1009 auto name = std::string_view(e->d_name);
1010 if (name.starts_with(constants().mountpointMdPrefix)) {
1011 bindPoints.emplace_back(name,
1012 parseFromIncfs<metadata::BindPoint>(mIncFs.get(),
1013 ifs->control,
1014 path::join(mountTarget,
1015 name)));
1016 if (bindPoints.back().second.dest_path().empty() ||
1017 bindPoints.back().second.source_subdir().empty()) {
1018 bindPoints.pop_back();
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -08001019 mIncFs->unlink(ifs->control, path::join(ifs->root, constants().mount, name));
Songchun Fan3c82a302019-11-29 14:23:45 -08001020 }
1021 }
1022 } else if (e->d_type == DT_DIR) {
1023 if (e->d_name == "."sv || e->d_name == ".."sv) {
1024 continue;
1025 }
1026 auto name = std::string_view(e->d_name);
1027 if (name.starts_with(constants().storagePrefix)) {
1028 auto md = parseFromIncfs<metadata::Storage>(mIncFs.get(), ifs->control,
1029 path::join(mountTarget, name));
1030 auto [_, inserted] = mMounts.try_emplace(md.id(), ifs);
1031 if (!inserted) {
1032 LOG(WARNING) << "Ignoring storage with duplicate id " << md.id()
1033 << " for mount " << root;
1034 continue;
1035 }
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -08001036 ifs->storages.insert_or_assign(md.id(), IncFsMount::Storage{std::string(name)});
Songchun Fan3c82a302019-11-29 14:23:45 -08001037 mNextId = std::max(mNextId, md.id() + 1);
1038 }
1039 }
1040 }
1041
1042 if (ifs->storages.empty()) {
1043 LOG(WARNING) << "No valid storages in mount " << root;
1044 return false;
1045 }
1046
1047 int bindCount = 0;
1048 for (auto&& bp : bindPoints) {
1049 std::unique_lock l(mLock, std::defer_lock);
1050 bindCount += !addBindMountWithMd(*ifs, bp.second.storage_id(), std::move(bp.first),
1051 std::move(*bp.second.mutable_source_subdir()),
1052 std::move(*bp.second.mutable_dest_path()),
1053 BindKind::Permanent, l);
1054 }
1055
1056 if (bindCount == 0) {
1057 LOG(WARNING) << "No valid bind points for mount " << root;
1058 deleteStorage(*ifs);
1059 return false;
1060 }
1061
1062 DataLoaderParamsParcel dlParams;
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08001063 dlParams.type = (DataLoaderType)m.loader().type();
Songchun Fan3c82a302019-11-29 14:23:45 -08001064 dlParams.packageName = std::move(*m.mutable_loader()->mutable_package_name());
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08001065 dlParams.className = std::move(*m.mutable_loader()->mutable_class_name());
1066 dlParams.arguments = std::move(*m.mutable_loader()->mutable_arguments());
Songchun Fan3c82a302019-11-29 14:23:45 -08001067 if (!prepareDataLoader(*ifs, &dlParams)) {
1068 deleteStorage(*ifs);
1069 return false;
1070 }
1071
1072 mMounts[ifs->mountId] = std::move(ifs);
1073 return true;
1074}
1075
1076bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs,
1077 DataLoaderParamsParcel* params) {
1078 if (!mSystemReady.load(std::memory_order_relaxed)) {
1079 std::unique_lock l(ifs.lock);
1080 if (params) {
1081 if (ifs.savedDataLoaderParams) {
1082 LOG(WARNING) << "Trying to pass second set of data loader parameters, ignored it";
1083 } else {
1084 ifs.savedDataLoaderParams = std::move(*params);
1085 }
1086 } else {
1087 if (!ifs.savedDataLoaderParams) {
1088 LOG(ERROR) << "Mount " << ifs.mountId
1089 << " is broken: no data loader params (system is not ready yet)";
1090 return false;
1091 }
1092 }
1093 return true; // eventually...
1094 }
1095 if (base::GetBoolProperty("incremental.skip_loader", false)) {
1096 LOG(INFO) << "Skipped data loader because of incremental.skip_loader property";
1097 std::unique_lock l(ifs.lock);
1098 ifs.savedDataLoaderParams.reset();
1099 return true;
1100 }
1101
1102 std::unique_lock l(ifs.lock);
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08001103 if (ifs.dataLoaderStatus == IDataLoaderStatusListener::DATA_LOADER_CREATED) {
Songchun Fan3c82a302019-11-29 14:23:45 -08001104 LOG(INFO) << "Skipped data loader preparation because it already exists";
1105 return true;
1106 }
1107
1108 auto* dlp = params ? params
1109 : ifs.savedDataLoaderParams ? &ifs.savedDataLoaderParams.value() : nullptr;
1110 if (!dlp) {
1111 LOG(ERROR) << "Mount " << ifs.mountId << " is broken: no data loader params";
1112 return false;
1113 }
1114 FileSystemControlParcel fsControlParcel;
1115 fsControlParcel.incremental = std::make_unique<IncrementalFileSystemControlParcel>();
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -08001116 fsControlParcel.incremental->cmd.reset(base::unique_fd(::dup(ifs.control.cmd)));
1117 fsControlParcel.incremental->pendingReads.reset(
1118 base::unique_fd(::dup(ifs.control.pendingReads)));
1119 fsControlParcel.incremental->log.reset(base::unique_fd(::dup(ifs.control.logs)));
Songchun Fan3c82a302019-11-29 14:23:45 -08001120 sp<IncrementalDataLoaderListener> listener = new IncrementalDataLoaderListener(*this);
1121 bool created = false;
1122 auto status = mIncrementalManager->prepareDataLoader(ifs.mountId, fsControlParcel, *dlp,
1123 listener, &created);
1124 if (!status.isOk() || !created) {
1125 LOG(ERROR) << "Failed to create a data loader for mount " << ifs.mountId;
1126 return false;
1127 }
1128 ifs.savedDataLoaderParams.reset();
1129 return true;
1130}
1131
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001132// Extract lib filse from zip, create new files in incfs and write data to them
1133bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_view apkFullPath,
1134 std::string_view libDirRelativePath,
1135 std::string_view abi) {
1136 const auto ifs = getIfs(storage);
1137 // First prepare target directories if they don't exist yet
1138 if (auto res = makeDirs(storage, libDirRelativePath, 0755)) {
1139 LOG(ERROR) << "Failed to prepare target lib directory " << libDirRelativePath
1140 << " errno: " << res;
1141 return false;
1142 }
1143
1144 std::unique_ptr<ZipFileRO> zipFile(ZipFileRO::open(apkFullPath.data()));
1145 if (!zipFile) {
1146 LOG(ERROR) << "Failed to open zip file at " << apkFullPath;
1147 return false;
1148 }
1149 void* cookie = nullptr;
1150 const auto libFilePrefix = path::join(constants().libDir, abi);
1151 if (!zipFile.get()->startIteration(&cookie, libFilePrefix.c_str() /* prefix */,
1152 constants().libSuffix.data() /* suffix */)) {
1153 LOG(ERROR) << "Failed to start zip iteration for " << apkFullPath;
1154 return false;
1155 }
1156 ZipEntryRO entry = nullptr;
1157 bool success = true;
1158 while ((entry = zipFile.get()->nextEntry(cookie)) != nullptr) {
1159 char fileName[PATH_MAX];
1160 if (zipFile.get()->getEntryFileName(entry, fileName, sizeof(fileName))) {
1161 continue;
1162 }
1163 const auto libName = path::basename(fileName);
1164 const auto targetLibPath = path::join(libDirRelativePath, libName);
1165 const auto targetLibPathAbsolute = normalizePathToStorage(ifs, storage, targetLibPath);
1166 // If the extract file already exists, skip
1167 struct stat st;
1168 if (stat(targetLibPathAbsolute.c_str(), &st) == 0) {
1169 LOG(INFO) << "Native lib file already exists: " << targetLibPath
1170 << "; skipping extraction";
1171 continue;
1172 }
1173
1174 uint32_t uncompressedLen;
1175 if (!zipFile.get()->getEntryInfo(entry, nullptr, &uncompressedLen, nullptr, nullptr,
1176 nullptr, nullptr)) {
1177 LOG(ERROR) << "Failed to read native lib entry: " << fileName;
1178 success = false;
1179 break;
1180 }
1181
1182 // Create new lib file without signature info
1183 incfs::NewFileParams libFileParams;
1184 libFileParams.size = uncompressedLen;
1185 libFileParams.verification.hashAlgorithm = INCFS_HASH_NONE;
1186 // Metadata of the new lib file is its relative path
1187 IncFsSpan libFileMetadata;
1188 libFileMetadata.data = targetLibPath.c_str();
1189 libFileMetadata.size = targetLibPath.size();
1190 libFileParams.metadata = libFileMetadata;
1191 incfs::FileId libFileId = idFromMetadata(targetLibPath);
1192 if (auto res = makeFile(storage, targetLibPath, 0777, libFileId, libFileParams)) {
1193 LOG(ERROR) << "Failed to make file for: " << targetLibPath << " errno: " << res;
1194 success = false;
1195 // If one lib file fails to be created, abort others as well
1196 break;
1197 }
1198
1199 // Write extracted data to new file
1200 std::vector<uint8_t> libData(uncompressedLen);
1201 if (!zipFile.get()->uncompressEntry(entry, &libData[0], uncompressedLen)) {
1202 LOG(ERROR) << "Failed to extract native lib zip entry: " << fileName;
1203 success = false;
1204 break;
1205 }
1206 android::base::unique_fd writeFd(mIncFs->openWrite(ifs->control, libFileId));
1207 if (writeFd < 0) {
1208 LOG(ERROR) << "Failed to open write fd for: " << targetLibPath << " errno: " << writeFd;
1209 success = false;
1210 break;
1211 }
1212 const int numBlocks = uncompressedLen / constants().blockSize + 1;
1213 std::vector<IncFsDataBlock> instructions;
1214 auto remainingData = std::span(libData);
1215 for (int i = 0; i < numBlocks - 1; i++) {
1216 auto inst = IncFsDataBlock{
1217 .fileFd = writeFd,
1218 .pageIndex = static_cast<IncFsBlockIndex>(i),
1219 .compression = INCFS_COMPRESSION_KIND_NONE,
1220 .kind = INCFS_BLOCK_KIND_DATA,
1221 .dataSize = static_cast<uint16_t>(constants().blockSize),
1222 .data = reinterpret_cast<const char*>(remainingData.data()),
1223 };
1224 instructions.push_back(inst);
1225 remainingData = remainingData.subspan(constants().blockSize);
1226 }
1227 // Last block
1228 auto inst = IncFsDataBlock{
1229 .fileFd = writeFd,
1230 .pageIndex = static_cast<IncFsBlockIndex>(numBlocks - 1),
1231 .compression = INCFS_COMPRESSION_KIND_NONE,
1232 .kind = INCFS_BLOCK_KIND_DATA,
1233 .dataSize = static_cast<uint16_t>(remainingData.size()),
1234 .data = reinterpret_cast<const char*>(remainingData.data()),
1235 };
1236 instructions.push_back(inst);
1237 size_t res = mIncFs->writeBlocks(instructions);
1238 if (res != instructions.size()) {
1239 LOG(ERROR) << "Failed to write data into: " << targetLibPath;
1240 success = false;
1241 }
1242 instructions.clear();
1243 }
1244 zipFile.get()->endIteration(cookie);
1245 return success;
1246}
1247
Songchun Fan3c82a302019-11-29 14:23:45 -08001248binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChanged(MountId mountId,
1249 int newStatus) {
1250 std::unique_lock l(incrementalService.mLock);
1251 const auto& ifs = incrementalService.getIfsLocked(mountId);
1252 if (!ifs) {
1253 LOG(WARNING) << "Received data loader status " << int(newStatus) << " for unknown mount "
1254 << mountId;
1255 return binder::Status::ok();
1256 }
1257 ifs->dataLoaderStatus = newStatus;
1258 switch (newStatus) {
1259 case IDataLoaderStatusListener::DATA_LOADER_NO_CONNECTION: {
1260 auto now = Clock::now();
1261 if (ifs->connectionLostTime.time_since_epoch().count() == 0) {
1262 ifs->connectionLostTime = now;
1263 break;
1264 }
1265 auto duration =
1266 std::chrono::duration_cast<Seconds>(now - ifs->connectionLostTime).count();
1267 if (duration >= 10) {
1268 incrementalService.mIncrementalManager->showHealthBlockedUI(mountId);
1269 }
1270 break;
1271 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08001272 case IDataLoaderStatusListener::DATA_LOADER_CONNECTION_OK: {
1273 ifs->dataLoaderStatus = IDataLoaderStatusListener::DATA_LOADER_STARTED;
1274 break;
1275 }
1276 case IDataLoaderStatusListener::DATA_LOADER_CREATED: {
Songchun Fan3c82a302019-11-29 14:23:45 -08001277 ifs->dataLoaderReady.notify_one();
1278 break;
1279 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08001280 case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: {
Songchun Fan3c82a302019-11-29 14:23:45 -08001281 ifs->dataLoaderStatus = IDataLoaderStatusListener::DATA_LOADER_STOPPED;
1282 incrementalService.deleteStorageLocked(*ifs, std::move(l));
1283 break;
1284 }
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -08001285 case IDataLoaderStatusListener::DATA_LOADER_STARTED: {
Songchun Fan3c82a302019-11-29 14:23:45 -08001286 break;
1287 }
1288 case IDataLoaderStatusListener::DATA_LOADER_STOPPED: {
1289 break;
1290 }
1291 default: {
1292 LOG(WARNING) << "Unknown data loader status: " << newStatus
1293 << " for mount: " << mountId;
1294 break;
1295 }
1296 }
1297
1298 return binder::Status::ok();
1299}
1300
1301} // namespace android::incremental