diff options
Diffstat (limited to 'services/incremental/IncrementalService.cpp')
-rw-r--r-- | services/incremental/IncrementalService.cpp | 186 |
1 files changed, 185 insertions, 1 deletions
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index ac45d7695ab9..3b513774b615 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -35,6 +35,7 @@ #include <uuid/uuid.h> #include <zlib.h> +#include <ctime> #include <iterator> #include <span> #include <stack> @@ -59,6 +60,9 @@ struct Constants { static constexpr auto storagePrefix = "st"sv; static constexpr auto mountpointMdPrefix = ".mountpoint."sv; static constexpr auto infoMdName = ".info"sv; + static constexpr auto libDir = "lib"sv; + static constexpr auto libSuffix = ".so"sv; + static constexpr auto blockSize = 4096; }; static const Constants& constants() { @@ -169,7 +173,7 @@ auto IncrementalService::IncFsMount::makeStorage(StorageId id) -> StorageMap::it base::StringAppendF(&name, "%.*s_%d_%d", int(constants().storagePrefix.size()), constants().storagePrefix.data(), id, no); auto fullName = path::join(root, constants().mount, name); - if (auto err = incrementalService.mIncFs->makeDir(control, fullName); !err) { + if (auto err = incrementalService.mIncFs->makeDir(control, fullName, 0755); !err) { std::lock_guard l(lock); return storages.insert_or_assign(id, Storage{std::move(fullName)}).first; } else if (err != EEXIST) { @@ -256,6 +260,70 @@ FileId IncrementalService::idFromMetadata(std::span<const uint8_t> metadata) { IncrementalService::~IncrementalService() = default; +inline const char* toString(TimePoint t) { + using SystemClock = std::chrono::system_clock; + time_t time = SystemClock::to_time_t( + SystemClock::now() + + std::chrono::duration_cast<SystemClock::duration>(t - Clock::now())); + return std::ctime(&time); +} + +inline const char* toString(IncrementalService::BindKind kind) { + switch (kind) { + case IncrementalService::BindKind::Temporary: + return "Temporary"; + case IncrementalService::BindKind::Permanent: + return "Permanent"; + } +} + +void IncrementalService::onDump(int fd) { + dprintf(fd, "Incremental is %s\n", incfs::enabled() ? "ENABLED" : "DISABLED"); + dprintf(fd, "Incremental dir: %s\n", mIncrementalDir.c_str()); + + std::unique_lock l(mLock); + + dprintf(fd, "Mounts (%d):\n", int(mMounts.size())); + for (auto&& [id, ifs] : mMounts) { + const IncFsMount& mnt = *ifs.get(); + dprintf(fd, "\t[%d]:\n", id); + dprintf(fd, "\t\tmountId: %d\n", mnt.mountId); + dprintf(fd, "\t\tnextStorageDirNo: %d\n", mnt.nextStorageDirNo.load()); + dprintf(fd, "\t\tdataLoaderStatus: %d\n", mnt.dataLoaderStatus.load()); + dprintf(fd, "\t\tconnectionLostTime: %s\n", toString(mnt.connectionLostTime)); + if (mnt.savedDataLoaderParams) { + const auto& params = mnt.savedDataLoaderParams.value(); + dprintf(fd, "\t\tsavedDataLoaderParams:\n"); + dprintf(fd, "\t\t\ttype: %s\n", toString(params.type).c_str()); + dprintf(fd, "\t\t\tpackageName: %s\n", params.packageName.c_str()); + dprintf(fd, "\t\t\tclassName: %s\n", params.className.c_str()); + dprintf(fd, "\t\t\targuments: %s\n", params.arguments.c_str()); + dprintf(fd, "\t\t\tdynamicArgs: %d\n", int(params.dynamicArgs.size())); + } + dprintf(fd, "\t\tstorages (%d):\n", int(mnt.storages.size())); + for (auto&& [storageId, storage] : mnt.storages) { + dprintf(fd, "\t\t\t[%d] -> [%s]\n", storageId, storage.name.c_str()); + } + + dprintf(fd, "\t\tbindPoints (%d):\n", int(mnt.bindPoints.size())); + for (auto&& [target, bind] : mnt.bindPoints) { + dprintf(fd, "\t\t\t[%s]->[%d]:\n", target.c_str(), bind.storage); + dprintf(fd, "\t\t\t\tsavedFilename: %s\n", bind.savedFilename.c_str()); + dprintf(fd, "\t\t\t\tsourceDir: %s\n", bind.sourceDir.c_str()); + dprintf(fd, "\t\t\t\tkind: %s\n", toString(bind.kind)); + } + } + + dprintf(fd, "Sorted binds (%d):\n", int(mBindsByPath.size())); + for (auto&& [target, mountPairIt] : mBindsByPath) { + const auto& bind = mountPairIt->second; + dprintf(fd, "\t\t[%s]->[%d]:\n", target.c_str(), bind.storage); + dprintf(fd, "\t\t\tsavedFilename: %s\n", bind.savedFilename.c_str()); + dprintf(fd, "\t\t\tsourceDir: %s\n", bind.sourceDir.c_str()); + dprintf(fd, "\t\t\tkind: %s\n", toString(bind.kind)); + } +} + std::optional<std::future<void>> IncrementalService::onSystemReady() { std::promise<void> threadFinished; if (mSystemReady.exchange(true)) { @@ -1061,6 +1129,122 @@ bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs, return true; } +// Extract lib filse from zip, create new files in incfs and write data to them +bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_view apkFullPath, + std::string_view libDirRelativePath, + std::string_view abi) { + const auto ifs = getIfs(storage); + // First prepare target directories if they don't exist yet + if (auto res = makeDirs(storage, libDirRelativePath, 0755)) { + LOG(ERROR) << "Failed to prepare target lib directory " << libDirRelativePath + << " errno: " << res; + return false; + } + + std::unique_ptr<ZipFileRO> zipFile(ZipFileRO::open(apkFullPath.data())); + if (!zipFile) { + LOG(ERROR) << "Failed to open zip file at " << apkFullPath; + return false; + } + void* cookie = nullptr; + const auto libFilePrefix = path::join(constants().libDir, abi); + if (!zipFile.get()->startIteration(&cookie, libFilePrefix.c_str() /* prefix */, + constants().libSuffix.data() /* suffix */)) { + LOG(ERROR) << "Failed to start zip iteration for " << apkFullPath; + return false; + } + ZipEntryRO entry = nullptr; + bool success = true; + while ((entry = zipFile.get()->nextEntry(cookie)) != nullptr) { + char fileName[PATH_MAX]; + if (zipFile.get()->getEntryFileName(entry, fileName, sizeof(fileName))) { + continue; + } + const auto libName = path::basename(fileName); + const auto targetLibPath = path::join(libDirRelativePath, libName); + const auto targetLibPathAbsolute = normalizePathToStorage(ifs, storage, targetLibPath); + // If the extract file already exists, skip + struct stat st; + if (stat(targetLibPathAbsolute.c_str(), &st) == 0) { + LOG(INFO) << "Native lib file already exists: " << targetLibPath + << "; skipping extraction"; + continue; + } + + uint32_t uncompressedLen; + if (!zipFile.get()->getEntryInfo(entry, nullptr, &uncompressedLen, nullptr, nullptr, + nullptr, nullptr)) { + LOG(ERROR) << "Failed to read native lib entry: " << fileName; + success = false; + break; + } + + // Create new lib file without signature info + incfs::NewFileParams libFileParams; + libFileParams.size = uncompressedLen; + libFileParams.verification.hashAlgorithm = INCFS_HASH_NONE; + // Metadata of the new lib file is its relative path + IncFsSpan libFileMetadata; + libFileMetadata.data = targetLibPath.c_str(); + libFileMetadata.size = targetLibPath.size(); + libFileParams.metadata = libFileMetadata; + incfs::FileId libFileId = idFromMetadata(targetLibPath); + if (auto res = makeFile(storage, targetLibPath, 0777, libFileId, libFileParams)) { + LOG(ERROR) << "Failed to make file for: " << targetLibPath << " errno: " << res; + success = false; + // If one lib file fails to be created, abort others as well + break; + } + + // Write extracted data to new file + std::vector<uint8_t> libData(uncompressedLen); + if (!zipFile.get()->uncompressEntry(entry, &libData[0], uncompressedLen)) { + LOG(ERROR) << "Failed to extract native lib zip entry: " << fileName; + success = false; + break; + } + android::base::unique_fd writeFd(mIncFs->openWrite(ifs->control, libFileId)); + if (writeFd < 0) { + LOG(ERROR) << "Failed to open write fd for: " << targetLibPath << " errno: " << writeFd; + success = false; + break; + } + const int numBlocks = uncompressedLen / constants().blockSize + 1; + std::vector<IncFsDataBlock> instructions; + auto remainingData = std::span(libData); + for (int i = 0; i < numBlocks - 1; i++) { + auto inst = IncFsDataBlock{ + .fileFd = writeFd, + .pageIndex = static_cast<IncFsBlockIndex>(i), + .compression = INCFS_COMPRESSION_KIND_NONE, + .kind = INCFS_BLOCK_KIND_DATA, + .dataSize = static_cast<uint16_t>(constants().blockSize), + .data = reinterpret_cast<const char*>(remainingData.data()), + }; + instructions.push_back(inst); + remainingData = remainingData.subspan(constants().blockSize); + } + // Last block + auto inst = IncFsDataBlock{ + .fileFd = writeFd, + .pageIndex = static_cast<IncFsBlockIndex>(numBlocks - 1), + .compression = INCFS_COMPRESSION_KIND_NONE, + .kind = INCFS_BLOCK_KIND_DATA, + .dataSize = static_cast<uint16_t>(remainingData.size()), + .data = reinterpret_cast<const char*>(remainingData.data()), + }; + instructions.push_back(inst); + size_t res = mIncFs->writeBlocks(instructions); + if (res != instructions.size()) { + LOG(ERROR) << "Failed to write data into: " << targetLibPath; + success = false; + } + instructions.clear(); + } + zipFile.get()->endIteration(cookie); + return success; +} + binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChanged(MountId mountId, int newStatus) { std::unique_lock l(incrementalService.mLock); |