• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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