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/AppOpsManager.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 com::android::internal::app::BnAppOpsCallback { 204 public: AppOpsListener(IncrementalService & incrementalService,std::string packageName)205 AppOpsListener(IncrementalService& incrementalService, std::string packageName) 206 : incrementalService(incrementalService), packageName(std::move(packageName)) {} 207 binder::Status opChanged(int32_t op, int32_t uid, const String16& packageName, 208 const String16& persistentDeviceId) final; 209 210 private: 211 IncrementalService& incrementalService; 212 const std::string packageName; 213 }; 214 215 class IncrementalServiceConnector : public os::incremental::BnIncrementalServiceConnector { 216 public: IncrementalServiceConnector(IncrementalService & incrementalService,int32_t storage)217 IncrementalServiceConnector(IncrementalService& incrementalService, int32_t storage) 218 : incrementalService(incrementalService), storage(storage) {} 219 binder::Status setStorageParams(bool enableReadLogs, int32_t* _aidl_return) final; 220 221 private: 222 IncrementalService& incrementalService; 223 int32_t const storage; 224 }; 225 226 private: 227 struct IncFsMount; 228 229 class DataLoaderStub : public content::pm::BnDataLoaderStatusListener { 230 public: 231 DataLoaderStub(IncrementalService& service, MountId id, 232 content::pm::DataLoaderParamsParcel&& params, 233 content::pm::FileSystemControlParcel&& control, 234 DataLoaderStatusListener&& statusListener, 235 const StorageHealthCheckParams& healthCheckParams, 236 StorageHealthListener&& healthListener, std::string&& healthPath); 237 ~DataLoaderStub(); 238 // Cleans up the internal state and invalidates DataLoaderStub. Any subsequent calls will 239 // result in an error. 240 void cleanupResources(); 241 242 bool requestCreate(); 243 bool requestStart(); 244 bool requestDestroy(); 245 246 void onDump(int fd); 247 id()248 MountId id() const { return mId.load(std::memory_order_relaxed); } params()249 const content::pm::DataLoaderParamsParcel& params() const { return mParams; } 250 bool isSystemDataLoader() const; 251 void setHealthListener(const StorageHealthCheckParams& healthCheckParams, 252 StorageHealthListener&& healthListener); 253 void getMetrics(android::os::PersistableBundle* _aidl_return); 254 255 private: 256 binder::Status onStatusChanged(MountId mount, int newStatus) final; 257 258 void setCurrentStatus(int newStatus); 259 void compareAndSetCurrentStatus(int expectedStatus, int newStatus); 260 261 sp<content::pm::IDataLoader> getDataLoader(); 262 263 bool bind(); 264 bool create(); 265 bool start(); 266 bool destroy(); 267 268 bool setTargetStatus(int status); 269 void setTargetStatusLocked(int status); 270 271 bool fsmStep(); 272 273 void onHealthStatus(const StorageHealthListener& healthListener, int healthStatus); 274 void updateHealthStatus(bool baseline = false); 275 isValid()276 bool isValid() const { return id() != kInvalidStorageId; } 277 278 bool isHealthParamsValid() const; 279 280 const incfs::UniqueControl& initializeHealthControl(); 281 void resetHealthControl(); 282 283 BootClockTsUs getOldestPendingReadTs(); 284 BootClockTsUs getOldestTsFromLastPendingReads(); 285 Milliseconds elapsedMsSinceKernelTs(TimePoint now, BootClockTsUs kernelTsUs); 286 long elapsedMsSinceOldestPendingRead(); 287 288 // If the stub has to bind to the DL. 289 // Returns {} if bind operation is already in progress. 290 // Or bind delay in ms. 291 std::optional<Milliseconds> needToBind(); 292 293 void registerForPendingReads(); 294 void unregisterFromPendingReads(); 295 296 IncrementalService& mService; 297 298 std::mutex mMutex; 299 std::atomic<MountId> mId = kInvalidStorageId; 300 content::pm::DataLoaderParamsParcel mParams; 301 content::pm::FileSystemControlParcel mControl; 302 DataLoaderStatusListener mStatusListener; 303 StorageHealthListener mHealthListener; 304 std::atomic<int> mHealthStatus = IStorageHealthListener::HEALTH_STATUS_OK; 305 306 std::condition_variable mStatusCondition; 307 int mCurrentStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED; 308 TimePoint mCurrentStatusTs = {}; 309 int mTargetStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED; 310 TimePoint mTargetStatusTs = {}; 311 312 TimePoint mPreviousBindTs = {}; 313 Milliseconds mPreviousBindDelay = {}; 314 315 std::string mHealthPath; 316 incfs::UniqueControl mHealthControl; 317 struct { 318 TimePoint userTs; 319 BootClockTsUs kernelTsUs; 320 } mHealthBase = {TimePoint::max(), kMaxBootClockTsUs}; 321 StorageHealthCheckParams mHealthCheckParams; 322 std::vector<incfs::ReadInfoWithUid> mLastPendingReads; 323 }; 324 using DataLoaderStubPtr = sp<DataLoaderStub>; 325 326 struct IncFsMount { 327 struct Bind { 328 StorageId storage; 329 std::string savedFilename; 330 std::string sourceDir; 331 BindKind kind; 332 }; 333 334 struct Storage { 335 std::string name; 336 }; 337 338 using Control = incfs::UniqueControl; 339 340 using BindMap = std::map<std::string, Bind, path::PathLess>; 341 using StorageMap = std::unordered_map<StorageId, Storage>; 342 343 mutable std::mutex lock; 344 const std::string root; 345 const std::string metricsKey; 346 Control control; 347 /*const*/ MountId mountId; 348 int32_t flags = StorageFlags::ReadLogsAllowed; 349 StorageMap storages; 350 BindMap bindPoints; 351 DataLoaderStubPtr dataLoaderStub; 352 TimePoint startLoadingTs = {}; 353 std::atomic<int> nextStorageDirNo{0}; 354 const IncrementalService& incrementalService; 355 IncFsMountIncFsMount356 IncFsMount(std::string root, std::string metricsKey, MountId mountId, Control control, 357 const IncrementalService& incrementalService) 358 : root(std::move(root)), 359 metricsKey(std::move(metricsKey)), 360 control(std::move(control)), 361 mountId(mountId), 362 incrementalService(incrementalService) {} 363 IncFsMount(IncFsMount&&) = delete; 364 IncFsMount& operator=(IncFsMount&&) = delete; 365 ~IncFsMount(); 366 367 StorageMap::iterator makeStorage(StorageId id); 368 disallowReadLogsIncFsMount369 void disallowReadLogs() { flags &= ~StorageFlags::ReadLogsAllowed; } readLogsAllowedIncFsMount370 int32_t readLogsAllowed() const { return (flags & StorageFlags::ReadLogsAllowed); } 371 setReadLogsEnabledIncFsMount372 void setReadLogsEnabled(bool value) { 373 return setFlag(StorageFlags::ReadLogsEnabled, value); 374 } readLogsEnabledIncFsMount375 int32_t readLogsEnabled() const { return (flags & StorageFlags::ReadLogsEnabled); } 376 setReadLogsRequestedIncFsMount377 void setReadLogsRequested(bool value) { 378 return setFlag(StorageFlags::ReadLogsRequested, value); 379 } readLogsRequestedIncFsMount380 int32_t readLogsRequested() const { return (flags & StorageFlags::ReadLogsRequested); } 381 setReadTimeoutsEnabledIncFsMount382 void setReadTimeoutsEnabled(bool value) { 383 return setFlag(StorageFlags::ReadTimeoutsEnabled, value); 384 } readTimeoutsEnabledIncFsMount385 int32_t readTimeoutsEnabled() const { return (flags & StorageFlags::ReadTimeoutsEnabled); } 386 setReadTimeoutsRequestedIncFsMount387 void setReadTimeoutsRequested(bool value) { 388 return setFlag(StorageFlags::ReadTimeoutsRequested, value); 389 } readTimeoutsRequestedIncFsMount390 int32_t readTimeoutsRequested() const { 391 return (flags & StorageFlags::ReadTimeoutsRequested); 392 } 393 394 static void cleanupFilesystem(std::string_view root); 395 396 private: 397 void setFlag(StorageFlags flag, bool value); 398 }; 399 400 using IfsMountPtr = std::shared_ptr<IncFsMount>; 401 using MountMap = std::unordered_map<MountId, IfsMountPtr>; 402 using BindPathMap = std::map<std::string, IncFsMount::BindMap::iterator, path::PathLess>; 403 404 static bool perfLoggingEnabled(); 405 406 void setUidReadTimeouts(StorageId storage, 407 std::vector<PerUidReadTimeouts>&& perUidReadTimeouts); 408 void clearUidReadTimeouts(StorageId storage); 409 bool checkUidReadTimeouts(StorageId storage, IfsState state, Clock::time_point timeLimit); 410 411 std::unordered_set<std::string_view> adoptMountedInstances(); 412 void mountExistingImages(const std::unordered_set<std::string_view>& mountedRootNames); 413 bool mountExistingImage(std::string_view root); 414 415 IfsMountPtr getIfs(StorageId storage) const; 416 const IfsMountPtr& getIfsLocked(StorageId storage) const; 417 int addBindMount(IncFsMount& ifs, StorageId storage, std::string_view storageRoot, 418 std::string&& source, std::string&& target, BindKind kind, 419 std::unique_lock<std::mutex>& mainLock); 420 421 int addBindMountWithMd(IncFsMount& ifs, StorageId storage, std::string&& metadataName, 422 std::string&& source, std::string&& target, BindKind kind, 423 std::unique_lock<std::mutex>& mainLock); 424 425 void addBindMountRecordLocked(IncFsMount& ifs, StorageId storage, std::string&& metadataName, 426 std::string&& source, std::string&& target, BindKind kind); 427 428 bool needStartDataLoaderLocked(IncFsMount& ifs); 429 430 void prepareDataLoaderLocked(IncFsMount& ifs, content::pm::DataLoaderParamsParcel&& params, 431 DataLoaderStatusListener&& statusListener = {}, 432 const StorageHealthCheckParams& healthCheckParams = {}, 433 StorageHealthListener&& healthListener = {}); 434 435 BindPathMap::const_iterator findStorageLocked(std::string_view path) const; 436 StorageId findStorageId(std::string_view path) const; 437 438 void deleteStorage(IncFsMount& ifs); 439 void deleteStorageLocked(IncFsMount& ifs, std::unique_lock<std::mutex>&& ifsLock); 440 MountMap::iterator getStorageSlotLocked(); 441 std::string normalizePathToStorage(const IncFsMount& incfs, StorageId storage, 442 std::string_view path) const; 443 std::string normalizePathToStorageLocked(const IncFsMount& incfs, 444 IncFsMount::StorageMap::const_iterator storageIt, 445 std::string_view path) const; 446 int makeDirs(const IncFsMount& ifs, StorageId storageId, std::string_view path, int mode); 447 448 int disableReadLogsLocked(IncFsMount& ifs); 449 int applyStorageParamsLocked(IncFsMount& ifs); 450 451 LoadingProgress getLoadingProgressFromPath(const IncFsMount& ifs, std::string_view path) const; 452 453 int setFileContent(const IfsMountPtr& ifs, const incfs::FileId& fileId, 454 std::string_view debugFilePath, std::span<const uint8_t> data) const; 455 456 void registerAppOpsCallback(const std::string& packageName); 457 bool unregisterAppOpsCallback(const std::string& packageName); 458 void onAppOpChanged(const std::string& packageName); 459 460 void runJobProcessing(); 461 void extractZipFile(const IfsMountPtr& ifs, ZipArchiveHandle zipFile, ZipEntry& entry, 462 const incfs::FileId& libFileId, std::string_view debugLibPath, 463 Clock::time_point scheduledTs); 464 465 void runCmdLooper(); 466 467 bool addTimedJob(TimedQueueWrapper& timedQueue, MountId id, Milliseconds after, Job what); 468 bool removeTimedJobs(TimedQueueWrapper& timedQueue, MountId id); 469 470 void addIfsStateCallback(StorageId storageId, IfsStateCallback callback); 471 void removeIfsStateCallbacks(StorageId storageId); 472 void processIfsStateCallbacks(); 473 void processIfsStateCallbacks(StorageId storageId, std::vector<IfsStateCallback>& callbacks); 474 475 bool updateLoadingProgress(int32_t storageId, 476 StorageLoadingProgressListener&& progressListener); 477 478 void trimReservedSpaceV1(const IncFsMount& ifs); 479 int64_t elapsedUsSinceMonoTs(uint64_t monoTsUs); 480 481 private: 482 const std::unique_ptr<VoldServiceWrapper> mVold; 483 const std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager; 484 const std::unique_ptr<IncFsWrapper> mIncFs; 485 const std::unique_ptr<AppOpsManagerWrapper> mAppOpsManager; 486 const std::unique_ptr<JniWrapper> mJni; 487 const std::unique_ptr<LooperWrapper> mLooper; 488 const std::unique_ptr<TimedQueueWrapper> mTimedQueue; 489 const std::unique_ptr<TimedQueueWrapper> mProgressUpdateJobQueue; 490 const std::unique_ptr<FsWrapper> mFs; 491 const std::unique_ptr<ClockWrapper> mClock; 492 const std::string mIncrementalDir; 493 494 mutable std::mutex mLock; 495 mutable std::mutex mMountOperationLock; 496 MountMap mMounts; 497 BindPathMap mBindsByPath; 498 499 std::mutex mCallbacksLock; 500 std::unordered_map<std::string, sp<AppOpsListener>> mCallbackRegistered; 501 502 using IfsStateCallbacks = std::map<StorageId, std::vector<IfsStateCallback>>; 503 std::mutex mIfsStateCallbacksLock; 504 IfsStateCallbacks mIfsStateCallbacks; 505 506 std::atomic_bool mSystemReady = false; 507 StorageId mNextId = 0; 508 509 std::atomic_bool mRunning{true}; 510 511 std::unordered_map<MountId, std::vector<Job>> mJobQueue; 512 MountId mPendingJobsMount = kInvalidStorageId; 513 std::condition_variable mJobCondition; 514 std::mutex mJobMutex; 515 std::thread mJobProcessor; 516 517 std::thread mCmdLooperThread; 518 }; 519 520 } // namespace android::incremental 521