diff options
Diffstat (limited to 'services/incremental/IncrementalService.cpp')
-rw-r--r-- | services/incremental/IncrementalService.cpp | 103 |
1 files changed, 95 insertions, 8 deletions
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index 56cb3d11d552..2fa927bcccfd 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -66,9 +66,19 @@ struct Constants { static constexpr auto blockSize = 4096; static constexpr auto systemPackage = "android"sv; + static constexpr auto userStatusDelay = 100ms; + static constexpr auto progressUpdateInterval = 1000ms; static constexpr auto perUidTimeoutOffset = progressUpdateInterval * 2; static constexpr auto minPerUidTimeout = progressUpdateInterval * 3; + + // If DL was up and not crashing for 10mins, we consider it healthy and reset all delays. + static constexpr auto healthyDataLoaderUptime = 10min; + // 10s, 100s (~2min), 1000s (~15min), 10000s (~3hrs) + static constexpr auto minBindDelay = 10s; + static constexpr auto maxBindDelay = 10000s; + static constexpr auto bindDelayMultiplier = 10; + static constexpr auto bindDelayJitterDivider = 10; }; static const Constants& constants() { @@ -386,6 +396,28 @@ void IncrementalService::onDump(int fd) { dprintf(fd, "}\n"); } +bool IncrementalService::needStartDataLoaderLocked(IncFsMount& ifs) { + if (ifs.dataLoaderStub->params().packageName == Constants::systemPackage) { + return true; + } + + // Check all permanent binds. + for (auto&& [_, bindPoint] : ifs.bindPoints) { + if (bindPoint.kind != BindKind::Permanent) { + continue; + } + const auto progress = getLoadingProgressFromPath(ifs, bindPoint.sourceDir, + /*stopOnFirstIncomplete=*/true); + if (!progress.isError() && !progress.fullyLoaded()) { + LOG(INFO) << "Non system mount: [" << bindPoint.sourceDir + << "], partial progress: " << progress.getProgress() * 100 << "%"; + return true; + } + } + + return false; +} + void IncrementalService::onSystemReady() { if (mSystemReady.exchange(true)) { return; @@ -396,8 +428,11 @@ void IncrementalService::onSystemReady() { std::lock_guard l(mLock); mounts.reserve(mMounts.size()); for (auto&& [id, ifs] : mMounts) { - if (ifs->mountId == id && - ifs->dataLoaderStub->params().packageName == Constants::systemPackage) { + if (ifs->mountId != id) { + continue; + } + + if (needStartDataLoaderLocked(*ifs)) { mounts.push_back(ifs); } } @@ -1539,6 +1574,11 @@ static long elapsedMcs(Duration start, Duration end) { return std::chrono::duration_cast<std::chrono::microseconds>(end - start).count(); } +template <class Duration> +static constexpr auto castToMs(Duration d) { + return std::chrono::duration_cast<std::chrono::milliseconds>(d); +} + // Extract lib files from zip, create new files in incfs and write data to them // Lib files should be placed next to the APK file in the following matter: // Example: @@ -2134,9 +2174,43 @@ void IncrementalService::DataLoaderStub::setTargetStatusLocked(int status) { << status << " (current " << mCurrentStatus << ")"; } +Milliseconds IncrementalService::DataLoaderStub::updateBindDelay() { + std::unique_lock lock(mMutex); + const auto previousBindTs = mPreviousBindTs; + const auto now = Clock::now(); + mPreviousBindTs = now; + + const auto nonCrashingInterval = std::max(castToMs(now - previousBindTs), 100ms); + if (previousBindTs.time_since_epoch() == Clock::duration::zero() || + nonCrashingInterval > Constants::healthyDataLoaderUptime) { + mPreviousBindDelay = 0ms; + return mPreviousBindDelay; + } + + constexpr auto minBindDelayMs = castToMs(Constants::minBindDelay); + constexpr auto maxBindDelayMs = castToMs(Constants::maxBindDelay); + + const auto bindDelayMs = + std::min(std::max(mPreviousBindDelay * Constants::bindDelayMultiplier, minBindDelayMs), + maxBindDelayMs) + .count(); + const auto bindDelayJitterRangeMs = bindDelayMs / Constants::bindDelayJitterDivider; + const auto bindDelayJitterMs = rand() % (bindDelayJitterRangeMs * 2) - bindDelayJitterRangeMs; + mPreviousBindDelay = std::chrono::milliseconds(bindDelayMs + bindDelayJitterMs); + + return mPreviousBindDelay; +} + bool IncrementalService::DataLoaderStub::bind() { + const auto bindDelay = updateBindDelay(); + if (bindDelay > 1s) { + LOG(INFO) << "Delaying bind to " << mParams.packageName << " by " + << bindDelay.count() / 1000 << "s"; + } + bool result = false; - auto status = mService.mDataLoaderManager->bindToDataLoader(id(), mParams, this, &result); + auto status = mService.mDataLoaderManager->bindToDataLoader(id(), mParams, bindDelay.count(), + this, &result); if (!status.isOk() || !result) { LOG(ERROR) << "Failed to bind a data loader for mount " << id(); return false; @@ -2234,13 +2308,24 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount LOG(ERROR) << "Mount ID mismatch: expected " << id() << ", but got: " << mountId; return binder::Status::fromServiceSpecificError(-EPERM, "Mount ID mismatch."); } + if (newStatus == IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE) { + // User-provided status, let's postpone the handling to avoid possible deadlocks. + mService.addTimedJob(*mService.mTimedQueue, id(), Constants::userStatusDelay, + [this, newStatus]() { setCurrentStatus(newStatus); }); + return binder::Status::ok(); + } + setCurrentStatus(newStatus); + return binder::Status::ok(); +} + +void IncrementalService::DataLoaderStub::setCurrentStatus(int newStatus) { int targetStatus, oldStatus; DataLoaderStatusListener listener; { std::unique_lock lock(mMutex); if (mCurrentStatus == newStatus) { - return binder::Status::ok(); + return; } oldStatus = mCurrentStatus; @@ -2249,7 +2334,8 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount listener = mStatusListener; - if (mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE) { + if (mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE || + mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNRECOVERABLE) { // For unavailable, unbind from DataLoader to ensure proper re-commit. setTargetStatusLocked(IDataLoaderStatusListener::DATA_LOADER_DESTROYED); } @@ -2259,14 +2345,12 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount << newStatus << " (target " << targetStatus << ")"; if (listener) { - listener->onStatusChanged(mountId, newStatus); + listener->onStatusChanged(id(), newStatus); } fsmStep(); mStatusCondition.notify_all(); - - return binder::Status::ok(); } binder::Status IncrementalService::DataLoaderStub::reportStreamHealth(MountId mountId, @@ -2544,6 +2628,9 @@ void IncrementalService::DataLoaderStub::onDump(int fd) { dprintf(fd, " blockIndex: %d\n", pendingRead.block); dprintf(fd, " bootClockTsUs: %lld\n", (long long)pendingRead.bootClockTsUs); } + dprintf(fd, " bind: %llds ago (delay: %llds)\n", + (long long)(elapsedMcs(mPreviousBindTs, Clock::now()) / 1000000), + (long long)(mPreviousBindDelay.count() / 1000)); dprintf(fd, " }\n"); const auto& params = mParams; dprintf(fd, " dataLoaderParams: {\n"); |