blob: a03ffa00d035fbcf7713f967f964136df0092f04 [file] [log] [blame]
Songchun Fan3c82a302019-11-29 14:23:45 -08001/*
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-base/strings.h>
20#include <android-base/unique_fd.h>
21#include <android/os/incremental/IIncrementalManager.h>
22#include <android/content/pm/DataLoaderParamsParcel.h>
23#include <binder/IServiceManager.h>
24#include <utils/String16.h>
25#include <utils/StrongPointer.h>
26#include <utils/Vector.h>
27
28#include <atomic>
29#include <chrono>
30#include <future>
31#include <limits>
32#include <map>
33#include <mutex>
34#include <string>
35#include <string_view>
36#include <unordered_map>
37#include <utility>
38#include <vector>
39
40#include "ServiceWrappers.h"
41#include "android/content/pm/BnDataLoaderStatusListener.h"
42#include "incfs.h"
43#include "path.h"
44
45using namespace android::os::incremental;
46
47namespace android::os {
48class IVold;
49}
50
51namespace android::incremental {
52
53using MountId = int;
54using StorageId = int;
55using Inode = incfs::Inode;
56using BlockIndex = incfs::BlockIndex;
57using RawMetadata = incfs::RawMetadata;
58using Clock = std::chrono::steady_clock;
59using TimePoint = std::chrono::time_point<Clock>;
60using Seconds = std::chrono::seconds;
61
62class IncrementalService {
63public:
64 explicit IncrementalService(const ServiceManagerWrapper& sm, std::string_view rootDir);
65
66#pragma GCC diagnostic push
67#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
68 ~IncrementalService();
69#pragma GCC diagnostic pop
70
71 static constexpr StorageId kInvalidStorageId = -1;
72 static constexpr StorageId kMaxStorageId = std::numeric_limits<int>::max();
73
74 enum CreateOptions {
75 TemporaryBind = 1,
76 PermanentBind = 2,
77 CreateNew = 4,
78 OpenExisting = 8,
79
80 Default = TemporaryBind | CreateNew
81 };
82
83 enum class BindKind {
84 Temporary = 0,
85 Permanent = 1,
86 };
87
88 std::optional<std::future<void>> onSystemReady();
89
90 StorageId createStorage(std::string_view mountPoint,
91 DataLoaderParamsParcel&& dataLoaderParams,
92 CreateOptions options = CreateOptions::Default);
93 StorageId createLinkedStorage(std::string_view mountPoint, StorageId linkedStorage,
94 CreateOptions options = CreateOptions::Default);
95 StorageId openStorage(std::string_view pathInMount);
96
97 Inode nodeFor(StorageId storage, std::string_view subpath) const;
98 std::pair<Inode, std::string_view> parentAndNameFor(StorageId storage,
99 std::string_view subpath) const;
100
101 int bind(StorageId storage, std::string_view subdir, std::string_view target, BindKind kind);
102 int unbind(StorageId storage, std::string_view target);
103 void deleteStorage(StorageId storage);
104
105 Inode makeFile(StorageId storage, std::string_view name, long size, std::string_view metadata,
106 std::string_view signature);
107 Inode makeDir(StorageId storage, std::string_view name, std::string_view metadata = {});
108 Inode makeDirs(StorageId storage, std::string_view name, std::string_view metadata = {});
109
110 int link(StorageId storage, Inode item, Inode newParent, std::string_view newName);
111 int unlink(StorageId storage, Inode parent, std::string_view name);
112
113 bool isRangeLoaded(StorageId storage, Inode file, std::pair<BlockIndex, BlockIndex> range) {
114 return false;
115 }
116
117 RawMetadata getMetadata(StorageId storage, Inode node) const;
118 std::string getSigngatureData(StorageId storage, Inode node) const { return {}; }
119
120 std::vector<std::string> listFiles(StorageId storage) const;
121 bool startLoading(StorageId storage) const;
122
123 class IncrementalDataLoaderListener : public android::content::pm::BnDataLoaderStatusListener {
124 public:
125 IncrementalDataLoaderListener(IncrementalService& incrementalService)
126 : incrementalService(incrementalService) {}
127 // Callbacks interface
128 binder::Status onStatusChanged(MountId mount, int newStatus) override;
129
130 private:
131 IncrementalService& incrementalService;
132 };
133
134private:
135 struct IncFsMount {
136 struct Bind {
137 StorageId storage;
138 std::string savedFilename;
139 std::string sourceDir;
140 BindKind kind;
141 };
142
143 struct Storage {
144 std::string name;
145 Inode node;
146 };
147
148 struct Control {
149 operator IncFsControl() const { return {cmdFd, logFd}; }
150 void reset() {
151 cmdFd.reset();
152 logFd.reset();
153 }
154
155 base::unique_fd cmdFd;
156 base::unique_fd logFd;
157 };
158
159 using BindMap = std::map<std::string, Bind>;
160 using StorageMap = std::unordered_map<StorageId, Storage>;
161
162 mutable std::mutex lock;
163 const std::string root;
164 Control control;
165 /*const*/ MountId mountId;
166 StorageMap storages;
167 BindMap bindPoints;
168 std::optional<DataLoaderParamsParcel> savedDataLoaderParams;
169 std::atomic<int> nextStorageDirNo{0};
170 std::atomic<int> dataLoaderStatus = -1;
171 std::condition_variable dataLoaderReady;
172 TimePoint connectionLostTime = TimePoint();
173 const IncrementalService& incrementalService;
174
175 IncFsMount(std::string root, MountId mountId, Control control,
176 const IncrementalService& incrementalService)
177 : root(std::move(root)),
178 control(std::move(control)),
179 mountId(mountId),
180 incrementalService(incrementalService) {}
181 IncFsMount(IncFsMount&&) = delete;
182 IncFsMount& operator=(IncFsMount&&) = delete;
183 ~IncFsMount();
184
185 StorageMap::iterator makeStorage(StorageId id);
186
187 static void cleanupFilesystem(std::string_view root);
188 };
189
190 using IfsMountPtr = std::shared_ptr<IncFsMount>;
191 using MountMap = std::unordered_map<MountId, IfsMountPtr>;
192 using BindPathMap = std::map<std::string, IncFsMount::BindMap::iterator, path::PathLess>;
193
194 void mountExistingImages();
195 bool mountExistingImage(std::string_view root, std::string_view key);
196
197 IfsMountPtr getIfs(StorageId storage) const;
198 const IfsMountPtr& getIfsLocked(StorageId storage) const;
199 int addBindMount(IncFsMount& ifs, StorageId storage, std::string&& sourceSubdir,
200 std::string&& target, BindKind kind, std::unique_lock<std::mutex>& mainLock);
201
202 int addBindMountWithMd(IncFsMount& ifs, StorageId storage, std::string&& metadataName,
203 std::string&& sourceSubdir, std::string&& target, BindKind kind,
204 std::unique_lock<std::mutex>& mainLock);
205
206 bool prepareDataLoader(IncFsMount& ifs, DataLoaderParamsParcel* params);
207 BindPathMap::const_iterator findStorageLocked(std::string_view path) const;
208 StorageId findStorageId(std::string_view path) const;
209
210 void deleteStorage(IncFsMount& ifs);
211 void deleteStorageLocked(IncFsMount& ifs, std::unique_lock<std::mutex>&& ifsLock);
212 MountMap::iterator getStorageSlotLocked();
213
214 // Member variables
215 // These are shared pointers for the sake of unit testing
216 std::shared_ptr<VoldServiceWrapper> mVold;
217 std::shared_ptr<IncrementalManagerWrapper> mIncrementalManager;
218 std::shared_ptr<IncFsWrapper> mIncFs;
219 const std::string mIncrementalDir;
220
221 mutable std::mutex mLock;
222 mutable std::mutex mMountOperationLock;
223 MountMap mMounts;
224 BindPathMap mBindsByPath;
225
226 std::atomic_bool mSystemReady = false;
227 StorageId mNextId = 0;
228 std::promise<void> mPrepareDataLoaders;
229};
230
231} // namespace android::incremental