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