• 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/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