blob: 06418721955b8ecb64ce81f1e704bf20a966bc2c [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#define LOG_TAG "IncrementalService"
18
19#include "IncrementalService.h"
20
Songchun Fan3c82a302019-11-29 14:23:45 -080021#include <android-base/logging.h>
Yurii Zubrytskyi0cd80122020-04-09 23:08:31 -070022#include <android-base/no_destructor.h>
Songchun Fan3c82a302019-11-29 14:23:45 -080023#include <android-base/properties.h>
24#include <android-base/stringprintf.h>
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -070025#include <binder/AppOpsManager.h>
Jooyung Han66c567a2020-03-07 21:47:09 +090026#include <binder/Nullable.h>
Songchun Fan3c82a302019-11-29 14:23:45 -080027#include <binder/Status.h>
28#include <sys/stat.h>
29#include <uuid/uuid.h>
Songchun Fan3c82a302019-11-29 14:23:45 -080030
Yurii Zubrytskyi107ae352020-04-03 13:12:51 -070031#include <charconv>
Alex Buynytskyy18b07a42020-02-03 20:06:00 -080032#include <ctime>
Songchun Fan3c82a302019-11-29 14:23:45 -080033#include <iterator>
34#include <span>
Songchun Fan3c82a302019-11-29 14:23:45 -080035#include <type_traits>
36
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -070037#include "IncrementalServiceValidation.h"
Songchun Fan3c82a302019-11-29 14:23:45 -080038#include "Metadata.pb.h"
39
40using namespace std::literals;
Songchun Fan1124fd32020-02-10 12:49:41 -080041namespace fs = std::filesystem;
Songchun Fan3c82a302019-11-29 14:23:45 -080042
Alex Buynytskyy96e350b2020-04-02 20:03:47 -070043constexpr const char* kDataUsageStats = "android.permission.LOADER_USAGE_STATS";
Alex Buynytskyy119de1f2020-04-08 16:15:35 -070044constexpr const char* kOpUsage = "android:loader_usage_stats";
Alex Buynytskyy96e350b2020-04-02 20:03:47 -070045
Songchun Fan3c82a302019-11-29 14:23:45 -080046namespace android::incremental {
47
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -070048using content::pm::DataLoaderParamsParcel;
49using content::pm::FileSystemControlParcel;
50using content::pm::IDataLoader;
51
Songchun Fan3c82a302019-11-29 14:23:45 -080052namespace {
53
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -070054using IncrementalFileSystemControlParcel = os::incremental::IncrementalFileSystemControlParcel;
Songchun Fan3c82a302019-11-29 14:23:45 -080055
56struct Constants {
57 static constexpr auto backing = "backing_store"sv;
58 static constexpr auto mount = "mount"sv;
Songchun Fan1124fd32020-02-10 12:49:41 -080059 static constexpr auto mountKeyPrefix = "MT_"sv;
Songchun Fan3c82a302019-11-29 14:23:45 -080060 static constexpr auto storagePrefix = "st"sv;
61 static constexpr auto mountpointMdPrefix = ".mountpoint."sv;
62 static constexpr auto infoMdName = ".info"sv;
Songchun Fan0f8b6fe2020-02-05 17:41:25 -080063 static constexpr auto libDir = "lib"sv;
64 static constexpr auto libSuffix = ".so"sv;
65 static constexpr auto blockSize = 4096;
Songchun Fan3c82a302019-11-29 14:23:45 -080066};
67
68static const Constants& constants() {
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -070069 static constexpr Constants c;
Songchun Fan3c82a302019-11-29 14:23:45 -080070 return c;
71}
72
73template <base::LogSeverity level = base::ERROR>
74bool mkdirOrLog(std::string_view name, int mode = 0770, bool allowExisting = true) {
75 auto cstr = path::c_str(name);
76 if (::mkdir(cstr, mode)) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -080077 if (!allowExisting || errno != EEXIST) {
Songchun Fan3c82a302019-11-29 14:23:45 -080078 PLOG(level) << "Can't create directory '" << name << '\'';
79 return false;
80 }
81 struct stat st;
82 if (::stat(cstr, &st) || !S_ISDIR(st.st_mode)) {
83 PLOG(level) << "Path exists but is not a directory: '" << name << '\'';
84 return false;
85 }
86 }
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -080087 if (::chmod(cstr, mode)) {
88 PLOG(level) << "Changing permission failed for '" << name << '\'';
89 return false;
90 }
91
Songchun Fan3c82a302019-11-29 14:23:45 -080092 return true;
93}
94
95static std::string toMountKey(std::string_view path) {
96 if (path.empty()) {
97 return "@none";
98 }
99 if (path == "/"sv) {
100 return "@root";
101 }
102 if (path::isAbsolute(path)) {
103 path.remove_prefix(1);
104 }
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700105 if (path.size() > 16) {
106 path = path.substr(0, 16);
107 }
Songchun Fan3c82a302019-11-29 14:23:45 -0800108 std::string res(path);
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700109 std::replace_if(
110 res.begin(), res.end(), [](char c) { return c == '/' || c == '@'; }, '_');
111 return std::string(constants().mountKeyPrefix) += res;
Songchun Fan3c82a302019-11-29 14:23:45 -0800112}
113
114static std::pair<std::string, std::string> makeMountDir(std::string_view incrementalDir,
115 std::string_view path) {
116 auto mountKey = toMountKey(path);
117 const auto prefixSize = mountKey.size();
118 for (int counter = 0; counter < 1000;
119 mountKey.resize(prefixSize), base::StringAppendF(&mountKey, "%d", counter++)) {
120 auto mountRoot = path::join(incrementalDir, mountKey);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800121 if (mkdirOrLog(mountRoot, 0777, false)) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800122 return {mountKey, mountRoot};
123 }
124 }
125 return {};
126}
127
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700128template <class Map>
129typename Map::const_iterator findParentPath(const Map& map, std::string_view path) {
130 const auto nextIt = map.upper_bound(path);
131 if (nextIt == map.begin()) {
132 return map.end();
133 }
134 const auto suspectIt = std::prev(nextIt);
135 if (!path::startsWith(path, suspectIt->first)) {
136 return map.end();
137 }
138 return suspectIt;
139}
140
141static base::unique_fd dup(base::borrowed_fd fd) {
142 const auto res = fcntl(fd.get(), F_DUPFD_CLOEXEC, 0);
143 return base::unique_fd(res);
144}
145
Songchun Fan3c82a302019-11-29 14:23:45 -0800146template <class ProtoMessage, class Control>
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700147static ProtoMessage parseFromIncfs(const IncFsWrapper* incfs, const Control& control,
Songchun Fan3c82a302019-11-29 14:23:45 -0800148 std::string_view path) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800149 auto md = incfs->getMetadata(control, path);
Songchun Fan3c82a302019-11-29 14:23:45 -0800150 ProtoMessage message;
151 return message.ParseFromArray(md.data(), md.size()) ? message : ProtoMessage{};
152}
153
154static bool isValidMountTarget(std::string_view path) {
155 return path::isAbsolute(path) && path::isEmptyDir(path).value_or(true);
156}
157
158std::string makeBindMdName() {
159 static constexpr auto uuidStringSize = 36;
160
161 uuid_t guid;
162 uuid_generate(guid);
163
164 std::string name;
165 const auto prefixSize = constants().mountpointMdPrefix.size();
166 name.reserve(prefixSize + uuidStringSize);
167
168 name = constants().mountpointMdPrefix;
169 name.resize(prefixSize + uuidStringSize);
170 uuid_unparse(guid, name.data() + prefixSize);
171
172 return name;
173}
174} // namespace
175
176IncrementalService::IncFsMount::~IncFsMount() {
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -0700177 if (dataLoaderStub) {
Alex Buynytskyy9a54579a2020-04-17 15:34:47 -0700178 dataLoaderStub->cleanupResources();
179 dataLoaderStub = {};
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -0700180 }
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700181 control.close();
Songchun Fan3c82a302019-11-29 14:23:45 -0800182 LOG(INFO) << "Unmounting and cleaning up mount " << mountId << " with root '" << root << '\'';
183 for (auto&& [target, _] : bindPoints) {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700184 LOG(INFO) << " bind: " << target;
Songchun Fan3c82a302019-11-29 14:23:45 -0800185 incrementalService.mVold->unmountIncFs(target);
186 }
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700187 LOG(INFO) << " root: " << root;
Songchun Fan3c82a302019-11-29 14:23:45 -0800188 incrementalService.mVold->unmountIncFs(path::join(root, constants().mount));
189 cleanupFilesystem(root);
190}
191
192auto IncrementalService::IncFsMount::makeStorage(StorageId id) -> StorageMap::iterator {
Songchun Fan3c82a302019-11-29 14:23:45 -0800193 std::string name;
194 for (int no = nextStorageDirNo.fetch_add(1, std::memory_order_relaxed), i = 0;
195 i < 1024 && no >= 0; no = nextStorageDirNo.fetch_add(1, std::memory_order_relaxed), ++i) {
196 name.clear();
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800197 base::StringAppendF(&name, "%.*s_%d_%d", int(constants().storagePrefix.size()),
198 constants().storagePrefix.data(), id, no);
199 auto fullName = path::join(root, constants().mount, name);
Songchun Fan96100932020-02-03 19:20:58 -0800200 if (auto err = incrementalService.mIncFs->makeDir(control, fullName, 0755); !err) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800201 std::lock_guard l(lock);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800202 return storages.insert_or_assign(id, Storage{std::move(fullName)}).first;
203 } else if (err != EEXIST) {
204 LOG(ERROR) << __func__ << "(): failed to create dir |" << fullName << "| " << err;
205 break;
Songchun Fan3c82a302019-11-29 14:23:45 -0800206 }
207 }
208 nextStorageDirNo = 0;
209 return storages.end();
210}
211
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700212template <class Func>
213static auto makeCleanup(Func&& f) {
214 auto deleter = [f = std::move(f)](auto) { f(); };
215 return std::unique_ptr<Func, decltype(deleter)>(&f, std::move(deleter));
216}
217
218static std::unique_ptr<DIR, decltype(&::closedir)> openDir(const char* dir) {
219 return {::opendir(dir), ::closedir};
220}
221
222static auto openDir(std::string_view dir) {
223 return openDir(path::c_str(dir));
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800224}
225
226static int rmDirContent(const char* path) {
227 auto dir = openDir(path);
228 if (!dir) {
229 return -EINVAL;
230 }
231 while (auto entry = ::readdir(dir.get())) {
232 if (entry->d_name == "."sv || entry->d_name == ".."sv) {
233 continue;
234 }
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700235 auto fullPath = base::StringPrintf("%s/%s", path, entry->d_name);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800236 if (entry->d_type == DT_DIR) {
237 if (const auto err = rmDirContent(fullPath.c_str()); err != 0) {
238 PLOG(WARNING) << "Failed to delete " << fullPath << " content";
239 return err;
240 }
241 if (const auto err = ::rmdir(fullPath.c_str()); err != 0) {
242 PLOG(WARNING) << "Failed to rmdir " << fullPath;
243 return err;
244 }
245 } else {
246 if (const auto err = ::unlink(fullPath.c_str()); err != 0) {
247 PLOG(WARNING) << "Failed to delete " << fullPath;
248 return err;
249 }
250 }
251 }
252 return 0;
253}
254
Songchun Fan3c82a302019-11-29 14:23:45 -0800255void IncrementalService::IncFsMount::cleanupFilesystem(std::string_view root) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800256 rmDirContent(path::join(root, constants().backing).c_str());
Songchun Fan3c82a302019-11-29 14:23:45 -0800257 ::rmdir(path::join(root, constants().backing).c_str());
258 ::rmdir(path::join(root, constants().mount).c_str());
259 ::rmdir(path::c_str(root));
260}
261
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800262IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_view rootDir)
Songchun Fan3c82a302019-11-29 14:23:45 -0800263 : mVold(sm.getVoldService()),
Songchun Fan68645c42020-02-27 15:57:35 -0800264 mDataLoaderManager(sm.getDataLoaderManager()),
Songchun Fan3c82a302019-11-29 14:23:45 -0800265 mIncFs(sm.getIncFs()),
Alex Buynytskyy96e350b2020-04-02 20:03:47 -0700266 mAppOpsManager(sm.getAppOpsManager()),
Yurii Zubrytskyi86321402020-04-09 19:22:30 -0700267 mJni(sm.getJni()),
Songchun Fan3c82a302019-11-29 14:23:45 -0800268 mIncrementalDir(rootDir) {
269 if (!mVold) {
270 LOG(FATAL) << "Vold service is unavailable";
271 }
Songchun Fan68645c42020-02-27 15:57:35 -0800272 if (!mDataLoaderManager) {
273 LOG(FATAL) << "DataLoaderManagerService is unavailable";
Songchun Fan3c82a302019-11-29 14:23:45 -0800274 }
Alex Buynytskyy96e350b2020-04-02 20:03:47 -0700275 if (!mAppOpsManager) {
276 LOG(FATAL) << "AppOpsManager is unavailable";
277 }
Yurii Zubrytskyida208012020-04-07 15:35:21 -0700278
279 mJobQueue.reserve(16);
Yurii Zubrytskyi86321402020-04-09 19:22:30 -0700280 mJobProcessor = std::thread([this]() {
281 mJni->initializeForCurrentThread();
282 runJobProcessing();
283 });
Yurii Zubrytskyida208012020-04-07 15:35:21 -0700284
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700285 const auto mountedRootNames = adoptMountedInstances();
286 mountExistingImages(mountedRootNames);
Songchun Fan3c82a302019-11-29 14:23:45 -0800287}
288
Yurii Zubrytskyida208012020-04-07 15:35:21 -0700289IncrementalService::~IncrementalService() {
290 {
291 std::lock_guard lock(mJobMutex);
292 mRunning = false;
293 }
294 mJobCondition.notify_all();
295 mJobProcessor.join();
296}
Songchun Fan3c82a302019-11-29 14:23:45 -0800297
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700298static const char* toString(IncrementalService::BindKind kind) {
Alex Buynytskyy18b07a42020-02-03 20:06:00 -0800299 switch (kind) {
Songchun Fan0f8b6fe2020-02-05 17:41:25 -0800300 case IncrementalService::BindKind::Temporary:
301 return "Temporary";
302 case IncrementalService::BindKind::Permanent:
303 return "Permanent";
Alex Buynytskyy18b07a42020-02-03 20:06:00 -0800304 }
305}
306
307void IncrementalService::onDump(int fd) {
308 dprintf(fd, "Incremental is %s\n", incfs::enabled() ? "ENABLED" : "DISABLED");
309 dprintf(fd, "Incremental dir: %s\n", mIncrementalDir.c_str());
310
311 std::unique_lock l(mLock);
312
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700313 dprintf(fd, "Mounts (%d): {\n", int(mMounts.size()));
Alex Buynytskyy18b07a42020-02-03 20:06:00 -0800314 for (auto&& [id, ifs] : mMounts) {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700315 const IncFsMount& mnt = *ifs;
316 dprintf(fd, " [%d]: {\n", id);
317 if (id != mnt.mountId) {
318 dprintf(fd, " reference to mountId: %d\n", mnt.mountId);
319 } else {
320 dprintf(fd, " mountId: %d\n", mnt.mountId);
321 dprintf(fd, " root: %s\n", mnt.root.c_str());
322 dprintf(fd, " nextStorageDirNo: %d\n", mnt.nextStorageDirNo.load());
323 if (mnt.dataLoaderStub) {
324 mnt.dataLoaderStub->onDump(fd);
325 } else {
326 dprintf(fd, " dataLoader: null\n");
327 }
328 dprintf(fd, " storages (%d): {\n", int(mnt.storages.size()));
329 for (auto&& [storageId, storage] : mnt.storages) {
330 dprintf(fd, " [%d] -> [%s]\n", storageId, storage.name.c_str());
331 }
332 dprintf(fd, " }\n");
Alex Buynytskyy18b07a42020-02-03 20:06:00 -0800333
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700334 dprintf(fd, " bindPoints (%d): {\n", int(mnt.bindPoints.size()));
335 for (auto&& [target, bind] : mnt.bindPoints) {
336 dprintf(fd, " [%s]->[%d]:\n", target.c_str(), bind.storage);
337 dprintf(fd, " savedFilename: %s\n", bind.savedFilename.c_str());
338 dprintf(fd, " sourceDir: %s\n", bind.sourceDir.c_str());
339 dprintf(fd, " kind: %s\n", toString(bind.kind));
340 }
341 dprintf(fd, " }\n");
Alex Buynytskyy18b07a42020-02-03 20:06:00 -0800342 }
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700343 dprintf(fd, " }\n");
Alex Buynytskyy18b07a42020-02-03 20:06:00 -0800344 }
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700345 dprintf(fd, "}\n");
346 dprintf(fd, "Sorted binds (%d): {\n", int(mBindsByPath.size()));
Alex Buynytskyy18b07a42020-02-03 20:06:00 -0800347 for (auto&& [target, mountPairIt] : mBindsByPath) {
348 const auto& bind = mountPairIt->second;
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700349 dprintf(fd, " [%s]->[%d]:\n", target.c_str(), bind.storage);
350 dprintf(fd, " savedFilename: %s\n", bind.savedFilename.c_str());
351 dprintf(fd, " sourceDir: %s\n", bind.sourceDir.c_str());
352 dprintf(fd, " kind: %s\n", toString(bind.kind));
Alex Buynytskyy18b07a42020-02-03 20:06:00 -0800353 }
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700354 dprintf(fd, "}\n");
Alex Buynytskyy18b07a42020-02-03 20:06:00 -0800355}
356
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -0700357void IncrementalService::onSystemReady() {
Songchun Fan3c82a302019-11-29 14:23:45 -0800358 if (mSystemReady.exchange(true)) {
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -0700359 return;
Songchun Fan3c82a302019-11-29 14:23:45 -0800360 }
361
362 std::vector<IfsMountPtr> mounts;
363 {
364 std::lock_guard l(mLock);
365 mounts.reserve(mMounts.size());
366 for (auto&& [id, ifs] : mMounts) {
367 if (ifs->mountId == id) {
368 mounts.push_back(ifs);
369 }
370 }
371 }
372
Alex Buynytskyy69941662020-04-11 21:40:37 -0700373 if (mounts.empty()) {
374 return;
375 }
376
Songchun Fan3c82a302019-11-29 14:23:45 -0800377 std::thread([this, mounts = std::move(mounts)]() {
Alex Buynytskyy69941662020-04-11 21:40:37 -0700378 mJni->initializeForCurrentThread();
Songchun Fan3c82a302019-11-29 14:23:45 -0800379 for (auto&& ifs : mounts) {
Alex Buynytskyyab65cb12020-04-17 10:01:47 -0700380 ifs->dataLoaderStub->requestStart();
Songchun Fan3c82a302019-11-29 14:23:45 -0800381 }
Songchun Fan3c82a302019-11-29 14:23:45 -0800382 }).detach();
Songchun Fan3c82a302019-11-29 14:23:45 -0800383}
384
385auto IncrementalService::getStorageSlotLocked() -> MountMap::iterator {
386 for (;;) {
387 if (mNextId == kMaxStorageId) {
388 mNextId = 0;
389 }
390 auto id = ++mNextId;
391 auto [it, inserted] = mMounts.try_emplace(id, nullptr);
392 if (inserted) {
393 return it;
394 }
395 }
396}
397
Songchun Fan1124fd32020-02-10 12:49:41 -0800398StorageId IncrementalService::createStorage(
399 std::string_view mountPoint, DataLoaderParamsParcel&& dataLoaderParams,
400 const DataLoaderStatusListener& dataLoaderStatusListener, CreateOptions options) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800401 LOG(INFO) << "createStorage: " << mountPoint << " | " << int(options);
402 if (!path::isAbsolute(mountPoint)) {
403 LOG(ERROR) << "path is not absolute: " << mountPoint;
404 return kInvalidStorageId;
405 }
406
407 auto mountNorm = path::normalize(mountPoint);
408 {
409 const auto id = findStorageId(mountNorm);
410 if (id != kInvalidStorageId) {
411 if (options & CreateOptions::OpenExisting) {
412 LOG(INFO) << "Opened existing storage " << id;
413 return id;
414 }
415 LOG(ERROR) << "Directory " << mountPoint << " is already mounted at storage " << id;
416 return kInvalidStorageId;
417 }
418 }
419
420 if (!(options & CreateOptions::CreateNew)) {
421 LOG(ERROR) << "not requirested create new storage, and it doesn't exist: " << mountPoint;
422 return kInvalidStorageId;
423 }
424
425 if (!path::isEmptyDir(mountNorm)) {
426 LOG(ERROR) << "Mounting over existing non-empty directory is not supported: " << mountNorm;
427 return kInvalidStorageId;
428 }
429 auto [mountKey, mountRoot] = makeMountDir(mIncrementalDir, mountNorm);
430 if (mountRoot.empty()) {
431 LOG(ERROR) << "Bad mount point";
432 return kInvalidStorageId;
433 }
434 // Make sure the code removes all crap it may create while still failing.
435 auto firstCleanup = [](const std::string* ptr) { IncFsMount::cleanupFilesystem(*ptr); };
436 auto firstCleanupOnFailure =
437 std::unique_ptr<std::string, decltype(firstCleanup)>(&mountRoot, firstCleanup);
438
439 auto mountTarget = path::join(mountRoot, constants().mount);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800440 const auto backing = path::join(mountRoot, constants().backing);
441 if (!mkdirOrLog(backing, 0777) || !mkdirOrLog(mountTarget)) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800442 return kInvalidStorageId;
443 }
444
Songchun Fan3c82a302019-11-29 14:23:45 -0800445 IncFsMount::Control control;
446 {
447 std::lock_guard l(mMountOperationLock);
448 IncrementalFileSystemControlParcel controlParcel;
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800449
450 if (auto err = rmDirContent(backing.c_str())) {
451 LOG(ERROR) << "Coudn't clean the backing directory " << backing << ": " << err;
452 return kInvalidStorageId;
453 }
454 if (!mkdirOrLog(path::join(backing, ".index"), 0777)) {
455 return kInvalidStorageId;
456 }
457 auto status = mVold->mountIncFs(backing, mountTarget, 0, &controlParcel);
Songchun Fan3c82a302019-11-29 14:23:45 -0800458 if (!status.isOk()) {
459 LOG(ERROR) << "Vold::mountIncFs() failed: " << status.toString8();
460 return kInvalidStorageId;
461 }
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800462 if (controlParcel.cmd.get() < 0 || controlParcel.pendingReads.get() < 0 ||
463 controlParcel.log.get() < 0) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800464 LOG(ERROR) << "Vold::mountIncFs() returned invalid control parcel.";
465 return kInvalidStorageId;
466 }
Songchun Fan20d6ef22020-03-03 09:47:15 -0800467 int cmd = controlParcel.cmd.release().release();
468 int pendingReads = controlParcel.pendingReads.release().release();
469 int logs = controlParcel.log.release().release();
470 control = mIncFs->createControl(cmd, pendingReads, logs);
Songchun Fan3c82a302019-11-29 14:23:45 -0800471 }
472
473 std::unique_lock l(mLock);
474 const auto mountIt = getStorageSlotLocked();
475 const auto mountId = mountIt->first;
476 l.unlock();
477
478 auto ifs =
479 std::make_shared<IncFsMount>(std::move(mountRoot), mountId, std::move(control), *this);
480 // Now it's the |ifs|'s responsibility to clean up after itself, and the only cleanup we need
481 // is the removal of the |ifs|.
482 firstCleanupOnFailure.release();
483
484 auto secondCleanup = [this, &l](auto itPtr) {
485 if (!l.owns_lock()) {
486 l.lock();
487 }
488 mMounts.erase(*itPtr);
489 };
490 auto secondCleanupOnFailure =
491 std::unique_ptr<decltype(mountIt), decltype(secondCleanup)>(&mountIt, secondCleanup);
492
493 const auto storageIt = ifs->makeStorage(ifs->mountId);
494 if (storageIt == ifs->storages.end()) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800495 LOG(ERROR) << "Can't create a default storage directory";
Songchun Fan3c82a302019-11-29 14:23:45 -0800496 return kInvalidStorageId;
497 }
498
499 {
500 metadata::Mount m;
501 m.mutable_storage()->set_id(ifs->mountId);
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -0700502 m.mutable_loader()->set_type((int)dataLoaderParams.type);
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700503 m.mutable_loader()->set_allocated_package_name(&dataLoaderParams.packageName);
504 m.mutable_loader()->set_allocated_class_name(&dataLoaderParams.className);
505 m.mutable_loader()->set_allocated_arguments(&dataLoaderParams.arguments);
Songchun Fan3c82a302019-11-29 14:23:45 -0800506 const auto metadata = m.SerializeAsString();
507 m.mutable_loader()->release_arguments();
Alex Buynytskyy1ecfcec2019-12-17 12:10:41 -0800508 m.mutable_loader()->release_class_name();
Songchun Fan3c82a302019-11-29 14:23:45 -0800509 m.mutable_loader()->release_package_name();
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800510 if (auto err =
511 mIncFs->makeFile(ifs->control,
512 path::join(ifs->root, constants().mount,
513 constants().infoMdName),
514 0777, idFromMetadata(metadata),
515 {.metadata = {metadata.data(), (IncFsSize)metadata.size()}})) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800516 LOG(ERROR) << "Saving mount metadata failed: " << -err;
517 return kInvalidStorageId;
518 }
519 }
520
521 const auto bk =
522 (options & CreateOptions::PermanentBind) ? BindKind::Permanent : BindKind::Temporary;
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800523 if (auto err = addBindMount(*ifs, storageIt->first, storageIt->second.name,
524 std::string(storageIt->second.name), std::move(mountNorm), bk, l);
Songchun Fan3c82a302019-11-29 14:23:45 -0800525 err < 0) {
526 LOG(ERROR) << "adding bind mount failed: " << -err;
527 return kInvalidStorageId;
528 }
529
530 // Done here as well, all data structures are in good state.
531 secondCleanupOnFailure.release();
532
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -0700533 auto dataLoaderStub =
534 prepareDataLoader(*ifs, std::move(dataLoaderParams), &dataLoaderStatusListener);
535 CHECK(dataLoaderStub);
Songchun Fan3c82a302019-11-29 14:23:45 -0800536
537 mountIt->second = std::move(ifs);
538 l.unlock();
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -0700539
Alex Buynytskyyab65cb12020-04-17 10:01:47 -0700540 if (mSystemReady.load(std::memory_order_relaxed) && !dataLoaderStub->requestCreate()) {
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -0700541 // failed to create data loader
542 LOG(ERROR) << "initializeDataLoader() failed";
543 deleteStorage(dataLoaderStub->id());
544 return kInvalidStorageId;
545 }
546
Songchun Fan3c82a302019-11-29 14:23:45 -0800547 LOG(INFO) << "created storage " << mountId;
548 return mountId;
549}
550
551StorageId IncrementalService::createLinkedStorage(std::string_view mountPoint,
552 StorageId linkedStorage,
553 IncrementalService::CreateOptions options) {
554 if (!isValidMountTarget(mountPoint)) {
555 LOG(ERROR) << "Mount point is invalid or missing";
556 return kInvalidStorageId;
557 }
558
559 std::unique_lock l(mLock);
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700560 auto ifs = getIfsLocked(linkedStorage);
Songchun Fan3c82a302019-11-29 14:23:45 -0800561 if (!ifs) {
562 LOG(ERROR) << "Ifs unavailable";
563 return kInvalidStorageId;
564 }
565
566 const auto mountIt = getStorageSlotLocked();
567 const auto storageId = mountIt->first;
568 const auto storageIt = ifs->makeStorage(storageId);
569 if (storageIt == ifs->storages.end()) {
570 LOG(ERROR) << "Can't create a new storage";
571 mMounts.erase(mountIt);
572 return kInvalidStorageId;
573 }
574
575 l.unlock();
576
577 const auto bk =
578 (options & CreateOptions::PermanentBind) ? BindKind::Permanent : BindKind::Temporary;
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800579 if (auto err = addBindMount(*ifs, storageIt->first, storageIt->second.name,
580 std::string(storageIt->second.name), path::normalize(mountPoint),
581 bk, l);
Songchun Fan3c82a302019-11-29 14:23:45 -0800582 err < 0) {
583 LOG(ERROR) << "bindMount failed with error: " << err;
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700584 (void)mIncFs->unlink(ifs->control, storageIt->second.name);
585 ifs->storages.erase(storageIt);
Songchun Fan3c82a302019-11-29 14:23:45 -0800586 return kInvalidStorageId;
587 }
588
589 mountIt->second = ifs;
590 return storageId;
591}
592
593IncrementalService::BindPathMap::const_iterator IncrementalService::findStorageLocked(
594 std::string_view path) const {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700595 return findParentPath(mBindsByPath, path);
Songchun Fan3c82a302019-11-29 14:23:45 -0800596}
597
598StorageId IncrementalService::findStorageId(std::string_view path) const {
599 std::lock_guard l(mLock);
600 auto it = findStorageLocked(path);
601 if (it == mBindsByPath.end()) {
602 return kInvalidStorageId;
603 }
604 return it->second->second.storage;
605}
606
Alex Buynytskyy5e860ba2020-03-31 15:30:21 -0700607int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLogs) {
608 const auto ifs = getIfs(storageId);
609 if (!ifs) {
Alex Buynytskyy5f9e3a02020-04-07 21:13:41 -0700610 LOG(ERROR) << "setStorageParams failed, invalid storageId: " << storageId;
Alex Buynytskyy5e860ba2020-03-31 15:30:21 -0700611 return -EINVAL;
612 }
613
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -0700614 const auto& params = ifs->dataLoaderStub->params();
Alex Buynytskyy96e350b2020-04-02 20:03:47 -0700615 if (enableReadLogs) {
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -0700616 if (auto status = mAppOpsManager->checkPermission(kDataUsageStats, kOpUsage,
617 params.packageName.c_str());
Alex Buynytskyy96e350b2020-04-02 20:03:47 -0700618 !status.isOk()) {
Alex Buynytskyy1d892162020-04-03 23:00:19 -0700619 LOG(ERROR) << "checkPermission failed: " << status.toString8();
Alex Buynytskyy96e350b2020-04-02 20:03:47 -0700620 return fromBinderStatus(status);
621 }
622 }
623
Alex Buynytskyy1d892162020-04-03 23:00:19 -0700624 if (auto status = applyStorageParams(*ifs, enableReadLogs); !status.isOk()) {
625 LOG(ERROR) << "applyStorageParams failed: " << status.toString8();
626 return fromBinderStatus(status);
627 }
628
629 if (enableReadLogs) {
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -0700630 registerAppOpsCallback(params.packageName);
Alex Buynytskyy1d892162020-04-03 23:00:19 -0700631 }
632
633 return 0;
634}
635
636binder::Status IncrementalService::applyStorageParams(IncFsMount& ifs, bool enableReadLogs) {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700637 os::incremental::IncrementalFileSystemControlParcel control;
638 control.cmd.reset(dup(ifs.control.cmd()));
639 control.pendingReads.reset(dup(ifs.control.pendingReads()));
Alex Buynytskyy96e350b2020-04-02 20:03:47 -0700640 auto logsFd = ifs.control.logs();
Alex Buynytskyy5e860ba2020-03-31 15:30:21 -0700641 if (logsFd >= 0) {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700642 control.log.reset(dup(logsFd));
Alex Buynytskyy5e860ba2020-03-31 15:30:21 -0700643 }
644
645 std::lock_guard l(mMountOperationLock);
Alex Buynytskyy1d892162020-04-03 23:00:19 -0700646 return mVold->setIncFsMountOptions(control, enableReadLogs);
Alex Buynytskyy5e860ba2020-03-31 15:30:21 -0700647}
648
Songchun Fan3c82a302019-11-29 14:23:45 -0800649void IncrementalService::deleteStorage(StorageId storageId) {
650 const auto ifs = getIfs(storageId);
651 if (!ifs) {
652 return;
653 }
654 deleteStorage(*ifs);
655}
656
657void IncrementalService::deleteStorage(IncrementalService::IncFsMount& ifs) {
658 std::unique_lock l(ifs.lock);
659 deleteStorageLocked(ifs, std::move(l));
660}
661
662void IncrementalService::deleteStorageLocked(IncrementalService::IncFsMount& ifs,
663 std::unique_lock<std::mutex>&& ifsLock) {
664 const auto storages = std::move(ifs.storages);
665 // Don't move the bind points out: Ifs's dtor will use them to unmount everything.
666 const auto bindPoints = ifs.bindPoints;
667 ifsLock.unlock();
668
669 std::lock_guard l(mLock);
670 for (auto&& [id, _] : storages) {
671 if (id != ifs.mountId) {
672 mMounts.erase(id);
673 }
674 }
675 for (auto&& [path, _] : bindPoints) {
676 mBindsByPath.erase(path);
677 }
678 mMounts.erase(ifs.mountId);
679}
680
681StorageId IncrementalService::openStorage(std::string_view pathInMount) {
682 if (!path::isAbsolute(pathInMount)) {
683 return kInvalidStorageId;
684 }
685
686 return findStorageId(path::normalize(pathInMount));
687}
688
Songchun Fan3c82a302019-11-29 14:23:45 -0800689IncrementalService::IfsMountPtr IncrementalService::getIfs(StorageId storage) const {
690 std::lock_guard l(mLock);
691 return getIfsLocked(storage);
692}
693
694const IncrementalService::IfsMountPtr& IncrementalService::getIfsLocked(StorageId storage) const {
695 auto it = mMounts.find(storage);
696 if (it == mMounts.end()) {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700697 static const base::NoDestructor<IfsMountPtr> kEmpty{};
Yurii Zubrytskyi0cd80122020-04-09 23:08:31 -0700698 return *kEmpty;
Songchun Fan3c82a302019-11-29 14:23:45 -0800699 }
700 return it->second;
701}
702
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800703int IncrementalService::bind(StorageId storage, std::string_view source, std::string_view target,
704 BindKind kind) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800705 if (!isValidMountTarget(target)) {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700706 LOG(ERROR) << __func__ << ": not a valid bind target " << target;
Songchun Fan3c82a302019-11-29 14:23:45 -0800707 return -EINVAL;
708 }
709
710 const auto ifs = getIfs(storage);
711 if (!ifs) {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700712 LOG(ERROR) << __func__ << ": no ifs object for storage " << storage;
Songchun Fan3c82a302019-11-29 14:23:45 -0800713 return -EINVAL;
714 }
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800715
Songchun Fan3c82a302019-11-29 14:23:45 -0800716 std::unique_lock l(ifs->lock);
717 const auto storageInfo = ifs->storages.find(storage);
718 if (storageInfo == ifs->storages.end()) {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700719 LOG(ERROR) << "no storage";
Songchun Fan3c82a302019-11-29 14:23:45 -0800720 return -EINVAL;
721 }
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700722 std::string normSource = normalizePathToStorageLocked(ifs, storageInfo, source);
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -0700723 if (normSource.empty()) {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700724 LOG(ERROR) << "invalid source path";
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -0700725 return -EINVAL;
726 }
Songchun Fan3c82a302019-11-29 14:23:45 -0800727 l.unlock();
728 std::unique_lock l2(mLock, std::defer_lock);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800729 return addBindMount(*ifs, storage, storageInfo->second.name, std::move(normSource),
730 path::normalize(target), kind, l2);
Songchun Fan3c82a302019-11-29 14:23:45 -0800731}
732
733int IncrementalService::unbind(StorageId storage, std::string_view target) {
734 if (!path::isAbsolute(target)) {
735 return -EINVAL;
736 }
737
738 LOG(INFO) << "Removing bind point " << target;
739
740 // Here we should only look up by the exact target, not by a subdirectory of any existing mount,
741 // otherwise there's a chance to unmount something completely unrelated
742 const auto norm = path::normalize(target);
743 std::unique_lock l(mLock);
744 const auto storageIt = mBindsByPath.find(norm);
745 if (storageIt == mBindsByPath.end() || storageIt->second->second.storage != storage) {
746 return -EINVAL;
747 }
748 const auto bindIt = storageIt->second;
749 const auto storageId = bindIt->second.storage;
750 const auto ifs = getIfsLocked(storageId);
751 if (!ifs) {
752 LOG(ERROR) << "Internal error: storageId " << storageId << " for bound path " << target
753 << " is missing";
754 return -EFAULT;
755 }
756 mBindsByPath.erase(storageIt);
757 l.unlock();
758
759 mVold->unmountIncFs(bindIt->first);
760 std::unique_lock l2(ifs->lock);
761 if (ifs->bindPoints.size() <= 1) {
762 ifs->bindPoints.clear();
763 deleteStorageLocked(*ifs, std::move(l2));
764 } else {
765 const std::string savedFile = std::move(bindIt->second.savedFilename);
766 ifs->bindPoints.erase(bindIt);
767 l2.unlock();
768 if (!savedFile.empty()) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800769 mIncFs->unlink(ifs->control, path::join(ifs->root, constants().mount, savedFile));
Songchun Fan3c82a302019-11-29 14:23:45 -0800770 }
771 }
772 return 0;
773}
774
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -0700775std::string IncrementalService::normalizePathToStorageLocked(
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700776 const IfsMountPtr& incfs, IncFsMount::StorageMap::iterator storageIt,
777 std::string_view path) const {
778 if (!path::isAbsolute(path)) {
779 return path::normalize(path::join(storageIt->second.name, path));
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -0700780 }
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700781 auto normPath = path::normalize(path);
782 if (path::startsWith(normPath, storageIt->second.name)) {
783 return normPath;
784 }
785 // not that easy: need to find if any of the bind points match
786 const auto bindIt = findParentPath(incfs->bindPoints, normPath);
787 if (bindIt == incfs->bindPoints.end()) {
788 return {};
789 }
790 return path::join(bindIt->second.sourceDir, path::relativize(bindIt->first, normPath));
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -0700791}
792
793std::string IncrementalService::normalizePathToStorage(const IncrementalService::IfsMountPtr& ifs,
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700794 StorageId storage,
795 std::string_view path) const {
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -0700796 std::unique_lock l(ifs->lock);
Songchun Fan103ba1d2020-02-03 17:32:32 -0800797 const auto storageInfo = ifs->storages.find(storage);
798 if (storageInfo == ifs->storages.end()) {
799 return {};
800 }
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700801 return normalizePathToStorageLocked(ifs, storageInfo, path);
Songchun Fan103ba1d2020-02-03 17:32:32 -0800802}
803
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800804int IncrementalService::makeFile(StorageId storage, std::string_view path, int mode, FileId id,
805 incfs::NewFileParams params) {
806 if (auto ifs = getIfs(storage)) {
Songchun Fan103ba1d2020-02-03 17:32:32 -0800807 std::string normPath = normalizePathToStorage(ifs, storage, path);
808 if (normPath.empty()) {
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -0700809 LOG(ERROR) << "Internal error: storageId " << storage
810 << " failed to normalize: " << path;
Songchun Fan54c6aed2020-01-31 16:52:41 -0800811 return -EINVAL;
812 }
813 auto err = mIncFs->makeFile(ifs->control, normPath, mode, id, params);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800814 if (err) {
Alex Buynytskyy5e860ba2020-03-31 15:30:21 -0700815 LOG(ERROR) << "Internal error: storageId " << storage << " failed to makeFile: " << err;
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800816 return err;
Songchun Fan3c82a302019-11-29 14:23:45 -0800817 }
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800818 return 0;
Songchun Fan3c82a302019-11-29 14:23:45 -0800819 }
820 return -EINVAL;
821}
822
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800823int IncrementalService::makeDir(StorageId storageId, std::string_view path, int mode) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800824 if (auto ifs = getIfs(storageId)) {
Songchun Fan103ba1d2020-02-03 17:32:32 -0800825 std::string normPath = normalizePathToStorage(ifs, storageId, path);
826 if (normPath.empty()) {
827 return -EINVAL;
828 }
829 return mIncFs->makeDir(ifs->control, normPath, mode);
Songchun Fan3c82a302019-11-29 14:23:45 -0800830 }
831 return -EINVAL;
832}
833
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800834int IncrementalService::makeDirs(StorageId storageId, std::string_view path, int mode) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800835 const auto ifs = getIfs(storageId);
836 if (!ifs) {
837 return -EINVAL;
838 }
Songchun Fan103ba1d2020-02-03 17:32:32 -0800839 std::string normPath = normalizePathToStorage(ifs, storageId, path);
840 if (normPath.empty()) {
841 return -EINVAL;
842 }
843 auto err = mIncFs->makeDir(ifs->control, normPath, mode);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800844 if (err == -EEXIST) {
845 return 0;
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700846 }
847 if (err != -ENOENT) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800848 return err;
Songchun Fan3c82a302019-11-29 14:23:45 -0800849 }
Songchun Fan103ba1d2020-02-03 17:32:32 -0800850 if (auto err = makeDirs(storageId, path::dirname(normPath), mode)) {
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800851 return err;
Songchun Fan3c82a302019-11-29 14:23:45 -0800852 }
Songchun Fan103ba1d2020-02-03 17:32:32 -0800853 return mIncFs->makeDir(ifs->control, normPath, mode);
Songchun Fan3c82a302019-11-29 14:23:45 -0800854}
855
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800856int IncrementalService::link(StorageId sourceStorageId, std::string_view oldPath,
857 StorageId destStorageId, std::string_view newPath) {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700858 std::unique_lock l(mLock);
859 auto ifsSrc = getIfsLocked(sourceStorageId);
860 if (!ifsSrc) {
861 return -EINVAL;
Songchun Fan3c82a302019-11-29 14:23:45 -0800862 }
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700863 if (sourceStorageId != destStorageId && getIfsLocked(destStorageId) != ifsSrc) {
864 return -EINVAL;
865 }
866 l.unlock();
867 std::string normOldPath = normalizePathToStorage(ifsSrc, sourceStorageId, oldPath);
868 std::string normNewPath = normalizePathToStorage(ifsSrc, destStorageId, newPath);
869 if (normOldPath.empty() || normNewPath.empty()) {
870 LOG(ERROR) << "Invalid paths in link(): " << normOldPath << " | " << normNewPath;
871 return -EINVAL;
872 }
873 return mIncFs->link(ifsSrc->control, normOldPath, normNewPath);
Songchun Fan3c82a302019-11-29 14:23:45 -0800874}
875
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800876int IncrementalService::unlink(StorageId storage, std::string_view path) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800877 if (auto ifs = getIfs(storage)) {
Songchun Fan103ba1d2020-02-03 17:32:32 -0800878 std::string normOldPath = normalizePathToStorage(ifs, storage, path);
879 return mIncFs->unlink(ifs->control, normOldPath);
Songchun Fan3c82a302019-11-29 14:23:45 -0800880 }
881 return -EINVAL;
882}
883
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800884int IncrementalService::addBindMount(IncFsMount& ifs, StorageId storage,
885 std::string_view storageRoot, std::string&& source,
Songchun Fan3c82a302019-11-29 14:23:45 -0800886 std::string&& target, BindKind kind,
887 std::unique_lock<std::mutex>& mainLock) {
888 if (!isValidMountTarget(target)) {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700889 LOG(ERROR) << __func__ << ": invalid mount target " << target;
Songchun Fan3c82a302019-11-29 14:23:45 -0800890 return -EINVAL;
891 }
892
893 std::string mdFileName;
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700894 std::string metadataFullPath;
Songchun Fan3c82a302019-11-29 14:23:45 -0800895 if (kind != BindKind::Temporary) {
896 metadata::BindPoint bp;
897 bp.set_storage_id(storage);
898 bp.set_allocated_dest_path(&target);
Songchun Fan1124fd32020-02-10 12:49:41 -0800899 bp.set_allocated_source_subdir(&source);
Songchun Fan3c82a302019-11-29 14:23:45 -0800900 const auto metadata = bp.SerializeAsString();
Songchun Fan3c82a302019-11-29 14:23:45 -0800901 bp.release_dest_path();
Songchun Fan1124fd32020-02-10 12:49:41 -0800902 bp.release_source_subdir();
Songchun Fan3c82a302019-11-29 14:23:45 -0800903 mdFileName = makeBindMdName();
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700904 metadataFullPath = path::join(ifs.root, constants().mount, mdFileName);
905 auto node = mIncFs->makeFile(ifs.control, metadataFullPath, 0444, idFromMetadata(metadata),
906 {.metadata = {metadata.data(), (IncFsSize)metadata.size()}});
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800907 if (node) {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700908 LOG(ERROR) << __func__ << ": couldn't create a mount node " << mdFileName;
Songchun Fan3c82a302019-11-29 14:23:45 -0800909 return int(node);
910 }
911 }
912
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700913 const auto res = addBindMountWithMd(ifs, storage, std::move(mdFileName), std::move(source),
914 std::move(target), kind, mainLock);
915 if (res) {
916 mIncFs->unlink(ifs.control, metadataFullPath);
917 }
918 return res;
Songchun Fan3c82a302019-11-29 14:23:45 -0800919}
920
921int IncrementalService::addBindMountWithMd(IncrementalService::IncFsMount& ifs, StorageId storage,
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800922 std::string&& metadataName, std::string&& source,
Songchun Fan3c82a302019-11-29 14:23:45 -0800923 std::string&& target, BindKind kind,
924 std::unique_lock<std::mutex>& mainLock) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800925 {
Songchun Fan3c82a302019-11-29 14:23:45 -0800926 std::lock_guard l(mMountOperationLock);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800927 const auto status = mVold->bindMount(source, target);
Songchun Fan3c82a302019-11-29 14:23:45 -0800928 if (!status.isOk()) {
929 LOG(ERROR) << "Calling Vold::bindMount() failed: " << status.toString8();
930 return status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC
931 ? status.serviceSpecificErrorCode() > 0 ? -status.serviceSpecificErrorCode()
932 : status.serviceSpecificErrorCode() == 0
933 ? -EFAULT
934 : status.serviceSpecificErrorCode()
935 : -EIO;
936 }
937 }
938
939 if (!mainLock.owns_lock()) {
940 mainLock.lock();
941 }
942 std::lock_guard l(ifs.lock);
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700943 addBindMountRecordLocked(ifs, storage, std::move(metadataName), std::move(source),
944 std::move(target), kind);
945 return 0;
946}
947
948void IncrementalService::addBindMountRecordLocked(IncFsMount& ifs, StorageId storage,
949 std::string&& metadataName, std::string&& source,
950 std::string&& target, BindKind kind) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800951 const auto [it, _] =
952 ifs.bindPoints.insert_or_assign(target,
953 IncFsMount::Bind{storage, std::move(metadataName),
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800954 std::move(source), kind});
Songchun Fan3c82a302019-11-29 14:23:45 -0800955 mBindsByPath[std::move(target)] = it;
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700956}
957
958RawMetadata IncrementalService::getMetadata(StorageId storage, std::string_view path) const {
959 const auto ifs = getIfs(storage);
960 if (!ifs) {
961 return {};
962 }
963 const auto normPath = normalizePathToStorage(ifs, storage, path);
964 if (normPath.empty()) {
965 return {};
966 }
967 return mIncFs->getMetadata(ifs->control, normPath);
Songchun Fan3c82a302019-11-29 14:23:45 -0800968}
969
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -0800970RawMetadata IncrementalService::getMetadata(StorageId storage, FileId node) const {
Songchun Fan3c82a302019-11-29 14:23:45 -0800971 const auto ifs = getIfs(storage);
972 if (!ifs) {
973 return {};
974 }
975 return mIncFs->getMetadata(ifs->control, node);
976}
977
Songchun Fan3c82a302019-11-29 14:23:45 -0800978bool IncrementalService::startLoading(StorageId storage) const {
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -0700979 DataLoaderStubPtr dataLoaderStub;
Alex Buynytskyybf1c0632020-03-10 15:49:29 -0700980 {
981 std::unique_lock l(mLock);
982 const auto& ifs = getIfsLocked(storage);
983 if (!ifs) {
Songchun Fan3c82a302019-11-29 14:23:45 -0800984 return false;
985 }
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -0700986 dataLoaderStub = ifs->dataLoaderStub;
987 if (!dataLoaderStub) {
988 return false;
Alex Buynytskyybf1c0632020-03-10 15:49:29 -0700989 }
Songchun Fan3c82a302019-11-29 14:23:45 -0800990 }
Alex Buynytskyy9a54579a2020-04-17 15:34:47 -0700991 dataLoaderStub->requestStart();
992 return true;
Songchun Fan3c82a302019-11-29 14:23:45 -0800993}
994
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -0700995std::unordered_set<std::string_view> IncrementalService::adoptMountedInstances() {
996 std::unordered_set<std::string_view> mountedRootNames;
997 mIncFs->listExistingMounts([this, &mountedRootNames](auto root, auto backingDir, auto binds) {
998 LOG(INFO) << "Existing mount: " << backingDir << "->" << root;
999 for (auto [source, target] : binds) {
1000 LOG(INFO) << " bind: '" << source << "'->'" << target << "'";
1001 LOG(INFO) << " " << path::join(root, source);
1002 }
1003
1004 // Ensure it's a kind of a mount that's managed by IncrementalService
1005 if (path::basename(root) != constants().mount ||
1006 path::basename(backingDir) != constants().backing) {
1007 return;
1008 }
1009 const auto expectedRoot = path::dirname(root);
1010 if (path::dirname(backingDir) != expectedRoot) {
1011 return;
1012 }
1013 if (path::dirname(expectedRoot) != mIncrementalDir) {
1014 return;
1015 }
1016 if (!path::basename(expectedRoot).starts_with(constants().mountKeyPrefix)) {
1017 return;
1018 }
1019
1020 LOG(INFO) << "Looks like an IncrementalService-owned: " << expectedRoot;
1021
1022 // make sure we clean up the mount if it happens to be a bad one.
1023 // Note: unmounting needs to run first, so the cleanup object is created _last_.
1024 auto cleanupFiles = makeCleanup([&]() {
1025 LOG(INFO) << "Failed to adopt existing mount, deleting files: " << expectedRoot;
1026 IncFsMount::cleanupFilesystem(expectedRoot);
1027 });
1028 auto cleanupMounts = makeCleanup([&]() {
1029 LOG(INFO) << "Failed to adopt existing mount, cleaning up: " << expectedRoot;
1030 for (auto&& [_, target] : binds) {
1031 mVold->unmountIncFs(std::string(target));
1032 }
1033 mVold->unmountIncFs(std::string(root));
1034 });
1035
1036 auto control = mIncFs->openMount(root);
1037 if (!control) {
1038 LOG(INFO) << "failed to open mount " << root;
1039 return;
1040 }
1041
1042 auto mountRecord =
1043 parseFromIncfs<metadata::Mount>(mIncFs.get(), control,
1044 path::join(root, constants().infoMdName));
1045 if (!mountRecord.has_loader() || !mountRecord.has_storage()) {
1046 LOG(ERROR) << "Bad mount metadata in mount at " << expectedRoot;
1047 return;
1048 }
1049
1050 auto mountId = mountRecord.storage().id();
1051 mNextId = std::max(mNextId, mountId + 1);
1052
1053 DataLoaderParamsParcel dataLoaderParams;
1054 {
1055 const auto& loader = mountRecord.loader();
1056 dataLoaderParams.type = (content::pm::DataLoaderType)loader.type();
1057 dataLoaderParams.packageName = loader.package_name();
1058 dataLoaderParams.className = loader.class_name();
1059 dataLoaderParams.arguments = loader.arguments();
1060 }
1061
1062 auto ifs = std::make_shared<IncFsMount>(std::string(expectedRoot), mountId,
1063 std::move(control), *this);
1064 cleanupFiles.release(); // ifs will take care of that now
1065
1066 std::vector<std::pair<std::string, metadata::BindPoint>> permanentBindPoints;
1067 auto d = openDir(root);
1068 while (auto e = ::readdir(d.get())) {
1069 if (e->d_type == DT_REG) {
1070 auto name = std::string_view(e->d_name);
1071 if (name.starts_with(constants().mountpointMdPrefix)) {
1072 permanentBindPoints
1073 .emplace_back(name,
1074 parseFromIncfs<metadata::BindPoint>(mIncFs.get(),
1075 ifs->control,
1076 path::join(root,
1077 name)));
1078 if (permanentBindPoints.back().second.dest_path().empty() ||
1079 permanentBindPoints.back().second.source_subdir().empty()) {
1080 permanentBindPoints.pop_back();
1081 mIncFs->unlink(ifs->control, path::join(root, name));
1082 } else {
1083 LOG(INFO) << "Permanent bind record: '"
1084 << permanentBindPoints.back().second.source_subdir() << "'->'"
1085 << permanentBindPoints.back().second.dest_path() << "'";
1086 }
1087 }
1088 } else if (e->d_type == DT_DIR) {
1089 if (e->d_name == "."sv || e->d_name == ".."sv) {
1090 continue;
1091 }
1092 auto name = std::string_view(e->d_name);
1093 if (name.starts_with(constants().storagePrefix)) {
1094 int storageId;
1095 const auto res =
1096 std::from_chars(name.data() + constants().storagePrefix.size() + 1,
1097 name.data() + name.size(), storageId);
1098 if (res.ec != std::errc{} || *res.ptr != '_') {
1099 LOG(WARNING) << "Ignoring storage with invalid name '" << name
1100 << "' for mount " << expectedRoot;
1101 continue;
1102 }
1103 auto [_, inserted] = mMounts.try_emplace(storageId, ifs);
1104 if (!inserted) {
1105 LOG(WARNING) << "Ignoring storage with duplicate id " << storageId
1106 << " for mount " << expectedRoot;
1107 continue;
1108 }
1109 ifs->storages.insert_or_assign(storageId,
1110 IncFsMount::Storage{path::join(root, name)});
1111 mNextId = std::max(mNextId, storageId + 1);
1112 }
1113 }
1114 }
1115
1116 if (ifs->storages.empty()) {
1117 LOG(WARNING) << "No valid storages in mount " << root;
1118 return;
1119 }
1120
1121 // now match the mounted directories with what we expect to have in the metadata
1122 {
1123 std::unique_lock l(mLock, std::defer_lock);
1124 for (auto&& [metadataFile, bindRecord] : permanentBindPoints) {
1125 auto mountedIt = std::find_if(binds.begin(), binds.end(),
1126 [&, bindRecord = bindRecord](auto&& bind) {
1127 return bind.second == bindRecord.dest_path() &&
1128 path::join(root, bind.first) ==
1129 bindRecord.source_subdir();
1130 });
1131 if (mountedIt != binds.end()) {
1132 LOG(INFO) << "Matched permanent bound " << bindRecord.source_subdir()
1133 << " to mount " << mountedIt->first;
1134 addBindMountRecordLocked(*ifs, bindRecord.storage_id(), std::move(metadataFile),
1135 std::move(*bindRecord.mutable_source_subdir()),
1136 std::move(*bindRecord.mutable_dest_path()),
1137 BindKind::Permanent);
1138 if (mountedIt != binds.end() - 1) {
1139 std::iter_swap(mountedIt, binds.end() - 1);
1140 }
1141 binds = binds.first(binds.size() - 1);
1142 } else {
1143 LOG(INFO) << "Didn't match permanent bound " << bindRecord.source_subdir()
1144 << ", mounting";
1145 // doesn't exist - try mounting back
1146 if (addBindMountWithMd(*ifs, bindRecord.storage_id(), std::move(metadataFile),
1147 std::move(*bindRecord.mutable_source_subdir()),
1148 std::move(*bindRecord.mutable_dest_path()),
1149 BindKind::Permanent, l)) {
1150 mIncFs->unlink(ifs->control, metadataFile);
1151 }
1152 }
1153 }
1154 }
1155
1156 // if anything stays in |binds| those are probably temporary binds; system restarted since
1157 // they were mounted - so let's unmount them all.
1158 for (auto&& [source, target] : binds) {
1159 if (source.empty()) {
1160 continue;
1161 }
1162 mVold->unmountIncFs(std::string(target));
1163 }
1164 cleanupMounts.release(); // ifs now manages everything
1165
1166 if (ifs->bindPoints.empty()) {
1167 LOG(WARNING) << "No valid bind points for mount " << expectedRoot;
1168 deleteStorage(*ifs);
1169 return;
1170 }
1171
1172 prepareDataLoaderLocked(*ifs, std::move(dataLoaderParams));
1173 CHECK(ifs->dataLoaderStub);
1174
1175 mountedRootNames.insert(path::basename(ifs->root));
1176
1177 // not locking here at all: we're still in the constructor, no other calls can happen
1178 mMounts[ifs->mountId] = std::move(ifs);
1179 });
1180
1181 return mountedRootNames;
1182}
1183
1184void IncrementalService::mountExistingImages(
1185 const std::unordered_set<std::string_view>& mountedRootNames) {
1186 auto dir = openDir(mIncrementalDir);
1187 if (!dir) {
1188 PLOG(WARNING) << "Couldn't open the root incremental dir " << mIncrementalDir;
1189 return;
1190 }
1191 while (auto entry = ::readdir(dir.get())) {
1192 if (entry->d_type != DT_DIR) {
1193 continue;
1194 }
1195 std::string_view name = entry->d_name;
1196 if (!name.starts_with(constants().mountKeyPrefix)) {
1197 continue;
1198 }
1199 if (mountedRootNames.find(name) != mountedRootNames.end()) {
Songchun Fan3c82a302019-11-29 14:23:45 -08001200 continue;
1201 }
Songchun Fan1124fd32020-02-10 12:49:41 -08001202 const auto root = path::join(mIncrementalDir, name);
Yurii Zubrytskyi107ae352020-04-03 13:12:51 -07001203 if (!mountExistingImage(root)) {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001204 IncFsMount::cleanupFilesystem(root);
Songchun Fan3c82a302019-11-29 14:23:45 -08001205 }
1206 }
1207}
1208
Yurii Zubrytskyi107ae352020-04-03 13:12:51 -07001209bool IncrementalService::mountExistingImage(std::string_view root) {
Songchun Fan3c82a302019-11-29 14:23:45 -08001210 auto mountTarget = path::join(root, constants().mount);
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -08001211 const auto backing = path::join(root, constants().backing);
Songchun Fan3c82a302019-11-29 14:23:45 -08001212
Songchun Fan3c82a302019-11-29 14:23:45 -08001213 IncrementalFileSystemControlParcel controlParcel;
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -08001214 auto status = mVold->mountIncFs(backing, mountTarget, 0, &controlParcel);
Songchun Fan3c82a302019-11-29 14:23:45 -08001215 if (!status.isOk()) {
1216 LOG(ERROR) << "Vold::mountIncFs() failed: " << status.toString8();
1217 return false;
1218 }
Songchun Fan20d6ef22020-03-03 09:47:15 -08001219
1220 int cmd = controlParcel.cmd.release().release();
1221 int pendingReads = controlParcel.pendingReads.release().release();
1222 int logs = controlParcel.log.release().release();
1223 IncFsMount::Control control = mIncFs->createControl(cmd, pendingReads, logs);
Songchun Fan3c82a302019-11-29 14:23:45 -08001224
1225 auto ifs = std::make_shared<IncFsMount>(std::string(root), -1, std::move(control), *this);
1226
Alex Buynytskyy96e350b2020-04-02 20:03:47 -07001227 auto mount = parseFromIncfs<metadata::Mount>(mIncFs.get(), ifs->control,
1228 path::join(mountTarget, constants().infoMdName));
1229 if (!mount.has_loader() || !mount.has_storage()) {
Songchun Fan3c82a302019-11-29 14:23:45 -08001230 LOG(ERROR) << "Bad mount metadata in mount at " << root;
1231 return false;
1232 }
1233
Alex Buynytskyy96e350b2020-04-02 20:03:47 -07001234 ifs->mountId = mount.storage().id();
Songchun Fan3c82a302019-11-29 14:23:45 -08001235 mNextId = std::max(mNextId, ifs->mountId + 1);
1236
Alex Buynytskyy96e350b2020-04-02 20:03:47 -07001237 // DataLoader params
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001238 DataLoaderParamsParcel dataLoaderParams;
Alex Buynytskyy96e350b2020-04-02 20:03:47 -07001239 {
Alex Buynytskyy96e350b2020-04-02 20:03:47 -07001240 const auto& loader = mount.loader();
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001241 dataLoaderParams.type = (content::pm::DataLoaderType)loader.type();
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001242 dataLoaderParams.packageName = loader.package_name();
1243 dataLoaderParams.className = loader.class_name();
1244 dataLoaderParams.arguments = loader.arguments();
Alex Buynytskyy96e350b2020-04-02 20:03:47 -07001245 }
1246
Alex Buynytskyy69941662020-04-11 21:40:37 -07001247 prepareDataLoader(*ifs, std::move(dataLoaderParams), nullptr);
1248 CHECK(ifs->dataLoaderStub);
1249
Songchun Fan3c82a302019-11-29 14:23:45 -08001250 std::vector<std::pair<std::string, metadata::BindPoint>> bindPoints;
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001251 auto d = openDir(mountTarget);
Songchun Fan3c82a302019-11-29 14:23:45 -08001252 while (auto e = ::readdir(d.get())) {
1253 if (e->d_type == DT_REG) {
1254 auto name = std::string_view(e->d_name);
1255 if (name.starts_with(constants().mountpointMdPrefix)) {
1256 bindPoints.emplace_back(name,
1257 parseFromIncfs<metadata::BindPoint>(mIncFs.get(),
1258 ifs->control,
1259 path::join(mountTarget,
1260 name)));
1261 if (bindPoints.back().second.dest_path().empty() ||
1262 bindPoints.back().second.source_subdir().empty()) {
1263 bindPoints.pop_back();
Yurii Zubrytskyi4a25dfb2020-01-10 11:53:24 -08001264 mIncFs->unlink(ifs->control, path::join(ifs->root, constants().mount, name));
Songchun Fan3c82a302019-11-29 14:23:45 -08001265 }
1266 }
1267 } else if (e->d_type == DT_DIR) {
1268 if (e->d_name == "."sv || e->d_name == ".."sv) {
1269 continue;
1270 }
1271 auto name = std::string_view(e->d_name);
1272 if (name.starts_with(constants().storagePrefix)) {
Yurii Zubrytskyi107ae352020-04-03 13:12:51 -07001273 int storageId;
1274 const auto res = std::from_chars(name.data() + constants().storagePrefix.size() + 1,
1275 name.data() + name.size(), storageId);
1276 if (res.ec != std::errc{} || *res.ptr != '_') {
1277 LOG(WARNING) << "Ignoring storage with invalid name '" << name << "' for mount "
1278 << root;
1279 continue;
1280 }
1281 auto [_, inserted] = mMounts.try_emplace(storageId, ifs);
Songchun Fan3c82a302019-11-29 14:23:45 -08001282 if (!inserted) {
Yurii Zubrytskyi107ae352020-04-03 13:12:51 -07001283 LOG(WARNING) << "Ignoring storage with duplicate id " << storageId
Songchun Fan3c82a302019-11-29 14:23:45 -08001284 << " for mount " << root;
1285 continue;
1286 }
Yurii Zubrytskyi107ae352020-04-03 13:12:51 -07001287 ifs->storages.insert_or_assign(storageId,
1288 IncFsMount::Storage{
1289 path::join(root, constants().mount, name)});
1290 mNextId = std::max(mNextId, storageId + 1);
Songchun Fan3c82a302019-11-29 14:23:45 -08001291 }
1292 }
1293 }
1294
1295 if (ifs->storages.empty()) {
1296 LOG(WARNING) << "No valid storages in mount " << root;
1297 return false;
1298 }
1299
1300 int bindCount = 0;
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001301 {
Songchun Fan3c82a302019-11-29 14:23:45 -08001302 std::unique_lock l(mLock, std::defer_lock);
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001303 for (auto&& bp : bindPoints) {
1304 bindCount += !addBindMountWithMd(*ifs, bp.second.storage_id(), std::move(bp.first),
1305 std::move(*bp.second.mutable_source_subdir()),
1306 std::move(*bp.second.mutable_dest_path()),
1307 BindKind::Permanent, l);
1308 }
Songchun Fan3c82a302019-11-29 14:23:45 -08001309 }
1310
1311 if (bindCount == 0) {
1312 LOG(WARNING) << "No valid bind points for mount " << root;
1313 deleteStorage(*ifs);
1314 return false;
1315 }
1316
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001317 // not locking here at all: we're still in the constructor, no other calls can happen
Songchun Fan3c82a302019-11-29 14:23:45 -08001318 mMounts[ifs->mountId] = std::move(ifs);
1319 return true;
1320}
1321
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001322IncrementalService::DataLoaderStubPtr IncrementalService::prepareDataLoader(
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001323 IncFsMount& ifs, DataLoaderParamsParcel&& params,
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001324 const DataLoaderStatusListener* externalListener) {
Songchun Fan3c82a302019-11-29 14:23:45 -08001325 std::unique_lock l(ifs.lock);
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001326 prepareDataLoaderLocked(ifs, std::move(params), externalListener);
1327 return ifs.dataLoaderStub;
1328}
1329
1330void IncrementalService::prepareDataLoaderLocked(IncFsMount& ifs, DataLoaderParamsParcel&& params,
1331 const DataLoaderStatusListener* externalListener) {
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001332 if (ifs.dataLoaderStub) {
Songchun Fan3c82a302019-11-29 14:23:45 -08001333 LOG(INFO) << "Skipped data loader preparation because it already exists";
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001334 return;
Songchun Fan3c82a302019-11-29 14:23:45 -08001335 }
1336
Songchun Fan3c82a302019-11-29 14:23:45 -08001337 FileSystemControlParcel fsControlParcel;
Jooyung Han66c567a2020-03-07 21:47:09 +09001338 fsControlParcel.incremental = aidl::make_nullable<IncrementalFileSystemControlParcel>();
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001339 fsControlParcel.incremental->cmd.reset(dup(ifs.control.cmd()));
1340 fsControlParcel.incremental->pendingReads.reset(dup(ifs.control.pendingReads()));
1341 fsControlParcel.incremental->log.reset(dup(ifs.control.logs()));
Alex Buynytskyyf4156792020-04-07 14:26:55 -07001342 fsControlParcel.service = new IncrementalServiceConnector(*this, ifs.mountId);
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001343
1344 ifs.dataLoaderStub = new DataLoaderStub(*this, ifs.mountId, std::move(params),
1345 std::move(fsControlParcel), externalListener);
Songchun Fan3c82a302019-11-29 14:23:45 -08001346}
1347
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001348template <class Duration>
1349static long elapsedMcs(Duration start, Duration end) {
1350 return std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
1351}
1352
1353// Extract lib files from zip, create new files in incfs and write data to them
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001354bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_view apkFullPath,
1355 std::string_view libDirRelativePath,
1356 std::string_view abi) {
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001357 auto start = Clock::now();
1358
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001359 const auto ifs = getIfs(storage);
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001360 if (!ifs) {
1361 LOG(ERROR) << "Invalid storage " << storage;
1362 return false;
1363 }
1364
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001365 // First prepare target directories if they don't exist yet
1366 if (auto res = makeDirs(storage, libDirRelativePath, 0755)) {
1367 LOG(ERROR) << "Failed to prepare target lib directory " << libDirRelativePath
1368 << " errno: " << res;
1369 return false;
1370 }
1371
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001372 auto mkDirsTs = Clock::now();
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001373 ZipArchiveHandle zipFileHandle;
1374 if (OpenArchive(path::c_str(apkFullPath), &zipFileHandle)) {
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001375 LOG(ERROR) << "Failed to open zip file at " << apkFullPath;
1376 return false;
1377 }
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001378
1379 // Need a shared pointer: will be passing it into all unpacking jobs.
1380 std::shared_ptr<ZipArchive> zipFile(zipFileHandle, [](ZipArchiveHandle h) { CloseArchive(h); });
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001381 void* cookie = nullptr;
1382 const auto libFilePrefix = path::join(constants().libDir, abi);
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001383 if (StartIteration(zipFile.get(), &cookie, libFilePrefix, constants().libSuffix)) {
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001384 LOG(ERROR) << "Failed to start zip iteration for " << apkFullPath;
1385 return false;
1386 }
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001387 auto endIteration = [](void* cookie) { EndIteration(cookie); };
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001388 auto iterationCleaner = std::unique_ptr<void, decltype(endIteration)>(cookie, endIteration);
1389
1390 auto openZipTs = Clock::now();
1391
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001392 std::vector<Job> jobQueue;
1393 ZipEntry entry;
1394 std::string_view fileName;
1395 while (!Next(cookie, &entry, &fileName)) {
1396 if (fileName.empty()) {
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001397 continue;
1398 }
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001399
1400 auto startFileTs = Clock::now();
1401
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001402 const auto libName = path::basename(fileName);
1403 const auto targetLibPath = path::join(libDirRelativePath, libName);
1404 const auto targetLibPathAbsolute = normalizePathToStorage(ifs, storage, targetLibPath);
1405 // If the extract file already exists, skip
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001406 if (access(targetLibPathAbsolute.c_str(), F_OK) == 0) {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001407 if (perfLoggingEnabled()) {
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001408 LOG(INFO) << "incfs: Native lib file already exists: " << targetLibPath
1409 << "; skipping extraction, spent "
1410 << elapsedMcs(startFileTs, Clock::now()) << "mcs";
1411 }
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001412 continue;
1413 }
1414
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001415 // Create new lib file without signature info
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001416 incfs::NewFileParams libFileParams = {
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001417 .size = entry.uncompressed_length,
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001418 .signature = {},
1419 // Metadata of the new lib file is its relative path
1420 .metadata = {targetLibPath.c_str(), (IncFsSize)targetLibPath.size()},
1421 };
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001422 incfs::FileId libFileId = idFromMetadata(targetLibPath);
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001423 if (auto res = mIncFs->makeFile(ifs->control, targetLibPathAbsolute, 0777, libFileId,
1424 libFileParams)) {
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001425 LOG(ERROR) << "Failed to make file for: " << targetLibPath << " errno: " << res;
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001426 // If one lib file fails to be created, abort others as well
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001427 return false;
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001428 }
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001429
1430 auto makeFileTs = Clock::now();
1431
Songchun Fanafaf6e92020-03-18 14:12:20 -07001432 // If it is a zero-byte file, skip data writing
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001433 if (entry.uncompressed_length == 0) {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001434 if (perfLoggingEnabled()) {
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001435 LOG(INFO) << "incfs: Extracted " << libName
1436 << "(0 bytes): " << elapsedMcs(startFileTs, makeFileTs) << "mcs";
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001437 }
Songchun Fanafaf6e92020-03-18 14:12:20 -07001438 continue;
1439 }
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001440
Yurii Zubrytskyi86321402020-04-09 19:22:30 -07001441 jobQueue.emplace_back([this, zipFile, entry, ifs = std::weak_ptr<IncFsMount>(ifs),
1442 libFileId, libPath = std::move(targetLibPath),
1443 makeFileTs]() mutable {
1444 extractZipFile(ifs.lock(), zipFile.get(), entry, libFileId, libPath, makeFileTs);
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001445 });
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001446
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001447 if (perfLoggingEnabled()) {
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001448 auto prepareJobTs = Clock::now();
1449 LOG(INFO) << "incfs: Processed " << libName << ": "
1450 << elapsedMcs(startFileTs, prepareJobTs)
1451 << "mcs, make file: " << elapsedMcs(startFileTs, makeFileTs)
1452 << " prepare job: " << elapsedMcs(makeFileTs, prepareJobTs);
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001453 }
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001454 }
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001455
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001456 auto processedTs = Clock::now();
1457
1458 if (!jobQueue.empty()) {
1459 {
1460 std::lock_guard lock(mJobMutex);
1461 if (mRunning) {
Yurii Zubrytskyi721ac4d2020-04-13 11:34:32 -07001462 auto& existingJobs = mJobQueue[ifs->mountId];
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001463 if (existingJobs.empty()) {
1464 existingJobs = std::move(jobQueue);
1465 } else {
1466 existingJobs.insert(existingJobs.end(), std::move_iterator(jobQueue.begin()),
1467 std::move_iterator(jobQueue.end()));
1468 }
1469 }
1470 }
1471 mJobCondition.notify_all();
1472 }
1473
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001474 if (perfLoggingEnabled()) {
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001475 auto end = Clock::now();
1476 LOG(INFO) << "incfs: configureNativeBinaries complete in " << elapsedMcs(start, end)
1477 << "mcs, make dirs: " << elapsedMcs(start, mkDirsTs)
1478 << " open zip: " << elapsedMcs(mkDirsTs, openZipTs)
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001479 << " make files: " << elapsedMcs(openZipTs, processedTs)
1480 << " schedule jobs: " << elapsedMcs(processedTs, end);
Yurii Zubrytskyi3787c9f2020-04-06 23:10:28 -07001481 }
1482
1483 return true;
Songchun Fan0f8b6fe2020-02-05 17:41:25 -08001484}
1485
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001486void IncrementalService::extractZipFile(const IfsMountPtr& ifs, ZipArchiveHandle zipFile,
1487 ZipEntry& entry, const incfs::FileId& libFileId,
1488 std::string_view targetLibPath,
1489 Clock::time_point scheduledTs) {
Yurii Zubrytskyi86321402020-04-09 19:22:30 -07001490 if (!ifs) {
1491 LOG(INFO) << "Skipping zip file " << targetLibPath << " extraction for an expired mount";
1492 return;
1493 }
1494
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001495 auto libName = path::basename(targetLibPath);
1496 auto startedTs = Clock::now();
1497
1498 // Write extracted data to new file
1499 // NOTE: don't zero-initialize memory, it may take a while for nothing
1500 auto libData = std::unique_ptr<uint8_t[]>(new uint8_t[entry.uncompressed_length]);
1501 if (ExtractToMemory(zipFile, &entry, libData.get(), entry.uncompressed_length)) {
1502 LOG(ERROR) << "Failed to extract native lib zip entry: " << libName;
1503 return;
1504 }
1505
1506 auto extractFileTs = Clock::now();
1507
1508 const auto writeFd = mIncFs->openForSpecialOps(ifs->control, libFileId);
1509 if (!writeFd.ok()) {
1510 LOG(ERROR) << "Failed to open write fd for: " << targetLibPath << " errno: " << writeFd;
1511 return;
1512 }
1513
1514 auto openFileTs = Clock::now();
1515 const int numBlocks =
1516 (entry.uncompressed_length + constants().blockSize - 1) / constants().blockSize;
1517 std::vector<IncFsDataBlock> instructions(numBlocks);
1518 auto remainingData = std::span(libData.get(), entry.uncompressed_length);
1519 for (int i = 0; i < numBlocks; i++) {
Yurii Zubrytskyi6c65a562020-04-14 15:25:49 -07001520 const auto blockSize = std::min<long>(constants().blockSize, remainingData.size());
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001521 instructions[i] = IncFsDataBlock{
1522 .fileFd = writeFd.get(),
1523 .pageIndex = static_cast<IncFsBlockIndex>(i),
1524 .compression = INCFS_COMPRESSION_KIND_NONE,
1525 .kind = INCFS_BLOCK_KIND_DATA,
Yurii Zubrytskyi6c65a562020-04-14 15:25:49 -07001526 .dataSize = static_cast<uint32_t>(blockSize),
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001527 .data = reinterpret_cast<const char*>(remainingData.data()),
1528 };
1529 remainingData = remainingData.subspan(blockSize);
1530 }
1531 auto prepareInstsTs = Clock::now();
1532
1533 size_t res = mIncFs->writeBlocks(instructions);
1534 if (res != instructions.size()) {
1535 LOG(ERROR) << "Failed to write data into: " << targetLibPath;
1536 return;
1537 }
1538
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001539 if (perfLoggingEnabled()) {
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001540 auto endFileTs = Clock::now();
1541 LOG(INFO) << "incfs: Extracted " << libName << "(" << entry.compressed_length << " -> "
1542 << entry.uncompressed_length << " bytes): " << elapsedMcs(startedTs, endFileTs)
1543 << "mcs, scheduling delay: " << elapsedMcs(scheduledTs, startedTs)
1544 << " extract: " << elapsedMcs(startedTs, extractFileTs)
1545 << " open: " << elapsedMcs(extractFileTs, openFileTs)
1546 << " prepare: " << elapsedMcs(openFileTs, prepareInstsTs)
1547 << " write: " << elapsedMcs(prepareInstsTs, endFileTs);
1548 }
1549}
1550
1551bool IncrementalService::waitForNativeBinariesExtraction(StorageId storage) {
Yurii Zubrytskyi721ac4d2020-04-13 11:34:32 -07001552 struct WaitPrinter {
1553 const Clock::time_point startTs = Clock::now();
1554 ~WaitPrinter() noexcept {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001555 if (perfLoggingEnabled()) {
Yurii Zubrytskyi721ac4d2020-04-13 11:34:32 -07001556 const auto endTs = Clock::now();
1557 LOG(INFO) << "incfs: waitForNativeBinariesExtraction() complete in "
1558 << elapsedMcs(startTs, endTs) << "mcs";
1559 }
1560 }
1561 } waitPrinter;
1562
1563 MountId mount;
1564 {
1565 auto ifs = getIfs(storage);
1566 if (!ifs) {
1567 return true;
1568 }
1569 mount = ifs->mountId;
1570 }
1571
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001572 std::unique_lock lock(mJobMutex);
Yurii Zubrytskyi721ac4d2020-04-13 11:34:32 -07001573 mJobCondition.wait(lock, [this, mount] {
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001574 return !mRunning ||
Yurii Zubrytskyi721ac4d2020-04-13 11:34:32 -07001575 (mPendingJobsMount != mount && mJobQueue.find(mount) == mJobQueue.end());
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001576 });
Yurii Zubrytskyi721ac4d2020-04-13 11:34:32 -07001577 return mRunning;
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001578}
1579
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001580bool IncrementalService::perfLoggingEnabled() {
1581 static const bool enabled = base::GetBoolProperty("incremental.perflogging", false);
1582 return enabled;
1583}
1584
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001585void IncrementalService::runJobProcessing() {
1586 for (;;) {
1587 std::unique_lock lock(mJobMutex);
1588 mJobCondition.wait(lock, [this]() { return !mRunning || !mJobQueue.empty(); });
1589 if (!mRunning) {
1590 return;
1591 }
1592
1593 auto it = mJobQueue.begin();
Yurii Zubrytskyi721ac4d2020-04-13 11:34:32 -07001594 mPendingJobsMount = it->first;
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001595 auto queue = std::move(it->second);
1596 mJobQueue.erase(it);
1597 lock.unlock();
1598
1599 for (auto&& job : queue) {
1600 job();
1601 }
1602
1603 lock.lock();
Yurii Zubrytskyi721ac4d2020-04-13 11:34:32 -07001604 mPendingJobsMount = kInvalidStorageId;
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001605 lock.unlock();
1606 mJobCondition.notify_all();
1607 }
1608}
1609
Alex Buynytskyy96e350b2020-04-02 20:03:47 -07001610void IncrementalService::registerAppOpsCallback(const std::string& packageName) {
Alex Buynytskyy1d892162020-04-03 23:00:19 -07001611 sp<IAppOpsCallback> listener;
1612 {
1613 std::unique_lock lock{mCallbacksLock};
1614 auto& cb = mCallbackRegistered[packageName];
1615 if (cb) {
1616 return;
1617 }
1618 cb = new AppOpsListener(*this, packageName);
1619 listener = cb;
1620 }
1621
Yurii Zubrytskyida208012020-04-07 15:35:21 -07001622 mAppOpsManager->startWatchingMode(AppOpsManager::OP_GET_USAGE_STATS,
1623 String16(packageName.c_str()), listener);
Alex Buynytskyy1d892162020-04-03 23:00:19 -07001624}
1625
1626bool IncrementalService::unregisterAppOpsCallback(const std::string& packageName) {
1627 sp<IAppOpsCallback> listener;
1628 {
1629 std::unique_lock lock{mCallbacksLock};
1630 auto found = mCallbackRegistered.find(packageName);
1631 if (found == mCallbackRegistered.end()) {
1632 return false;
1633 }
1634 listener = found->second;
1635 mCallbackRegistered.erase(found);
1636 }
1637
1638 mAppOpsManager->stopWatchingMode(listener);
1639 return true;
1640}
1641
1642void IncrementalService::onAppOpChanged(const std::string& packageName) {
1643 if (!unregisterAppOpsCallback(packageName)) {
Alex Buynytskyy96e350b2020-04-02 20:03:47 -07001644 return;
1645 }
1646
Alex Buynytskyy96e350b2020-04-02 20:03:47 -07001647 std::vector<IfsMountPtr> affected;
1648 {
1649 std::lock_guard l(mLock);
1650 affected.reserve(mMounts.size());
1651 for (auto&& [id, ifs] : mMounts) {
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001652 if (ifs->mountId == id && ifs->dataLoaderStub->params().packageName == packageName) {
Alex Buynytskyy96e350b2020-04-02 20:03:47 -07001653 affected.push_back(ifs);
1654 }
1655 }
1656 }
Alex Buynytskyy96e350b2020-04-02 20:03:47 -07001657 for (auto&& ifs : affected) {
Alex Buynytskyy1d892162020-04-03 23:00:19 -07001658 applyStorageParams(*ifs, false);
Alex Buynytskyy96e350b2020-04-02 20:03:47 -07001659 }
Alex Buynytskyy96e350b2020-04-02 20:03:47 -07001660}
1661
Alex Buynytskyyab65cb12020-04-17 10:01:47 -07001662IncrementalService::DataLoaderStub::DataLoaderStub(IncrementalService& service, MountId id,
1663 DataLoaderParamsParcel&& params,
1664 FileSystemControlParcel&& control,
1665 const DataLoaderStatusListener* externalListener)
1666 : mService(service),
1667 mId(id),
1668 mParams(std::move(params)),
1669 mControl(std::move(control)),
1670 mListener(externalListener ? *externalListener : DataLoaderStatusListener()) {
Alex Buynytskyyab65cb12020-04-17 10:01:47 -07001671}
1672
Alex Buynytskyy9a54579a2020-04-17 15:34:47 -07001673IncrementalService::DataLoaderStub::~DataLoaderStub() = default;
1674
1675void IncrementalService::DataLoaderStub::cleanupResources() {
1676 requestDestroy();
1677 mParams = {};
1678 mControl = {};
1679 waitForStatus(IDataLoaderStatusListener::DATA_LOADER_DESTROYED, std::chrono::seconds(60));
1680 mListener = {};
1681 mId = kInvalidStorageId;
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001682}
1683
Alex Buynytskyyab65cb12020-04-17 10:01:47 -07001684bool IncrementalService::DataLoaderStub::requestCreate() {
1685 return setTargetStatus(IDataLoaderStatusListener::DATA_LOADER_CREATED);
1686}
1687
1688bool IncrementalService::DataLoaderStub::requestStart() {
1689 return setTargetStatus(IDataLoaderStatusListener::DATA_LOADER_STARTED);
1690}
1691
1692bool IncrementalService::DataLoaderStub::requestDestroy() {
1693 return setTargetStatus(IDataLoaderStatusListener::DATA_LOADER_DESTROYED);
1694}
1695
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001696bool IncrementalService::DataLoaderStub::setTargetStatus(int newStatus) {
1697 int oldStatus, curStatus;
Alex Buynytskyy0b202662020-04-13 09:53:04 -07001698 {
1699 std::unique_lock lock(mStatusMutex);
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001700 oldStatus = mTargetStatus;
1701 mTargetStatus = newStatus;
Alex Buynytskyyab65cb12020-04-17 10:01:47 -07001702 mTargetStatusTs = Clock::now();
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001703 curStatus = mCurrentStatus;
Alex Buynytskyy0b202662020-04-13 09:53:04 -07001704 }
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001705 LOG(DEBUG) << "Target status update for DataLoader " << mId << ": " << oldStatus << " -> "
1706 << newStatus << " (current " << curStatus << ")";
Alex Buynytskyyab65cb12020-04-17 10:01:47 -07001707 return fsmStep();
1708}
1709
1710bool IncrementalService::DataLoaderStub::waitForStatus(int status, Clock::duration duration) {
1711 auto now = Clock::now();
1712 std::unique_lock lock(mStatusMutex);
1713 return mStatusCondition.wait_until(lock, now + duration,
1714 [this, status] { return mCurrentStatus == status; });
1715}
1716
1717bool IncrementalService::DataLoaderStub::create() {
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001718 bool created = false;
1719 auto status = mService.mDataLoaderManager->initializeDataLoader(mId, mParams, mControl, this,
1720 &created);
1721 if (!status.isOk() || !created) {
1722 LOG(ERROR) << "Failed to create a data loader for mount " << mId;
1723 return false;
1724 }
1725 return true;
1726}
1727
Alex Buynytskyy0b202662020-04-13 09:53:04 -07001728bool IncrementalService::DataLoaderStub::start() {
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001729 sp<IDataLoader> dataloader;
1730 auto status = mService.mDataLoaderManager->getDataLoader(mId, &dataloader);
1731 if (!status.isOk()) {
Alex Buynytskyyab65cb12020-04-17 10:01:47 -07001732 LOG(ERROR) << "Failed to get dataloader: " << status.toString8();
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001733 return false;
1734 }
1735 if (!dataloader) {
Alex Buynytskyyab65cb12020-04-17 10:01:47 -07001736 LOG(ERROR) << "DataLoader is null: " << status.toString8();
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001737 return false;
1738 }
1739 status = dataloader->start(mId);
1740 if (!status.isOk()) {
Alex Buynytskyyab65cb12020-04-17 10:01:47 -07001741 LOG(ERROR) << "Failed to start DataLoader: " << status.toString8();
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001742 return false;
1743 }
1744 return true;
1745}
1746
Alex Buynytskyyab65cb12020-04-17 10:01:47 -07001747bool IncrementalService::DataLoaderStub::destroy() {
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001748 mService.mDataLoaderManager->destroyDataLoader(mId);
Alex Buynytskyyab65cb12020-04-17 10:01:47 -07001749 return true;
Alex Buynytskyy0b202662020-04-13 09:53:04 -07001750}
1751
Alex Buynytskyyab65cb12020-04-17 10:01:47 -07001752bool IncrementalService::DataLoaderStub::fsmStep() {
Alex Buynytskyy9a54579a2020-04-17 15:34:47 -07001753 if (!isValid()) {
1754 return false;
1755 }
1756
Alex Buynytskyyab65cb12020-04-17 10:01:47 -07001757 int currentStatus;
1758 int targetStatus;
1759 {
1760 std::unique_lock lock(mStatusMutex);
1761 currentStatus = mCurrentStatus;
1762 targetStatus = mTargetStatus;
1763 }
1764
1765 if (currentStatus == targetStatus) {
1766 return true;
1767 }
1768
1769 switch (targetStatus) {
1770 case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: {
1771 return destroy();
1772 }
1773 case IDataLoaderStatusListener::DATA_LOADER_STARTED: {
1774 switch (currentStatus) {
1775 case IDataLoaderStatusListener::DATA_LOADER_CREATED:
1776 case IDataLoaderStatusListener::DATA_LOADER_STOPPED:
1777 return start();
1778 }
1779 // fallthrough
1780 }
1781 case IDataLoaderStatusListener::DATA_LOADER_CREATED:
1782 switch (currentStatus) {
1783 case IDataLoaderStatusListener::DATA_LOADER_DESTROYED:
1784 return create();
1785 }
1786 break;
1787 default:
1788 LOG(ERROR) << "Invalid target status: " << targetStatus
1789 << ", current status: " << currentStatus;
1790 break;
1791 }
1792 return false;
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001793}
1794
1795binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mountId, int newStatus) {
Alex Buynytskyy9a54579a2020-04-17 15:34:47 -07001796 if (!isValid()) {
1797 return binder::Status::
1798 fromServiceSpecificError(-EINVAL, "onStatusChange came to invalid DataLoaderStub");
1799 }
1800 if (mId != mountId) {
1801 LOG(ERROR) << "Mount ID mismatch: expected " << mId << ", but got: " << mountId;
1802 return binder::Status::fromServiceSpecificError(-EPERM, "Mount ID mismatch.");
1803 }
1804
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001805 int targetStatus, oldStatus;
Alex Buynytskyyab65cb12020-04-17 10:01:47 -07001806 {
1807 std::unique_lock lock(mStatusMutex);
1808 if (mCurrentStatus == newStatus) {
1809 return binder::Status::ok();
1810 }
1811 mCurrentStatus = newStatus;
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001812 oldStatus = mCurrentStatus;
1813 targetStatus = mTargetStatus;
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001814 }
1815
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001816 LOG(DEBUG) << "Current status update for DataLoader " << mId << ": " << oldStatus << " -> "
1817 << newStatus << " (target " << targetStatus << ")";
1818
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001819 if (mListener) {
Alex Buynytskyy0ea4ff42020-04-09 17:25:42 -07001820 mListener->onStatusChanged(mountId, newStatus);
1821 }
1822
Alex Buynytskyyab65cb12020-04-17 10:01:47 -07001823 fsmStep();
Songchun Fan3c82a302019-11-29 14:23:45 -08001824
Alex Buynytskyyc2a645d2020-04-20 14:11:55 -07001825 mStatusCondition.notify_all();
1826
Songchun Fan3c82a302019-11-29 14:23:45 -08001827 return binder::Status::ok();
1828}
1829
Alex Buynytskyyab65cb12020-04-17 10:01:47 -07001830void IncrementalService::DataLoaderStub::onDump(int fd) {
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001831 dprintf(fd, " dataLoader: {\n");
1832 dprintf(fd, " currentStatus: %d\n", mCurrentStatus);
1833 dprintf(fd, " targetStatus: %d\n", mTargetStatus);
1834 dprintf(fd, " targetStatusTs: %lldmcs\n",
Alex Buynytskyyab65cb12020-04-17 10:01:47 -07001835 (long long)(elapsedMcs(mTargetStatusTs, Clock::now())));
1836 const auto& params = mParams;
Yurii Zubrytskyi629051fd2020-04-17 23:13:47 -07001837 dprintf(fd, " dataLoaderParams: {\n");
1838 dprintf(fd, " type: %s\n", toString(params.type).c_str());
1839 dprintf(fd, " packageName: %s\n", params.packageName.c_str());
1840 dprintf(fd, " className: %s\n", params.className.c_str());
1841 dprintf(fd, " arguments: %s\n", params.arguments.c_str());
1842 dprintf(fd, " }\n");
1843 dprintf(fd, " }\n");
Alex Buynytskyyab65cb12020-04-17 10:01:47 -07001844}
1845
Alex Buynytskyy1d892162020-04-03 23:00:19 -07001846void IncrementalService::AppOpsListener::opChanged(int32_t, const String16&) {
1847 incrementalService.onAppOpChanged(packageName);
Alex Buynytskyy96e350b2020-04-02 20:03:47 -07001848}
1849
Alex Buynytskyyf4156792020-04-07 14:26:55 -07001850binder::Status IncrementalService::IncrementalServiceConnector::setStorageParams(
1851 bool enableReadLogs, int32_t* _aidl_return) {
1852 *_aidl_return = incrementalService.setStorageParams(storage, enableReadLogs);
1853 return binder::Status::ok();
1854}
1855
Alex Buynytskyy0b202662020-04-13 09:53:04 -07001856FileId IncrementalService::idFromMetadata(std::span<const uint8_t> metadata) {
1857 return IncFs_FileIdFromMetadata({(const char*)metadata.data(), metadata.size()});
1858}
1859
Songchun Fan3c82a302019-11-29 14:23:45 -08001860} // namespace android::incremental