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/BnIncrementalServiceConnector.h> 24 #include <android/os/incremental/BnStorageHealthListener.h> 25 #include <android/os/incremental/StorageHealthCheckParams.h> 26 #include <binder/IAppOpsCallback.h> 27 #include <utils/String16.h> 28 #include <utils/StrongPointer.h> 29 #include <ziparchive/zip_archive.h> 30 31 #include <atomic> 32 #include <chrono> 33 #include <condition_variable> 34 #include <functional> 35 #include <limits> 36 #include <map> 37 #include <mutex> 38 #include <set> 39 #include <span> 40 #include <string> 41 #include <string_view> 42 #include <thread> 43 #include <unordered_map> 44 #include <unordered_set> 45 #include <utility> 46 #include <vector> 47 48 #include "ServiceWrappers.h" 49 #include "incfs.h" 50 #include "path.h" 51 52 namespace android::incremental { 53 54 using MountId = int; 55 using StorageId = int; 56 using FileId = incfs::FileId; 57 using BlockIndex = incfs::BlockIndex; 58 using RawMetadata = incfs::RawMetadata; 59 using Seconds = std::chrono::seconds; 60 using BootClockTsUs = uint64_t; 61 62 using IDataLoaderStatusListener = ::android::content::pm::IDataLoaderStatusListener; 63 using DataLoaderStatusListener = ::android::sp<IDataLoaderStatusListener>; 64 65 using StorageHealthCheckParams = ::android::os::incremental::StorageHealthCheckParams; 66 using IStorageHealthListener = ::android::os::incremental::IStorageHealthListener; 67 using StorageHealthListener = ::android::sp<IStorageHealthListener>; 68 69 class IncrementalService final { 70 public: 71 explicit IncrementalService(ServiceManagerWrapper&& sm, std::string_view rootDir); 72 73 #pragma GCC diagnostic push 74 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" 75 ~IncrementalService(); 76 #pragma GCC diagnostic pop 77 78 static constexpr StorageId kInvalidStorageId = -1; 79 static constexpr StorageId kMaxStorageId = std::numeric_limits<int>::max(); 80 81 static constexpr BootClockTsUs kMaxBootClockTsUs = std::numeric_limits<BootClockTsUs>::max(); 82 83 enum CreateOptions { 84 TemporaryBind = 1, 85 PermanentBind = 2, 86 CreateNew = 4, 87 OpenExisting = 8, 88 89 Default = TemporaryBind | CreateNew 90 }; 91 92 enum class BindKind { 93 Temporary = 0, 94 Permanent = 1, 95 }; 96 97 enum StorageFlags { 98 ReadLogsEnabled = 1, 99 }; 100 101 static FileId idFromMetadata(std::span<const uint8_t> metadata); idFromMetadata(std::span<const char> metadata)102 static inline FileId idFromMetadata(std::span<const char> metadata) { 103 return idFromMetadata({(const uint8_t*)metadata.data(), metadata.size()}); 104 } 105 106 void onDump(int fd); 107 108 void onSystemReady(); 109 110 StorageId createStorage(std::string_view mountPoint, 111 content::pm::DataLoaderParamsParcel&& dataLoaderParams, 112 CreateOptions options, const DataLoaderStatusListener& statusListener, 113 StorageHealthCheckParams&& healthCheckParams, 114 const StorageHealthListener& healthListener); 115 StorageId createLinkedStorage(std::string_view mountPoint, StorageId linkedStorage, 116 CreateOptions options = CreateOptions::Default); 117 StorageId openStorage(std::string_view path); 118 119 int bind(StorageId storage, std::string_view source, std::string_view target, BindKind kind); 120 int unbind(StorageId storage, std::string_view target); 121 void deleteStorage(StorageId storage); 122 123 void disableReadLogs(StorageId storage); 124 int setStorageParams(StorageId storage, bool enableReadLogs); 125 126 int makeFile(StorageId storage, std::string_view path, int mode, FileId id, 127 incfs::NewFileParams params); 128 int makeDir(StorageId storage, std::string_view path, int mode = 0755); 129 int makeDirs(StorageId storage, std::string_view path, int mode = 0755); 130 131 int link(StorageId sourceStorageId, std::string_view oldPath, StorageId destStorageId, 132 std::string_view newPath); 133 int unlink(StorageId storage, std::string_view path); 134 isRangeLoaded(StorageId storage,FileId file,std::pair<BlockIndex,BlockIndex> range)135 bool isRangeLoaded(StorageId storage, FileId file, std::pair<BlockIndex, BlockIndex> range) { 136 return false; 137 } 138 139 RawMetadata getMetadata(StorageId storage, std::string_view path) const; 140 RawMetadata getMetadata(StorageId storage, FileId node) const; 141 142 bool startLoading(StorageId storage) const; 143 144 bool configureNativeBinaries(StorageId storage, std::string_view apkFullPath, 145 std::string_view libDirRelativePath, std::string_view abi, 146 bool extractNativeLibs); 147 bool waitForNativeBinariesExtraction(StorageId storage); 148 149 class AppOpsListener : public android::BnAppOpsCallback { 150 public: AppOpsListener(IncrementalService & incrementalService,std::string packageName)151 AppOpsListener(IncrementalService& incrementalService, std::string packageName) 152 : incrementalService(incrementalService), packageName(std::move(packageName)) {} 153 void opChanged(int32_t op, const String16& packageName) final; 154 155 private: 156 IncrementalService& incrementalService; 157 const std::string packageName; 158 }; 159 160 class IncrementalServiceConnector : public os::incremental::BnIncrementalServiceConnector { 161 public: IncrementalServiceConnector(IncrementalService & incrementalService,int32_t storage)162 IncrementalServiceConnector(IncrementalService& incrementalService, int32_t storage) 163 : incrementalService(incrementalService), storage(storage) {} 164 binder::Status setStorageParams(bool enableReadLogs, int32_t* _aidl_return) final; 165 166 private: 167 IncrementalService& incrementalService; 168 int32_t const storage; 169 }; 170 171 private: 172 struct IncFsMount; 173 174 class DataLoaderStub : public content::pm::BnDataLoaderStatusListener { 175 public: 176 DataLoaderStub(IncrementalService& service, MountId id, 177 content::pm::DataLoaderParamsParcel&& params, 178 content::pm::FileSystemControlParcel&& control, 179 const DataLoaderStatusListener* statusListener, 180 StorageHealthCheckParams&& healthCheckParams, 181 const StorageHealthListener* healthListener, std::string&& healthPath); 182 ~DataLoaderStub(); 183 // Cleans up the internal state and invalidates DataLoaderStub. Any subsequent calls will 184 // result in an error. 185 void cleanupResources(); 186 187 bool requestCreate(); 188 bool requestStart(); 189 bool requestDestroy(); 190 191 void onDump(int fd); 192 id()193 MountId id() const { return mId.load(std::memory_order_relaxed); } params()194 const content::pm::DataLoaderParamsParcel& params() const { return mParams; } 195 196 private: 197 binder::Status onStatusChanged(MountId mount, int newStatus) final; 198 199 sp<content::pm::IDataLoader> getDataLoader(); 200 201 bool bind(); 202 bool create(); 203 bool start(); 204 bool destroy(); 205 206 bool setTargetStatus(int status); 207 void setTargetStatusLocked(int status); 208 209 bool fsmStep(); 210 bool fsmStep(int currentStatus, int targetStatus); 211 212 void onHealthStatus(StorageHealthListener healthListener, int healthStatus); 213 void updateHealthStatus(bool baseline = false); 214 isValid()215 bool isValid() const { return id() != kInvalidStorageId; } 216 217 bool isHealthParamsValid() const; 218 219 const incfs::UniqueControl& initializeHealthControl(); 220 void resetHealthControl(); 221 222 BootClockTsUs getOldestPendingReadTs(); 223 224 void registerForPendingReads(); 225 void unregisterFromPendingReads(); 226 227 IncrementalService& mService; 228 229 std::mutex mMutex; 230 std::atomic<MountId> mId = kInvalidStorageId; 231 content::pm::DataLoaderParamsParcel mParams; 232 content::pm::FileSystemControlParcel mControl; 233 DataLoaderStatusListener mStatusListener; 234 StorageHealthListener mHealthListener; 235 236 std::condition_variable mStatusCondition; 237 int mCurrentStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED; 238 int mTargetStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED; 239 TimePoint mTargetStatusTs = {}; 240 241 std::string mHealthPath; 242 incfs::UniqueControl mHealthControl; 243 struct { 244 TimePoint userTs; 245 BootClockTsUs kernelTsUs; 246 } mHealthBase = {TimePoint::max(), kMaxBootClockTsUs}; 247 StorageHealthCheckParams mHealthCheckParams; 248 }; 249 using DataLoaderStubPtr = sp<DataLoaderStub>; 250 251 struct IncFsMount { 252 struct Bind { 253 StorageId storage; 254 std::string savedFilename; 255 std::string sourceDir; 256 BindKind kind; 257 }; 258 259 struct Storage { 260 std::string name; 261 }; 262 263 using Control = incfs::UniqueControl; 264 265 using BindMap = std::map<std::string, Bind, path::PathLess>; 266 using StorageMap = std::unordered_map<StorageId, Storage>; 267 268 mutable std::mutex lock; 269 const std::string root; 270 Control control; 271 /*const*/ MountId mountId; 272 int32_t flags = StorageFlags::ReadLogsEnabled; 273 StorageMap storages; 274 BindMap bindPoints; 275 DataLoaderStubPtr dataLoaderStub; 276 std::atomic<int> nextStorageDirNo{0}; 277 const IncrementalService& incrementalService; 278 IncFsMountIncFsMount279 IncFsMount(std::string root, MountId mountId, Control control, 280 const IncrementalService& incrementalService) 281 : root(std::move(root)), 282 control(std::move(control)), 283 mountId(mountId), 284 incrementalService(incrementalService) {} 285 IncFsMount(IncFsMount&&) = delete; 286 IncFsMount& operator=(IncFsMount&&) = delete; 287 ~IncFsMount(); 288 289 StorageMap::iterator makeStorage(StorageId id); 290 disableReadLogsIncFsMount291 void disableReadLogs() { flags &= ~StorageFlags::ReadLogsEnabled; } readLogsEnabledIncFsMount292 int32_t readLogsEnabled() const { return (flags & StorageFlags::ReadLogsEnabled); } 293 294 static void cleanupFilesystem(std::string_view root); 295 }; 296 297 using IfsMountPtr = std::shared_ptr<IncFsMount>; 298 using MountMap = std::unordered_map<MountId, IfsMountPtr>; 299 using BindPathMap = std::map<std::string, IncFsMount::BindMap::iterator, path::PathLess>; 300 301 static bool perfLoggingEnabled(); 302 303 std::unordered_set<std::string_view> adoptMountedInstances(); 304 void mountExistingImages(const std::unordered_set<std::string_view>& mountedRootNames); 305 bool mountExistingImage(std::string_view root); 306 307 IfsMountPtr getIfs(StorageId storage) const; 308 const IfsMountPtr& getIfsLocked(StorageId storage) const; 309 int addBindMount(IncFsMount& ifs, StorageId storage, std::string_view storageRoot, 310 std::string&& source, std::string&& target, BindKind kind, 311 std::unique_lock<std::mutex>& mainLock); 312 313 int addBindMountWithMd(IncFsMount& ifs, StorageId storage, std::string&& metadataName, 314 std::string&& source, std::string&& target, BindKind kind, 315 std::unique_lock<std::mutex>& mainLock); 316 317 void addBindMountRecordLocked(IncFsMount& ifs, StorageId storage, std::string&& metadataName, 318 std::string&& source, std::string&& target, BindKind kind); 319 320 DataLoaderStubPtr prepareDataLoader(IncFsMount& ifs, 321 content::pm::DataLoaderParamsParcel&& params, 322 const DataLoaderStatusListener* statusListener = nullptr, 323 StorageHealthCheckParams&& healthCheckParams = {}, 324 const StorageHealthListener* healthListener = nullptr); 325 void prepareDataLoaderLocked(IncFsMount& ifs, content::pm::DataLoaderParamsParcel&& params, 326 const DataLoaderStatusListener* statusListener = nullptr, 327 StorageHealthCheckParams&& healthCheckParams = {}, 328 const StorageHealthListener* healthListener = nullptr); 329 330 BindPathMap::const_iterator findStorageLocked(std::string_view path) const; 331 StorageId findStorageId(std::string_view path) const; 332 333 void deleteStorage(IncFsMount& ifs); 334 void deleteStorageLocked(IncFsMount& ifs, std::unique_lock<std::mutex>&& ifsLock); 335 MountMap::iterator getStorageSlotLocked(); 336 std::string normalizePathToStorage(const IncFsMount& incfs, StorageId storage, 337 std::string_view path) const; 338 std::string normalizePathToStorageLocked(const IncFsMount& incfs, 339 IncFsMount::StorageMap::const_iterator storageIt, 340 std::string_view path) const; 341 int makeDirs(const IncFsMount& ifs, StorageId storageId, std::string_view path, int mode); 342 binder::Status applyStorageParams(IncFsMount& ifs, bool enableReadLogs); 343 344 void registerAppOpsCallback(const std::string& packageName); 345 bool unregisterAppOpsCallback(const std::string& packageName); 346 void onAppOpChanged(const std::string& packageName); 347 348 void runJobProcessing(); 349 void extractZipFile(const IfsMountPtr& ifs, ZipArchiveHandle zipFile, ZipEntry& entry, 350 const incfs::FileId& libFileId, std::string_view targetLibPath, 351 Clock::time_point scheduledTs); 352 353 void runCmdLooper(); 354 355 void addTimedJob(MountId id, Milliseconds after, Job what); 356 void removeTimedJobs(MountId id); 357 358 private: 359 const std::unique_ptr<VoldServiceWrapper> mVold; 360 const std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager; 361 const std::unique_ptr<IncFsWrapper> mIncFs; 362 const std::unique_ptr<AppOpsManagerWrapper> mAppOpsManager; 363 const std::unique_ptr<JniWrapper> mJni; 364 const std::unique_ptr<LooperWrapper> mLooper; 365 const std::unique_ptr<TimedQueueWrapper> mTimedQueue; 366 const std::string mIncrementalDir; 367 368 mutable std::mutex mLock; 369 mutable std::mutex mMountOperationLock; 370 MountMap mMounts; 371 BindPathMap mBindsByPath; 372 373 std::mutex mCallbacksLock; 374 std::map<std::string, sp<AppOpsListener>> mCallbackRegistered; 375 376 std::atomic_bool mSystemReady = false; 377 StorageId mNextId = 0; 378 379 std::atomic_bool mRunning{true}; 380 381 std::unordered_map<MountId, std::vector<Job>> mJobQueue; 382 MountId mPendingJobsMount = kInvalidStorageId; 383 std::condition_variable mJobCondition; 384 std::mutex mJobMutex; 385 std::thread mJobProcessor; 386 387 std::thread mCmdLooperThread; 388 }; 389 390 } // namespace android::incremental 391