1 /* 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 #pragma once 18 19 #include <android/content/pm/BnDataLoaderStatusListener.h> 20 #include <android/content/pm/DataLoaderParamsParcel.h> 21 #include <android/content/pm/FileSystemControlParcel.h> 22 #include <android/content/pm/IDataLoaderStatusListener.h> 23 #include <android/os/incremental/BnIncrementalService.h> 24 #include <android/os/incremental/BnIncrementalServiceConnector.h> 25 #include <android/os/incremental/BnStorageHealthListener.h> 26 #include <android/os/incremental/BnStorageLoadingProgressListener.h> 27 #include <android/os/incremental/PerUidReadTimeouts.h> 28 #include <android/os/incremental/StorageHealthCheckParams.h> 29 #include <binder/IAppOpsCallback.h> 30 #include <binder/PersistableBundle.h> 31 #include <utils/String16.h> 32 #include <utils/StrongPointer.h> 33 #include <ziparchive/zip_archive.h> 34 35 #include <atomic> 36 #include <chrono> 37 #include <condition_variable> 38 #include <functional> 39 #include <limits> 40 #include <map> 41 #include <mutex> 42 #include <set> 43 #include <span> 44 #include <string> 45 #include <string_view> 46 #include <thread> 47 #include <unordered_map> 48 #include <unordered_set> 49 #include <utility> 50 #include <vector> 51 52 #include "ServiceWrappers.h" 53 #include "incfs.h" 54 #include "path.h" 55 56 namespace android::incremental { 57 58 using MountId = int; 59 using StorageId = int; 60 using FileId = incfs::FileId; 61 using BlockIndex = incfs::BlockIndex; 62 using RawMetadata = incfs::RawMetadata; 63 using Seconds = std::chrono::seconds; 64 using BootClockTsUs = uint64_t; 65 66 using IDataLoaderStatusListener = ::android::content::pm::IDataLoaderStatusListener; 67 using DataLoaderStatusListener = ::android::sp<IDataLoaderStatusListener>; 68 69 using StorageHealthCheckParams = ::android::os::incremental::StorageHealthCheckParams; 70 using IStorageHealthListener = ::android::os::incremental::IStorageHealthListener; 71 using StorageHealthListener = ::android::sp<IStorageHealthListener>; 72 using IStorageLoadingProgressListener = ::android::os::incremental::IStorageLoadingProgressListener; 73 using StorageLoadingProgressListener = ::android::sp<IStorageLoadingProgressListener>; 74 75 using PerUidReadTimeouts = ::android::os::incremental::PerUidReadTimeouts; 76 77 struct IfsState { 78 // If mount is fully loaded. 79 bool fullyLoaded = false; 80 // If read logs are enabled on this mount. Populated only if fullyLoaded == true. 81 bool readLogsEnabled = false; 82 // If there was an error fetching any of the above. 83 bool error = false; 84 }; 85 // Returns true if wants to be called again. 86 using IfsStateCallback = std::function<bool(StorageId, IfsState)>; 87 88 class IncrementalService final { 89 public: 90 explicit IncrementalService(ServiceManagerWrapper&& sm, std::string_view rootDir); 91 92 #pragma GCC diagnostic push 93 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" 94 ~IncrementalService(); 95 #pragma GCC diagnostic pop 96 97 static constexpr StorageId kInvalidStorageId = -1; 98 static constexpr StorageId kMaxStorageId = std::numeric_limits<int>::max() - 1; 99 static constexpr StorageId kAllStoragesId = kMaxStorageId + 1; 100 101 static constexpr BootClockTsUs kMaxBootClockTsUs = std::numeric_limits<BootClockTsUs>::max(); 102 103 enum CreateOptions { 104 TemporaryBind = 1, 105 PermanentBind = 2, 106 CreateNew = 4, 107 OpenExisting = 8, 108 109 Default = TemporaryBind | CreateNew 110 }; 111 112 enum class BindKind { 113 Temporary = 0, 114 Permanent = 1, 115 }; 116 117 enum StorageFlags { 118 ReadLogsAllowed = 1 << 0, 119 ReadLogsEnabled = 1 << 1, 120 ReadLogsRequested = 1 << 2, 121 122 ReadTimeoutsEnabled = 1 << 3, 123 ReadTimeoutsRequested = 1 << 4, 124 }; 125 126 struct LoadingProgress { 127 ssize_t filledBlocks; 128 ssize_t totalBlocks; 129 isErrorLoadingProgress130 bool isError() const { return totalBlocks < 0; } startedLoadingProgress131 bool started() const { return totalBlocks > 0; } fullyLoadedLoadingProgress132 bool fullyLoaded() const { return !isError() && (totalBlocks == filledBlocks); } 133 blocksRemainingOrErrorLoadingProgress134 int blocksRemainingOrError() const { 135 return totalBlocks <= 0 ? totalBlocks : totalBlocks - filledBlocks; 136 } 137 getProgressLoadingProgress138 float getProgress() const { 139 return totalBlocks < 0 140 ? totalBlocks 141 : totalBlocks > 0 ? double(filledBlocks) / double(totalBlocks) : 1.f; 142 } 143 }; 144 145 static FileId idFromMetadata(std::span<const uint8_t> metadata); idFromMetadata(std::span<const char> metadata)146 static inline FileId idFromMetadata(std::span<const char> metadata) { 147 return idFromMetadata({(const uint8_t*)metadata.data(), metadata.size()}); 148 } 149 150 void onDump(int fd); 151 152 void onSystemReady(); 153 154 StorageId createStorage(std::string_view mountPoint, 155 content::pm::DataLoaderParamsParcel dataLoaderParams, 156 CreateOptions options); 157 StorageId createLinkedStorage(std::string_view mountPoint, StorageId linkedStorage, 158 CreateOptions options = CreateOptions::Default); 159 StorageId openStorage(std::string_view path); 160 161 bool startLoading(StorageId storage, content::pm::DataLoaderParamsParcel dataLoaderParams, 162 DataLoaderStatusListener statusListener, 163 const StorageHealthCheckParams& healthCheckParams, 164 StorageHealthListener healthListener, 165 std::vector<PerUidReadTimeouts> perUidReadTimeouts); 166 void onInstallationComplete(StorageId storage); 167 168 int bind(StorageId storage, std::string_view source, std::string_view target, BindKind kind); 169 int unbind(StorageId storage, std::string_view target); 170 void deleteStorage(StorageId storage); 171 172 void disallowReadLogs(StorageId storage); 173 int setStorageParams(StorageId storage, bool enableReadLogs); 174 175 int makeFile(StorageId storage, std::string_view path, int mode, FileId id, 176 incfs::NewFileParams params, std::span<const uint8_t> data); 177 int makeDir(StorageId storage, std::string_view path, int mode = 0755); 178 int makeDirs(StorageId storage, std::string_view path, int mode = 0755); 179 180 int link(StorageId sourceStorageId, std::string_view oldPath, StorageId destStorageId, 181 std::string_view newPath); 182 int unlink(StorageId storage, std::string_view path); 183 184 incfs::LoadingState isFileFullyLoaded(StorageId storage, std::string_view filePath) const; 185 incfs::LoadingState isMountFullyLoaded(StorageId storage) const; 186 187 LoadingProgress getLoadingProgress(StorageId storage) const; 188 189 bool registerLoadingProgressListener(StorageId storage, 190 StorageLoadingProgressListener progressListener); 191 bool unregisterLoadingProgressListener(StorageId storage); 192 193 RawMetadata getMetadata(StorageId storage, std::string_view path) const; 194 RawMetadata getMetadata(StorageId storage, FileId node) const; 195 196 bool configureNativeBinaries(StorageId storage, std::string_view apkFullPath, 197 std::string_view libDirRelativePath, std::string_view abi, 198 bool extractNativeLibs); 199 bool waitForNativeBinariesExtraction(StorageId storage); 200 201 void getMetrics(int32_t storageId, android::os::PersistableBundle* _aidl_return); 202 203 class AppOpsListener : public android::BnAppOpsCallback { 204 public: AppOpsListener(IncrementalService & incrementalService,std::string packageName)205 AppOpsListener(IncrementalService& incrementalService, std::string packageName) 206 : incrementalService(incrementalService), packageName(std::move(packageName)) {} 207 void opChanged(int32_t op, const String16& packageName) final; 208 209 private: 210 IncrementalService& incrementalService; 211 const std::string packageName; 212 }; 213 214 class IncrementalServiceConnector : public os::incremental::BnIncrementalServiceConnector { 215 public: IncrementalServiceConnector(IncrementalService & incrementalService,int32_t storage)216 IncrementalServiceConnector(IncrementalService& incrementalService, int32_t storage) 217 : incrementalService(incrementalService), storage(storage) {} 218 binder::Status setStorageParams(bool enableReadLogs, int32_t* _aidl_return) final; 219 220 private: 221 IncrementalService& incrementalService; 222 int32_t const storage; 223 }; 224 225 private: 226 struct IncFsMount; 227 228 class DataLoaderStub : public content::pm::BnDataLoaderStatusListener { 229 public: 230 DataLoaderStub(IncrementalService& service, MountId id, 231 content::pm::DataLoaderParamsParcel&& params, 232 content::pm::FileSystemControlParcel&& control, 233 DataLoaderStatusListener&& statusListener, 234 const StorageHealthCheckParams& healthCheckParams, 235 StorageHealthListener&& healthListener, std::string&& healthPath); 236 ~DataLoaderStub(); 237 // Cleans up the internal state and invalidates DataLoaderStub. Any subsequent calls will 238 // result in an error. 239 void cleanupResources(); 240 241 bool requestCreate(); 242 bool requestStart(); 243 bool requestDestroy(); 244 245 void onDump(int fd); 246 id()247 MountId id() const { return mId.load(std::memory_order_relaxed); } params()248 const content::pm::DataLoaderParamsParcel& params() const { return mParams; } 249 bool isSystemDataLoader() const; 250 void setHealthListener(const StorageHealthCheckParams& healthCheckParams, 251 StorageHealthListener&& healthListener); 252 void getMetrics(android::os::PersistableBundle* _aidl_return); 253 254 private: 255 binder::Status onStatusChanged(MountId mount, int newStatus) final; 256 257 void setCurrentStatus(int newStatus); 258 void compareAndSetCurrentStatus(int expectedStatus, int newStatus); 259 260 sp<content::pm::IDataLoader> getDataLoader(); 261 262 bool bind(); 263 bool create(); 264 bool start(); 265 bool destroy(); 266 267 bool setTargetStatus(int status); 268 void setTargetStatusLocked(int status); 269 270 bool fsmStep(); 271 272 void onHealthStatus(const StorageHealthListener& healthListener, int healthStatus); 273 void updateHealthStatus(bool baseline = false); 274 isValid()275 bool isValid() const { return id() != kInvalidStorageId; } 276 277 bool isHealthParamsValid() const; 278 279 const incfs::UniqueControl& initializeHealthControl(); 280 void resetHealthControl(); 281 282 BootClockTsUs getOldestPendingReadTs(); 283 BootClockTsUs getOldestTsFromLastPendingReads(); 284 Milliseconds elapsedMsSinceKernelTs(TimePoint now, BootClockTsUs kernelTsUs); 285 long elapsedMsSinceOldestPendingRead(); 286 287 // If the stub has to bind to the DL. 288 // Returns {} if bind operation is already in progress. 289 // Or bind delay in ms. 290 std::optional<Milliseconds> needToBind(); 291 292 void registerForPendingReads(); 293 void unregisterFromPendingReads(); 294 295 IncrementalService& mService; 296 297 std::mutex mMutex; 298 std::atomic<MountId> mId = kInvalidStorageId; 299 content::pm::DataLoaderParamsParcel mParams; 300 content::pm::FileSystemControlParcel mControl; 301 DataLoaderStatusListener mStatusListener; 302 StorageHealthListener mHealthListener; 303 std::atomic<int> mHealthStatus = IStorageHealthListener::HEALTH_STATUS_OK; 304 305 std::condition_variable mStatusCondition; 306 int mCurrentStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED; 307 TimePoint mCurrentStatusTs = {}; 308 int mTargetStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED; 309 TimePoint mTargetStatusTs = {}; 310 311 TimePoint mPreviousBindTs = {}; 312 Milliseconds mPreviousBindDelay = {}; 313 314 std::string mHealthPath; 315 incfs::UniqueControl mHealthControl; 316 struct { 317 TimePoint userTs; 318 BootClockTsUs kernelTsUs; 319 } mHealthBase = {TimePoint::max(), kMaxBootClockTsUs}; 320 StorageHealthCheckParams mHealthCheckParams; 321 std::vector<incfs::ReadInfoWithUid> mLastPendingReads; 322 }; 323 using DataLoaderStubPtr = sp<DataLoaderStub>; 324 325 struct IncFsMount { 326 struct Bind { 327 StorageId storage; 328 std::string savedFilename; 329 std::string sourceDir; 330 BindKind kind; 331 }; 332 333 struct Storage { 334 std::string name; 335 }; 336 337 using Control = incfs::UniqueControl; 338 339 using BindMap = std::map<std::string, Bind, path::PathLess>; 340 using StorageMap = std::unordered_map<StorageId, Storage>; 341 342 mutable std::mutex lock; 343 const std::string root; 344 const std::string metricsKey; 345 Control control; 346 /*const*/ MountId mountId; 347 int32_t flags = StorageFlags::ReadLogsAllowed; 348 StorageMap storages; 349 BindMap bindPoints; 350 DataLoaderStubPtr dataLoaderStub; 351 TimePoint startLoadingTs = {}; 352 std::atomic<int> nextStorageDirNo{0}; 353 const IncrementalService& incrementalService; 354 IncFsMountIncFsMount355 IncFsMount(std::string root, std::string metricsKey, MountId mountId, Control control, 356 const IncrementalService& incrementalService) 357 : root(std::move(root)), 358 metricsKey(std::move(metricsKey)), 359 control(std::move(control)), 360 mountId(mountId), 361 incrementalService(incrementalService) {} 362 IncFsMount(IncFsMount&&) = delete; 363 IncFsMount& operator=(IncFsMount&&) = delete; 364 ~IncFsMount(); 365 366 StorageMap::iterator makeStorage(StorageId id); 367 disallowReadLogsIncFsMount368 void disallowReadLogs() { flags &= ~StorageFlags::ReadLogsAllowed; } readLogsAllowedIncFsMount369 int32_t readLogsAllowed() const { return (flags & StorageFlags::ReadLogsAllowed); } 370 setReadLogsEnabledIncFsMount371 void setReadLogsEnabled(bool value) { 372 return setFlag(StorageFlags::ReadLogsEnabled, value); 373 } readLogsEnabledIncFsMount374 int32_t readLogsEnabled() const { return (flags & StorageFlags::ReadLogsEnabled); } 375 setReadLogsRequestedIncFsMount376 void setReadLogsRequested(bool value) { 377 return setFlag(StorageFlags::ReadLogsRequested, value); 378 } readLogsRequestedIncFsMount379 int32_t readLogsRequested() const { return (flags & StorageFlags::ReadLogsRequested); } 380 setReadTimeoutsEnabledIncFsMount381 void setReadTimeoutsEnabled(bool value) { 382 return setFlag(StorageFlags::ReadTimeoutsEnabled, value); 383 } readTimeoutsEnabledIncFsMount384 int32_t readTimeoutsEnabled() const { return (flags & StorageFlags::ReadTimeoutsEnabled); } 385 setReadTimeoutsRequestedIncFsMount386 void setReadTimeoutsRequested(bool value) { 387 return setFlag(StorageFlags::ReadTimeoutsRequested, value); 388 } readTimeoutsRequestedIncFsMount389 int32_t readTimeoutsRequested() const { 390 return (flags & StorageFlags::ReadTimeoutsRequested); 391 } 392 393 static void cleanupFilesystem(std::string_view root); 394 395 private: 396 void setFlag(StorageFlags flag, bool value); 397 }; 398 399 using IfsMountPtr = std::shared_ptr<IncFsMount>; 400 using MountMap = std::unordered_map<MountId, IfsMountPtr>; 401 using BindPathMap = std::map<std::string, IncFsMount::BindMap::iterator, path::PathLess>; 402 403 static bool perfLoggingEnabled(); 404 405 void setUidReadTimeouts(StorageId storage, 406 std::vector<PerUidReadTimeouts>&& perUidReadTimeouts); 407 void clearUidReadTimeouts(StorageId storage); 408 bool checkUidReadTimeouts(StorageId storage, IfsState state, Clock::time_point timeLimit); 409 410 std::unordered_set<std::string_view> adoptMountedInstances(); 411 void mountExistingImages(const std::unordered_set<std::string_view>& mountedRootNames); 412 bool mountExistingImage(std::string_view root); 413 414 IfsMountPtr getIfs(StorageId storage) const; 415 const IfsMountPtr& getIfsLocked(StorageId storage) const; 416 int addBindMount(IncFsMount& ifs, StorageId storage, std::string_view storageRoot, 417 std::string&& source, std::string&& target, BindKind kind, 418 std::unique_lock<std::mutex>& mainLock); 419 420 int addBindMountWithMd(IncFsMount& ifs, StorageId storage, std::string&& metadataName, 421 std::string&& source, std::string&& target, BindKind kind, 422 std::unique_lock<std::mutex>& mainLock); 423 424 void addBindMountRecordLocked(IncFsMount& ifs, StorageId storage, std::string&& metadataName, 425 std::string&& source, std::string&& target, BindKind kind); 426 427 bool needStartDataLoaderLocked(IncFsMount& ifs); 428 429 void prepareDataLoaderLocked(IncFsMount& ifs, content::pm::DataLoaderParamsParcel&& params, 430 DataLoaderStatusListener&& statusListener = {}, 431 const StorageHealthCheckParams& healthCheckParams = {}, 432 StorageHealthListener&& healthListener = {}); 433 434 BindPathMap::const_iterator findStorageLocked(std::string_view path) const; 435 StorageId findStorageId(std::string_view path) const; 436 437 void deleteStorage(IncFsMount& ifs); 438 void deleteStorageLocked(IncFsMount& ifs, std::unique_lock<std::mutex>&& ifsLock); 439 MountMap::iterator getStorageSlotLocked(); 440 std::string normalizePathToStorage(const IncFsMount& incfs, StorageId storage, 441 std::string_view path) const; 442 std::string normalizePathToStorageLocked(const IncFsMount& incfs, 443 IncFsMount::StorageMap::const_iterator storageIt, 444 std::string_view path) const; 445 int makeDirs(const IncFsMount& ifs, StorageId storageId, std::string_view path, int mode); 446 447 int disableReadLogsLocked(IncFsMount& ifs); 448 int applyStorageParamsLocked(IncFsMount& ifs); 449 450 LoadingProgress getLoadingProgressFromPath(const IncFsMount& ifs, std::string_view path) const; 451 452 int setFileContent(const IfsMountPtr& ifs, const incfs::FileId& fileId, 453 std::string_view debugFilePath, std::span<const uint8_t> data) const; 454 455 void registerAppOpsCallback(const std::string& packageName); 456 bool unregisterAppOpsCallback(const std::string& packageName); 457 void onAppOpChanged(const std::string& packageName); 458 459 void runJobProcessing(); 460 void extractZipFile(const IfsMountPtr& ifs, ZipArchiveHandle zipFile, ZipEntry& entry, 461 const incfs::FileId& libFileId, std::string_view debugLibPath, 462 Clock::time_point scheduledTs); 463 464 void runCmdLooper(); 465 466 bool addTimedJob(TimedQueueWrapper& timedQueue, MountId id, Milliseconds after, Job what); 467 bool removeTimedJobs(TimedQueueWrapper& timedQueue, MountId id); 468 469 void addIfsStateCallback(StorageId storageId, IfsStateCallback callback); 470 void removeIfsStateCallbacks(StorageId storageId); 471 void processIfsStateCallbacks(); 472 void processIfsStateCallbacks(StorageId storageId, std::vector<IfsStateCallback>& callbacks); 473 474 bool updateLoadingProgress(int32_t storageId, 475 StorageLoadingProgressListener&& progressListener); 476 477 void trimReservedSpaceV1(const IncFsMount& ifs); 478 int64_t elapsedUsSinceMonoTs(uint64_t monoTsUs); 479 480 private: 481 const std::unique_ptr<VoldServiceWrapper> mVold; 482 const std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager; 483 const std::unique_ptr<IncFsWrapper> mIncFs; 484 const std::unique_ptr<AppOpsManagerWrapper> mAppOpsManager; 485 const std::unique_ptr<JniWrapper> mJni; 486 const std::unique_ptr<LooperWrapper> mLooper; 487 const std::unique_ptr<TimedQueueWrapper> mTimedQueue; 488 const std::unique_ptr<TimedQueueWrapper> mProgressUpdateJobQueue; 489 const std::unique_ptr<FsWrapper> mFs; 490 const std::unique_ptr<ClockWrapper> mClock; 491 const std::string mIncrementalDir; 492 493 mutable std::mutex mLock; 494 mutable std::mutex mMountOperationLock; 495 MountMap mMounts; 496 BindPathMap mBindsByPath; 497 498 std::mutex mCallbacksLock; 499 std::unordered_map<std::string, sp<AppOpsListener>> mCallbackRegistered; 500 501 using IfsStateCallbacks = std::map<StorageId, std::vector<IfsStateCallback>>; 502 std::mutex mIfsStateCallbacksLock; 503 IfsStateCallbacks mIfsStateCallbacks; 504 505 std::atomic_bool mSystemReady = false; 506 StorageId mNextId = 0; 507 508 std::atomic_bool mRunning{true}; 509 510 std::unordered_map<MountId, std::vector<Job>> mJobQueue; 511 MountId mPendingJobsMount = kInvalidStorageId; 512 std::condition_variable mJobCondition; 513 std::mutex mJobMutex; 514 std::thread mJobProcessor; 515 516 std::thread mCmdLooperThread; 517 }; 518 519 } // namespace android::incremental 520